来源:《Python从小白到大牛》关东升
1、封装性
封装性是面向对象的三大特征之一,Python语言没有与封装性相关的关键字,它通过特定的名称实现对变量和方法的封装。
1.1私有变量
默认情况下Python中的变量是公有的,可以在类的外部访问他们。如果想让他们成为私有变量,可以在变量前加上双下划线“__”。
class Animal(object):
"""定义动物类"""
def _inti_(self,age,sex=1,weight=0.0):
self.age=age # 定义年龄实例变量
self.sex=sex # 定义性别实例变量
self.__weight=weight # 定义体重实例变量
def eat(self):
self.__weight+=0.01
print('eat...')
def run(self):
self.__weight-=0.01
print('run...')
a1=Animal(2,0,10.0)
print('a1体重:{0:0.2f}'.format(a1.weight))
a1.eat()
a1.run()
运行结果:Traceback(most recent call last):...
AttributeError:'Animal' object has no attribute 'weight'
上述内容中self.__weight=weight,weight前面加了双下画线,这会定义私有变量__weight。__weight变量在类内部访问没有问题,但是如果在外部访问则会发生错误。
提示:Python中并没有演的意义上的封装,所谓的私有变量只是形式上的限值,如果想在类的外部访问这些私有变量也是可以的,这些双下画线"__"开头的私有变量其实只是换了一个名字,他们的命名规律为“__类名__变量”,所以将上述代码al.weight改成al._Animal_weight就可以访问了,但这种访问方式并不符合规范,会破坏封装。可见Python的封装性靠的是程序员的自律,而非强制性的语法。
1.2私有方法
私有方法与私有变量的封装是类似的,只要在方法前加上双下画线“__”就是私有方法了。
class Animal(object):
"""定义动物类"""
def _inti_(self,age,sex=1,weight=0.0):
self.age=age # 定义年龄实例变量
self.sex=sex # 定义性别实例变量
self.__weight=weight # 定义体重实例变量
def eat(self):
self.__weight+=0.01
self._run()
print('eat...')
def _run(self):
self.__weight-=0.01
print('run...')
a1=Animal(2,0,10.0)
a1.eat()
a1.run()
运行结果为:
eat...
Traceback(most recent call last):...
AttributeError:'Animal' object has no attribute 'run'
上述代码中__run()方法是私有方法,__run()方法可以在类的内部访问,不能在类的外部访问,否则会发生错误。
提示:如果一定要在类的外部访问私有方法也是可疑的。与私有变量访问类似,命名规律为“__类名__方法”。这也是不符合规范,也会破坏封装。
1.3定义属性
封装通常是对成员进行的封装。在严格意义上的面向对象设计中,一个类是不应该有公有的实例成员变量的,这些实例成员变量应该被设计为私有的,然后通过公有的setter和getter访问器访问。
class Animal(object):
"""定义动物类"""
def _inti_(self,age,sex=1,weight=0.0):
self.age=age # 定义年龄实例变量
self.sex=sex # 定义性别实例变量
self.__weight=weight # 定义体重实例变量
def set_weight(self,weight):
self.__weight=weight
def get_weight(self):
return self.__weight
a1=Animal(2,0,10.0)
print('a1体重:{0:0.2f}'.format(a1.get_weight())) # 10.00
a1.set_weight(123.45)
print('a1体重:{0:0.2f}'.format(a1.get_weight())) # 123.45
上述set_weight()方法是setter访问器,他有一个参数,用来替换现有成员变量。get_weight方法是getter访问器。
访问器形式的封装需要一个私有便令,需要提供getter访问器和一个setter访问器,只读变量不用提供setter访问器。总之,访问器形式的封装在编写代码时比较麻烦。为了解决这个问题,Python中提供了属性(property),定义属性可以使用@property和@属性名.setter装饰器,@property用来装饰getter访问器,@属性名.setter用来装饰setter访问器。
class Animal(object):
"""定义动物类"""
def _inti_(self,age,sex=1,weight=0.0):
self.age=age # 定义年龄实例变量
self.sex=sex # 定义性别实例变量
self.__weight=weight # 定义体重实例变量
@property
def weight(self): # 替代get_weight(self):
return self.__weight
@weight.setter
def weight(self,weight): # 替代set_weight(self,weight):
self.__weight=weight
a1=Animal(2,0,10.0)
print('a1体重:{0:0.2f}'.format(a1.get_weight())) # 10.00
a1.weight(123.45) # a1.set_weight(123.45)
print('a1体重:{0:0.2f}'.format(a1.get_weight())) # 123.45
定义属性getter访问器,使用了@property装饰器进行修饰,方法名就是属性名,这样就可以通过属性取值了。定义属性setter访问器,使用了@weight.setter装饰器进行修饰,weight是属性名,与getter和setter访问器方法名保持一致,可以通过a1.weight(123.45)赋值。属性本质就是两个方法,在方法前面加上装饰器使得方法成为属性。属性使用起来类似于共有变量,可以在赋值符“=”左边或右边,左边是被赋值,右边是取值。
提示:定义属性时应该先定义getter访问器,在定义setter访问器。同时定义顺序不能颠倒,否则会出现错误。这是因为@property修饰getter访问器时, 定义了weight属性,这样在后面使用@weight.setter装饰器才是合法的。
1万+



被折叠的 条评论
为什么被折叠?



