访问可见性
很多面向对象编程语言中,通常会将对象的属性设置为私有的(private)或受保护的(protected),简单的说就是不允许外界访问,而对象的方法通常都是公开的(public),因为公开的方法就是对象能够接受的消息。
在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头:
class Test(object):
def __init__(self, foo):
self.__foo = foo
def __bar(self):
print(self.__foo)
print('__bar')
def main():
test = Test('hello')
test.__bar() # AttributeError: 'Test' object has no attribute '__bar'
print(test.__foo) # AttributeError: 'Test' object has no attribute '__foo'
if __name__ == "__main__":
main()
然而实际上并没有任何办法让python的类属性和方法完全私有,我们仍可以从外界这样调用:
test = Test('hello')
test._Test__bar()
print(test._Test__foo)
其实两个下划线开头的变量只是让原变量名字变了,来“妨碍”我们调用它。但实际开发中,并不建议将属性设置为私有的,因为这会导致子类无法访问。因此约定俗成的变量属性写法是单下划线加变量名(_xx),这并不是语法规则,也不能阻止外部代码调用它,只是告诉你这是个类属性,请不要从外部直接调用,“防君子不防小人”。
@property装饰器
如果外部想直接访问类的属性,但同时又不建议直接访问,办法是使用装饰器将类方法“伪装”成属性,通过属性的getter(访问器)和setter(修改器)方法进行对应的操作,既方便又安全。
class Person(object):
def __init__(self, name, age):
self._name = name
self._age = age
# 访问器 - getter方法
@property
def name(self):
return self._name
# 修改器 - setter方法
@name.setter
def name(self, name):
self._name = name
# 访问器 - getter方法
@property
def age(self):
return self._age
# 修改器 - setter方法
@age.setter
def age(self, age):
self._age = age
def main():
p = Person('小明', 12)
print(p.name)
p.name = '大明'
print(p.name)
print(p.age)
p.age = 16
print(p.age)
if __name__ == '__main__':
main()
注意访问器和修改器下定义的类方法名称要一致。
静态方法和类方法
静态方法无需将类实例化,直接在类之后使用。最常见的使用场景是校验类传入值是否符合要求,比如实例化三角形前判断传入的三条边长是否能构成三角形:
class Triangle(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
@staticmethod #静态方法装饰器
def is_valid(a, b, c): # 无需传入表示实例参数self,也无需传入表示类参数cls
return a + b > c and b + c > a and a + c > b
def main():
if Triangle.is_valid(3, 4, 5): # 调用静态方法前面需要跟上类名称
t = Triangle(3,4,5)
if __name__ == '__main__':
main()
和静态方法比较类似,Python还可以在类中定义类方法,类方法的第一个参数约定名为cls,它代表的是当前类相关的信息的对象(类本身也是一个对象,有的地方也称之为类的元数据对象),通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象:
class Triangle(object):
def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c
@staticmethod #静态方法装饰器
def is_valid(a, b, c): # 无需传入表示实例参数self,也无需传入表示类参数cls
return a + b > c and b + c > a and a + c > b
@classmethod
def create_triangle(cls, a, b, c):
if cls.is_valid(a, b, c):
return cls(a, b, c)
else:
return '无法构成三角形'
def main():
t = Triangle.create_triangle(3,4,5)
if __name__ == '__main__':
main()
该例中类方法调用了静态方法,当条件满足时,创建类的实例;不满足时输出提示信息。注意类方法用来被类直接调用,但实例也可以调用类方法,同理对于静态方法类和实例都可以调用。