标签: python-dataclasses

在数据类上的自定义“__init__”重写中调用生成的“__init__”

目前我有这样的事情:

@dataclass(frozen=True)
class MyClass:
  a: str
  b: str
  c: str
  d: Dict[str, str]
Run Code Online (Sandbox Code Playgroud)

...这一切都很好,除了dicts 是可变的,所以我不能使用我的类来键入另一本字典。

相反,我希望 fieldd类似于 a FrozenSet[Tuple[str, str]],但我仍然希望有人构造我的类的实例,以便能够在构造函数上传递字典,因为这更直观。

所以我想做一些类似的事情

@dataclass(frozen=True)
class MyClass:
  a: str
  b: str
  c: str
  d: FrozenSet[Tuple[str, str]] = field(init=False)

  def __init__(self, a, b, c, d: Dict[str, str]):
    self.original_generated_init(a, b, c)  # ???
    object.setattr(self, 'd', frozenset(d.items()))  # required because my dataclass is frozen
Run Code Online (Sandbox Code Playgroud)

我该如何实现这一目标?或者有没有更优雅的方法来实现同样的事情?

python python-3.x python-dataclasses

6
推荐指数
2
解决办法
4945
查看次数

Python:如何从数据类中获取属性及其类型?

我想从(数据)类中读取所有属性及其类型,如所需的(伪)代码所示:

from dataclasses import dataclass


@dataclass
class HelloWorld:
    name: str = 'Earth'
    is_planet: bool = True
    radius: int = 6371


if __name__ == '__main__':
    attrs = get_attributes(HelloWorld)
    for attr in attrs:
        print(attr.name, attr.type)  # name, str
Run Code Online (Sandbox Code Playgroud)

我检查了几个答案,但还找不到我需要的东西。

任何想法?提前致谢!

python oop python-dataclasses

6
推荐指数
1
解决办法
2万
查看次数

如何模拟数据类

我如何创建一个可以在其上运行的dataclass模拟asdict

这似乎不起作用:

>>> from dataclasses import dataclass, asdict
>>> @dataclass
... class A:
...     foo: int
>>> asdict(A(foo=1))
{'foo': 1}
>>> from unittest import mock
>>>
>>> asdict(mock.create_autospec(A))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.8/dataclasses.py", line 1072, in asdict
    raise TypeError("asdict() should be called on dataclass instances")
TypeError: asdict() should be called on dataclass instances
Run Code Online (Sandbox Code Playgroud)

注:Python 3.8.5

python python-dataclasses

6
推荐指数
0
解决办法
899
查看次数

如果分配了不同的字段类型,如何使用数据类装饰类以引发错误?

我不确定我做错了什么。当传递不同类型的输入时,如何防止 Test 类接受和抛出错误。我正在使用Python 3.9.2

from dataclasses import dataclass, fields


@dataclass
class Test:
    a: str = 'a'
    b: int = 1


t = Test(2, 'b')

print(fields(t))
print(type(t.a))
print(type(t.b))

# output
# (venv) D:\Playground>python dataClassesTest.py
# (Field(name='a',type=<class 'str'>,default='a',default_factory=<dataclasses._MISSING_TYPE object at 0x00000232952D5880>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD), Field(name='b',type=<class 'int'>,default=1,default_factory=<dataclasses._MISSING_TYPE object at 0x00000232952D5880>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD))
# <class 'int'>
# <class 'str'>
Run Code Online (Sandbox Code Playgroud)

python-3.x python-dataclasses

6
推荐指数
1
解决办法
2538
查看次数

如何比较数据类?

我想比较两个全局数据类的相等性。我更改了其中一个数据类中的字段,但 python 仍然坚持告诉我,这些对象是相等的。我不知道数据类内部如何工作,但是当我打印时,asdict我得到一个空字典...我做错了什么以及如何通过检查其成员的相等性来比较数据类?

我正在使用Python 3.9.4

from dataclasses import dataclass, asdict

@dataclass
class TestClass:
    field1 = None
    field2 = False

test1 = TestClass()
test2 = TestClass()

def main():
    global test1
    global test2

    test2.field2 = True

    print('Test1:        ', id(test1), asdict(test1), test1.field1, test1.field2)
    print('Test2:        ', id(test2), asdict(test2), test2.field1, test2.field2)
    print('Are equal?    ', test1 == test2)
    print('Are not equal?', test1 != test2)

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

输出:

Test1:         2017289121504 {} None False
Test2:         2017289119296 {} None True
Are equal?     True
Are …
Run Code Online (Sandbox Code Playgroud)

python python-3.x python-dataclasses

6
推荐指数
1
解决办法
6975
查看次数

如何让 Python 数据类 InitVar 字段与 Typing.get_type_hints 一起使用,同时还使用注释?

当处理 Python 数据类时,我遇到了这个很容易重现的奇怪错误。

from __future__ import annotations

import dataclasses as dc
import typing

@dc.dataclass
class Test:
    foo: dc.InitVar[int]

print(typing.get_type_hints(Test))
Run Code Online (Sandbox Code Playgroud)

运行它会得到以下结果:

