资讯动态

Python:类的属性(实例属性、类属性)和方法(实例方法、类方法、静态方法)的详细解释

发布时间:2026/10/27 1:14:40 来源:尧图企业网站定制
相关阅读Pythonhttps://blog.csdn.net/weixin_45791458/category_12403403.html?spm1001.2014.3001.5482Python是一门面向对象的编程语言其核心概念之一是类。类是对象的蓝图或模板定义了对象的属性和方法。理解类的属性和方法对于掌握Python编程至关重要。本文将深入探讨Python中的类的属性和方法帮助读者全面掌握这一重要主题。1、类和实例在Python中类是使用class关键字定义的。类定义了对象的属性和方法对象也可以称为实例是类的具体实现。例1是一个简单的类定义和其实例化# 例1 class Person: def __init__(self, name, age): self.name name self.age age person1 Person(Alice, 30) # 创建一个实例它拥有两个属性当Python解释器遇到Person(Alice, 30)时它会调用Person类的__new__()魔术方法例1中看不到该方法是因为它继承自object基类创建一个实例并在返回前调用__init__()魔术方法将该实例作为第一个参数(self)传入进行初始化。2、类的属性类的属性可以分为两类实例属性和类属性。实例属性实例属性是绑定到实例上的属性而每个实例都有独立的实例属性通常在__init__()魔术方法中定义可以通过实例名.实例属性名或者内建函数getattr()访问实例属性仅能作为右值。例2展示了一些关于实例属性的操作。# 例2 class Car: def __init__(self, make, model): self.make make self.model model car1 Car(Toyota, Camry) # 创建一个实例它拥有两个属性 car2 Car(Honda, Civic) # 创建一个实例它拥有两个属性 print(car1.make) # 使用实例名.实例属性名访问实例的属性输出Toyota print(getattr(car1, make)) # 使用内建函数getattr()访问实例的属性输出Toyota print(car2.make) # 使用实例名.实例属性名访问实例的属性输出Honda print(getattr(car2, make)) # 使用内建函数getattr()访问实例的属性输出Honda事实上其实在任何能访问到实例的地方都能访问它的属性如例3所示但不建议这样做。# 例3 class Car: def __init__(self, make, model): self.make make self.model model car1 Car(Toyota, Camry) # 创建一个实例它拥有两个属性 car1.year 1998 # 对于car1实例又创建了一个属性 car1.make Benz # 对于car1实例将其make属性改为字符串Benz实际上是创建了字符串对象并将属性make换绑到它类属性类属性是绑定到类本身的属性所有实例共享一个类属性类属性通常在类内方法外定义可以通过实例名.类属性名、类名.类属性名或者内建函数getattr()访问类属性仅能作为右值。例4展示了一些关于类属性的操作。# 例4 class Dog: species Canis old [1, 2, 3] def __init__(self, name): self.name name dog1 Dog(Buddy) print(dog1.species) # 使用实例名.类属性名访问类属性输出Canis print(Dog.species) # 使用类名.类属性名访问类属性输出Canis print(getattr(Dog, species)) # 使用内建函数getattr()访问类属性输出Canis print(getattr(dog1, species)) # 使用内建函数getattr()访问类属性输出Canis Dog.species Hello # 通过类名.类属性名改变类属性这会影响所有实例的类属性 dog2 Dog(Max) print(dog1.species) # 输出Hello print(dog2.species) # 输出Hello dog1.species World # 如果将实例名.类属性名作为左值且不是针对可变对象的索引会创建一个实例属性实际上是创建了字符串对象并将属性species换绑到它这不会影响类属性 print(dog1.species) # 输出World print(dog2.species) # 输出Hello dog1.old[0] 4 # 如果将实例名.类属性名作为左值且是针对可变对象的索引不会创建一个实例属性而是改变类属性 print(dog1.old) # 输出[4, 2, 3] print(dog1.old) # 输出[4, 2, 3]3. 类的方法类的方法是绑定到类或实例的函数。根据绑定方式的不同类的方法可以分为实例方法、类方法和静态方法。实例方法实例方法是绑定到实例上的方法一般通过实例名.实例方法名调用调用时会自动将实例作为第一个参数传入实例方法因此其第一个参数通常命名为self不建议更改表示实例本身例5展示了实例方法的调用过程# 例5 class Cat: def __init__(self, name): self.name name def meow(self): print(f{self.name} says meow.) cat1 Cat(Whiskers) cat1.meow() # 输出Whiskers says meow. print(cat1.meow) # 输出bound method Cat.meow of __main__.Cat object at 0x000001586AE68160 这个地址指的是实例(cat1)的地址 print(id(cat1.meow)) # 输出1995396036288 print(id(cat1.meow)) # 输出1995396036288 print(id(cat1.meow)) # 输出1995396036288 a cat1.meow b cat1.meow c cat1.meow print(id(a)) # 输出1995396036288 print(id(b)) # 输出1995396036352 print(id(c)) # 输出1995396036416实例方法在每次调用时都会重新创建方法对象直接使用内建函数id()检测无法观察到这一点因为每次调用结束后实例方法会被销毁相应id号都会被回收因此下次调用可能分配到相同的id号。将实例方法赋给标识符保证其至少有一个引用这样就可以观察到不同调用时实例方法是重新创建的。类方法类方法使用classmethod装饰器修饰绑定到类而不是实例但使用实例也能访问它这在之后的特殊情况会进行说明一般通过类名.类方法名调用调用时会自动将类作为第一个参数传入类方法第一个参数通常命名为cls建议不更改表示类本身例6展示了类方法的调用过程# 例6 class Bird: species Aves def __init__(self, name): self.name name classmethod def set_species(cls, species): cls.species species # 注意此处是访问类属性 bird1 Bird(Sparrow) Bird.set_species(NewSpecies) print(bird1.species) # 输出NewSpecies print(Bird.set_species) # 输出bound method Bird.set_species of class __main__.Bird a Bird.set_species b Bird.set_species c Bird.set_species print(id(a)) # 输出2228195894336 print(id(b)) # 输出2228195894400 print(id(c)) # 输出2228195894272类方法在每次调用时都会重新创建方法对象直接使用内建函数id()检测无法观察到这一点因为每次调用结束后类方法会被销毁相应id号都会被回收因此下次调用可能分配到相同的id号。将类方法赋给标识符保证其至少有一个引用这样就可以观察到不同调用时类方法是重新创建的。静态方法静态方法使用staticmethod装饰器修饰它不绑定到类或实例但一般通过类名.静态方法名调用静态方法是一种逻辑上属于类但不需要访问实例属性或类属性的方法例7展示了静态方法的调用过程# 例7 class Math: staticmethod def add(a, b): return a b result Math.add(5, 3) print(result) # 输出8 print(Math.add) # 输出function Math.add at 0x000001B90619BAF0 这个地址指的是静态方法的地址它不会改变 a Math.add b Math.add c Math.add print(hex(id(a))) # 输出0x1b90619baf0 print(hex(id(b))) # 输出0x1b90619baf0 print(hex(id(c))) # 输出0x1b90619baf0静态方法不会在每次调用时都会重新创建方法对象将类方法赋给标识符保证其至少有一个引用这样就可以观察到不同调用时静态方法不会重新创建。4. 特殊情况实例方法的非绑定调用上面所说的实例方法的调用是绑定式调用即对于实例方法使用了相应的实例调用但这并不是Python强制要求的例8展示了实例方法的非绑定调用使用“类名.实例方法名”就可以做到。# 例8 class Cat: def __init__(self, name): self.name name def meow(self): print(f{self.name} says meow.) cat1 Cat(Whiskers) # 利用“实例名.实例方法名”的形式绑定调用无需手动传递实例作为参数会自动将实例作为实例方法的第一个参数传入 cat1.meow() # 输出Whiskers says meow. # 利用“类名.实例方法名”的形式非绑定调用需要手动传递实例作为参数 Cat.meow(cat1) # 输出Whiskers says meow. Cat.meow(selfcat1) # 输出Whiskers says meow. print(Cat.meow) # 输出function Cat.meow at 0x0000024D1973BB80 这个地址指的是非绑定的实例方法的地址 print(cat1.meow) # 输出bound method Cat.meow of __main__.Cat object at 0x0000021E51FF3FD0 这个地址指的是实例(cat1)的地址 a Cat.meow b Cat.meow c Cat.meow print(hex(id(a))) # 输出0x24d1973bb80 print(hex(id(b))) # 输出0x24d1973bb80 print(hex(id(c))) # 输出0x24d1973bb80可以看到print(类名.实例方法名)的输出结果就像是静态方法那样没有绑定到类或实例事实上非绑定的实例方法就像是静态方法那样不会在每次调用时都会重新创建方法对象。在进行非绑定调用时需要手动传递实例对象而对于绑定式调用实例对象会自动传入并作为实例方法的第一个参数。实际上在进行非绑定调用时传入的甚至可以不是该类的实例如例9所示。# 例9 class Cat: def __init__(self, name): self.name name def meow(self): print(f{self.name} says meow.) class Dog: def __init__(self, name): self.name name def bark(self): print(f{self.name} says bark.) def What(self): print(fThis is just like an {self}) cat1 Cat(Whiskers) dog1 Dog(Fido) Cat.meow(dog1) # 输出Fido says meow. Dog.bark(cat1) # 输出Whiskers says bark. Dog.What(function) # 输出This is just like an function对于例9只要传入bark方法的实例拥有name属性传入meow方法的实例拥有name属性就不会报错这是因为方法中访问了传入对象的name属性。对于What方法传入的参数甚至没要求。警告这是个不建议的行为因为它消除了实例方法和实例之间的绑定甚至在某种意义上该方法都不能称为实例方法了因为可以像调用任何普通的函数一样调用它。一个好的建议是对于所有的实例方法都使用实例绑定式调用。类方法的非绑定调用上面所说的类方法的调用是绑定式调用即对于类方法使用了相应的类调用。这并不是Python强制要求的例10展示了类方法的非绑定调用使用“实例名.类方法名”就可以做到。# 例10 class Bird: species Aves def __init__(self, name): self.name name classmethod def show_species(cls): print(cls) bird1 Bird(Sparrow) # 利用“类名.类方法名”的形式绑定调用会自动将类作为类方法的第一个参数传入 Bird.show_species() # 输出class __main__.Bird # 利用“实例名.类方法名”的形式非绑定调用会自动将实例所属的类作为类方法的第一个参数传入 bird1.show_species() # 输出class __main__.Bird print(Bird.show_species) # 输出bound method Bird.show_species of class __main__.Bird print(bird1.show_species) # 输出bound method Bird.show_species of class __main__.Bird a bird1.show_species b bird1.show_species c bird1.show_species print(id(a)) # 输出2268603949888 print(id(b)) # 输出2268603949952 print(id(c)) # 输出2268603950016可以看到print(实例名.类方法名)的输出结果还是绑定到类且在每次调用时都会重新创建方法对象类方法的非绑定调用要求调用类方法的必须是该类的实例。一个好的建议是对于所有的类方法都使用相应的类进行调用。静态方法的实例调用和访问实例属性其实静态方法只代表着不论是使用实例还是类对其进行调用时不会自动传递实例或类作为参数在实例方法的非绑定调用中手动传入了实例这也代表着静态方法其实也可以访问类或实例属性尽管这不推荐。使用实例名也可以调用静态方法即“实例名.静态方法名”。如例11所示。# 例11 class Math: def __init__(self, x, y): self.x x self.y y staticmethod def add(a, b): return a b staticmethod def mul(self): return self.x * self.y math1 Math(2, 3) # 利用“类名.静态方法名”的形式调用 result1 Math.add(5, 3) print(result1) # 输出8 # 利用“实例名.静态方法名”的形式调用此时相当于使用该实例所属的类调用 result2 math1.add(5, 3) print(result2) # 输出6 print(Math.add) # 输出function Math.add at 0x000001DAE0E9A9D0 这个地址指的是静态方法的地址它不会改变 print(math1.add) # 输出function Math.add at 0x000001DAE0E9A9D0 这个地址指的是静态方法的地址它不会改变 a math1.add b math1.add c math1.add print(hex(id(a))) # 输出0x1dae0e9a9d0 print(hex(id(b))) # 输出0x1dae0e9a9d0 print(hex(id(c))) # 输出0x1dae0e9a9d0 result3 Math.mul(math1) print(result3) # 输出6可以看到print(实例名.静态方法名)的输出结果和print(Math.add)一样都是静态方法的地址且在每次调用时不会重新创建方法对象静态方法的实例调用要求调用静态方法的实例必须是该类的实例。一个好的建议是对于所有的静态方法使用相应的类进行调用并且不要访问任何属性和方法。总结本文总结了Python中类的属性实例属性、类属性和方法实例方法、类方法、静态方法相关的知识点并在最后给出了一些特殊情况这并不是鼓励去使用只是为了更加严谨避免”类方法不能访问实例属性“或”静态方法不能访问属性“之类的绝对说辞。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