我想用 Python 编写数据类定义,但无法在声明中引用同一类。
我主要想要实现的是这个嵌套结构的类型,如下图所示:
@dataclass
class Category:
title: str
children: [Category] # I can't refer to a "Category"
tree = Category(title='title 1', children=[
Category('title 11', children=[]),
Category('title 12', children=[])
])
Run Code Online (Sandbox Code Playgroud) python type-hinting recursive-datastructures python-dataclasses
从Python 3.7开始,有一种称为数据类的东西:
from dataclasses import dataclass
@dataclass
class Foo:
x: str
Run Code Online (Sandbox Code Playgroud)
但是,以下失败:
>>> import json
>>> foo = Foo(x="bar")
>>> json.dumps(foo)
TypeError: Object of type Foo is not JSON serializable
Run Code Online (Sandbox Code Playgroud)
如何将json.dumps()编码实例Foo转换为json 对象?
Python 3.7引入了称为数据类的新功能.
from dataclasses import dataclass
@dataclass
class MyClass:
id: int = 0
name: str = ''
Run Code Online (Sandbox Code Playgroud)
在函数参数中使用类型提示(注释)时,可以使用inspect模块轻松获取带注释的类型.如何获取dataclass字段类型?
从3.0开始,只支持创建一个参数关键字:
class S3Obj:
def __init__(self, bucket, key, *, storage_class='Standard'):
self.bucket = bucket
self.key = key
self.storage_class = storage_class
Run Code Online (Sandbox Code Playgroud)
如何使用数据类获得这种签名?像这样的东西,但最好没有SyntaxError:
@dataclass
class S3Obj:
bucket: str
key: str
*
storage_class: str = 'Standard'
Run Code Online (Sandbox Code Playgroud)
理想情况下是声明性的,但是使用__post_init__钩子和/或替换类装饰器也很好 - 只要代码是可重用的.
编辑:可能是这样的语法,使用省略号文字
@mydataclass
class S3Obj:
bucket: str
key: str
...
storage_class: str = 'Standard'
Run Code Online (Sandbox Code Playgroud) PEP-557引入了数据类到Python标准库,基本上可以填补因为同样的作用collections.namedtuple和typing.NamedTuple.现在我想知道如何分离使用namedtuple仍然是更好的解决方案的用例.
当然,dataclass如果我们需要,所有的功劳都归功于:
property 装饰器,可管理的属性在同一个PEP中简要解释了数据类的优点:为什么不使用namedtuple.
但是对于namedtuples这个相反的问题怎么样:为什么不使用dataclass呢?我想从性能的角度来看,名字元组可能更好,但尚未确认.
让我们考虑以下情况:
我们将页面维度存储在一个小容器中,该容器具有静态定义的字段,类型提示和命名访问.不需要进一步散列,比较等.
NamedTuple方法:
from typing import NamedTuple
PageDimensions = NamedTuple("PageDimensions", [('width', int), ('height', int)])
Run Code Online (Sandbox Code Playgroud)
DataClass方法:
from dataclasses import dataclass
@dataclass
class PageDimensions:
width: int
height: int
Run Code Online (Sandbox Code Playgroud)
哪种解决方案更可取,为什么?
PS这个问题不是以任何方式重复那个问题,因为我在这里询问的是哪个命名元组更好,而不是区别(我在询问之前检查了文档和来源)
Python 3.7即将到来,我想测试一些奇特的新dataclass+打字功能.使用本机类型和typing模块中的类型,可以很容易地获得正确工作的提示:
>>> import dataclasses
>>> import typing as ty
>>>
... @dataclasses.dataclass
... class Structure:
... a_str: str
... a_str_list: ty.List[str]
...
>>> my_struct = Structure(a_str='test', a_str_list=['t', 'e', 's', 't'])
>>> my_struct.a_str_list[0]. # IDE suggests all the string methods :)
Run Code Online (Sandbox Code Playgroud)
但是我想要尝试的另一件事是在运行时强制类型提示作为条件,即不应该dataclass存在具有不正确类型的类型.它可以很好地实现__post_init__:
>>> @dataclasses.dataclass
... class Structure:
... a_str: str
... a_str_list: ty.List[str]
...
... def validate(self):
... ret = True
... for field_name, field_def in self.__dataclass_fields__.items():
... actual_type = type(getattr(self, …Run Code Online (Sandbox Code Playgroud) 我使用 field(init= False) 来禁用初始化 self.ref。那么它就是 post 中的一个值。以下代码引发AttributeError: 'Data' object has no attribute 'ref'
from dataclasses import dataclass, field
def make_list(): return [[0] for k in range(9)]
@dataclass
class Data:
rows: list
cols: list
blocks: list
ref: dict = field(init=False)
def __init__(self, slots=None):
self.rows = make_list()
self.cols = make_list()
self.blocks = make_list()
if slots:
for i in range(9):
for j in range(9):
self.cols[j][i] = self.rows[i][j] = slots[i][j]
def __post_init__(self):
print("post-init executed")
self.ref = {"rows": self.rows, "cols": self.cols, "blocks": self.blocks}
test …Run Code Online (Sandbox Code Playgroud) Python 3.7提供了dataclasses具有预定义特殊功能的新功能.
从全局来看,dataclasses并SimpleNameSpace都提供了很好的数据封装工厂.
@dataclass
class MyData:
name:str
age: int
data_1 = MyData(name = 'JohnDoe' , age = 23)
data_2 = SimpleNameSpace(name = 'JohnDoe' , age = 23)
Run Code Online (Sandbox Code Playgroud)
很多时候我SimpleNameSpace只是用来包装数据并移动它.
我甚至将它子类化为添加特殊功能:
from types import SimpleNameSpace
class NewSimpleNameSpace(SimpleNameSpace):
def __hash__(self):
return some_hashing_func(self.__dict__)
Run Code Online (Sandbox Code Playgroud)
对于我的问题:
SimpleNameSpace和dataclasses?SimpleNameSpace?dataclasses迎合什么?请注意,这类似于如何在 asdict 中获取 @property 方法?。
我有一个(冻结的)嵌套数据结构,如下所示。定义了一些(纯粹)依赖于字段的属性。
import copy
import dataclasses
import json
from dataclasses import dataclass
@dataclass(frozen=True)
class Bar:
x: int
y: int
@property
def z(self):
return self.x + self.y
@dataclass(frozen=True)
class Foo:
a: int
b: Bar
@property
def c(self):
return self.a + self.b.x - self.b.y
Run Code Online (Sandbox Code Playgroud)
我可以按如下方式序列化数据结构:
class CustomEncoder(json.JSONEncoder):
def default(self, o):
if dataclasses and dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
return json.JSONEncoder.default(self, o)
foo = Foo(1, Bar(2,3))
print(json.dumps(foo, cls=CustomEncoder))
# Outputs {"a": 1, "b": {"x": 2, "y": 3}}
Run Code Online (Sandbox Code Playgroud)
但是,我还想序列化属性 ( …
python serialization immutability python-3.x python-dataclasses
我在使用新的 defaultdict(dict) 设置简单的数据类时遇到问题。
如果我告诉工厂使用“dict”,如下所示,实例化将失败并出现typerror collection.defaultdict对象不可调用
from collections import defaultdict
from dataclasses import dataclass, field
@dataclass
class ResultSet:
changed: bool = False
mqttdata: defaultdict(dict) = field(default_factory=defaultdict(dict)) # does not work!
Run Code Online (Sandbox Code Playgroud)
它确实使用field(default_factory=defaultdict)工作,但是当我的代码遇到丢失的键时,它会失败 - 大概是因为没有为 dict 设置 defaultdict。
如何在数据类中正确设置新的defaultdict(dict)?
python ×9
python-3.7 ×3
python-3.x ×3
defaultdict ×1
immutability ×1
namedtuple ×1
pep ×1
type-hinting ×1
typing ×1