封装
隐藏对象的属性和实现细节,仅对外提供公共访问模式
好处
将变化隔离
便于使用
提高复用性
提高安全性
封装原则
将不需要对外提供的内容都隐藏起来
把属性都隐藏,提供公共方法对其访问
如果不想让别人改我的属性 或者干脆就不想让别人看到 那么可以使用私有化的方法和属性
什么是私有化
所谓的私有化就是只能在类的内部可见,类的外部是不能访问或查看的
私有化是怎么完成的
所有的私有化的变化都是在类的 [内部] 完成的
方法/静态变量/实例变量(对象属性)都可以私有化
私有的对象属性
class Goods: def __init__(self,name,price): self.name = name self.__price = price # 私有属性 def get_price(self): print(self.__price) apple= Goods('苹果',5) print(apple.name) # print(apple.__price)#这种方法不可以,对象属性已经被私有化了,不能直接打印 apple.get_price() print(apple._Goods__price) 因为私有化在类的内部可见,所以可以在类的内部设置一个查看私有化对象属性的函数,在类的外部调用这个函数,就可以查看私有化的对象属性
私有的静态变量
class Role: __Country='China' # 静态变量的私有化 def func(self): print(self.__Country) #print(Role.__Country) # 报错 : 因为不能再类的外部引用变量 Role().func() #可以不需要self,直接实例化,再调用类的内部方法
私有的方法
class Big(object): def __init__(self,name,money): self.name = name self.money = money def pay(self): print('%s成功消费了%s元'%(self.name,self.money)) def __back(self): print('%s已退款%s元'%(self.name,self.money)) alex = Big('alex',100) alex.pay() alex._Big__back()
私有的属性可以被继承吗?
先看几个代码
class Foo: def __init__(self): self.__func() def __func(self): print('in foo') class Son(Foo): def __func(self): print('in son') Son() 实例化Son后先去父类中的 __init__ 之后变为 _Fon__func() 回到自己的类中,并没有可以调用的方法,去父类中寻找 可以调用父类中的 __func() 于是输出结果为 in foo
class User: def func(self): self.__wahaha() #在所有的空间里找不到 _User__wahaha class VipUser(User): def __wahaha(self): print('in vip user') VipUser().func() #报错 实例化Vipuser后要进行func方法的调用 在自己的类中没有找到,在父类中找到了,但父类中的方法被私有化了 于是变为 _User__wahaha 而在所有的空间中都找不到 _User__wahaha 可以调用的方法 于是输出结果为报错
class User: def __wahaha(self): print('in user') class VipUser(User): def func(self): self.__wahaha() VipUser().func() # 报错,因为在命名空间中根本不存在一个_VipUser__wahaha 输出结果为报错 原因与上一例子相同
私有的这个概念,但凡在类的外部,都不能用
私有的所有内容:实例变量(对象属性)静态变量(类变量),方法都不能被子类继承
小总结
公有的 在类的内部外部随便使用
保护的 (其他语言)
私有的 只能在类的内部使用 既不能被继承,也不能在类的外部使用
property
property是一个内置函数,作用是把被自己装饰以一个方法伪装成一个属性
写代码时候可以用到,让代码更有逻辑性
class Circle: def __init__(self,r): self.r = r @property # 把装饰的一个方法伪装成一个属性 def area(self): return 3.14*self.r**2 @property def perimeter(self): return 2*3.14*self.r c1 = Circle(5) c1.r=10 print(c1.area) #想使用area方法,只要像查看属性一样用类名 + . + 方法名就可以实现 print(c1.perimeter)
property和私有概念
可以创造出一个属性,只能看,不能改
class Goods: def __init__(self,name,price): self.name = name self.__price = price @property def price(self): return self.__price apple = Goods('苹果',5) print(apple.name) print(apple.price)
但如果想要修改的话,就要引入另一个函数
setter
class Goods: discount = 0.8 def __init__(self, name, price): self.name = name self.__price = price @property def price(self): p = self.__price * self.discount return p apple = Goods('苹果', 5) banana = Goods('香蕉', 10) print(apple.name) print(apple.price) print(banana.price) Goods.discount = 1 print(apple.price) print(banana.price)
如果想在类的内部修改 price 的值
class Goods: discount = 0.8 def __init__(self, name, price): self.name = name self.__price = price @property # 只支持obj.price的方式查看这个结果,不支持修改,也不支持删除 def price(self): p = self.__price * self.discount return p @price.setter def price(self,value): if type(value) is int or type(value) is float: self.__price = value apple = Goods('苹果', 5) banana = Goods('香蕉', 10) apple.price = 16 # 对应的调用的是被setter装饰的price方法 print(apple.price) # 对应调用的是被property装饰的price方法
如果我们定义的是普通的变量或者属性 那么这个属性可以从外部直接访问 可以任意的修改 obj.attr = 123 甚至可以删除 del obj.attr 私有化 把一个属性加上双下划线 __属性名 这个属性就连在外面看都看不见了 我们实际上有些场景允许别人看,不许改 __属性 @property装饰的属性名 def 属性(): 我们允许别人看,也允许别人改,但是不能瞎改,有一些要求:数据类型 范围 __属性 @property装饰的属性名 def 属性():return __属性 @属性.setter def 属性(self,value): 加点儿条件 修改__属性
class Goods: discount = 0.8 def __init__(self, name, price): self.name = name self.__price = price @property # 只支持obj.price的方式查看这个结果,不支持修改,也不支持删除 def price(self): p = self.__price * self.discount return p @price.setter def price(self,value): if type(value) is int or type(value) is float: self.__price = value @price.deleter def price(self): del self.__price # 想删除一个属性 apple = Goods('苹果', 5) del apple.price print(apple.__dict__) apple.price apple.price = 9
私有的 :通过过给__名字这样的属性或者方法加上当前所在类的前缀,把属性隐藏起来了
只能在本类的内部使用,不能在类的外部使用,不能被继承
property 把一个方法伪装成属性
property和私有的两个概念一起用
定义一个私有的
再定义一个同名共有的方法,被property装饰
@方法名.setter
@方法名.deleter
classmethod 和 staticmethod
classmethod
class Fruits: __discount = 0.8 def __init__(self, name, price): print('init',self) self.name = name self.__price = price @classmethod # 把一个方法从对象方法,变成一个类方法 def change_discount(cls,value): cls.__discount = value # cls到底是谁??? Fruits @classmethod def get_discount(cls): return cls.__discount print(Fruits.get_discount()) Fruits.change_discount(1) print(Fruits.get_discount()) # 类方法 # 1. 有些时候我们要修改的是类中的静态变量/类变量 # 此时根本不会和self有任何的操作关联 # 这时传一个self参数对我们来说完全没有用 # 我们希望接受的是当前我们所在的类 apple = Fruits('apple',8) apple.change_discount(0.5) print(Fruits.get_discount()) # 类方法推荐使用类名调用而不是使用对象名调用
staticmethd
class A: @staticmethod # 声明这个方法只是一个普通的不会使用任何和这个类中的变量相关的方法 def func(): # 此时 func是一个静态方法 print('既不操作和self相关的内容') print('也不操作和类名相关的内容') A.func() # login 登录 class Student: def __init__(self,name): self.name = name @staticmethod def login(): pass # 先获取这个学生的用户名和密码 # 判断他登录成功之后进行实例化 # Student.login() # stu = Student('alex')