找回密码
 会员注册
查看: 31|回复: 0

深入解析Pythondataclass:类属性与类方法解释

[复制链接]

6

主题

0

回帖

19

积分

新手上路

积分
19
发表于 2024-9-12 18:00:51 | 显示全部楼层 |阅读模式
文章目录dataclass实例属性和类属性自动设置属性实例方法静态方法(@staticmethod)和类方法(@classmethod)静态方法类方法dataclassdataclass是Python3.7引入的一个装饰器,用于简化类的定义。使用dataclass可以自动生成一些常用方法,比如__init__、__repr__、__eq__等等。这些方法均无需手动实现,除非有定制化需求。本文介绍dataclass的用法,同时也介绍了相关面向对象的一些属性和方法,包括:如何判断实例属性和类属性;对比分析实例方法、静态方法(@staticmethod)和类方法(@classmethod)实例属性和类属性使用dataclass定义一个类非常简单,只需要在类定义前加上@dataclass装饰器,并在类中定义属性即可。fromdataclassesimportdataclass,field@dataclassclassPerson:home="Wuhan"name:str123456类属性是定义在类体中,在任何方法之外(包括__init__方法)的变量。它们属于类本身,而不是类的实例。类属性在内存中只有一个副本,无论创建了多少个类的实例,这个副本都是共享的。在上述的代码中,home就是一个类属性。它被定义在类体中,在任何方法之外,且没有与实例变量相同的类型注解。由于home被定义为一个字符串,它将作为Person类的一个共享属性。所有Person类的实例都将访问到同一个home属性的值。实例属性是定义在类的__init__方法或其他实例方法中的变量。它们属于类的实例,每个实例都有自己的实例属性副本。实例属性通常通过类型注解来指定其期望的数据类型,并使用self参数来引用实例本身。在上述代码中,name被声明为一个类型注解为str的变量,虽然其没有在__init__方法内部被初始化。由于使用了@dataclass装饰器,dataclasses模块会自动生成__init__方法,该方法将接受与类型注解相匹配的参数,并将它们设置为实例属性。因此,尽管没有明确写出__init__方法,但name仍然是一个实例属性。故在创建一个Person类的实例时,需要提供一个name值,该值将被设置为该实例的name属性。由于name是一个实例属性,每个Person实例都将有自己的name属性副本。只需要给实例属性name传参,无需给类属性home传参。p1=Person("Alice")p1=Person("Bob")print(p1.name,p1.home)print(p2.name,p2.home)1234Output:AliceWuhanBobWuhan12由于home是类属性,故对其进行修改后,p1.home和p2.home会变成同一个值。Person.home="Fuzhou"print(p1.home,p2.home)12Output:FuzhouFuzhou1自动设置属性在初始化某些类别的时候,某些属性,可以通过传入的属性,推测与计算出来。在dataclass中,实例变量是在__init__方法中初始化的属性。可以使用field函数并指定init=False,表示这个字段不在__init__方法中进行初始化。以下述代码为例,根据输入的年龄age,添加是否成年(is_adult)的属性。__post_init__在__init__之后运行,在其中实现为Person实例,添加is_adult的属性。在下面的例子中,is_adult的默认值是False,并且不会在__init__方法中初始化。通过定义一个__post_init__方法,对is_adult进行赋值。@dataclassclassPerson:name:strage:intis_adult:bool=field(init=False,default=False)def__post_init__(self):ifself.age>=18:self.is_adult=Trueelse:self.is_adult=False1234567891011p1=Person("Alice",25)p2=Person("Bob",17)print(p1)print(p2)1234Outputerson(name='Alice',age=25,is_adult=True)Person(name='Bob',age=17,is_adult=False)12如结果所示,实现自动根据age,为Person实例,添加is_adult属性。实例方法在面向对象编程(Object-OrientedProgramming,OOP)的术语中,一个实例方法能够访问和改变对象状态。@dataclassclassPerson:name:strage:intdefgrow_up(self):self.age+=11234567grow_up是一个实例方法(InstanceMethod)定义在Person类中。静态方法(@staticmethod)和类方法(@classmethod)除了实例方法之外,还有两种类型的方法:静态方法(@staticmethod)和类方法(@classmethod)。它们的用途和定义方式如下:静态方法与类或实例无关,它只是类定义体中的一个普通函数。静态方法不需要传递类实例(self)或类(cls)作为第一个参数。类方法是绑定到类而不是类实例的方法。类方法的第一个参数是类本身(通常命名为cls)。类方法可以访问和修改类状态。静态方法静态方法,比较简单且易于理解,不做过多描述;写一个简单的静态方法,供大家参考!@dataclassclassPerson:name:strage:int@staticmethoddefadd(value):returnvalue+1defgrow_up(self):#self.age=self.add(self.age)self.age=Person.add(self.age)123456789101112add是一个静态方法,使用self.add和Person.add都可以。p=Person("Alice",17)p.grow_up()print(p)123Outputerson(name='Alice',age=18)1类方法在类方法中,使用cls而不是self在Python中,定义一个类方法(即使用@classmethod装饰器的方法)时,第一个参数被命名为cls而不是self。cls是一个约定俗成的名称用来代表类本身,而不是类的实例。使用cls而不是self的原因是:语义清晰:self通常用于表示类的实例,而**cls用于表示类本身**。使用不同的名称可以帮助阅读代码的人更容易地理解方法的上下文和用途。避免混淆:在类方法中,实际上并没有一个类的实例可以引用,因此使用self可能会引发混淆。如果尝试在类方法内部使用self作为第一个参数,Python解释器会抛出一个TypeError,因为它期望的是类本身,而不是类的实例。符合Python的习惯和约定:Python社区广泛接受并使用cls作为类方法的第一个参数的命名约定。这有助于保持代码的一致性和可读性。下面是一个简单的例子,展示了为什么类方法需要cls而不是self:@dataclassclassPerson:home="Wuhan"name:str@classmethoddefget_name(cls)->str:returncls.name@classmethoddefget_home(cls)->str:returncls.homep=Person("Alice")1234567891011121314p.get_home()1Output:'Wuhan'1类方法传入的cls,是类本身而不是类的实例化。如果忘记了,为什么home是类属性,name是实例属性,请返回实例属性和类属性章节重新阅读!由于home是类属性,cls可以访问到;name是实例属性,cls无法访问到,只有实例对象(self)才能访问到name。所以get_home成功,get_name失败。p.get_name()1Output:
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 02:11 , Processed in 0.365492 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表