Python之旅.第五章.面向对象.
一、封装的property
BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
首先需要明确。bmi是算出来的,不是一个固定死的值,也就说我们必须编写一个功能,每次调用该功能都会立即计算一个值,但很明显人的bmi值听起来更像一个名词而非动词,于是我们需要为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 * self.height)
egon=People('egon',75,1.80)
print(egon.bmi) #23.148148148148145
egon.weight=70 #可以为weight改值,bmi随˙之变化
print(egon.bmi) #21.604938271604937,调用egon.bmi本质就是触发函数bmi的执行,从而拿到其返回值
egon.bmi=123 # 报错,egon.bmi背后对应的是一个函数,所以不能赋值
# 了解
class People:
def __init__(self,name):
self.__name=name
@property
def name(self): #obj.name
print('您现在访问的是用户名。。。')
return self.__name
@name.setter #obj.name='EGON' # @property装饰的函数可以掉setter及deleter
def name(self,x):
if type(x) is not str:
raise TypeError('名字必须是str类型')
self.__name=x
@name.deleter
def name(self):
# print('就不让你删')
del self.__name
obj=People('egon')
print(obj.name) #查
obj.name='EGON' #改
print(obj.name)
obj.name=123 #限制改
del obj.name #删
obj.name
#property, classmethod和staticmethod为面向对象中的三大函数
#用装饰器property将数据属性藏起来,进行查改删操作,用户无感
二、多态
什么是多态:多态指的是同一种事物多种形态
为什要用多态:用基类创建一套统一的规则,强制子类去遵循(使用抽象类实现),这样便可以在不用考虑对象具体类型的前提下而直接使用对象下的方法。多态在程序中表现可以是继承,但单纯意义伤的继承无法让父类严格限制子类。
多态性:可以在不用考虑对象具体类型的前提下而直接使用对象下的方法
如何用多态
import abc #abstract class
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def eat(self):
pass
@abc.abstractmethod
def drink(self):
pass
@abc.abstractmethod
def run(self):
pass
@abc.abstractmethod
def bark(self):
pass
class Cat(Animal):
def eat(self):
print('cat eat')
def drink(self):
print('cat drink')
def run(self):
print('cat run')
def bark(self):
print('喵喵喵')
class Dog(Animal):
def eat(self):
print('dog eat')
def drink(self):
print('dog drink')
def run(self):
print('dog run')
def bark(self):
print('汪汪汪')
obj=Animal() # 报错,抽象基类本身不能被实例化
c=Cat() #当子类的定义形式不符合要求是,定义阶段不报错,在调用该类定义对象时才报错
d=Dog()
c.bark()
d.bark()
or
c=Cat()
d=Dog()
def BARK(animal):
animal.bark()
BARK(c)
BARK(d)
多态概念在python中纵观始终的被使用,也提现了python一切皆对象的理念
s='hello'
l=[1,2,3]
t=(4,5,6)
s.__len__()
l.__len__()
t.__len__()
def LEN(obj):
return obj.__len__()
print(LEN(s))
print(LEN(l))
print(LEN(t))
or
print(len(l))
print(len(s))
print(len(t))
三、 鸭子类型
class Foo:
def f1(self):
print('from foo.f1')
def f2(self):
print('from foo.f2')
class Bar:
def f1(self):
print('from bar.f1')
def f2(self):
print('from bar.f2')
obj1=Foo()
obj2=Bar()
obj1.f1()
obj1.f2()
obj2.f1()
obj2.f2()
#在python中,长得像鸭子,叫起来像鸭子,就是一只鸭子
#linux中一切皆文件,皆可读写
class Disk:
def read(self):
print('disk read')
def write(self):
print('disk write')
class Txt:
def read(self):
print('txt read')
def write(self):
print('txt write')
class Process:
def read(self):
print('process read')
def write(self):
print('process write')
obj1=Disk()
obj2=Txt()
obj3=Process()
obj1.read()
obj2.read()
obj3.read()
四、 classmethod和staticmethod
1 绑定方法:
在类内部定义的函数,默认就是给对象来用,而且是绑定给对象用的,称为对象的绑定方法。 #什么装饰器都不加
绑定对象的方法特殊之处:应该由对象来调用,对象来调用,会自动将对象当作第一个参数传入。
绑定到类的方法特殊之处:应该由类来调用,类来调用,会自动将类当作第一个参数传入。 #加classmethod装饰器
总的来说,类中的函数可和对象绑定,可和类绑定(classmethod),也可随都不绑定(statismethod)
import settings
class People:
def __init__(self,name,age):
self.name=name
self.age=age
def tell(self):
print('%s:%s' %(self.name,self.age))
@classmethod
def from_conf(cls): #加classmethod装饰器时,pycharm自动加参数cls,为类的绑定方法
return cls(settings.NAME,settings.AGE)
p=People('egon',19)
p.tell()
p4=People.from_conf() #类调用不用传第一个参数,自动传参
p4.tell()
2、staticmethod:非绑定方法,就是一个普通函数
特性:既不跟类绑定,也不跟对象绑定,这意味着谁都能用;谁来用都是一个普通函数,也就是说没有自动传值的特性了
import settings
import hashlib
import time
class People:
def __init__(self,name,age):
self.uid=self.create_id()
self.name=name
self.age=age
def tell(self):
print('%s: %s:%s' %(self.uid,self.name,self.age))
@classmethod
def from_conf(cls):
return cls(settings.NAME,settings.AGE)
@staticmethod
def create_id():
m=hashlib.md5()
m.update(str(time.clock()).encode('utf-8')) #time.clock()与cpu有关,每次值都不同
return m.hexdigest()
obj=People('egon',18)
obj.tell() #print(obj.uid,obj.name,obj.age)
print(obj.create_id()) #对象可调用
print(People.create_id()) #类可调用