DÜZENLEME : Tüm anahtarlarınız dize ise , bu yanıtı okumaya devam etmeden önce, lütfen Jack O'Connor'ın önemli ölçüde daha basit (ve daha hızlı) çözümüne bakın (bu da iç içe sözlükler için de geçerlidir).
Her ne kadar bir cevap kabul edilmiş olsa da, sorunun başlığı "bir python sözlüğünü karıştırmak" tır ve bu başlık ile ilgili cevap eksiktir. (Sorunun içeriği ile ilgili olarak cevap tamamlandı.)
İç İçe Sözlükler
Bir sözlük nasıl karmalaştırılacağı için Stack Overflow ararsa, bu uygun başlıklı soruya rastlayabilir ve iç içe sözlükleri çoğaltmaya çalışıyorsa tatminsiz bırakılabilir. Yukarıdaki cevap bu durumda işe yaramaz ve hash'ı almak için bir çeşit özyinelemeli mekanizma uygulamanız gerekir.
İşte böyle bir mekanizma:
import copy
def make_hash(o):
"""
Makes a hash from a dictionary, list, tuple or set to any level, that contains
only other hashable types (including any lists, tuples, sets, and
dictionaries).
"""
if isinstance(o, (set, tuple, list)):
return tuple([make_hash(e) for e in o])
elif not isinstance(o, dict):
return hash(o)
new_o = copy.deepcopy(o)
for k, v in new_o.items():
new_o[k] = make_hash(v)
return hash(tuple(frozenset(sorted(new_o.items()))))
Bonus: Nesneleri ve Sınıfları Karma
hash()
Eğer sınıfları veya örneklerini karma zaman fonksiyonu iyi çalışıyor. Ancak, nesnelerle ilgili olarak karma ile bulduğum bir sorun var:
class Foo(object): pass
foo = Foo()
print (hash(foo)) # 1209812346789
foo.a = 1
print (hash(foo)) # 1209812346789
Çileyi değiştirdikten sonra bile karma aynı. Çünkü foo kimliği değişmedi, bu yüzden karma aynı. Foo'nun mevcut tanımına bağlı olarak farklı şekilde karma yapmasını istiyorsanız, çözüm aslında değişen her şeyi karma etmektir. Bu durumda, __dict__
özellik:
class Foo(object): pass
foo = Foo()
print (make_hash(foo.__dict__)) # 1209812346789
foo.a = 1
print (make_hash(foo.__dict__)) # -78956430974785
Ne yazık ki, sınıfın kendisiyle aynı şeyi yapmaya çalıştığınızda:
print (make_hash(Foo.__dict__)) # TypeError: unhashable type: 'dict_proxy'
Class __dict__
özelliği normal bir sözlük değildir:
print (type(Foo.__dict__)) # type <'dict_proxy'>
Sınıfları uygun şekilde işleyecek öncekine benzer bir mekanizma:
import copy
DictProxyType = type(object.__dict__)
def make_hash(o):
"""
Makes a hash from a dictionary, list, tuple or set to any level, that
contains only other hashable types (including any lists, tuples, sets, and
dictionaries). In the case where other kinds of objects (like classes) need
to be hashed, pass in a collection of object attributes that are pertinent.
For example, a class can be hashed in this fashion:
make_hash([cls.__dict__, cls.__name__])
A function can be hashed like so:
make_hash([fn.__dict__, fn.__code__])
"""
if type(o) == DictProxyType:
o2 = {}
for k, v in o.items():
if not k.startswith("__"):
o2[k] = v
o = o2
if isinstance(o, (set, tuple, list)):
return tuple([make_hash(e) for e in o])
elif not isinstance(o, dict):
return hash(o)
new_o = copy.deepcopy(o)
for k, v in new_o.items():
new_o[k] = make_hash(v)
return hash(tuple(frozenset(sorted(new_o.items()))))
İstediğiniz birçok öğenin karma grubunu döndürmek için bunu kullanabilirsiniz:
# -7666086133114527897
print (make_hash(func.__code__))
# (-7666086133114527897, 3527539)
print (make_hash([func.__code__, func.__dict__]))
# (-7666086133114527897, 3527539, -509551383349783210)
print (make_hash([func.__code__, func.__dict__, func.__name__]))
NOT: yukarıdaki kodların tümü Python 3.x'i varsayar. make_hash()
2.7.2 'de çalışacağını varsaysam da önceki sürümlerde test yapmadım. Uzak örnekler işi yapmak kadar, ben do biliyorum
func.__code__
ile değiştirilmelidir
func.func_code