Day22
1、封装
面向对象的三大特性 : 继承 多态 封装
封装 :
广义上的
狭义上的 :会对一种现象起一个专门属于它的名字
把一堆东西装在一个容器里
函数和属性装到了一个非全局的命名空间 —— 封装
class A:
__N = 'aaa' # 静态变量
print(A.__N)
python
pulic 公有的
private 私有的
java完全面向对象的语言
public 公有的
protect 保护的
private 私有的
定义一个私有的名字 : 就是在私有的名字前面加两条下划线 __N = 'aaa'
所谓私有,就是不能在类的外面去引用它
class A: __N = 'aaa' # 静态变量 def func(self): print(A.__N) # 在类的内部使用正常 a = A() a.func() print(A.__N) # 在类的外部直接使用 报错
class A: __N = 'aaa' # 静态变量 def func(self): print(A.__N) # 在类的内部使用正常 print(A.__dict__) print(A._A__N) # python就是把__名字当成私有的语法
一个私有的名字 在存储的过程中仍然会出现在A.__dict__中,所以我们仍然可以调用到
python对其的名字进行了修改:_类名__名字
只不过在类的外部调用:需要''_类名_名字''去使用
在类的内部可以正常的使用名字
在类内 只要你的代码遇到__名字,就会被python解释器自动的转换成_类名__名字
class B: def __init__(self,name): self.__name=name def func(self): print('in func :%s' %self.__name) b=B('alex') print(b._B__name) b.func()
class C: def __wahaha(self): print('wahaha') def ADCa(self): self.__wahaha() c = C() c._C__wahaha() c.ADCa()
class D: def __func(self): # '_D__func' print('in func') class E(D): def __init__(self): self.__func() # '_E__func' e = 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 #私有的名字,在类内使用的时候,就是会变形成_该类名__方法名 #以此为例:没有双下划綫会先找E中的func #但是有了双下划綫,会在调用这个名字的类D中直接找_D__func
class F:pass F.__name = 'alex' # 不是在创建私有属性 print(F.__name) print(F.__dict__) #变形只在类的内部发生
java中的对比
public 公有的 在类的内部可以使用,子类可以使用,外部可以使用 python中所有正常
protect 保护的 在类的内部可以使用,子类可以使用,外部不可以使用 python中没有protect
private 私有的 只能在类的内部使用,子类和外部都不可以使用 python中的__名字
私有的用法
当一个方法不想被子类继承的时候 有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用
2、property方法
class Person: def __init__(self,name,weight,height): self.name = name self.__height = height self.__weight = weight # self.bmi = self.__weight / self.__height ** 2 # self.bmi = self.cal_BMI() def cal_BMI(self): return self.__weight / self.__height ** 2 @property def bmi(self): return self.__weight / self.__height ** 2 p = Person('大表哥',92,1.85) # print(p.cal_BMI()) # p.cal_BMI() # bmi是一个名词 print(p.bmi) # bmi是一个名词 p._Person__weight = 90 print(p.bmi)
@property 能够将一个方法伪装成一个属性
从原来的对象名.方法名(),变成了对象名,方法名
并不会让代码有什么逻辑上的提高
只是从调用者的角度上换了一种方式,使之看起来更合理
# 如果有重名的名字 class Person: def __init__(self,name,weight,height): self.name = name self.__height = height self.__weight = weight #self.bmi=111 @property def bmi(self): return self.__weight / self.__height ** 2 print(Person.__dict__) p = Person('大表哥',92,1.85) print(p.__dict__) print(p.bmi) # 对这个属性 只能看了 # 被property装饰的bmi仍然是一个方法 存在Person.__dict__ # 对象的.__dict__中不会存储这个属性 # 在一个类加载的过程中,会先加载这个中的名字,包括被property装饰的 # 在实例化对象的时候,python解释器会先到类的空间里看看有没有这个被装饰的属性, # 如果有就不能再在自己对象的空间中创建这个属性了
#方法伪装成的属性的修改 class Person: def __init__(self,n): self.__name=n @property def name(self): return self.__name @name.setter def name(self,new_name) if type(new_name) is str: self.__name=new_name else: print('您提供的姓名数据类型不合法') p=Person('alex') print(p.name) #def name(self) p.name='wusir' #def name(self,new_name) print(p.name )#def name(self)
#方法伪装成的属性的删除 class Person: def __init__(self,n): self.__name = n # 私有的属性了 @property # 重要程度 **** def name(self): return self.__name @name.deleter def name(self): del self.__name p=Person('alex') print(p.name) del p.name #只是执行了被@name.deleter装饰的函数 print(p.name)
@property -->func 将方法伪装成属性,只观看的事儿
@func.setter -->func 对伪装的属性进行赋值的时候调用这个方法 一般情况下用来做修改
@func.deleter -->func 在执行del 对象.func的时候调用这个方法 一般情况下用来做删除 基本不用
# 商品的 折扣 # 有一个商品 : 原价 折扣 # 当我要查看价格的时候 我想看折后价 class Goods: def __init__(self,name,origin_price,discount): self.name = name self.__price = origin_price self.__discount = discount @property def price(self): return self.__price * self.__discount @price.setter def price(self,new_price): if type(new_price) is int or type(new_price) is float: self.__price = new_price apple = Goods('apple',5,0.8) print(apple.price) # 修改苹果的原价 apple.price = 8 print(apple.price)
将一些需要随着一部分属性的变化而变化的值的计算过程 从方法 伪装成属性
将私有的属性保护起来,让修改的部分增加一些约束,来提高程序的稳定性和数据的安全性
3、classmethod和staticmethod
classmethod
#全场八折 class Goods: __discount=0.8 def __init__(self,name,origin_price): self.name=name self.__price=origin_price @property def price(self): return self.__price*Goods.__discount @classmethod def change_discount(cls,new_discount): #类方法 可以直接被类调用 不需要默认传对象参数 只需要传一个类参数就可以了 cls.__discount=new_discount Goods.change_discount(1) #不依赖对象的方法 就应该定义成类方法 类方法可以任意的操作类中的静态变量 apple=Goods('apple',5) banana=Goods('banana',8) print(apple.price)
staticmethod
class Studeng: def __init__(self,name):pass @staticmethod def login(a): user=input('user:') if user =='alex': print('success') else: print('faild') Student.login(1)
完全面向对象编程
先登录后实例化
还没有一个具体的对象的时候 就要执行login方法
使用什么样的方法要看具体用到了哪些名称空间中变量
当一个方法要使用对象的属性时 就是用普通的方法
当一个方法要使用类中的静态属性时 就是用类方法
当一个方法要既不适用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法