property,多态,绑定方法与非绑定方法

Posted dominic-ji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了property,多态,绑定方法与非绑定方法相关的知识,希望对你有一定的参考价值。

1.property

  property本质就是一个python为你准备好了的——装饰器,那既然他是装饰器,也就意味着他的用法就是我们熟悉的装饰器语法糖用法@+名字,而它的作用就是将装饰的函数(类中定义的方法)伪装成一种属性(类中有两种特质,一是属性你也可以理解为不变的量,二是方法也就是多态变化的函数),那property具体是怎么做到这点呢?先来思考一个问题。

成人的BMI数值:

过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
  体质指数(BMI)=体重(kg)÷身高^2(m)
  EX:70kg÷(1.75×1.75)=22.86
请听题:让你定义一个类,里面有三个属性姓名,身高和体重,然后我要让你根据身高和体重算出这个人的BMI指数,你会怎么做?(你肯定会说这不简单嘛,类中定义专门算BMI指数的函数不就行了嘛~ 答案如下:)
class People:
    def __init__(self, name, weight, height):
        self.__name=name
        self.weight=weight
        self.height=height
    def bmi(self):
        return self.weight/(self.height*self.height)
p1=People(胖虎,80,1.6)
print(p1.bmi())#31.249999999999993
#这不就搞定了嘛,so easy的东西好不好~~

  上面这样是没有多大问题,但是我想问的是人的BMI指数应该是人的一个属性吧,你这里把它定义成一个方法,是不是不太好,(如何判断是属性还是方法,很简单:名词就是属性,动词就是方法,很显然BMI应该是名词)那对象访问自己的属性应该怎么访问?是不是直接对象加点加所要访问的属性即可~那这该怎么实现? 来来来 请property帮你装饰一下就好,保证天衣无缝,让使用者根本看不出来他在调用一个方法

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))
p1=People(胖虎801.60)
print(p1.bmi) 

  上面这个需求解决了之后,那我现在又有了新的需求,我要在外部直接访问到内部定义的对象的名字,我该怎么做?(注意类中对名字这一属性是做了隐藏的哦),其实很简单了,用property就好啦

# class People:
#     def __init__(self,name,weight,height):
#         self.__name=name
#         self.weight=weight
#         self.height=height
       @property#装饰器,将方法伪装成属性
#     def name(self):
#         # 可增加限制条件流程
#         return self.__name

  那我现在需要在外部通过正常的操作想对name这个属性进行修改和删除操作,又该如何操作呢?方法一样,需要知道的是,在被property装饰过的函数,在下面就会有另外两种方法分别对应的就是对所装饰对象的属性进行修改和删除操作

技术分享图片
# 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))
#     @property#装饰器,将方法伪装成属性
#     def name(self):
#         # 可增加限制条件流程
#         return self.__name
#     @name.setter#(被property装饰过的方法,下面就会有对应的设置 
#       和删除装饰器)
#     用户修改这个属性还是通过obj.name=name
#     def name(self,name):#obj.name=name
#         # 可增加限制条件流程
#         self.__name=name
#     @name.deleter #删除装饰
#     def name(self):
#         # 可增加限制条件流程
#         del self.__name
property方法大汇总

  学了property加上之前的封装知识,大家脑子里估计会产生很多想法,比如以后再写一些隐私安全性比较高的程序时就可以这样去写,这样的话在外部想要访问某一属性,就必须通过你给他开的接口,在接口里面我们就可以增加一些限制条件,比如人用户输入密码或者验证码之类的验证性操作,用户需要修改用户信息时给他们设置一些身份的验证操作(输个身份证号啥的),这样你的程序在用户看来还是照常使用,但是内部却设置了很多限制条件,是不是有一种对现在的支付宝这些涉及到money的软件里面的密保措施有点大致了解内部原理了

2.多态性

  首先问一个问题,请问水有几种状态,答:固液气态(其实现在的物质除了这三态之外还有一种叫等离子态),那冰是不是水,水蒸气是不是水,液态水是不是水,这不废话嘛,当然都是水了,那在程序中我们定义一个动物类,那有它产生猫狗猪,这些都是动物类的不同形态,那怎么做到不管看到谁都知道他就是动物类,它就有这么多明确的对应方法,不管哪个对象你都能很好的做到随意调用它们的方法和属性,不需要去查看对象所在类中如何设置的————就是说,你只需要掌握动物类中有哪些方法和属性就行,其他的只要是继承了动物类的类产生的对象都会也只会有我父类中的这些方法和属性,只是他们对应的输出结果不同呢?

