我编写了一个 Flask-SQLAlchemy 模型类,如下所示(来自此参考):
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'user'
user_id = db.Column(db.Integer, primary_key=True)
user_url = db.Column(db.String(2083), unique=True, nullable=False)
username = db.Column(db.String(80), unique=True, nullable=False)
avatar_url = db.Column(db.String(2083), unique=True, nullable=False)
def __init__(self, user_id, user_url, username, avatar_url):
self.user_id = user_id
self.user_url = user_url
self.username = username
self.avatar_url = avatar_url
Run Code Online (Sandbox Code Playgroud)
但是,我想使用dataclass装饰器(参考)来简化其实现,特别是避免重写__init__dunder 方法,并更容易地将此类序列化为 Python dict。
但是,将此类的实现更改为:
@dataclass
class User(db.Model):
__tablename__ = 'user'
user_id: …Run Code Online (Sandbox Code Playgroud) 我有一个数据类,说Car:
from dataclasses import dataclass
@dataclass
class Car:
make: str
model: str
color: hex
owner: Owner
Run Code Online (Sandbox Code Playgroud)
如何在列表中提取数据类的属性或字段?,例如
attributes = ['make', 'model', 'color', 'owner']
Run Code Online (Sandbox Code Playgroud) 我想让set参数可选,但仍然允许None为有效值。根据文档,它建议dataclasses.MISSING可以使用默认值来帮助实现这一点。
如上所示,
MISSINGvalue是一个哨兵对象,用于检测用户是否提供了某些参数。使用此标记是因为None它对于某些具有不同含义的参数来说是有效值。任何代码都不应直接使用该MISSING值。
但通过如下使用:
import dataclasses
from dataclasses import dataclass, field
@dataclass
class Var:
get: list
set: list = dataclasses.MISSING
def __post_init__(self):
if self.set is dataclasses.MISSING:
self.set = self.get
print(Var(get=['Title']))
Run Code Online (Sandbox Code Playgroud)
我收到错误:
Traceback (most recent call last):
File "main.py", line 31, in <module>
print(Var(get=['Title']))
TypeError: __init__() missing 1 required positional argument: 'set'
Run Code Online (Sandbox Code Playgroud) 我正在使用 Python 与 Web api 交互,其中 json 响应中的键采用驼峰命名法。我的Python模型是数据类,其字段名称是snake_case。当我从 json 转换为 model 时,反之亦然,名称显然不匹配。
作为参考,我使用 asdict 函数将模型转换为 json。
def to_json(self):
return asdict(
self,
dict_factory=lambda _fields: {
key: value for (key, value) in _fields if value is not None
}
)
Run Code Online (Sandbox Code Playgroud)
从 json 转换为 model 的代码稍微复杂一些,但也依赖于字段名称来映射到 json 键。这两种转换都足够通用,可以适用于我的所有模型,而无需为每个单独的模型(30 个左右)创建转换器。
在这种情况下,使用 comeCase 作为我的模型字段名称是否是常见做法(即使它不符合标准命名实践)?
我无法修改 api,无论好坏,键名称将始终采用驼峰命名法。
假设我有一个自定义用例,我需要动态创建或定义__init__数据类的方法。
例如,假设我需要像这样装饰它,@dataclass(init=False)然后修改__init__()方法以采用关键字参数,例如**kwargs. 但是,在kwargs对象中,我仅检查已知数据类字段是否存在,并相应地设置这些属性(下面的示例)
我想向我的 IDE (PyCharm) 键入提示,修改后的内容__init__仅接受列出的数据类字段作为参数或关键字参数。我不确定是否有办法解决这个问题,使用typing库或其他方式。我知道 PY3.11 已计划进行数据类转换,这可能会也可能不会满足我的要求(我的直觉是否定的)。
这是我正在使用的示例代码,这是一个基本案例,说明了我遇到的问题:
from dataclasses import dataclass
# get value from input source (can be a file or anything else)
def get_value_from_src(_name: str, tp: type):
return tp() # dummy value
@dataclass
class MyClass:
foo: str
apple: int
def __init__(self, **kwargs):
for name, tp in self.__annotations__.items():
if name in kwargs:
value = kwargs[name]
else:
# here …Run Code Online (Sandbox Code Playgroud) 我正在尝试创建一个数据类来将所有相关数据存储在单个对象中。如何初始化一个数据类实例,其中的值是从数据类中带有参数的函数求值的?
到目前为止,这就是我所在的位置:
@dataclass
class Person:
def Name(self):
return f'My name is {self.name[0]} {self.name[1]}.'
def Age(self):
return f'I am {self.age} years old.'
name: field(default_factory=Name(self), init=True)
age: field(default_factory=Age(self), init=True)
person = Person(('John', 'Smith'), '100')
print(person)
Run Code Online (Sandbox Code Playgroud)
电流输出:
@dataclass
class Person:
def Name(self):
return f'My name is {self.name[0]} {self.name[1]}.'
def Age(self):
return f'I am {self.age} years old.'
name: field(default_factory=Name(self), init=True)
age: field(default_factory=Age(self), init=True)
person = Person(('John', 'Smith'), '100')
print(person)
Run Code Online (Sandbox Code Playgroud)
这是我想要实现的输出:
Person(name=('John', 'Smith'), age='100')
Run Code Online (Sandbox Code Playgroud)
我试图使用如何在数据类字段中引用“self”?供有关此主题的参考。
我正在使用Python 3.6和ericvsmith的dataclassesbackport软件包。
看来通话dataclasses.asdict(my_dataclass)比通话慢约10倍my_dataclass.__dict__:
In [172]: @dataclass
...: class MyDataClass:
...: a: int
...: b: int
...: c: str
...:
In [173]: %%time
...: _ = [MyDataClass(1, 2, "A" * 1000).__dict__ for _ in range(1_000_000)]
...:
CPU times: user 631 ms, sys: 249 ms, total: 880 ms
Wall time: 880 ms
In [175]: %%time
...: _ = [dataclasses.asdict(MyDataClass(1, 2, "A" * 1000)) for _ in range(1_000_000)]
...:
CPU times: user 11.3 s, sys: …Run Code Online (Sandbox Code Playgroud) 我有以下课程:
class WordItem:
def __init__(self, phrase: str, word_type: WORD_TYPE):
self.id = f'{phrase}_{word_type.name.lower()}'
self.phrase = phrase
self.word_type = word_type
@classmethod
def from_payload(cls, payload: Dict[str, Any]) -> 'WordItem':
return cls(**payload)
Run Code Online (Sandbox Code Playgroud)
如何将此类重写为数据类?
具体来说,如何id宣布该领域?它具有生成的值,而不是代码创建实例将提供的字段.
在没有覆盖内置 init 的数据类的情况下,在实例化之前验证 init 参数的 Pythonic 方法是什么?
我想也许利用__new__dunder 方法是合适的?
from dataclasses import dataclass
@dataclass
class MyClass:
is_good: bool = False
is_bad: bool = False
def __new__(cls, *args, **kwargs):
instance: cls = super(MyClass, cls).__new__(cls, *args, **kwargs)
if instance.is_good:
assert not instance.is_bad
return instance
Run Code Online (Sandbox Code Playgroud) 我试图在我的单元测试中使用 freezegun 来修补数据类中的字段,该字段设置为对象初始化时的当前日期。我想这个问题与任何修补被用作 default_factory 的函数的尝试有关,只是在 freezegun 之外。数据类被冻结,所以它是不可变的。
例如,如果我的数据类是:
@dataclass(frozen=True)
class MyClass:
name: str
timestamp: datetime.datetime = field(init=False, default_factory=datetime.datetime.now)
Run Code Online (Sandbox Code Playgroud)
当我使用 freezegun 修补 datetime 时,它对 MyClass 中时间戳的初始化没有影响(它仍然将时间戳设置为单元测试中 now() 返回的当前日期,导致测试失败)。
我假设它与在补丁到位之前加载的默认工厂和模块有关。我尝试修补日期时间,然后使用 importlib.reload 重新加载模块,但没有运气。
我目前的解决方案是:
@dataclass(frozen=True)
class MyClass:
name: str
timestamp: datetime.datetime = field(init=False)
def __post_init__(self):
object.__setattr__(self, "timestamp", datetime.datetime.now())
Run Code Online (Sandbox Code Playgroud)
哪个有效。
理想情况下,我想要一个非侵入性的解决方案,它不需要我更改我的生产代码来启用我的单元测试。
python ×10
python-3.x ×2
freezegun ×1
patch ×1
python-3.7 ×1
self ×1
sqlalchemy ×1
unit-testing ×1