我有以下非常简单的数据类:
import dataclasses
@dataclasses.dataclass
class Test:
value: int
Run Code Online (Sandbox Code Playgroud)
我创建了该类的实例,但我使用了一个字符串而不是整数:
>>> test = Test('1')
>>> type(test.value)
<class 'str'>
Run Code Online (Sandbox Code Playgroud)
我真正想要的是强制转换为我在类定义中定义的数据类型:
>>> test = Test('1')
>>> type(test.value)
<class 'int'>
Run Code Online (Sandbox Code Playgroud)
我必须__init__手动编写该方法还是有一种简单的方法来实现此目的?
我对在 Python 和 Cython 代码之间传递数据很感兴趣,以便可以从 C 访问数据而无需 GIL。我正在考虑使用数据类(自 py3.7 起)、命名元组(自 py3.6 起具有很好的定义语法)或 Cython 的扩展类型(cdef classess)来实现这一点。
不幸的是,数据类和命名元组似乎像来自 Cython 的通用对象一样被处理,而没有任何编译成 C 的支持。
可以使用 Cython 扩展类型(cdef 类),但与数据类相比,它们有许多缺点,最重要的是,您必须__init__使用样板代码来实现以设置所有类属性,对吗?
我正在浏览数据类并命名元组。我发现这种行为在使用 python 的不同特性创建对象时具有不同的性能。
数据类
In [1]: from dataclasses import dataclass
...:
...: @dataclass
...: class Position:
...: lon: float = 0.0
...: lat: float = 0.0
...:
In [2]: %timeit for _ in range(1000): Position(12.5, 345)
326 µs ± 34.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Run Code Online (Sandbox Code Playgroud)
普通班:
In [1]: class Position:
...:
...: def __init__(self, lon=0.0, lat=0.0):
...: self.lon = lon
...: self.lat = lat
...:
In [2]: %timeit for _ in range(1000): …Run Code Online (Sandbox Code Playgroud) python python-3.x python-internals python-performance python-dataclasses
我想创建一个类层次结构,其中类的所有对象Base都有一个字段field1,但不同的子类有不同的默认值field1。这些类是数据持有者,因此dataclasses看起来是一个完美的库。
考虑以下 python 3.7+ 代码。
from dataclasses import dataclass, field
from typing import Any, Iterable
@dataclass
class Base:
field1: Iterable[Any]
@dataclass
class Sub(Base):
field2: Any
field1: Iterable[Any] = field(default_factory=list)
Run Code Online (Sandbox Code Playgroud)
代码失败,给了我TypeError: non-default argument 'field2' follows default argument. 这有点令人惊讶,因为遵循超类的field2非默认参数,而该类的默认参数实际上位于.field1field1Subfield2
根据有关数据类继承的文档中的示例,子类中的字段会覆盖超类中的字段,但保留字段顺序。所以这个错误是有道理的。
这里有任何合适的解决方法,还是我必须手动实现所有内容?
我有一个这样设置的数据类:
from dataclasses import dataclass, field
from typing import List
@dataclass
class stats:
target_list: List[None] = field(default_factory=list)
Run Code Online (Sandbox Code Playgroud)
当我尝试像这样比较列表的内容时:
if stats.target_list == None:
pass
Run Code Online (Sandbox Code Playgroud)
我得到 AttributeError: type object 'stats' has no attribute 'target_list'
我该如何解决这个问题?谢谢
我正在优化我的代码以提高性能,当我用来cProfile检查我的代码时,大量的运行时间是由于类型注释造成的!删除类型注释确实可以提高性能。cProfiler您可以在下面看到带注释和不带注释的输出。
带注释的明显使用了__call__、__new__、inner、__getitem__、__hash__等方法typing.py,而且比不带注释的慢了一倍!
我的测试代码很简单:
from reil.datatypes import reildata
x = reildata.Categorical(name='cat', categories=('A', 'B', 'C', 'D', 'E'))
for _ in range(10000):
[x(v) for v in ('A', 'B', 'C', 'D', 'E')]Run Code Online (Sandbox Code Playgroud)
这是主代码的相关部分(datatypes.reildata.py):
from __future__ import annotations
import dataclasses
import itertools
from dataclasses import field
from typing import Any, Callable, Dict, Generic, Iterable, Iterator, List, Optional, Sequence, Tuple, TypeVar, Union, cast
from typing_extensions import …Run Code Online (Sandbox Code Playgroud)假设我有一个带有 set 方法的数据类。如何扩展 repr 方法,以便在调用 set 方法时它也会更新:
from dataclasses import dataclass
@dataclass
class State:
A: int = 1
B: int = 2
def set(self, var, val):
setattr(self, var, val)
Run Code Online (Sandbox Code Playgroud)
前任:
In [2]: x = State()
In [3]: x
Out[3]: State(A=1, B=2)
In [4]: x.set("C", 3)
In [5]: x
Out[5]: State(A=1, B=2)
In [6]: x.C
Out[6]: 3
Run Code Online (Sandbox Code Playgroud)
我想要的结果
In [7]: x
Out[7]: State(A=1, B=2, C=3)
Run Code Online (Sandbox Code Playgroud) h.json考虑这个名为“我想将其转换为 python 数据类”的 json 文件。
{
"acc1":{
"email":"acc1@example.com",
"password":"acc1",
"name":"ACC1",
"salary":1
},
"acc2":{
"email":"acc2@example.com",
"password":"acc2",
"name":"ACC2",
"salary":2
}
}
Run Code Online (Sandbox Code Playgroud)
我可以使用替代构造函数来获取每个帐户,例如:
import json
from dataclasses import dataclass
@dataclass
class Account(object):
email:str
password:str
name:str
salary:int
@classmethod
def from_json(cls, json_key):
file = json.load(open("h.json"))
return cls(**file[json_key])
Run Code Online (Sandbox Code Playgroud)
但这仅限于数据类中定义的参数(电子邮件、姓名等)。
如果我要修改 json 以包含其他内容(例如年龄)怎么办?该脚本最终将返回一个TypeError,特别是TypeError: __init__() got an unexpected keyword argument 'age'.
有没有办法根据dict(json对象)的键动态调整类属性,这样我就不必每次向json添加新键时都添加属性?
似乎已经对此进行了相当多的讨论。我发现这篇文章特别有帮助,它似乎提供了最好的解决方案之一。
但推荐的解决方案存在问题。
嗯,一开始看起来效果很好。考虑一个没有属性的简单测试用例:
@dataclass
class Foo:
x: int
Run Code Online (Sandbox Code Playgroud)
>>> # Instantiate the class
>>> f = Foo(2)
>>> # Nice, it works!
>>> f.x
2
Run Code Online (Sandbox Code Playgroud)
x现在尝试使用推荐的解决方案作为属性来实现:
@dataclass
class Foo:
x: int
_x: int = field(init=False, repr=False)
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
Run Code Online (Sandbox Code Playgroud)
>>> # Instantiate while explicitly passing `x`
>>> f = Foo(2)
>>> # Still appears to work
>>> f.x
2
Run Code Online (Sandbox Code Playgroud)
可是等等...
>>> # Instantiate without any arguments
>>> f …Run Code Online (Sandbox Code Playgroud) 我想解析 json 并将其保存在数据类中以模拟 DTO。目前,我必须手动将所有 json 字段传递给数据类。我想知道有没有一种方法可以通过添加 json 解析的字典来做到这一点。“dejlog”到数据类,所有字段都会自动填充。
from dataclasses import dataclass, asdict
@dataclass
class Dejlog(Dataclass):
PK: str
SK: str
eventtype: str
result: str
type: str
status: str
def lambda_handler(event, context):
try:
dejlog = json.loads(event['body'])
x = Dejlog(dejlog['PK'])
print(x)
print(x.PK)
Run Code Online (Sandbox Code Playgroud) python ×9
json ×2
python-3.x ×2
cprofile ×1
cython ×1
namedtuple ×1
oop ×1
properties ×1
python-3.7 ×1
python-class ×1
type-hinting ×1