面向对象之—property,staticmethod
一 特性( property)
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值。
property是内置的一种封装方法:把一个属性“伪装”成一个数据属性,做法就是在需要伪装的属性正上方加@property。
那么其实我们并不是说每个属性都需要伪装,比如说我们的身体bmi指数,是通过计算得来的,所以我们一般会定义一个函数,因为他需要计算,但是其实他更像
一个类似名字,性别这一类的属性,所以这个时候我们就可以使用@property。
class Poeple: 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) egon=Poeple('egon',80,1.80) # print(egon.bmi()) print(egon.bmi)#在属性正上方加@property class Poeple: def __init__(self,name): self.__name=name @property def name(self):###访问——name的值 print('你现在访问用户名') return self.__name @name.setter#####改变——name的值 def name(self,n):#####修改名字 print('修改名字为n') self.__name=n @name.deleter###删除名字——name def name(self): del self.__name obj=Poeple('egon') print(obj.name)####查看名字 obj.name='sb' print(obj.name)###把——name改为sb del obj.name print(obj.name)#删除之后找不到——name 有一点需要注意的是,改的是隐藏过得——name,在内部隐藏所以内部可以直接调用。
二 多态性
多态就是:同一事物的多种形态,比如我们的动物类有:猫,狗,等。我们的水:液态的水,气态的水,固态的水。
使用原则:可以在不用考虑对象的具体类型的前提下直接使用对象的方法。也就是说所有的对象都可以直接使用基类中定义的属性。
import abc class Animal(mateclass=abc.ABCMeta): @abc.abstractmethod def eat(self): pass @abc.abstractmethod def sleep(self): pass @abc.abstractmethod def run(self): pass @abc.abstractmethod def bark(self): pass class Cat(Animal): def sleep(self): print('sleep') print('cat') class Dog(Animal): print('dog') c=Cat()#c为一种动物 # c.bark() c.sleep() # c.eat() c.run() d=Dog()
那么对于c这个对象,他可以使用基类中的所有属性。也可以在继承的基础上派生自己的功能。也就是说所有的子类实例化产生的相都可以直接调用基类中的函数(属性),
同时又可以有自己的属性。
在我们调用import abc:时我们可以再基类的属性正上方加上@abc.abstractmethod,那么子类再调用的时候就不能扩展自己的功能,也就是不能派生。
只能调用基类中已有的,否则就会报错。
还有一点就是:抽象后的基类不能在进行实例化。
那么这种抽象化的方式耦合度是非常高的,我们可以通过鸭子类型来进行解耦合。
那么这种抽象化的方式耦合度是非常高的,我们可以通过鸭子类型来进行解耦合。
我们说:如果一个东西他叫起来像鸭子,走路像鸭子,游泳像鸭子我们就把它叫鸭子。
二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用,这种方式是一种解耦合。 class TxtFile: def read(self): pass def write(self): pass class DiskFile: def read(self): pass def write(self): pass
那么其实我们之前也学了多态:
#str,list,tuple都是序列类型 s=str('hello') l=list([1,2,3]) t=tuple((4,5,6)) #我们可以在不考虑三者类型的前提下使用s,l,t s.__len__() l.__len__() t.__len__() len(s) len(l) len(t)
三 classmethod与staticmethod
我们之前说过绑定方法:
1. 绑定到类的方法:用classmethod装饰器装饰的方法。 为类量身定制 类.boud_method(),自动将类当作第一个参数传入 (其实对象也可调用,但仍将类当作第一个参数传入) 2. 绑定到对象的方法:没有被任何装饰器装饰的方法。 为对象量身定制 对象.boud_method(),自动将对象当作第一个参数传入 (属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)
HOST='127.0.0.1' PORT=3306 DB_PATH=r'C:\Users\mackle\PycharmProjects\day02\第五周.py'
import setting class MySQL: def __init__(self,host,port): self.host=host self.port=port @classmethod def from_conf(cls):#我们一旦绑定到类,那么再定义函数后面就会自动出现(cls),我们调用这个方法就是把类作为第一个参数传入。 print(cls) return cls(setting.HOST,setting.PORT) print(MySQL.from_conf) #<bound method MySQL.from_conf of <class '__main__.MySQL'>> conn=MySQL.from_conf()###<class '__main__.MySQL'>
conn.from_conf() #<class '__main__.MySQL'>对象也可以调用,但是默认传的第一个参数仍然是类
非绑定方法:
非绑定方法:用staticmethod装饰器装饰的方法 1. 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。这个时候他就是一个普通函数而已。 注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,
对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说:
@staticmethod#####不绑定,将函数变成普通函数,没有自动传值的特性了 def creat_id(): m=hashlib.md5() m.update(str(time.clock).encode('utf-8')) return m.hexdigest()