私有属性包括私有变量和私有方法,在 Python 中,在变量名或者方法名前面加上双下划线,这个属性就成为了类的私有属性。
ide
class Person: def __init__(self, name, age): self.__name = name self.__age = age def __fun(self): print(self.__class__) def say(self): self.__fun() # 自动转换为 调用 _Person__fun 方法 print(self.__name + ' ' + str(self.__age)) # 自动转换为 调用 \_Person\_\_name 和 \_Person\_\_age 属性~ p = Person('Kitty', 18) p.say() # 输出结果: Kitty 18
上述示例中,__name 和 __age 为类的私有变量,私有变量仅能在类中进行访问,在类的外部访问不到。函数
p = Person('Kitty', 18) print(p.__name) # 报错信息: AttributeError: 'Person' object has no attribute '__name'
其实在类中定义私有属性时,__name 和 __age 已经自动变形为 _Person__name 和 _Person__age,__fun 自动变形为 _Person__fun,即私有属性会自动变形为_类名__属性~code
p = Person('Kitty', 18) print(p.__dict__) # 输出结果: {'_Person__name': 'Kitty', '_Person__age': 18}
当在类的内部经过属性名称访问私有属性时,会自动进行转换,例如 self.__name 转换为 self._Person__name,在类的外部不会进行这样的自动转换~
类的私有属性只是在语法上作了访问限制,可是并无真正限制从外部的访问。在外部不能经过 对象.__属性 来进行访问,可是能够经过变形后的属性名来进行访问~对象
p = Person('Kitty', 18) # print(p.__name) # 不能这样访问 print(p._Person__name) p._Person__fun() # 结果输出: Kitty <class '__main__.Person'>
对私有属性的访问限制只是一种规范,在开发过程当中通常不容许在外部经过这种方式访问私有属性~
私有属性的变形只在类的内部生效,在定义后的赋值操做,不会变形~blog
p = Person('Kitty', 18) p.__name = 'abc' print(p.__dict__) print(p.__name) # 调用的是 __name 属性,不是私有属性 # 输出结果: {'_Person__name': 'Kitty', '_Person__age': 18, '__name': 'abc'} # 这个属性就叫 __name abc
在子类中定义的私有属性如果和父类中的私有属性同名,不会覆盖父类的这些私有属性,由于这些私有属性变形后的名称不一样,子类:_子类名__属性,父类:_父类名__属性~ip
class Fu: __key = 123 # 静态私有属性 def __init__(self, name): self.__name = name class Zi(Fu): def get_name(self): print(self.__name) # 变形为 self._Zi__name def get_key(self): print(Fu.__key) # 变形为 self._Zi__key zi = Zi('hello') zi.get_name() # 报错信息:AttributeError: 'Zi' object has no attribute '_Zi__name' zi.get_key() # 报错信息:AttributeError: type object 'Fu' has no attribute '_Zi__key'
如果父类中定义的方法不想被子类调用到,能够将方法定义为私有方法~开发
class A: def __fun(self): # 在定义时就变形为_A__fun print('from A') def test(self): self.__fun() # 变形为 self._A__fun(),即以当前的类为准 class B(A): def __fun(self): print('from B') b=B() b.test() # 调用 A类中的test方法,test方法中的 self.__fun() 调用的是 A类中的私有方法__fun() # 输出结果: from A
封装的优点在于将类内部的实现细节隐藏起来,调用者无需了解,直接调用对应的方法便可(方法名,参数都不改变),若功能须要改变,只须要在类的内部进行调整,外部的调用代码无需改变~get
property为内置装饰器函数,只在面向对象中使用。@property装饰器 能够将 对方法的调用转为 对变量的调用。示例以下:it
class Person: def __init__(self, name, age): self.__name = name self.__age = age @property def name(self): return self.__name @property def age(self): return self.__age p = Person('Kitty', 18) print(p.name) print(p.age) # 结果输出: Kitty 18
p.name 和 p.age 实际上是执行了一个函数,而后将结果返回。这种特性的使用方式遵循了统一访问的原则。
p.属性 的这个过程也能够作一些运算操做而后将结果返回~class
class Room: def __init__(self, width, length, high): self.__width = width self.__length = length self.__high = high def area(self): return self.__width * self.__length * self.__high room = Room(1, 2, 3) print(room.area()) # 6
除了 @property,还有 @属性.setter和 @属性.deleter,要注意的是,定义了 property 后才能定义 属性.setter,属性.deleter ~
class Person: def __init__(self, name, age): self.__name = name self.__age = age @property def name(self): return self.__name @name.setter def name(self, value): if not isinstance(value, str): # 在设定值以前进行类型检查 raise TypeError('%s must be str' %value) self.__name = value @name.deleter def name(self): raise TypeError('Can not delete') @property def age(self): return self.__age p = Person('Kitty', 18) p.name = 'nihao' print(p.name) del p.name # TypeError: Can not delete
说明:
执行 p.name 的时候,调用 @name.setter 修饰的方法,这样的赋值方式在真正的赋值以前能够作一些类型检验的操做,或者别的自定义操做,更具灵活性~
执行 del p.name 的时候,调用 @name.deleter 修饰的方法
在使用 @property,@属性.setter 和 @属性.deleter 的时候,这几个地方必须保持一致,即属性名称须要保持一致。
上述示例也能够经过以下方式实现:
class Person: def __init__(self, name, age): self.__name = name self.__age = age def get_name(self): return self.__name def set_name(self, value): if not isinstance(value, str): # 在设定值以前进行类型检查 raise TypeError('%s must be str' %value) self.__name = value def del_name(self): print('delete name') name = property(get_name, set_name, del_name) @property def age(self): return self.__age
Tip:
.................^_^