前一章讲了类和对象的创建,现在我们讲一讲如何使用或访问类和对象的属性和方法。我们依然以Dog类的例子为例。
class Dog:# 类变量,所有对象共享dogs_count = 0 # 记录狗的创建数量def __init__(self, breed: str, hair_color: str):# 实例变量,每个对象独有self.breed = breedself.hair_color = hair_colorDog.dogs_count += 1# 成员方法或成员函数def action(self) -> str:if self.breed == "金毛":return "它的行为很聪明!"elif self.breed == "哈士奇":return "它的行为有点蠢!"return "不明狗品种!"dog1 = Dog(breed="金毛", hair_color="golden")dog2 = Dog(breed="哈士奇", hair_color="black-white")
一、访问属性或方法
从例子就可以推断出,类或对象在访问属性或方法时,使用的就是“类.属性”、“类.函数(参数)”、“对象.属性”、“对象.函数(参数)”的形式。例如:
print(f"The breed of dog1: {dog1.breed}")print(f"Let dog2 do something: {dog2.action()}")print(f"The count of dogs: {Dog.dogs_count}")# Output:# The breed of dog1: 金毛# Let dog2 do something: 它的行为有点蠢!# The count of dogs: 2
对象调动成员函数执行时,self相当于变为了当前对象,例如“dog2.action()”执行时,执行“self.breed”相当于执行“dog2.breed”。
除访问属性外,也可以使用同样的方法修改属性:
dog1.breed = "中华田园犬"Dog.dogs_count = 0print(f"New breed of dog1: {dog1.breed}")print(f"New count of dogs: {Dog.dogs_count}")# Output:# New breed of dog1: 中华田园犬# New count of dogs: 0
另需注意,尽管“dogs_count”是类变量,dog1、dog2等对象也是可以通过属性访问的方式获取到的,但是通常不推荐这么做,容易出现歧义或误解。
除上述内容外,还可以使用如如下函数来访问属性:
getattr(obj, name[, default]) : 访问对象的属性(name),可以设置属性不存在时的默认返回值(default)。
hasattr(obj, name) : 检查是否存在某个属性。
setattr(obj, name, value) : 修改一个属性,如果不存在,则创建新属性。
delattr(obj, name) : 删除属性。
print(getattr(dog1, "name", "Papi"), end=", ")print(hasattr(dog1, "age"), end=", ")setattr(dog1, "age", 3)print(getattr(dog1, "age"), end=", ")delattr(dog1, "hair_color")print(hasattr(dog1, "hair_color"))# Output: Papi, False, 3, False
二、内置类属性
Python的类内置类一些属性,用于获取类的一些基本信息。例如:
__dict__:类的属性,包含一个字典,由类的数据属性组成。
__doc__ :类的文档字符串。
__name__:类名。
__module__:类定义所在的模块。
__bases__ :类的所有父类构成元素。
print("Dog.__doc__: ", Dog.__doc__)print("Dog.__dict__: ", Dog.__dict__)print("Dog.__name__: ", Dog.__name__)print("Dog.__module__: ", Dog.__module__)print("Dog.__bases__: ", Dog.__bases__)# Output:# Dog.__doc__: None# Dog.__dict__: {'__module__': '__main__', 'dogs_count': 2, '__init__': <function...# Dog.__name__: Dog# Dog.__module__: __main__# Dog.__bases__: (<class 'object'>,)
注意,如果类不继承自某个父类,则其父类默认为object,此时解释器会为其自动添加,也可手动写入。
三、对象销毁
Python使用引用计数这一技术来跟踪和回收垃圾,即Python内部记录着所有使用中的对象被引用多少次。对象被创建时,就创建了一个引用计数,当这个对象不再需要时,即其引用计数变为0时,将被垃圾回收。但回收不是“立即”发生的,而是由解释器在适当的时机,将垃圾对象占用的内存空间回收。
a = 10 # 创建 int 对象 <10>b = a # 增加<10>的引用的计数del a # 减少<10>的引用计数b = 30 # 减少<10>的引用计数
上述代码,关键词“del”用于销毁一个变量。
回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用。循环引用,即两个对象相互引用,但是没有被其他变量引用。此时仅使用引用计数是无法满足要求的。Python提供了垃圾收集器作为引用计数的补充,用于注意未通过引用计数销毁的对象,便于解释器适时清理这些循环。
在类中,析构函数“__del__”会在对象被销毁时被调用,该函数同样解释器会自动填充,也可以手动修改其功能及重写析构函数函数。例如。我们在Dog类中添加如下析构函数:
def __del__(self):print(f"{self.breed} has been removed")
然后销毁对象dog1:
del dog1# Output: 金毛 has been removed
此时dog1被销毁,同时执行析构函数中的操作逻辑。
往期回顾:
用PyEcharts将多个图表联动起来!|PyEcharts教程Part.8