import abc#(多态性的本质是定义一个父类,继承的子类必须按照父类定义的这一套标准去定义属于自己的属性和方法
这样的好处在于你只需要知道父类中有哪些属性和方法就知道继承(这里的继承是一种标准的继承)它的所有的子类都有这些方法,不需要逐一再去看子类都有哪些属性
我们之前学的数据类型所对应的方法也是按照这种方式去定义的比如 len()。。。 )
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def eat(self):
        pass

    @abc.abstractmethod
    def drink(self):
        pass

    @abc.abstractmethod
    def sleep(self):
        pass

    @abc.abstractmethod
    def run(self):
        pass

class Cat(Animal):
    @abc.abstractmethod
    def eat(self):
        print(cat in eating)

    @abc.abstractmethod
    def drink(self):
        print(cat in drink)

    @abc.abstractmethod
    def sleep(self):
        print(cat is sleeping)

    @abc.abstractmethod
    def run(self):
        print(cat in running)

class Dog(Animal):
    @abc.abstractmethod
    def eat(self):
        print(dog in eating)

    @abc.abstractmethod
    def drink(self):
        print(dog in drink)

    @abc.abstractmethod
    def sleep(self):
        print(dog is sleeping)

    @abc.abstractmethod
    def run(self):
        print(dog in running)

  这里通过导入一个abc模块,做到了所有的子类都必须按照父类定义的属性和方法名去定义自己的属性和方法,一个都不能少一个都不能错,这样我只需要掌握父类里的方法和属性,就可以完全驾驭继承父类从而产生的其他任意类与对象他们中有什么,比如:你是狗那不用想你肯定有我父类定义的这些方法,而且名字都一样,那我直接调用就可以,无外乎结果不一样猫有猫叫,狗有狗叫~~

  大家是不是觉得上面这种父类制定规则,子类继承之后,按着父类的规则去定义就可以做到天下一统的感觉,但是这不是python所推崇的简约自由无拘无束,python不会像上面这样真正的去限制你,python采用的是鸭子类型

鸭子类型

逗比时刻:

  Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’

python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象

也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。

例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法

技术分享图片
#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass
View Code

例2:其实大家一直在享受着多态性带来的好处,比如Python的序列类型有多种形态:字符串,列表,元组,多态性体现如下

技术分享图片
#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)
View Code

学到这儿,是不是感觉到python还挺像墨家文化的——墨守成规~~~不会去真正的去限制你,而是大家达成一种共识,约定俗成的去遵循一些“规定准则”

3.绑定方法与非绑定方法

  这里的绑定方法不再单一的是绑定给对象,也可以绑定给类,非绑定方法指的是即不绑定给对象也不绑定给类,就是普普通通存在于类中的函数!

对于这种情况的实现,我们需要介绍两个内置方法,其实也是两个装饰器——classmethod与staticmethond

from conf import settings
import hashlib,time
m=hashlib.md5()
class People:
    def __init__(self,name,age):
        self.id=self.create_code()
        self.name=name
        self.age=age
    def tell(self):
        print(self.__dict__)
    @classmethod#装饰器,将类中定义的方法由默认绑定给对象变成绑定给类来调用,将类当作第一个参数传入!
    def from_conf(cls):#这里的cls就是类的缩写形式,这样就算类名变化,也不会影响这一功能执行
        return cls(settings.name,settings.age)#通过载入配置来自动实例化
    @staticmethod
    def create_code():#这个函数不需要任意参数,只是负责产生独有的id号,那么他就可以被设置成一个普通的函数,
        m.update(str(time.clock()).encode(utf-8))
        return m.hexdigest()
obj=People.from_conf()
print(obj.tell())
学到这里就给我们提供了两种实例化对象的方式,一种是调用类并传值来产生,还有就是上面介绍的由类来调用类的绑定方法自动产生

以上是关于property,多态,绑定方法与非绑定方法的主要内容,如果未能解决你的问题,请参考以下文章

面向对象:多态(多态性)封装(隐藏属性)绑定方法与非绑定方法

Mixins多态绑定方法与非绑定方法

python3 多态,绑定方法与非绑定方法

编程之路:多态和绑定与非绑定方法

python 3全栈开发-面向对象之绑定方法(classmethod与staticmethod的区别)多态封装的特性property

面向对象