最近在看一些源代码时,发现很多工程会用到python面向对象的一些高级一点的属性(至少是我之前没用过的,感觉自己的代码还是太低级了。所以在这里记录一下:
我阅读的代码如下所示:
@property
def ofmap_size(self):
"""
Get size of one output fmap.
"""
return self.hofm * self.wofm * self.nimg
@property
def total_ofmap_size(self):
"""
Get total size of all output fmaps.
"""
return self.nofm * self.ofmap_size
这是一个实现深度学习模型算子融合的代码,其中这是为表示模型层新构建的类,这两个方法主要是返回该层输出激活尺寸和所有的输出激活大小。再看代码时我在想如果我写,我肯定不会加入@property属性,不知道其有什么作用。
在第一个参考资料中,其说明如果在一个类中的方法加入@property
属性修饰,那么该方法就可以用像调用类属性的格式调用,例如下面的示例:
class Dog:
def __init__(self, name, gender, age, type) -> None:
self.name = name
self.gender = gender
self.age = age
self.type = type
@property
def grow(self):
age = self.age + 1
return age
dog = Dog("xiaohei", "male", 5, "tugou")
new_age = dog.grow
print(dog.age, new_age)
结果:
5 6
如果我们以另一种方式调用grow
,如:new_age = dog.grow()
,那么会报错如下:
----> 1 new_age = dog.grow()
2 print(dog.age, new_age)
TypeError: 'int' object is not callable
也就是说,在这里,本来是作为方法的grow,现在变成了一个属性。
在资料中,其指出,该方法可以被用作返回python中的只读属性,在python中没有真正实现只读属性,借用评论区中的评论:
类中定义私有属性有两种方式:一种用单下划线,表示这个属性是类的私有属性,不希望被外部访问到,但仅仅是不希望,还是可以被访问的;第二种是双下划线,表示这个属性就是类的私有属性,只能在类中被使用,不可以在实例化的对象中去使用。
纠正一下,类中 单下划线和双下划线的属性,在类外部,均可以使用实例化对象访问并且修改。区别在于:双下划线的属性名 ____FileName 被解释器重写为 _ClassName__FileName ,所以访问或者修改它的时候是 实例名._ClassName__FileName ,而单下划线的属性 _FileName,依然可以用 实例名._FileName 访问或修改
那么我们就可以使用上述@property
实现一种只读属性方法,如下:
class Dog:
def __init__(self, name, gender, age, type) -> None:
self.name = name
self.gender = gender
self._age = age
self.type = type
@property
def age(self):
return self._age
dog = Dog("xiaohei", "male", 5, "tugou")
print(dog.age)
结果:
5
dog.age += 1
print(dog.age)
结果:
AttributeError Traceback (most recent call last)
in
----> 1 dog.age += 1
2 print(dog.age)
AttributeError: can't set attribute
这样的话,用户可以直接用dog.age
返回其age属性,但是又不能随意修改。这样就很像实现了只读属性。
上面我们只实现了只读属性,我们不能直接修改它,除非直接调用_age
属性。而我们可以使用另一种方法实现对其修改。代码如下:
class Dog:
def __init__(self, name, gender, age, type) -> None:
self.name = name
self.gender = gender
self._age = age
self.type = type
@property
def age(self):
return self._age
@age.setter
def age(self, new):
self._age = new
dog = Dog("xiaohei", "male", 5, "tugou")
print(dog.age)
dog.age = 8
print(dog.age)
结果:
5
8
可以看到,类中表示age的真实属性是_age
,但是我们通过dog.age
就实现了对其访问和修改,就很像我们在C++中设置私有属性_age
,而设置公有方法get_age
和set_age
对该私有属性进行操作。