python之路_面向对象三大特性之封装
1、私有属性
(1)动态属性
在python中用双下划线开头的方式将属性隐藏起来。类中所有双下划线开头的名称,如__x都会自动变形成:_类名__x的形式。这种自动变形的特点是:
a.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。b.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。c.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
class Teacher: def __init__(self,name,pswd): self.name=name self.__pswd=pswd #私有属性 def func(self): print(self.__pswd) alex=Teacher('alex','3714') alex.func() # print(alex.__pswd) #私有属性不可以通过此方式查看 print(alex._Teacher__pswd) #私有属性外部查看的方式:_Teacher__pswd储存
(2)静态属性
私有化的方式同样为在属性名前加双下划线,只能在内部进行使用,外部查看方式与动态属性一样。
class Teacher: __identifier='teacher' #私有静态属性 def __init__(self,name,pwd): self.name=name self.__pwd=pwd #私有属性 def func(self): print(self.__pwd,Teacher.__identifier) print(Teacher._Teacher__identifier) #在外面查看静态属性方法 alex=Teacher('alex','1234') alex.__a='aaa' #在外部定义,并不会形成私有化,__a即为一个合法的正常变量名 print(alex.__dict__) #查看动态属性字典,结果为:{'name': 'alex', '_Teacher__pwd': '1234', '__a': 'aaa'}
问题点总结:
(a).这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N。
(b).“__属性”变形到“_类名__属性”只在类的内部生效,在定义后的进行的近似私有化赋值操作,不会变形,为正常的赋值过程。
2、私有方法
私有化方法也只能在类的内部进行进行使用,有一些方法的返回值只是用来作为中间结果,可以进行私有化,如下例:
class Teacher: def __init__(self,name,pwd): self.name=name self.__pwd=pwd #私有属性 def __func(self): #私有方法 return hash(self.__pwd) def login(self,password): return hash(password)==self.__func() alex=Teacher('alex','1234') ret=alex.login('2234') print(ret) #输出结果为:False
在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的。
class Foo: def __jinghong_sb(self): #变形为:_Foo__jinghong_sb print('Foo') class Son(Foo): def __jinghong_sb(self): #变形为:_Son__jinghong_sb print('Son') def func(self): self.__jinghong_sb() #变形为:_Son__jinghong_sb, son = Son() son.func() #结果为:son
3、property方法
实现类中的方法时,以查看类的属性的方式进行,即将类中的方法看起来像属性而不是方法。如下例:
#例1:
class Person: def __init__(self,name,height,weight): self.name = name self.__height = height self.__weight = weight @property def bmi(self): return self.__weight / (self.__height**2) jinghong = Person('景弘',1.8,94) print(jinghong.name,jinghong.bmi) #输出结果:景弘 29.012345679012345
#例2: import math class Circle: def __init__(self,radius): self.radius=radius @property def area(self): return math.pi * self.radius**2 #计算面积 @property def perimeter(self): return 2*math.pi*self.radius #计算周长 c=Circle(10) print(c.radius) print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值 print(c.perimeter) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则。以上不可以通过赋值对jinghong.bmi、c.area、c.perimeter进行更改。一个静态属性property本质就是实现了get,set,delete三种方法,具体实例如下:
class Shop: discount = 0.75 def __init__(self,name,price): self.name = name self.__price = price @property def price(self): return self.__price * Shop.discount @price.setter def price(self,new_price): self.__price = new_price @price.deleter def price(self): del self.__price apple = Shop('apple',5) print(apple.price) #获取商品价格 print(apple.__dict__) #输出结果:{'name': 'apple', '_Shop__price': 5} apple.price = 6 #修改商品原价 print(apple.price) print(apple.__dict__) #输出结果:{'name': 'apple', '_Shop__price': 6} del apple.price #删除商品原价 print(apple.__dict__) #输出结果:{'name': 'apple'}
注意:只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter,如上例且各属性方法名需一样,均为price。
4、classmethod和staticmethod
(1)普通方法:必须传一个对象 可以使用对象的属性和类的属性
class A: def __init__(self,name): self.name = name def func(self): #普通方法,self为形式参数 print( self.name)
(2)类方法(classmethod):必须传一个类,方法不需要使用对象的属性,但可以使用类的属性
class A: role = 'a' @classmethod def class_method(cls): #类方法,cls代表类 print(cls.role) A.class_method() #输出结果:a类名.方法名()调用
(3)静态方法(staticmethod):没有必须传的参数,方法不需要用对象的属性和类的属性
class Staticmethod_Demo(): role = 'dog' @staticmethod def func(): #静态方法,不需要参数 print("a") Staticmethod_Demo.func() #调用方式:类名.方法名()
使用情况:不能将函数独立的放在类外面 完全使用面向对象编程的时候,并且这个函数完全不需要依赖对象的属性和类的属性, 就可以用staticmethod装饰这个函数。