dataclasses 笔记
一、简介
dataclasses是python新的内置库,也是一种新的特性吧(对我来说吧,因为我很少用到)
具体内容官方文档也有:https://docs.python.org/3/library/dataclasses.html
二、使用
在python中创建一个类,我们需要写__init__方法进行初始化对象操作,需要对对象进一步说明的话,最好写一个__repr__方法,这样我们直接输出对象的话,方便理解这个对象是啥。写两三个这样的类还好,多了的话,就觉得烦躁了,因为每写个类,你都得需要写__init__,__repr__这些方法,都是重复性的操作。
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Student-{self.name}"
# 实例一个name为zhuyu的People对象
zhuyu = People("zhuyu", 23)
print(zhuyu.name) # 输出 zhuyu
print(zhuyu) # Student-zhuyu
下面使用dataclasses去创建一个类,相对于上面这个类的写法是不是显得简单很多,一些魔法方法不用我们自己去写dataclasss会帮我们完成。
from dataclasses import dataclass
@dataclass # 重点这里
class Goods:
"""商品类"""
name: str
price: float
milk = Goods("milk", 9.99)
print(milk.name) # milk
print(milk) # Goods(name='milk', price=9.99)
dataclass会帮我们重写一个魔法方法,可能是你想要的,也可能是你不想要的,我们可以通过一些参数进行控制(哪些魔法不想重写),继续看dataclass函数,它是可以传参数的,它的注释也写得很清楚了
def dataclass(_cls=None, *, init=True, repr=True, eq=True, order=False,
unsafe_hash=False, frozen=False):
"""Returns the same class as was passed in, with dunder methods
added based on the fields defined in the class.
Examines PEP 526 __annotations__ to determine fields.
If init is true, an __init__() method is added to the class. If
repr is true, a __repr__() method is added. If order is true, rich
comparison dunder methods are added. If unsafe_hash is true, a
__hash__() method function is added. If frozen is true, fields may
not be assigned to after instance creation.
"""
def wrap(cls):
return _process_class(cls, init, repr, eq, order, unsafe_hash, frozen)
# See if we're being called as @dataclass or @dataclass().
if _cls is None:
# We're called with parens.
return wrap
# We're called as @dataclass without parens.
return wrap(_cls)
init参数默认为True
,会默认帮你添加init方法,那么你实例化该对象的话,就需要传参数(如果需要参数传递话),为False
的话,实例对象就不用传递了
..................具体实现效果可以写个小demo,去看看就行
当然之前我们在写类的时候,init
方法中不单单只是对属性进行赋值,例如下面这个demo
import uuid
def get_id():
return str(uuid.uuid4())
class A:
def __init__(self, name):
self.name = name
self.id = get_id() # id不需要当作参数传来
self._init_config() # 执行其他一些初始化操作
def _init_config(self):
"""配置相关的操作"""
print("执行初始化操作")
print(self.name)
a = A("zhuyu")
print(a.id)
下面我们通过dataclass来实现上面这个例子,通过重写__post_init__
这个方法,在这个方法中做一个逻辑操作,它执行完__init__
方法之后就会调用__post_init__
这个方法
from dataclasses import dataclass
import uuid
def get_id():
return str(uuid.uuid4())
@dataclass
class A:
name: str
id: str = get_id() # id 通过调用一个函数生成,就不用传入了
def _init_config(self):
"""配置相关的操作"""
print("执行初始化操作")
print(self.name)
def __post_init__(self):
self._init_config()
a = A("zhu")
print(a.id)
关于类的继承,使用dataclass一样也是可以继承的
from dataclasses import dataclass
@dataclass
class A:
name: str
def __post_init__(self):
print('父类')
@dataclass
class B(A):
age: int
def __post_init__(self):
print('基类')
super().__post_init__()
b = B('name', 22)
继续看field,这个函数的位置为from dataclasses import field
def field(*, default=MISSING, default_factory=MISSING, init=True, repr=True,
hash=None, compare=True, metadata=None):
"""Return an object to identify dataclass fields.
default is the default value of the field. default_factory is a
0-argument function called to initialize a field's value. If init
is True, the field will be a parameter to the class's __init__()
function. If repr is True, the field will be included in the
object's repr(). If hash is True, the field will be included in
the object's hash(). If compare is True, the field will be used
in comparison functions. metadata, if specified, must be a
mapping which is stored but not otherwise examined by dataclass.
It is an error to specify both default and default_factory.
"""
if default is not MISSING and default_factory is not MISSING:
raise ValueError('cannot specify both default and default_factory')
return Field(default, default_factory, init, repr, hash, compare,
metadata)
写个demo看看这个怎么使用
from dataclasses import field, dataclass
@dataclass
class A:
name: str = field(default='zhuyu')
@dataclass
class B:
name: str = field(init=True)
a = A()
b = B('zhuyu')
print(a.name) # zhuyu
print(b.name) # zhuyu
# init默认为true,说明你在初始化对象的时候,需要传递该参数(参考class B),但是field中从参数default 或者default_factory不为空的时候,就算init为true,也是可以不用传递参数(参考class A)
from dataclasses import field, dataclass
@dataclass
class A:
name: str = field()
age: int = field(repr=False)
@dataclass
class B:
name: str = field()
age: int = field(repr=True)
a = A('zhuyu', 22)
b = B('zhuyu', 23)
print(a) # A(name='zhuyu')
print(b) # B(name='zhuyu', age=23)
# repr默认为True,会将该字段添加到__repr__中去,为False的话,则不会添加进去
......... 其他的一些参数,可以写一些demo看看显示效果
三、完。
后面会经常使用这样的写法吧,多了解python的新特性还是挺不错的,typing模块我看很多第三方库中也在经常使用,自己也要多学习学习。
参考文章:https://www.jianshu.com/p/22c07d6839ed