一、封装概念
封装是面向对象的特征之一,是对象和类概念的主要特性。
封装就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
二、隐藏属性
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
其实这仅仅这是一种变形操作,类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式。
class A: __x = 1 # _A__x = 1 def __init__(self, name): self.__name = name # self._A__name='egon' def __foo(self): # _A__foo print('%s foo run' % self.__name) def bar(self): self.__foo() # self._A__foo() print('from bar') # 无法找到类的属性和函数: # print(A.__x) # print(A.__foo) print(A.__dict__) # 可以查看到_A__foo;bar这两个函数 # 输出:{'__module__': '__main__', '_A__x': 1, '__init__': <function A.__init__ at 0x101f211e0>, '_A__foo': <function A.__foo at 0x101f21378>, 'bar': <function A.bar at 0x101f212f0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None} a = A('egon') a._A__foo() # 通过这种方式可以访问类隐藏函数 # 输出:egon foo run a.bar() """ egon foo run from bar """
可以看到类的属性和函数在前面加'__',在类定义阶段就发生了变形,变形后在外部就无法通过.__x或.__func来调用。
1、自动变形的特点
1)类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
2)这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。
3)在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
class Foo: def __func(self): # _Foo_func print('from foo') class Bar(Foo): def __func(self): # _Bar__func print('from bar') b = Bar() # b.func() # AttributeError:没有这个属性 b._Bar__func() # 输出:from bar
2、变形需要注意的问题
1)知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了
class B: __x = 1 def __init__(self, name): self.__name = name print(B._B__x) """ 1 """
2)变形的过程只在类的定义时发生一次,定义后的赋值操作,不会变形
>>> class A: ... def __init__(self): ... self.__X=10 ... >>> a=A() >>> a.__dict__ {'_A__X': 10} >>> a.__Y=2131 >>> a.__dict__ {'_A__X': 10, '__Y': 2131} # __Y没有变形
3)在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
class A: def __foo(self): # _A__foo print('A foo') def bar(self): print('A.bar') self.__foo() # self._A__foo() class B(A): def __foo(self): # _B__foo print('B.foo') b = B() b.bar() """ A.bar A foo # 只在自己类找方法不去其他类查找,子类不覆盖父类方法 """
#正常情况 >>> class A: ... def fa(self): ... print('from A') ... def test(self): ... self.fa() ... >>> class B(A): ... def fa(self): ... print('from B') ... >>> b=B() >>> b.test() from B #把fa定义成私有的,即__fa >>> class A: ... def __fa(self): #在定义时就变形为_A__fa ... print('from A') ... def test(self): ... self.__fa() #只会与自己所在的类为准,即调用_A__fa ... >>> class B(A): ... def __fa(self): ... print('from B') ... >>> b=B() >>> b.test() from A