属性、property和属性描述符

发布时间 2023-06-11 13:54:30作者: 腐汝

1、实例属性和类属性的区别

在 Python 中,类属性是定义在类级别上的变量或常量,它们是所有该类实例共享的值。而实例属性是定义在实例级别上的变量或常量,每个实例都有其自己的值。

 区别主要在于:
  1. 值的存储位置:类属性存储在类的命名空间中,而实例属性存储在实例的命名空间中。
  2. 访问方式:类属性可以通过类名或实例访问,但实例属性只能通过实例访问。
  3. 继承:子类会继承父类的类属性,但不会继承父类的实例属性。

示例:

class MyClass:
    class_attribute = 'class_value'

    def __init__(self, instance_attribute):
        self.instance_attribute = instance_attribute

my_instance_1 = MyClass('instance_value_1')
my_instance_2 = MyClass('instance_value_2')

print(MyClass.class_attribute)  # 输出:'class_value'
print(my_instance_1.class_attribute)  # 输出:'class_value'
print(my_instance_1.instance_attribute)  # 输出:'instance_value_1'
print(my_instance_2.instance_attribute)  # 输出:'instance_value_2'

在上述代码中,class_attribute 是一个类属性,被 MyClass 的所有实例共享。而 instance_attribute 则是一个实例属性,每个实例都有一份自己的值。

 

2、property应用场景

  1. 计算属性:有时候我们需要根据对象的状态计算出某个属性的值,这时候可以使用 property 将一个方法转换成一个只读属性,以便在访问这个属性时动态计算出其值。

  2. 数据校验:当我们想要限制对象的某个属性的取值范围或格式时,可以使用属性的 setter 方法对输入数据进行校验,并确保它们满足要求。

  3. 防止意外修改:有时候我们希望某些属性只能被读取,而不能被修改,可以使用 property 将其设置为只读属性。

  4. 封装内部实现细节:属性还可以用来隐藏对象内部的实现细节,从而提高代码的安全性和可维护性。

3、属性描述符和proprety的区别

属性描述符和property都是Python中用于定义类属性的机制,但它们的实现方式不同。

属性描述符是一个类,该类定义了三个方法:__get__()__set__()__delete__()。这些方法允许您控制属性的访问、修改和删除。属性描述符可以与任何类属性一起使用,并且一个属性描述符可以被多个类属性共享。当一个属性描述符被赋值给一个类属性时,它会替换该属性的默认行为。例如,在一个类中定义一个属性描述符用于限制属性的取值范围:

 
class Range:
    def __init__(self, min_value, max_value):
        self.min_value = min_value
        self.max_value = max_value

    def __get__(self, instance, owner):
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        if value < self.min_value or value > self.max_value:
            raise ValueError("Value out of range")
        instance.__dict__[self.name] = value

    def __set_name__(self, owner, name):
        self.name = name

class MyClass:
    x = Range(0, 10)

my_obj = MyClass()
my_obj.x = 5
print(my_obj.x)
my_obj.x = 15 # Raises ValueError: Value out of range

在这个例子中,属性描述符Range控制了属性x的取值范围。

 

另一方面,property是一个内置函数,它提供了一种简化属性访问的方式。与属性描述符不同,property不是一个类,而是一个包装器函数,它接受三个可选参数:fgetfsetfdel。这些参数分别指定获取、设置和删除属性时所调用的方法。如果只需要定义读取属性的方法,则可以省略fsetfdel。例如:

 
class MyClass:
    def __init__(self, x):
        self._x = x

    @property
    def x(self):
        print("Getting x")
        return self._x

    @x.setter
    def x(self, value):
        print("Setting x")
        self._x = value

my_obj = MyClass(5)
print(my_obj.x) # Calls getter method
my_obj.x = 10 # Calls setter method

在这个例子中,property包装器定义了一个名为x的属性,使用@property修饰器标记getter方法,使用@x.setter修饰器标记setter方法。这样就可以像访问普通属性一样来访问和修改x属性。当访问x属性时,会自动调用getter方法;当修改x属性时,会自动调用setter方法。

总的来说,属性描述符提供了更灵活的属性控制机制,而property则提供了更简单、更易于使用的语法糖。