यदि आप एक या अधिक वर्गों के साथ काम कर रहे हैं, जो आप अंदर से नहीं बदल सकते हैं , तो ऐसा करने के लिए सामान्य और सरल तरीके हैं जो एक विशिष्ट-विशिष्ट पुस्तकालय पर निर्भर नहीं करते हैं:
सबसे आसान, असुरक्षित-बहुत-जटिल-वस्तुओं के लिए विधि
pickle.dumps(a) == pickle.dumps(b)
pickle
पायथन वस्तुओं के लिए एक बहुत ही सामान्य क्रमबद्धता परिवाद है, और इस प्रकार वास्तव में बहुत अधिक कुछ भी प्रसारित करने में सक्षम होगा। उपरोक्त स्निपेट में मैं str
धारावाहिक से तुलना कर रहा हूं a
जिसमें से एक है b
। अगली विधि के विपरीत, यह भी कस्टम वर्गों की जाँच प्रकार का लाभ है।
सबसे बड़ी परेशानी: विशिष्ट आदेश देने और [डी / एन] कोडिंग विधियों के pickle
कारण, समान वस्तुओं के लिए एक ही परिणाम नहीं मिल सकता है , खासकर जब अधिक जटिल लोगों (जैसे नेस्टेड कस्टम-क्लास इंस्टेंसेस की सूची) जैसे कि आप अक्सर पाएंगे। कुछ तृतीय-पक्षीय परिवादों में। उन मामलों के लिए, मैं एक अलग दृष्टिकोण सुझाऊँगा:
पूरी तरह से, सुरक्षित-किसी भी वस्तु के लिए विधि
आप एक पुनरावर्ती प्रतिबिंब लिख सकते हैं जो आपको क्रमबद्ध वस्तुएं देगा, और फिर परिणामों की तुलना करेगा
from collections.abc import Iterable
BASE_TYPES = [str, int, float, bool, type(None)]
def base_typed(obj):
"""Recursive reflection method to convert any object property into a comparable form.
"""
T = type(obj)
from_numpy = T.__module__ == 'numpy'
if T in BASE_TYPES or callable(obj) or (from_numpy and not isinstance(T, Iterable)):
return obj
if isinstance(obj, Iterable):
base_items = [base_typed(item) for item in obj]
return base_items if from_numpy else T(base_items)
d = obj if T is dict else obj.__dict__
return {k: base_typed(v) for k, v in d.items()}
def deep_equals(*args):
return all(base_typed(args[0]) == base_typed(other) for other in args[1:])
अब इससे कोई फर्क नहीं पड़ता कि आपकी वस्तुएं क्या हैं, गहरी समानता काम करने का आश्वासन देती है
>>> from sklearn.ensemble import RandomForestClassifier
>>>
>>> a = RandomForestClassifier(max_depth=2, random_state=42)
>>> b = RandomForestClassifier(max_depth=2, random_state=42)
>>>
>>> deep_equals(a, b)
True
तुलनाओं की संख्या भी मायने नहीं रखती है
>>> c = RandomForestClassifier(max_depth=2, random_state=1000)
>>> deep_equals(a, b, c)
False
इसके लिए मेरा उपयोग मामला BDD परीक्षणों के अंदर पहले से प्रशिक्षित मशीन लर्निंग मॉडल के विविध सेट के बीच गहरी समानता की जाँच कर रहा था । मॉडल तीसरे पक्ष के लिबास के विविध सेट के थे। निश्चित रूप से __eq__
अन्य उत्तरों की तरह यहां लागू करना मेरे लिए एक विकल्प नहीं था।
सभी ठिकानों को कवर करना
आप एक ऐसे परिदृश्य में हो सकते हैं जहां एक या एक से अधिक कस्टम वर्ग की तुलना में __dict__
कार्यान्वयन नहीं होता है । यह किसी भी तरह से सामान्य नहीं है, लेकिन यह स्केलेर के रैंडम फॉरेस्ट क्लासिफायर के भीतर एक उपप्रकार का मामला है <type 'sklearn.tree._tree.Tree'>
:। केस के आधार पर किसी स्थिति में इन स्थितियों का इलाज करें - उदाहरण के लिए , विशेष रूप से , मैंने पीड़ित प्रकार की सामग्री को एक विधि की सामग्री के साथ बदलने का फैसला किया है जो मुझे उदाहरण पर प्रतिनिधि जानकारी देता है (इस मामले में, __getstate__
विधि)। इस तरह, दूसरी-से-अंतिम पंक्ति base_typed
बन गई
d = obj if T is dict else obj.__dict__ if '__dict__' in dir(obj) else obj.__getstate__()
संपादित करें: संगठन के लिए, मैं के अंतिम दो पंक्तियों की जगह base_typed
के साथ return dict_from(obj)
, और अधिक अस्पष्ट libs समायोजित करने के लिए एक बहुत सामान्य प्रतिबिंब लागू किया (मैं, तुम पर देख रहा हूँ Doc2Vec)
def isproperty(prop, obj):
return not callable(getattr(obj, prop)) and not prop.startswith('_')
def dict_from(obj):
"""Converts dict-like objects into dicts
"""
if isinstance(obj, dict):
# Dict and subtypes are directly converted
d = dict(obj)
elif '__dict__' in dir(obj):
d = obj.__dict__
elif str(type(obj)) == 'sklearn.tree._tree.Tree':
# Replaces sklearn trees with their state metadata
d = obj.__getstate__()
else:
# Extract non-callable, non-private attributes with reflection
kv = [(p, getattr(obj, p)) for p in dir(obj) if isproperty(p, obj)]
d = {k: v for k, v in kv}
return {k: base_typed(v) for k, v in d.items()}
उपरोक्त विधियों में से कोई भी True
एक ही कुंजी-मान वाले जोड़े के साथ अलग-अलग ऑब्जेक्ट्स के लिए उपज नहीं है, लेकिन अलग-अलग कुंजी / मूल्य आदेश, जैसे
>>> a = {'foo':[], 'bar':{}}
>>> b = {'bar':{}, 'foo':[]}
>>> pickle.dumps(a) == pickle.dumps(b)
False
लेकिन अगर आप चाहते हैं कि आप sorted
वैसे भी पहले से पाइथन की अंतर्निहित विधि का उपयोग कर सकते हैं ।
return NotImplemented
(उठाने के बजायNotImplementedError
) के उपयोग को लेकर उत्सुक था । उस विषय को यहां शामिल किया गया है: stackoverflow.com/questions/878943/…