1. 封装其实就是在类定义的时候,对以__开头(不包括__xxx__是内置方法)的属性进行变形,并且只变形一次,只是类定义时。
2. 变形后,类外部无法直接使用obj_name.__attribute_name。但python无法做到真正的隐藏,外部依然可以使用变形后的属性进行调用。如:对象._类名__属性名
3. 类内部是可以直接调用__属性名。因为定义的时候都已经变形,内部使用时,直接使用变形后的属性。
4. 子类无法覆盖父类的__开头的属性。因为定义时就已经变形了。他们的类名不一样,变形后的属性也不一样。
# class A: # __x=1 #_A__x=1 # # def __init__(self,name): # self.__name=name #self._A__name=name # # def __foo(self): #def _A__foo(self): # print('run foo') # # def bar(self): # self.__foo() #self._A__foo() # print('from bar') # print(A.__dict__) # print(A.__x) # print(A.__foo) # a=A('egon') # a._A__foo() # a._A__x # print(a.__name) #a.__dict__['__name'] # print(a.__dict__) # a.bar() ''' 这种变形的特点: 1、在类外部无法直接obj.__AttrName 2、在类内部是可以直接使用:obj.__AttrName 3、子类无法覆盖父类__开头的属性 '''
需要注意的问题:
1. 没有真正限制我们从外部调用,可以使用变形后的属性。
2.变形的过程,只在类的定义时发生一次,在定义后的赋值操作,并不会变形。
3. 在继承中,父类如果不想让子类覆盖自己的属性,可以将方法定义为私有的。
# 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() # class B: # __x=1 # # def __init__(self,name): # self.__name=name #self._B__name=name
#验证问题一:
没有真正限制我们从外部调用,可以使用变形后的属性。
print(B._B__x)
#是可以调用的。
#验证问题二:
变形的过程,只在类的定义时发生一次,在定义后的赋值操作,并不会变形。
B.__y=2
print(B.__dict__) # __y 不会变形。
b=B('egon')
print(b.__dict__)
b.__age=18
print(b.__dict__)
print(b.__age)
#验证问题三:
在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为__开头。
class A:
def foo(self):
print('A.foo')
def bar(self):
print('A.bar')
self.foo() #b.foo()
class B(A):
def foo(self):
print('B.foo')
b=B()
b.bar()
输出:A.bar
B.foo
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
#因为子类B没有_A__foo(),所以输出的是父类自己的__foo(),故父类定义的__方法并不会被子类覆盖。