对Python数据类使用标识哈希

对Python数据类使用标识哈希,python,identity,Python,Identity,我有以下域驱动设计意义上的文件管理器实体 from dataclasses import dataclass, field @dataclass class Address: street: str city: str state: str zipcode: str @dataclass class Filer: cik: int name: str = field(hash=False, compare=True) state: st

我有以下域驱动设计意义上的文件管理器实体

from dataclasses import dataclass, field

@dataclass
class Address:
    street: str
    city: str
    state: str
    zipcode: str

@dataclass
class Filer:
    cik: int
    name: str = field(hash=False, compare=True)
    state: str = field(hash=False, compare=True)
    yearend: str = field(hash=False, compare=True)
    businessaddress: Address = field(hash=False, compare=True)
    mailingaddress: Address = field(hash=False, compare=True)
    sic: int = field(hash=False, compare=True)
    ein: str = field(hash=False, compare=True, default=None)
对于任何文件管理器,cik本身决定身份。但是,我希望使用平等性比较来查看有关文件管理器的任何其他详细信息是否发生了变化,例如与同一文件管理器的早期版本相比。在此基础上,我在所有字段上设置hash=False,compare=True,默认情况下cik的hash=True除外

以下测试用例提供了预期行为的快速概述:

身份:完全由cik确定,并通过断言和断言进行测试 相等性:由所有字段确定,并通过AssertEqual和AssertNotEqual进行测试 结果并没有达到预期的效果

base) randm@pearljam /home/randm/Projects/secfilings $ /home/randm/Libraries/anaconda3/bin/python /home/randm/Projects/scrap/filer.py
....FF
======================================================================
FAIL: test_identity_same_filer (__main__.TestFiler)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/randm/Projects/scrap/filer.py", line 51, in test_identity_same_filer
    self.assertIs(a, b)
AssertionError: Filer(cik=1234, name='Some company', state='Some state', yearend='0930', businessaddress=Address(street='Some address', city='Some city', state='AB', zipcode='12345'), mailingaddress=Address(street='Some address', city='Some city', state='AB', zipcode='12345'), sic=1000, ein=1234567) is not Filer(cik=1234, name='Some company', state='Some state', yearend='0930', businessaddress=Address(street='Some address', city='Some city', state='AB', zipcode='12345'), mailingaddress=Address(street='Some address', city='Some city', state='AB', zipcode='12345'), sic=1000, ein=1234567)

======================================================================
FAIL: test_identity_same_filer_new_name (__main__.TestFiler)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/randm/Projects/scrap/filer.py", line 77, in test_identity_same_filer_new_name
    self.assertIs(a, b)
AssertionError: Filer(cik=1234, name='Some company', state='Some state', yearend='0930', businessaddress=Address(street='Some address', city='Some city', state='AB', zipcode='12345'), mailingaddress=Address(street='Some address', city='Some city', state='AB', zipcode='12345'), sic=1000, ein=1234567) is not Filer(cik=1234, name='A new name for the company', state='Some state', yearend='0930', businessaddress=Address(street='Some address', city='Some city', state='AB', zipcode='12345'), mailingaddress=Address(street='Some address', city='Some city', state='AB', zipcode='12345'), sic=1000, ein=1234567)

----------------------------------------------------------------------
Ran 6 tests in 0.001s

FAILED (failures=2)

有没有一种方法可以让我使用Is身份测试,而不用求助于dataclass方法Is_uu或类似的东西,这会改变我在客户机代码中寻找的干净语法。或者我只是误用了我认为基于CPython中指针值的标识,而应该在我的客户机代码中显式地使用哈希相等?

您没有使用断言。它使用python的is行为。也就是说,它们必须引用同一个对象。由于您构建了两个不同的对象,因此它们之间的is测试将始终为false。Equals是正确的等价性测试。

您无法使用断言。它使用python的is行为。也就是说,它们必须引用同一个对象。由于您构建了两个不同的对象,因此它们之间的is测试将始终为false。Equals是对等价性的正确测试。

没有办法覆盖Python的is标识检查。它将始终指的是实际相同的对象。有点适合弦乐,但是

您可以在数据类定义中使用hasha==hashb。但是,如果你想让它感觉更自然,那么你也可以创建一个方法is_u,并执行a.is_ub。请注意,如果您的类中有其他用户/编码者,则需要明确is_uu何时为真,而==何时为假;和所有其他组合

@dataclass(unsafe_hash=True)
Filer:
    ...  # everything else the same
然后,您的身份测试将基于散列

此外,您应该对a和b使用测试,而不是在每个测试中复制粘贴它们。像我们这样阅读您的代码的人仍然需要在每个测试中检查两者的整个定义,看看有什么不同。一个月后,你也会。对于仅与测试略有不同的对象,请使用

