python @property decorator

本文最后更新于:2024年4月3日 晚上

问题

遇到 @property 属性相关的问题,详情为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
## 可以工作
class B:
def test(self):
str = "abc"
# print(type(self.get_a_array))
if str not in self.get_a_array:
print("str is not in array")
else:
print("str is in array")

@property
def get_a_array(self) -> list:
return ["abc", "xyz"]

## 报错:TypeError: argument of type 'property' is not iterable
class A:
@classmethod
def test(cls):
str = "abc"
# print(type(cls.get_a_array))
if str not in cls.get_a_array:
print("str is not in array")
else:
print("str is in array")

@property
def get_a_array(self) -> list:
return ["abc", "xyz"]

可以看到唯一的区别在于调用该属性的位置:一个在实例方法内,一个在类方法中。

加上类型的输出,得到类B中 get_a_array 属性为 list,而类A中get_a_array属性为<class 'property'>,因此查阅相关文献,书写博客

概念

在Python中,@property装饰器是一种用于创建只读属性的方法。它允许类的方法被当作属性来访问,这意味着你可以像访问数据属性一样访问这些方法,而不需要在方法名后加上括号。这种机制提供了一种更加优雅的方式来实现对类内部数据的封装和访问控制。

当你在类定义中使用@property装饰器时,你实际上是在创建一个描述符(descriptor)。描述符是Python中的一种协议,它允许对象自定义它们的属性访问。具体来说,当你使用@property装饰一个方法时,Python会创建一个属性对象,这个对象有一个__get__方法,该方法在访问属性时被调用。

原因

1
2
3
@property
def get_a_array(self) -> list:
return ["abc", "xyz"]

这里,get_a_array被定义为一个只读属性,它的值是一个列表["abc", "xyz"]。在类的实例上访问这个属性时,Python会自动调用__get__方法,返回方法的返回值。因此,在实例方法中,get_a_array的类型是list,因为实际上访问的是方法的返回值。

然而,在类方法中,情况有所不同。当直接通过类访问get_a_array时,实际上访问的是属性对象本身,而不是属性的值。这是因为在这种情况下,没有实例来调用__get__方法。因此,在类方法中,get_a_array的类型是property

这种行为的根本原因在于描述符协议的工作方式。描述符协议定义了对象如何通过__get____set____delete__方法来控制对其属性的访问。当属性被访问时,如果存在相应的描述符方法,Python会调用这些方法。在@property的情况下,只定义了__get__方法,这使得属性成为只读的。当通过实例访问属性时,__get__方法被调用,返回方法的返回值。但是,当通过类访问属性时,没有实例来调用__get__方法,因此你直接访问的是属性对象本身。

总结

总结来说,@property装饰器的行为依赖于它是如何被访问的——通过实例还是通过类。

这解释了为什么在实例方法中get_a_array的类型是list,而在类方法中其类型是property


python @property decorator
https://blogoasis.github.io/post/6541701.html
作者
phInTJ
发布于
2024年4月3日
许可协议