目录:
-
类属性与实例属性概述
-
类属性示例
-
实例属性示例
-
实例属性与类属性的对比与应用
-
动态设置类属性
类属性与实例属性概述
类属性:类属性是属于类本身而不是类的某个具体实例的变量。这意味着,无论你创建了多少个该类的实例,它们都会共享同一个类属性。修改类属性会影响所有实例。
实例属性:与类属性相对,实例属性是每个实例独立拥有的变量。不同实例可以拥有不同值的实例属性,互不影响。
类属性示例
首先,我们定义一个简单的类Fisherman
,并给它添加一个类属性ocean
来表示所有渔民共有的捕鱼场所。
class Fisherman:
# 类属性,所有Fisherman实例共享的捕鱼地点
ocean = "山海"
def __init__(self, name):
# 实例属性,每个渔民的名字
self.name = name
# 创建两个渔民实例
fisherman1 = Fisherman("摸鱼人甲")
fisherman2 = Fisherman("摸鱼人乙")
print(f"{fisherman1.name} 在 {fisherman1.ocean} 摸鱼。") # 输出: 摸鱼人甲 在 山海 摸鱼。
print(f"{fisherman2.name} 也在 {fisherman2.ocean} 摸鱼。") # 输出: 摸鱼人乙 也在 山海 摸鱼。
# 改变类属性,观察影响
Fisherman.ocean = "云梦泽"
print(f"{fisherman1.name} 现在在 {fisherman1.ocean} 摸鱼了。") # 输出: 摸鱼人甲 现在在 云梦泽 摸鱼了。
print(f"{fisherman2.name} 也在 {fisherman2.ocean}。") # 输出: 摸鱼人乙 也在 云梦泽。
实例属性示例
接下来,让我们为每位渔民添加一个独特的catch_count
实例属性,记录他们的捕鱼数量。
class Fisherman:
ocean = "山海" # 类属性
def __init__(self, name, catch_count=0):
self.name = name # 实例属性
self.catch_count = catch_count # 实例属性,初始捕鱼数量为0
def catch_fish(self, number):
"""模拟捕鱼过程,增加捕鱼数量"""
self.catch_count += number
print(f"{self.name} 捕获了 {number} 条鱼。")
# 创建渔民实例并捕鱼
fisherman1 = Fisherman("摸鱼人甲")
fisherman2 = Fisherman("摸鱼人乙", 5) # 摸鱼人乙 初始有5条鱼
fisherman1.catch_fish(3) # 输出: 摸鱼人甲 捕获了 3 条鱼。
fisherman2.catch_fish(2) # 输出: 摸鱼人乙 捕获了 2 条鱼。
print(f"{fisherman1.name} 的捕鱼总数是 {fisherman1.catch_count} 条。") # 输出: 摸鱼人甲 的捕鱼总数是 3 条。
print(f"{fisherman2.name} 的捕鱼总数是 {fisherman2.catch_count} 条。") # 输出: 摸鱼人乙 的捕鱼总数是 7 条。
实例属性与类属性的对比与应用
-
灵活性:实例属性提供了更多的灵活性,因为每个对象可以有不同的状态。这对于模拟真实世界的复杂性和多样性非常有用。
-
资源效率:类属性在内存中只占用一份空间,所有实例共享,这在处理大量对象且某些信息固定不变时能节省内存。
-
应用场景:在设计游戏、模拟系统或任何需要大量相似但又不完全相同的对象时,类属性和实例属性的组合使用能够大大提高代码的组织性和效率。
动态设置类属性
动态设置类属性:在开发过程中,有时可能需要根据配置文件或用户输入动态地设置类属性,这可以通过类方法实现。
class Fisherman:
ocean = "山海" # 类属性
def __init__(self, name):
self.name = name
@classmethod
def set_common_ocean(cls, new_ocean):
cls.ocean = new_ocean
# 动态改变捕鱼地点
fisherman3 = Fisherman("摸鱼人丙")
print(f"{fisherman3.name} 在 {fisherman3.ocean}。") # 输出: 摸鱼人丙 在 山海。
Fisherman.set_common_ocean("桃花源")
print(f"{fisherman3.name} 在 {fisherman3.ocean} 开始了他的捕鱼生涯。") # 输出: 摸鱼人丙 在 桃花源 开始了他的捕鱼生涯。
fisherman3 = Fisherman("摸鱼人丁")
print(f"{fisherman3.name} 在 {fisherman3.ocean}。") # 输出: 摸鱼人丙 在 桃花源。
使用类属性进行默认值管理:在【实例属性示例】的Fisherman
类中,我们可以看到catch_count
使用了默认参数0
。实际上,对于复杂的默认值需求,类属性可以作为更灵活的默认值管理方式,避免了每次实例化时重复计算默认值的问题。
在该例中,使用了@classmethod
和cls
。
@classmethod 装饰器
作用:@classmethod
装饰器使得一个方法与类关联,而不是与类的实例关联。这意味着你可以直接通过类名来调用这个方法,而不需要创建类的实例。类方法可以访问类属性,也可以修改它们,因为它接收到的是类本身作为参数。
使用场景:
-
当你需要一个方法来创建类的实例,并且这个方法需要根据类的属性来定制实例时,类方法非常有用。
-
当一个方法逻辑上属于类,而不是某个具体的实例,比如工厂方法、辅助方法来操作类属性等。
-
用于实现多态,即子类可以覆盖父类的类方法,提供不同的实现。
cls 参数
含义:在类方法中,cls
是一个约定俗成的名称,代表调用该方法的类。你也可以选择其他名称,但cls
是最常见的命名方式,因为它清晰地表明了这个参数的意图。通过cls
,你可以访问或修改类的属性,调用类的其他类方法,甚至实例化新的对象。