封装 :
广义上的 :把属性函数都放到类里,只有这个类的对象才能使用类里的方法
狭义上的 :定义私有成员(私有变量和私有方法)
封装原则:
-
将不需要对外提供的内容都隐藏起来;
-
隐藏对象的属性和实现细节,提供公共方法对其访问。
在python中用双下划线开头的方式将属性隐藏起来。所谓私有,就是不能在类的外面去引用它
定义一个私有的名字:就是在私有的名字前面加两条下划线 __N = 'aaa'。
# 私有类的静态变量 class A: __N = 'aaa' # 静态变量 def func(self): print(A.__N) # 在类的内部使用正常 a = A() a.func() # aaa print(A.__N) # 在类的外部直接用 报错
那么__N真的私有的吗?
class A: __N = 'aaa' # 静态变量 def func(self): print(A.__N) # 在类的内部使用正常 print(A.__dict__) ''' 执行输出: {'__module__': '__main__', '_A__N': 'aaa', 'func':, '__dict__': ''', '__weakref__': , '__doc__': None}
从输出的结果中,可以看到_A__N。在外部,依然可以调用,只不过,存储的的时候,做了变形
print(A._A__N) # 禁止调用,这样是不规范的 执行输出: aaa
在类的内部 只要你的代码遇到__名字,就会被python解释器自动的转换成_类名__名字
私有属性
class B: def __init__(self,name): self.__name = name tony = B('Tony') # print(tony.__name) # AttributeError: 'B' object has no attribute '__name' print(tony._B__name) # Tony
私有方法
class C: def __wahaha(self): print('wahaha') def ADCa(self): # 在里面定义方法,调用私有方法 self.__wahaha() c = C() # c.__wahaha() # AttributeError: 'C' object has no attribute '__wahaha' c._C__wahaha() # wahaha c.ADCa() # wahaha
总结:
-
在类中,静态属性,方法,对象属性都可以变成私有的,只需要在这些名字之前加上__;
-
类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式;
-
在类中,可以使用self.__x的形式调用。外部无法调用,因为变形了。
面试题
class D: def __func(self): # 变形为 _D__func print('in func') class E(D): # E继承了D def __init__(self): # 执行初始化方法 self.__func() # 变形为 _E__func e = E() # AttributeError: 'E' object has no attribute '_E__func'
执行到self.__func()时,变形为_E__func,此时E里面找不到这个方法,执行报错
私有的名字不能被子类继承
查看当前范围内的变量、方法和定义的类型列表
class D: def __func(self): # 变形为 _D__func print('in func') class E(D): def __init__(self): pass e = E() print(e.__dir__()) 执行输出: ['__ge__', '__gt__', '__new__', '__reduce_ex__', '__reduce__', '__dict__', '__le__', '__eq__', '__sizeof__', '__format__', '__getattribute__', '_D__func', '__hash__', '__str__', '__init__', '__module__', '__subclasshook__', '__weakref__', '__repr__', '__lt__', '__setattr__', '__ne__', '__class__', '__dir__', '__delattr__', '__doc__']
从输出结果中,可以看出。_D__func就是D里面的__func方法。在内存中存储的值,已经变形了。
既然这样的话,那么就可以调用__func方法了
class D: def __func(self): # 变形为 _D__func print('in func') class E(D): def __init__(self): self._D__func() e = E() # in func
但是不建议这么写,既然是私有属性,不能这么做。
面试题:下面的代码执行输出in D还是in E ?
class D: def __init__(self): self.__func() def __func(self): print('in D') class E(D): def __func(self): print('in E') e = E() # in D
执行到第8部的时候,它需要找的是_D__func,所以结果输出in D
私有的名字,在类内使用的时候,就是会变形成_该类名__方法名
以此为例 :没有双下换线会先找E中的func,但是有了双下划线,会在调用这个名字的类D中直接找_D__func
class F:pass F.__name = 'Tony' # 是不是在创建私有属性?不是 print(F.__name) print(F.__dict__) ''' 执行输出: Tony {'__module__': '__main__', '__dict__':, '__weakref__': ''', '__doc__': None, '__name': 'Tony'}
what? 它为啥不是私有属性?
-
在类的外部,它不会发生变形,只有在类的内部,才关心双下划线
-
变形只在类的内部发生,在类的外部,禁止访问私有属性
java中的对比
- public 公有的 在类的内部可以使用,子类可以使用,外部可以使用 python中所有正常的名字;
- protect 保护的 在类的内部可以使用,子类可以使用,外部不可以使用 python中没有;
- private 私有的 只能在类的内部使用,子类和外部都不可以使用 python中的__名字;
python私有的用法
-
当一个方法不想被子类继承的时候;
-
有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用;
描述一个房子:这个例子,将长宽高隐藏起来的,外部知道名字,价格,面积就可以了。
class Room: def __init__(self, name, price, length, width, height): self.name = name self.price = price self.__length = length # 隐藏长 self.__width = width # 隐藏宽 self.__height = height # 隐藏高 def area(self): return self.__length * self.__width r = Room('鹏鹏', 100, 2, 1, 0.5) print(r.name) print(r.price) print(r.area()) ''' 执行输出: 鹏鹏 100 2 '''
用户名和密码问题,将密码保护起来
class Person: def __init__(self,name,pwd): self.name = name self.__pwd = pwd def __show_pwd(self): li = [] for i in self.__pwd: i = ord(str(i)) # 查看ascii码对应的顺序 li.append(str(i)) my_secret_pwd = ''.join(li) return my_secret_pwd a = Person('xiao','42423') ret = a._Person__show_pwd() # 外部调用私有方法 print(ret) # 5250525051
类中的私有成员:
- 私有的静态属性
- 私有的对象属性
- 私有的方法
为什么要定义私有变量?
- 不想让你看到这个值
- 不想让你修改这个值
- 不想让子类继承某些方法和属性
class Goods: __discount = 0.7 def __init__(self,name,price): self.name = name self.__price = price def price(self): return self.__price * Goods.__discount # 返回修改后的价格 apple = Goods('apple',10) print(apple.price()) # 7.0
class User: def __init__(self,name,pwd): self.name = name self.__pwd = pwd self.pwd = self.get_pwd() def get_pwd(self): return hash(self.__pwd) # 给密码加密 ming = User('ming','ming123') print(ming.pwd) # 5504467288710963649
私有变量不能在类外部被定义:只能定义出一个名字叫__X的普通属性,不是私有成员
class A: __country = 'China' print(A.__dict__) A.__language = 'English' print(A.__dict__) ''' 执行输出: {'__module__': '__main__', '_A__country': 'China', '__dict__':, '__weakref__': ''', '__doc__': None} {'__module__': '__main__', '_A__country': 'China', '__dict__': , '__weakref__': , '__doc__': None, '__language': 'English'}
私有变量不能被继承。因为子类在调用时,对象名字变为 _子类名__变量名,永远找不到父类中的 _父类名__变量名
class A: __country = 'China' def __init__(self,name): self.__name = name class B(A): print(__country) #程序报错,NameError: name '_B__country' is not defined def get_name(self): return self.__name #程序报错, AttributeError: 'B' object has no attribute '_B__name' b = B('ming') b.get_name()