下面是一个更易于阅读的单元测试版本,其中添加了基于哈希的检查:

导入数据类 导入单元测试 类TestFilerunittest.TestCase: def设置自我: self.a=Filer1234,一些公司,一些州,0930, 地址一些地址,一些城市,AB,12345, 地址一些地址,一些城市,AB,12345, 1000, 1234567 self.b=Filer1234,一些公司,一些州,0930, 地址一些地址,一些城市,AB,12345, 地址一些地址,一些城市,AB,12345, 1000, 1234567 def测试\u相等\u相同\u文件本身: self.assertEqualself.a,self.b def测试_标识_相同_文件自身:仍将失败 自我,自我,自我 def test_equality_same_filer_new_nameself: 请明确说明'a'和'c'只因名称不同: c=dataclasses.replaceself.a,name=公司的新名称 self.assertNotEqualself.a,c def test_identity_same_filer_new_nameself:仍将失败 或者把c也放在setUp中` c=dataclasses.replaceself.a,name=公司的新名称 自我主张自我主张 def测试\u相等\u不同\u文件服务器\u相同\u详细信息自身: new_a=dataclasses.replaceself.a,cik=4321 自我主张新的,自我,更好的 def测试\u标识\u不同\u文件管理器\u相同\u详细信息自身: new_a=dataclasses.replaceself.a,cik=4321 自我主张新的,自我 def test_hash_same_filerself:新建 self.assertEqualhashself.a,hashself.b def test_hash_same_filer_new_name self:new c=dataclasses.replaceself.a,name=公司的新名称 self.assertEqualhashc,hashself.a def测试\u标识\u不同\u文件管理器\u相同\u详细信息自身:新建 diff_a=dataclasses.replaceself.a,cik=4321 self.assertNotEqualhashdiff_a,hashself.a 如果uuuu name uuuuu==\uuuuuuuu main\uuuuuuuu: unittest.main
也没有办法覆盖Python的is标识检查。它将始终指的是实际相同的对象。有点适合弦乐,但是

您可以在数据类定义中使用hasha==hashb。但是,如果你想让它感觉更自然,那么你也可以创建一个方法is_u,并执行a.is_ub。请注意,如果您的类中有其他用户/编码者,则需要明确is_uu何时为真,而==何时为假;和所有其他组合

@dataclass(unsafe_hash=True)
Filer:
    ...  # everything else the same
然后是y 我们的身份测试将基于散列

此外,您应该对a和b使用测试,而不是在每个测试中复制粘贴它们。像我们这样阅读您的代码的人仍然需要在每个测试中检查两者的整个定义,看看有什么不同。一个月后,你也会。对于仅与测试略有不同的对象,请使用

下面是一个更易于阅读的单元测试版本,其中添加了基于哈希的检查:

导入数据类 导入单元测试 类TestFilerunittest.TestCase: def设置自我: self.a=Filer1234,一些公司,一些州,0930, 地址一些地址,一些城市,AB,12345, 地址一些地址,一些城市,AB,12345, 1000, 1234567 self.b=Filer1234,一些公司,一些州,0930, 地址一些地址,一些城市,AB,12345, 地址一些地址,一些城市,AB,12345, 1000, 1234567 def测试\u相等\u相同\u文件本身: self.assertEqualself.a,self.b def测试_标识_相同_文件自身:仍将失败 自我,自我,自我 def test_equality_same_filer_new_nameself: 请明确说明'a'和'c'只因名称不同: c=dataclasses.replaceself.a,name=公司的新名称 self.assertNotEqualself.a,c def test_identity_same_filer_new_nameself:仍将失败 或者把c也放在setUp中` c=dataclasses.replaceself.a,name=公司的新名称 自我主张自我主张 def测试\u相等\u不同\u文件服务器\u相同\u详细信息自身: new_a=dataclasses.replaceself.a,cik=4321 自我主张新的,自我,更好的 def测试\u标识\u不同\u文件管理器\u相同\u详细信息自身: new_a=dataclasses.replaceself.a,cik=4321 自我主张新的,自我 def test_hash_same_filerself:新建 self.assertEqualhashself.a,hashself.b def test_hash_same_filer_new_name self:new c=dataclasses.replaceself.a,name=公司的新名称 self.assertEqualhashc,hashself.a def测试\u标识\u不同\u文件管理器\u相同\u详细信息自身:新建 diff_a=dataclasses.replaceself.a,cik=4321 self.assertNotEqualhashdiff_a,hashself.a 如果uuuu name uuuuu==\uuuuuuuu main\uuuuuuuu: unittest.main