python's twenty-second day for me 封装,property方法
面对对象的三大特性:继承,多态,封装。
函数和属性装到了一个非全局的命名空间----封装。
封装:
在类中,静态属性,方法,对象属性都可以变成私有的,只需要在这些名字前加上‘__’(双下划线)。
在类内,只要你的代码遇到‘__’(双下划线).名字,就会被python解释器自动转换_类名__名字。
class A: __N = 'aaa' # 静态变量 def func(self): print(A.__N) # 在类的内部使用正常 ‘aaa’ print(A.__dict__) # 会以这种形式存储到字典中:{'_A__N': 'aaa'} # print(A.__N) # 直接在外部调用会报错 # print(A._A__N) # 所以可以使用这种方式调用,但是不能这样调用。 a = A() a.func() # 一个私有的名字,在存储的过程中仍然会出现在A.__dict__中,所以我们仍然可以调用到。 # python对其的名字进行了修改:_类名__名字。 # 只不过在类的外部调用: '_类名__名字'去使用。 # 在类的内部可以正常的使用名字调用。
私有的名字不能被子类继承:
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() # 在哪个类中定义的名字就会以固定方式存储: _D__func def __func(self): # _D__func print('in D') class E(D): def __func(self): # _E__func print('in E') e = E() # 私有的名字,在类内使用的时候,就是会变成: _该类名__方法名 # 以上为例:没有双下划线会先找E中的func # 但是有了双下划线,会在调用这个名字的类D中直接找_D__func
变形只在类的内部发生:
class F:pass F.__name = 'alex' # 并不是创建私有属性。 print(F.__name) print(F.__dict__) # {'__name': 'alex'} 并不是私有属性
Java中的对比:
public 共有的 在类的内部可以使用,子类可以使用,外部可以使用 python中所有正常的名字。
prctect 保护的 在类的内部可以使用,子类可以使用,外部不可以使用, python中没有
private 私有的 只能在类的内部使用,子类和外部都不可以使用 python中的 __名字。(双下划线)
私有的用法:
1,当一个方法不想被子类继承的时候。
2,有些属性或者方法不希望从外部被调用,只想提供给内部的方法使用。
@property 能够将一个方法伪装成一个属性。将代码变得更美观。
从原来的对象的对象名.方法名(),变成了对象名.方法名。
class Person: def __init__(self,name,weight,height): self.name = name self.__height = height self.__weight = weight @property def bmi(self): return self.__weight/self.__height**2 print(Person.__dict__) p = Person('顾小白',70,1.75) print(p.__dict__) #{'name': '顾小白', '_Person__weight': 70, '_Person__height': 1.75} # 被property装饰的bmi仍然是一个方法,存在Person.__dict__ # 对象的.__dict__中不会存储这个属性。 # 在一个类加载的过程中,会先加载这个的名字,包括被property装饰的。 # 在实例化对象的时候,python解释器会先到类的空间里看看有没有这个被装饰的属性。 # 如果有就不能在自己的对象空间中创建这个属性了。
@property ---> func 将方法伪装成属性,只能看,不能对之操作。
@func.setter ---> func 对伪装的属性进行赋值的时候调用这个方法,一般情况用来修改属性。
@func.deleter ---> func 在执行del 对象.func的时候调用这个方法,一般情况用来删除属性,一般不用。
class Person: def __init__(self,name): self.__name = name # 私有属性 @property # 将方法装饰成属性使用。 现在 p.name 相当于 p.name() def name(self): return self.__name @name.setter def name(self,new_name): if type(new_name) is str: # 类型不对无法替换,防止乱改。 self.__name = new_name # 将new_name 赋值给 self.__name 这一步改变了值。 else: print('类型不对,无法替换...') @name.deleter def name(self): del self.__name # 删除self.__name属性 p = Person('alex') print(p.name) # alex p.name = 'alex_sb' print(p.name) # alex_sb del p.name print(p.name) # 报错:AttributeError: 'Person' object has no attribute '_Person__name'
@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) # 可以在实例化之前使用。 g = Goods('薯片',10) print(g.price)
staticmethod:
当一个方法要使用对象的属性时,就是使用普通的方法。
当一个方法要使用类中的静态属性时,就是用类方法。
当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用 staticmethod 静态方法。
class Student: def __init__(self,name):pass @staticmethod def login(): # login就是一个类中的静态方法,静态方法没有默认参数,就当成普通函数。 pass Student.login()