此篇浅谈面向对象理论中的几个技巧
1:@property
- @property 是一个用在类中的装饰器,其作用是把本来在类中定义的方法变成属性,并且在实例化对象中也可以通过属性的方式调用
- 来看一段代码
class cat(object):
def __init__(self, name, age):
self.name = name
self.__age = age
def show_info(self):
print('我叫{},年龄是{}岁。'.format(self.name, self.__age))
if __name__ == '__main__':
cat_black = cat('小黑', 2)
cat_black.show_info()
可以看到这是一个很简单的例子。我们首先定义了一个cat类,然后实例化一只黑猫。黑猫想显示信息,所以调用了类中提供的方法show_infor()
- 接下来,在看看使用了@property的用法
class cat(object):
def __init__(self, name, age):
self.name = name
self.__age = age
# 将方法变成属性,直接调用
@property
def show_info(self):
print('我叫{},年龄是{}岁。'.format(self.name, self.__age))
if __name__ == '__main__':
cat_black = cat('小黑', 2)
cat_black.show_info
为什么要使用 @property
- 这样本来作为方法的show_info就变成了属性,可以通过调用属性的方式来调用方法
2:@setter
- 首先拿一段代码过来
class cat(object):
def __init__(self, name, age):
self.name = name
self.__age = age
if __name__ == '__main__':
cat_black = cat('小黑', 2)
可以看到这是一个很简单的cat类,并且实例化了一只黑猫。
在构造函数中,我们把age属性设置成了私有属性,即在age前面加上了两个下划线。
所谓私有属性,即不能通过以下方式获取和设置的属性
print(cat_black.name) # 这里打印出在构造时设置的名称,小黑
cat_black.name = '小白'# 把名字属性设置成 小白
print(cat_black.name)# 这里可以直接取到name属性,即小白
- 但如果我们想要修改私有属性改怎么办呢?这时就可以使用@setter
class cat(object):
def __init__(self, name, age):
self.name = name
self.__age = age
# 提供在外部通过使用非私有属性的方法获得属性值
@property
def age(self):
print(self.__age)
# 提供在外部通过使用非私有属性的方法设置属性值
@age.setter
def age(self, value):
# 通过这种方式,也可以在设置值时对值进行判断
if not isinstance(value, int):
print("年龄只能是整数")
return 0
if 0 > value or value > 100:
print('年龄只能在0-100之间')
return 0
self.__age = value
if __name__ == '__main__':
cat_black = cat('小黑', 2)
print(cat_black.age)# 输出2
cat_black.age = 9 #对于私有属性可以通过像普通属性一样的方法进行操作
print(cat_black.age)# 输出9
在这段代码中我们可以看到,首先定义了一个age方法,并装饰了上文提到的@property装饰器。该装饰器使得拥有访问私有属性功能的方法变成了属性,这样就可以直接使用属性的方式调用该方法,保持了私有属性和普通属性调用方法的一致
- 对age进行更改。依旧参考上面的代码,在定义的第二个age方法前使用了 @age.setter 装饰器,该装饰器使得私有属性age除了被访问,也具有了被修改的功能
为什么要使用 @setter
- 对于取age属性和修改age属性的方法定义为同名,更使得代码的格式保持了统一,age的使用实现了多态
- 使用 @setter 还可以比普通属性实现赋值时,对增加对于值的判断功能。观察上面的代码,可以发现age的值被定义在了int类型和0-100之间才能正常赋值
3:@staticmethod
静态方法,既可以通过类直接调用方法
class cat(object):
tag = '猫科动物'
def __init__(self, name):
self.name = name
@staticmethod
def breath():
"""呼吸"""
print('猫都会呼吸')
if __name__ == '__main__':
cat_black = cat('小黑') # 实例化一个对象。正常运行
cat_black.breath() # 使用对象调用方法。正常运行
cat.breath() # 使用类调用方法。正常运行
为什么要使用 @staticmethod
观察以下几段代码
- 一:
class cat(object):
tag = '猫科动物'
def __init__(self, name):
self.name = name
def breath(self):
"""呼吸"""
print('猫都会呼吸')
if __name__ == '__main__':
cat_black = cat('小黑') # 实例化一个对象。正常运行
cat_black.breath() # 使用对象调用方法。正常运行
cat.breath() # 使用类调用方法。 !报错!
- 二:
class cat(object):
tag = '猫科动物'
def __init__(self, name):
self.name = name
def breath():
"""呼吸"""
print('猫都会呼吸')
if __name__ == '__main__':
cat_black = cat('小黑') # 实例化一个对象。正常运行
cat_black.breath() # 使用对象调用方法。 !报错!
cat.breath() # 使用类调用方法。正常运行
结合上面的三段代码,可以发现如果想要让类和对象能采用相对的代码格式使用同一个方法的时候,就需要使用 @staticmethod 装饰器来装饰这个方法
4:@classmethod
类的方法,即对象不能调用的方法(理论上)
class cat(object):
tag = '猫科动物'
def __init__(self, name):
self.name = name
def show_info(self):
print('类的属性:{},实例的属性:{}.'.format(self.tag, self.name))
@classmethod
def test(cls, name):
return cat(name)
- 通过观察代码,在 @classmate 修饰的方法中,原本的self变成了cls,表示由对象变成了类,那么这个方法该怎么用呢?
if __name__ == '__main__':
cat_black = cat('小黑') # 正常的析构方法
cat_black.show_info()
cat_daju = cat.test('大橘') # 使用类调用test方法
cat_daju.show_info()
c_xiaohua = cat_daju.test('小花') # 使用对象去调用类的方法
c_xiaohua.show_info()
为什么要使用 @classmethod
- 不知道
5:slots
slots 为类设置一个静态的属性列表,即不允许出现其他的属性和方法
class cat(object):
def __init__(self, name, age):
self.name = name
self.age = age
def eat():
print('我喜欢吃鱼')
if __name__ == '__main__':
cat_black = cat('小黑',2)
cat_black.color = '黑色'
cat_black.eat = eat
- 可以看到在上面的代码中,我们向cat类中添加了一个本来不存在的属性color
- 同时还添加了一个名为eat的方法
class cat(object):
__slots__ = ('name', 'age')
def __init__(self, name, age):
self.name = name
self.age = age
def eat():
print('我喜欢吃鱼')
if __name__ == '__main__':
cat_black = cat('小黑',2)
cat_black.color = '黑色' # !报错!
cat_black.eat = eat # !报错!
为什么要使用 slots
- 限制对于类的随意修改
- 节省内存空间