【面向对象】类的三大特性 (4)

​ 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

#正常情况 >>> 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 #把fa定义成私有的,即__fa >>> class A: ... def __fa(self): #在定义时就变形为_A__fa ... print(\'from A\') ... def test(self): ... self.__fa() #只会与自己所在的类为准,即调用_A__fa ... >>> class B(A): ... def __fa(self): ... print(\'from B\') ... >>> b=B() >>> b.test() from A 3.3封装与扩张性

​ 封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。

#类的设计者 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积 return self.__width * self.__length #使用者 >>> r1=Room(\'卧室\',\'egon\',20,20,20) >>> r1.tell_area() #使用者调用接口tell_area #类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码 class Room: def __init__(self,name,owner,width,length,high): self.name=name self.owner=owner self.__width=width self.__length=length self.__high=high def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了 return self.__width * self.__length * self.__high #对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能 >>> r1.tell_area() 复制代码 3.4 property属性

​ property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

1、BMI指数

class People: def __init__(self,name,weight,height): self.name=name self.weight=weight self.height=height @property def bmi(self): return self.weight / (self.height**2) p1=People(\'egon\',75,1.85) print(p1.bmi)

2、计算圆的周长和面积

import math class Circle: def __init__(self,radius): #圆的半径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) #同上 \'\'\' 输出结果: 314.1592653589793 62.83185307179586 \'\'\' 注意: #注意:此时的特性area和perimeter不能被赋值 c.area=3 #为特性area赋值 \'\'\' 抛出异常: AttributeError: can\'t set attribute \'\'\'

3、为什么要用property

​ 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

4、一个静态属性property本质就是实现了get,set,delete三种方法

class Foo: def __init__(self,val): self.__NAME=val #将所有的数据属性都隐藏起来 @property def name(self): return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置) @name.setter def name(self,value): if not isinstance(value,str): #在设定值之前进行类型检查 raise TypeError(\'%s must be str\' %value) self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter def name(self): raise TypeError(\'Can not delete\') f=Foo(\'egon\') print(f.name) # f.name=10 #抛出异常\'TypeError: 10 must be str\' del f.name #抛出异常\'TypeError: Can not delete\'

商品价格举例:

class Goods: def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() obj.price # 获取商品价格 print(obj.price) #80 obj.price = 200 # 修改商品原价 print(obj.price)#160 del obj.price # 删除商品原价 print(obj.price) # 报错 AttributeError: \'Goods\' object has no attribute \'original_price\' 三个方法本质是对类的属性进行操作 3.5面向对象的封装有三种方式: ps:面向对象的封装有三种方式: 【public】 这种其实就是不封装,是对外公开的 【protected】 这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开 【private】 这种封装对谁都不公开 3.6 classmethod class Classmethod_Demo(): role = \'dog\' @classmethod def func(cls): print(cls.role) Classmethod_Demo.func() #dog 3.7 staticmethod class Staticmethod_Demo(): role = \'dog\' @staticmethod def func(): print("当普通方法用") Staticmethod_Demo.func() #"当普通方法用"

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwyjwz.html