在 Python 中语言中,类属性和实例属性是两个不同的概念。理解这两个属性的区别和用途对于编写清晰、高效的代码非常重要。类属性通常用于定义所有实例共享的数据。例如,植物种类、常量值、静态配置信息等。
Python类属性分类:
1. 类属性
类属性是定义在类体中,不属于任何实例的变量。它们由类名直接访问和修改,所有实例共享同一个类属性。访问类属性时,直接使用类名加属性名即可,如ClassName.class_attribute。修改时,也是通过类名进行。
2. 实例属性
实例属性是定义在类的实例(对象)上的变量,每个实例可以有自己的实例属性,互不干扰。访问实例属性时,需要通过实例对象名加属性名的方式,如instance.instance_attribute。实例属性通常在实例化对象时通过__init__方法或其他方法设置。
3. 私有属性
Python中并没有真正的私有属性,但可以通过在属性名前加双下划线(__)来模拟私有属性。这样的属性在外部无法直接访问,但可以通过类内部定义的方法来间接访问和修改。访问时,Python会自动将属性名“变形”,所以外部无法直接通过变形后的名字访问。
4. 继承中的属性访问
在继承体系中,子类可以继承父类的属性。访问时,如果子类没有同名属性,则直接访问父类的属性;如果子类定义了同名属性,则默认访问子类的属性,但可以通过super()函数或直接通过父类名来访问父类的同名属性。
5. 特殊属性
Python中还有一些特殊属性,如__dict__、__class__等,它们提供了对对象内部状态的访问。__dict__属性包含了对象(或类)的所有属性和方法的字典表示,而__class__属性则指向了对象的类。这些特殊属性为Python的反射和动态特性提供了强大的支持。
属性的定义:
python中的属性其实是普通方法的衍生。
操作类属性有三种方法:
1.使用@property装饰器操作类属性。
2.使用类或实例直接操作类属性(例如:obj.name,obj.age=18,del obj.age)
3.使用python内置函数操作属性。
属性存在的意义:
1、访问属性时可以制造出和访问字段完全相同的假象,属性由方法衍生而来,如果Python中没有属性,方法完全可以代替其功能。
2、定义属性可以动态获取某个属性值,属性值由属性对应的方式实现,应用更灵活。
3、可以制定自己的属性规则,用于防止他人随意修改属性值。
与实例属性区别
类属性是直接在类体中定义的属性,不属于任何一个实例,而是属于类本身。所有的实例共享同一个类属性。当你修改类属性时,所有实例都能看到变化。实例属性是在类的每一个实例中独立存在的属性。它们通常在 __init__
方法中定义。每个实例都有自己的实例属性,互不影响。
在 Python 中,属性可以分为实例属性和类属性:
- 实例属性 是在类的
__init__
方法中定义的,属于特定实例,每个实例都有自己的独立属性。 - 类属性 是在类体中定义的,属于类本身,在所有实例之间共享。
示例
假设我们要创建一个计数器类,每创建一个新的计数器实例,总的计数器数目就会增加,这样我们可以跟踪一共创建了多少个计数器实例。
class Counter:
# 类属性,用于跟踪创建的实例数
count = 0
def __init__(self, name):
# 实例属性
self.name = name
# 每创建一个新实例,类属性 count 增加
Counter.count += 1
def __del__(self):
# 实例被销毁时,类属性 count 减少
Counter.count -= 1
# 创建三个 Counter 实例
c1 = Counter("Counter 1")
c2 = Counter("Counter 2")
c3 = Counter("Counter 3")
# 输出类属性 count
print(Counter.count) # 输出: 3
# 销毁一个实例
del c1
# 输出类属性 count
print(Counter.count) # 输出: 2
解释:
- 类属性 count:用于记录创建的 Counter 实例总数。它属于类本身,所有实例共享。
- 实例属性 name:用于存储每个 Counter 实例的名称。每个实例都有自己独立的 name 属性。
运行流程:
- 创建第一个 Counter 实例 c1 时,Counter.count 增加到 1。
- 创建第二个 Counter 实例 c2 时,Counter.count 增加到 2。
- 创建第三个 Counter 实例 c3 时,Counter.count 增加到 3。
- 当删除实例 c1 时,Counter.count 减少到 2。
这个例子展示了类属性如何在所有实例之间共享并用于跟踪全局状态,而实例属性则用于存储每个实例独有的数据。
增加修改
在 Python 中,类属性的增加、修改和删除可以通过类本身或者类的实例来操作。可以直接在类体中定义类属性,或者在类外部动态添加类属性。类属性可以通过类本身或者任何一个实例来修改。然而,最好通过类本身来修改类属性以避免混淆。可以使用 del 语句删除类属性。
下面是一个更完整的示例,展示如何增加、修改和删除类属性。
class Example:
class_attr = 10
# 创建实例
e1 = Example()
e2 = Example()
# 访问类属性
print(Example.class_attr) # 输出: 10
print(e1.class_attr) # 输出: 10
print(e2.class_attr) # 输出: 10
# 修改类属性
Example.class_attr = 20
print(Example.class_attr) # 输出: 20
print(e1.class_attr) # 输出: 20
print(e2.class_attr) # 输出: 20
# 动态增加类属性
Example.new_class_attr = 30
print(Example.new_class_attr) # 输出: 30
print(e1.new_class_attr) # 输出: 30
print(e2.new_class_attr) # 输出: 30
# 删除类属性
del Example.class_attr
# 尝试访问已删除的类属性
try:
print(Example.class_attr)
except AttributeError as e:
print(e) # 输出: type object 'Example' has no attribute 'class_attr'
# 检查实例是否还能访问已删除的类属性
try:
print(e1.class_attr)
except AttributeError as e:
print(e) # 输出: type object 'Example' has no attribute 'class_attr'
案例
以下是一个关于商品打折的应用,通过类属性可以设置统一的折扣:
class Product:
discount = 0.5 # 类属性,所有实例共享
def __init__(self, name, price):
self.name = name # 实例属性
self.price = price # 实例属性
def get_price_after_discount(self):
return self.price * (1 - Product.discount)
# 创建实例
p1 = Product('Laptop', 1000)
p2 = Product('Phone', 500)
# 输出打折后的价格
print(p1.get_price_after_discount()) # 输出: 500.0
print(p2.get_price_after_discount()) # 输出: 250.0
应用场景及案例
类属性在很多场景中都非常有用,尤其是当你需要在类的所有实例之间共享数据时。以下是几个常见的类属性用途和场景:
计数器
跟踪类的实例数目。通过类属性可以方便地记录和访问某个类已经创建的实例数量。
class Counter:
instance_count = 0
def __init__(self):
Counter.instance_count += 1
@classmethod
def get_instance_count(cls):
return cls.instance_count
c1 = Counter()
c2 = Counter()
print(Counter.get_instance_count()) # 输出: 2
配置和常量
类属性可以用于存储与类相关的常量或配置信息,例如数据库连接信息、默认配置参数等。
class Config:
DATABASE_URI = "sqlite:///:memory:"
DEBUG = True
print(Config.DATABASE_URI) # 输出: sqlite:///:memory:
print(Config.DEBUG) # 输出: True
共享状态
当多个实例需要共享状态或数据时,类属性非常有用。例如,跟踪一个游戏中所有玩家的总得分。
class Player:
total_score = 0
def __init__(self, score):
self.score = score
Player.total_score += score
@classmethod
def get_total_score(cls):
return cls.total_score
p1 = Player(10)
p2 = Player(20)
print(Player.get_total_score()) # 输出: 30
缓存和共享资源
类属性可以用来缓存计算结果或共享资源,以便所有实例都能访问,而无需每次都重新计算或创建。
class MathOperations:
_factorial_cache = {}
@classmethod
def factorial(cls, n):
if n in cls._factorial_cache:
return cls._factorial_cache[n]
if n == 0:
result = 1
else:
result = n * cls.factorial(n-1)
cls._factorial_cache[n] = result
return result
print(MathOperations.factorial(5)) # 输出: 120
print(MathOperations._factorial_cache)
# 输出: {5: 120, 4: 24, 3: 6, 2: 2, 1: 1, 0: 1}
@classmethod
装饰器类方法和静态方法
类属性可以与类方法(使用 @classmethod
装饰器)或静态方法(使用 @staticmethod
装饰器)结合使用,以实现一些与类相关的操作或逻辑。
class MyClass:
class_attribute = 0
@classmethod
def increment_class_attribute(cls):
cls.class_attribute += 1
@staticmethod
def static_method_example():
return "This is a static method."
MyClass.increment_class_attribute()
print(MyClass.class_attribute) # 输出: 1
print(MyClass.static_method_example())
# 输出: This is a static method.
使用@property装饰器操作类属性。
定义时,在普通方法的基础上添加@property装饰器;属性仅有一个self参数,调用时无需括号;
优点:
1) @property装饰器可以实现其他语言所拥有的getter,setter和deleter的功能(例如实现获取,设置,删除隐藏的属性)
2) 通过@property装饰器可以对属性的取值和赋值加以控制,提高代码的稳定性。
#encoding=utf-8
class Goods(): #新式类
@property
def price(self): #查看属性值
print ('@property ')
@price.setter #修改、设置属性
def price(self, value):
print ('@price.setter' )
@price.deleter #删除属性
def price(self):
print ('@price.deleter')
obj = Goods(50)
obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
obj.price = 2000 # 自动执行 @price.setter 修饰的 price 方法,并将2000赋值给方法的参数
del obj.price # 自动执行 @price.deleter 修饰的 price 方法
结果输出:
@property
@price.setter
@price.deleter
实例代码2:通过@property装饰器对属性的取值和赋值加以控制
class Goods(object):
def __init__(self):
self.value=50
@property
def price(self): # 查看属性
return self.value
@price.setter # 添加或设置属性(属性名.setter)
def price(self, value):
if value >=50 and value<=100: #对属性的取值和赋值加以控制
self.value=value
print (self.value)
else:
print ("请输入一个50到100之间的数!")
@price.deleter # 删除属性(属性名.deleter) 注意:属性一旦删除,就无法设置和获取
def price(self):
del self.value
print ("price is deleted!")
obj = Goods()
print (obj.price) # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
obj.price=106 # 自动执行 @price.setter 修饰的 price 方法,并将106 赋值给方法
del obj.price # 自动执行 @price.deleter 修饰的 price 方法
结果输出:
50
请输入一个50到100之间的数!
price is deleted!
总结
Python的面向对象编程特性通过丰富的属性机制,使得代码更加模块化、易于管理和维护。理解并掌握这些属性的种类及其访问方式,对于编写高质量的Python代码至关重要。无论是类属性、实例属性、私有属性,还是继承中的属性访问和特殊属性,都是Python面向对象编程中不可或缺的知识点。