Traceback (most recent call last):
  File "test.py", line 11, in <module>
    print(typing.get_type_hints(Test))
  File "C:\Program Files\Python310\lib\typing.py", line 1804, in get_type_hints
    value = _eval_type(value, base_globals, base_locals)
  File "C:\Program Files\Python310\lib\typing.py", line 324, in _eval_type
    return t._evaluate(globalns, localns, recursive_guard)
  File "C:\Program Files\Python310\lib\typing.py", line 687, in _evaluate
    type_ =_type_check(
  File "C:\Program Files\Python310\lib\typing.py", line 173, in _type_check
    raise TypeError(f"{msg} Got {arg!r:.100}.")
TypeError: Forward references must evaluate …
Run Code Online (Sandbox Code Playgroud)

python python-3.x python-dataclasses python-typing python-3.10

6
推荐指数
1
解决办法
2133
查看次数

我可以创建数据类实例的枚举吗?

我有一组固定的三个传感器,我想将其建模为枚举。每个传感器都通过一些不同的属性进行参数化。因此,我想将传感器本身建模为数据类。

我天真的尝试看起来像这样:

@dataclass
class SensorLocation:
    address: int
    pins: int
    other_details: ...

class Sensors(SensorLocation, Enum):
    TOP_SENSOR = SensorLocation(address=0x10, pins=0xf,  other_details=...)
    BOTTOM_SENSOR = SensorLocation(address=0x10, pins=0xf0,  other_details=...)
    SIDE_SENSOR = SensorLocation(address=0x15, pins=0xf,  other_details=...)
Run Code Online (Sandbox Code Playgroud)

我的期望是,这本质上应该创建一个枚举,其中该枚举的实例的行为类似于SensorLocation. 这使得类型更加清晰,并将方法放在我期望的位置。

但是,在创建枚举时失败,并出现错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/to/python/3.7.10/lib/python3.7/enum.py", line 232, in __new__
    enum_member.__init__(*args)
  File "<string>", line 3, in __init__
  File "/path/to/python/3.7.10/lib/python3.7/types.py", line 175, in __set__
    raise AttributeError("can't set attribute")
AttributeError: can't set attribute
Run Code Online (Sandbox Code Playgroud)

我能做的是删除SensorLocation枚举声明中的子类化,但这意味着当使用 MyPy 或类似工具时,我失去了键入提示正确值的能力。它还使访问实际值变得更加复杂,但该枚举的主要目的是提供对这些值的访问。

有没有办法解决我缺少的这个错误,或者我现在看不到的其他解决方案?

python enums python-dataclasses

6
推荐指数
1
解决办法
2812
查看次数

从数据类中的自定义构造函数调用生成的 __init__ 作为默认值

是否可以从 中受益dataclasses.field,特别是对于默认值,但使用自定义构造函数?我知道@dataclass注释在生成的中设置默认值__init__,如果我替换它,就不会再这样做了。那么,是否可以替换生成的__init__,并仍然在内部调用它?

@dataclass
class A:
    l: list[int] = field(default_factory=list)
    i: int = field(default=0)
        
    def __init__(self, a: Optional[int]): # completely different args than instance attributes
        self.call_dataclass_generated_init() # call generated init to set defaults
        if a is not None: # custom settings of attributes
            i = 2*a
Run Code Online (Sandbox Code Playgroud)

解决方法是定义__new__而不是覆盖__init__,但我更愿意避免这种情况。

  • 这个问题非常接近,但答案仅解决作为代码示例给出的特定用例。另外,我不想使用,__post_init__因为我需要使用__setattr__这是静态类型检查的问题,并且它无助于调整__init__无论如何都会采用的参数。

  • 我也不想使用类方法,我真的希望调用者使用自定义构造函数。

  • 这一个也很接近,但它只是解释为什么新的构造函数替换生成的构造函数,而不是关于如何仍然调用后者(还有一个回复建议使用 Pydantic,但我不想子类化BaseModel,因为这会弄乱我的继承权)。

因此,简而言之,我希望受益于dataclass …

python python-dataclasses

6
推荐指数
1
解决办法
1579
查看次数

初始化Python数据类对象而不传递实例变量或默认值

我想初始化 python 数据类对象,即使没有实例变量传递给它并且我们没有向参数添加默认值

@dataclass
class TestClass:
   
   paramA: str
   paramB: float
   paramC: str

obj1 = TestClass(paramA="something", paramB=12.3)

Run Code Online (Sandbox Code Playgroud)

这里它不允许我创建对象并且它会抛出

TypeError: __init__() missing 1 required positional argument: 'paramC'
Run Code Online (Sandbox Code Playgroud)

我可以使用默认值来解决此错误。

paramC: str = None
# OR
paramC: str = ""
Run Code Online (Sandbox Code Playgroud)

但我不想使用 paramC 的默认值,因为我想要一个场景,如果我们传递 paramC 那么只有它应该存在于对象中,否则它不应该存在。因此,如果我们在这里使用默认值,paramC 将始终存在于对象中,其值为None或空字符串。

如果在初始化期间未传递参数,我想跳过参数的初始化。

python python-3.x python-dataclasses

6
推荐指数
1
解决办法
6668
查看次数

数据类字段可以为 repr 格式化其值吗?

我有一个 Node 类,以十六进制和 HSV 形式保存 RGB 数据。我将使用它以各种方式对颜色进行排序,并且希望 HSV 元组保持浮点形式进行比较,而不是每次使用时都从字符串进行转换。有没有一种方法可以指定数据类字段应该以类似于默认值的特定方式格式化值default_factory,即 a repr_factory

def RGB2HSV(r, g, b):
    '''Returns HSV values in the range H = [0, 360], S = [0, 100], V = [0, 100]'''
    r, g, b = r / 255, g / 255, b / 255
    maxRGB = max(r, g, b)
    minRGB = min(r, g, b)
    delta = maxRGB - minRGB

    V = maxRGB
    if V == 0:
        return 0, 0, V
    
    S = delta / V …
Run Code Online (Sandbox Code Playgroud)

python repr python-dataclasses

6
推荐指数
1
解决办法
1947
查看次数