我正在开发一个基于代理的模型,其中我使用不同类型的代理类,这些类的实例被分配给不同类型的对象,例如学校、公司、家庭等。我遇到的问题是我在调试时无法强制执行运行的再现性,由于模型的复杂性,这使得任务变得非常困难。经过长时间的调查,我意识到问题与集合的顺序有关(当然应用了内置的随机和 numpy 随机种子)。即使我设置了 PYHTONHASHSEED=0,我也观察到每次运行时集合的顺序是随机的。当代理移动时,这使得我的模型的每次运行都不同。
当然,我知道套装并不意味着有订单。当从对象中移除代理时,我想使用它们使模型尽可能轻巧和快速。我希望它们的行为是随机的,除非我需要调试引发异常的特定运行。
我添加了以下代码,以便可以验证我的声明。在启动代码之前,我总是通过导出从命令行设置 PYTHONHASHSEED。我从代码打印 PYTHONHASHSEED 值以检查该值是否确实已更新
import os
import random
import numpy as np
print('PYTHON HASH SEED IS', os.environ['PYTHONHASHSEED'])
random.seed(1)
np.random.seed(2)
class S:
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return "".join([type(self).__name__, "_{0.a!r}_",
"School", "_{0.b!r}" ]).format(self)
list1 = np.random.randint(1, 100,size=40)
list2 = np.random.randint(1, 10,size=40)
d1 = dict()
s1 = set()
d1['students'] = s1
# assign students to d1
for s_id, sch_id in zip(list1, list2):
d1['students'].add(S(s_id, sch_id))
print(s1)
Run Code Online (Sandbox Code Playgroud)
奇怪的是,如果我使用整数作为集合成员而不是类实例,则无法检测到随机性。问题是否与集合成员是类实例这一事实有关?为什么 ?
当然,我可以重塑代理分配给模型对象的方式,并用列表替换集合,但如果可能的话,我想了解这个问题。我使用的版本是python 3.5.4
我注意到当我使用用户定义的对象(覆盖__hash__方法)作为Python中我的dicts的键时,查找时间至少增加了5倍.
即使我使用非常基本的哈希方法,例如在以下示例中,也会观察到此行为:
class A:
def __init__(self, a):
self.a = a
def __hash__(self):
return hash(self.a)
def __eq__(self, other):
if not isinstance(other, A):
return NotImplemented
return (self.a == other.a and self.__class__ ==
other.__class__)
# get an instance of class A
mya = A(42)
# define dict
d1={mya:[1,2], 'foo':[3,4]}
Run Code Online (Sandbox Code Playgroud)
如果我通过两个不同的键进行访问,我会发现性能存在显着差异
%timeit d1['foo']
Run Code Online (Sandbox Code Playgroud)
结果约为100 ns.而
%timeit d1[mya]
Run Code Online (Sandbox Code Playgroud)
结果约为600 ns.
如果我删除覆盖__hash__和__eq__方法,性能与默认对象的级别相同
有没有办法避免性能损失并仍然实现自定义哈希计算?