一、什么是封装
封:就指的是隐藏,该隐藏是为了明确地区分内外,即该隐藏是对外不对内。(在类的外部无法直接访问隐藏的属性)
装:就是将数据属性或者函数属性存放到一个名称空间里
二、为何要封装
开发封闭原则:保护私隐,明确区分内外。将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。
三、如何用
在类内定义的属性前加__开头,该类的实例化的对象和子类都不可以访问。
class Foo():
__n = 1
def __init__(self, name='zhangsan'):
self.__name = name
def p(self):
print(self.n, self.__name)
class Bar(Foo):
pass
f = Foo()
print(f.__n)
运行代码如下:
Traceback (most recent call last): File "D:/python_studay/day8/封装.py", line 15, in <module> print(f.__n) AttributeError: 'Foo' object has no attribute '__n'
1.如何把外部能访问的属性给隐藏了?
2.到底如何实现对内就不隐藏了?
这种隐藏需要注意的点:
1.这种封装只能语法上的封装,没有真正的实现隐藏;系统默认在__xx变形为 __类名__xx
{'__module__': '__main__', '_Foo__n': 1, '__init__': <function Foo.__init__ at 0x00000000027F8AE8>, 'p': <function Foo.p at 0x00000000027F8B70>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
类__属性存在类名称空间中,self.__属性存在对象名称空间中,在访问这种隐藏属性时,在__属性前加上 _类名即可访问
print(f._Foo__name) print(Foo._Foo__n)
运行结果:
zhangsan
1
2.这种变形只在类定义阶段检测语法时变形一次,类定义阶段之后新增的__开头的属性不会发生变形
定义之后新增:
f = Foo() f.__xx = 1 print(f.__xx)
运行如下:
1
class Foo: def f1(self): print('foo f1') def f2(self): print('foo f2') self.f1() class Bar(Foo): def f1(self): print('bar f1') obj = Bar() obj.f2()
运行结果:
foo f2
bar f1
3.在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的。
在函数名前加上__xx.
class Foo: def __f1(self): print('foo f1') def f2(self): print('foo f2') self.f1()
这样运行结果变为:
foo f2
foo f1
封装的正确用法
class JDStudent: def __init__(self, name, age): self.__name = name self.__age = age def tell_info(self): print(self.__name, self.__age) def set_info(self, name, age): self.__name = name self.__age = age def get_info(self): return self.__name, self.__age