Bir veya daha fazla sınıfları ile konum uğraşan Eğer varsa edemez içeriden değiştirmek de bir fark özgü kütüphanesine bağlı olmadığını Bunu yapmak için genel ve basit yolu vardır:
En kolay, çok karmaşık nesneler için güvenli olmayan yöntem
pickle.dumps(a) == pickle.dumps(b)
pickle
Python nesneleri için çok yaygın bir serileştirme kütüphanesidir ve böylece hemen hemen her şeyi serileştirebilecektir. Yukarıdaki kod parçasında str
serileştirilmiş a
olan ile karşılaştırıyorum b
. Bir sonraki yöntemin aksine, bu da özel sınıfları kontrol etme avantajına sahiptir.
En büyük güçlük: belirli sıralama ve [de / en] kodlama yöntemleri pickle
nedeniyle , özellikle sık karşılaşacağınız gibi daha karmaşık olanlarla (örneğin iç içe geçmiş özel sınıf örneklerinin listeleri) uğraşırken eşit nesneler için aynı sonucu vermeyebilir. bazı üçüncü taraf kütüphanelerinde. Bu durumlar için farklı bir yaklaşım öneriyorum:
Kapsamlı, her nesne için güvenli yöntem
Size serileştirilebilir nesneler verecek yinelemeli bir yansıma yazabilir ve ardından sonuçları karşılaştırabilirsiniz
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:])
Şimdi nesnelerinizin ne olduğu önemli değil, derin eşitliğin çalışması güvence altında
>>> 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
Karşılaştırılabilirlerin sayısı da önemli değil
>>> c = RandomForestClassifier(max_depth=2, random_state=1000)
>>> deep_equals(a, b, c)
False
Bunun için benim durumum BDD testleri içinde zaten eğitilmiş olan çeşitli Machine Learning modelleri arasında derin eşitliği kontrol etmekti . Modeller çok çeşitli üçüncü taraf kütüphanelerine aitti. Kesinlikle __eq__
burada diğer cevaplar gibi uygulamak benim için bir seçenek değildi.
Tüm üsleri kapsayan
Karşılaştırılan bir veya daha fazla özel sınıfın bir __dict__
uygulaması olmadığı bir senaryoda olabilirsiniz . Bu, hiçbir şekilde yaygın değil ama sklearn en Rastgele Orman sınıflandırıcı içerisinde bir alt türü geçerlidir: <type 'sklearn.tree._tree.Tree'>
. Bu durumları duruma göre ele alın - örneğin, özellikle , etkilenen türün içeriğini, örnek hakkında temsili bilgi veren bir yöntemin içeriğiyle değiştirmeye karar verdim (bu durumda __getstate__
yöntem). Böyle, ikinci-to-son sırada base_typed
oldu
d = obj if T is dict else obj.__dict__ if '__dict__' in dir(obj) else obj.__getstate__()
Düzenleme: organizasyonun uğruna, ben son iki satır değiştirilir base_typed
ile return dict_from(obj)
(Ben, size Doc2Vec arıyorum) ve daha belirsiz kütüphanelerini barındıracak şekilde gerçekten jenerik yansıması hayata
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()}
Yukarıdaki yöntemlerden hiçbirinin True
, aynı anahtar / değer çiftlerine sahip ancak farklı anahtar / değer siparişlerine sahip farklı nesneler için vermediğini unutmayın .
>>> a = {'foo':[], 'bar':{}}
>>> b = {'bar':{}, 'foo':[]}
>>> pickle.dumps(a) == pickle.dumps(b)
False
Ancak isterseniz Python'un yerleşik sorted
yöntemini önceden kullanabilirsiniz.
return NotImplemented
(Yükseltmek yerineNotImplementedError
) kullanımını merak ettim . Bu konu burada ele alınmıştır: stackoverflow.com/questions/878943/…