封装
狭义上的封装——面向对象的三大特征之一
属性和方法都隐藏起来,不让看见
如何隐藏
在python中用双下划线开头的方式将属性隐藏起来,设置成私有的
其实这仅仅是一种变形操作
类中所有双下划线开头的名称如__x都会自动变形成:_类名_x的形式
class Person:
__key = 123 # 私有的静态属性
def __init__(self,name,pwd):
self.name = name
self.__pwd = pwd # 私有属性
def __get_pwd(self): # 私有方法
return self.__pwd # 只要是在类内部使用私有属性就会自动加上__类名
def login(self):
self.__get_pwd() # 正常的方法调用私有方法
class A:
__N = 0 # 私有静态属性
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是可以访问的,即这种操作并不是严格意义上的限制外部访问,仅仅是一种语法意义上的变形
特点
- 类中定义的私有属性和私有方法只能在类中使用,直接调用__X即可
- 外部无法通过__X直接调用
- 子类定义的__X不会覆盖父类定义的__X,因为自动更名为_子类名__X和_父类名__X
- 父类的私有属性不能由子类调用
未引入私有方法:
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
引入私有方法后:
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 A
封装不是单纯意义的隐藏
封装数据
将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,一次完成对数据属性操作的严格控制。
class Teacher:
def __init__(self,name,age):
self.__name = name
self.__age = age
def get_name(self):
return self.__name
def set_name(self,newName):
if type(newName) is str and not newName.isdigit():
self.__name = newName
else:
print('名字必须是字符串形式')
egon = Teacher('egon',18)
name = egon.get_name()
print(name)
egon.set_name('2')
egon.set_name('alex')
print(egon.get_name())
==========
结果
egon
名字必须是字符串形式
alex
封装方法:目的是隔离复杂度
1.取款功能由很多功能组成:插卡,密码认证,输入金额,打印账单,取钱等
2.对使用者来说,只需知道取款这个功能即可,其余功能我们都可以隐藏起来
3.隔离了复杂,同时提升了安全性
class ATM:
def __insert_card(self):
print('插卡')
def __login(self):
print('用户认证')
def __input(self):
print('输入取款金额')
def __print_bill(self):
print('打印账单')
def __take_money(self):
print('取款')
def withdraw(self):
self.__insert_card()
self.__login()
self.__input()
self.__print_bill()
self.__take_money()
a = ATM()
a.withdraw()
子类不能继承父类的私有属性和方法
class A:
__X = '123'
class B(A):
print(A.__X) # AttributeError: type object 'A' has no attribute '_B__X'
B()
property
property是一种装饰器函数,只在面向对象中使用
property可以将类中的方法伪装成属性
from math import pi
class Circle:
def __init__(self,r):
self.r = r
@property
def perimeter(self):
return 2*pi*self.r
@property
def area(self):
return pi*self.r**2
c = Circle(5)
print(c.perimeter) #31.41592653589793
print(c.area) #78.53981633974483
property可以提供set和get方法去设置和获取
class Foo:
def __init__(self,name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self,newName):
if not isinstance(newName,str):
raise TypeError('%s must be str'%newName)
self.__name = newName
@name.deleter
def name(self):
raise TypeError('无法删除')
f = Foo('alex')
print(f.name) # alex
f.name = 10 # TypeError: 10 must be str
# del f.name # TypeError: 无法删除