面向对象【林老师版】:封装-如何隐藏?(十四)

一、引子

从封装本身的意思去理解,封装就好像是拿来一个麻袋,把小猫,小狗,小王八,还有alex一起装进麻袋,然后把麻袋封上口子。照这种逻辑看,封装=‘隐藏’,这种理解是相当片面的

在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

1、代码

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')


print(A.__dict__)

二、自动变形的特点

1、这仅仅这是一种变形操作

1、代码

print(A.__dict__)

2、打印输出

{'__module__': '__main__', '_A__x': 1, '__dict__': <attribute '__dict__' of 'A' objects>, '__init__': <function A.__init__ at 0x0000000000B92378>, '__doc__': None, '_A__foo': <function A.__foo at 0x0000000000B92400>, '__weakref__': <attribute '__weakref__' of 'A' objects>}
类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式

2、在类内部是可以直接使用:obj.__AttrName

 1、代码


a=A('egon')
print(a.__dict__)

2、打印结果


{'_A__name': 'egon'}

类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

3、在类外部无法直接obj.__AttrName

1、打印类的属性代码

1、代码

print(A.__x)

2、打印输出

Traceback (most recent call last):
  File "F:/s13/day07/17 如何实现属性的隐藏.py", line 11, in <module>
    print(A.__x)
AttributeError: type object 'A' has no attribute '__x'

2、打印对象的属性

1、代码

print(A.__foo)

2、打印输出结果

Traceback (most recent call last):
  File "F:/s13/day07/17 如何实现属性的隐藏.py", line 12, in <module>
    print(A.__foo)
AttributeError: type object 'A' has no attribute '__foo'

这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的

4、子类无法覆盖父类__开头的属性

1、代码

    def bar(self):
        self.__foo() #self._A__foo()
        print('from bar')

a=A('egon')
a.bar()

2、输出结果

run foo
from bar

在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的

1、代码

a=A('egon')
a._A__foo()
a._A__x

#print(a.__name) #a.__dict__['__name']
print(a.__dict__)

2、打印输出结果

run foo
{'_A__name': 'egon'}

5、最终总结注释

#其实这仅仅这是一种变形操作
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo() #只有在类内部才可以通过__foo的形式访问到.

#A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

三、变形需要注意的问题

1、外部直接访问属性

1、代码

class Foo:
    def __func(self): #_Foo__func
        print('from foo')

class Bar(Foo):
    def __func(self): #_Bar__func
        print('from bar')


class B:
    __x=1

    def __init__(self,name):
        self.__name=name #self._B__name=name


print(B._B__x)

2、打印输出

1

这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

2、变形的过程只在类的定义时发生一次

1、代码

B.__y=2
print(B.__dict__)
b=B('egon')
print(b.__dict__)

b.__age=18
print(b.__dict__)
print(b.__age)

2、打印输出

{'__module__': '__main__', '__y': 2, '__doc__': None, '_B__x': 1, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__init__': <function B.__init__ at 0x0000000000A62488>}
{'_B__name': 'egon'}
{'_B__name': 'egon', '__age': 18}
18

变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形

 3、在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

1、代码

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()

2、打印输出

A.bar
B.foo

3、带注释的

class A:
    def __foo(self): #在定义时就变形为_A__foo
        print('A.foo')

    def bar(self):
        print('A.bar')
        self.__foo() #只会与自己所在的类为准,即调用_A__foo

class B(A):
    def __foo(self): #_B__foo
        print('B.foo')
原文地址:https://www.cnblogs.com/luoahong/p/9927702.html