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

一、Mixins机制

是一种命名规范,解决多继承中一个对象同时属于多个类的问题,Mixins机制的核心是在多继承背景下尽可能的提升代码的可读性,符合人类的思维:什么是什么。

拿交通工具来说,民航飞机、直升飞机、汽车都是属于交通工具。可以定义一个交通工具的父类,三者都可以继承这个父类,他们都有载客的功能。除了载客,飞机还能起飞、上天!!!,而汽车不行。显然民航飞机和直升机的飞行这个属性只是这两个交通工具的所特有的功能而已,在继承交通工具父类的同时可以用Mixins机制混入飞行这个功能,注意混入的只是一个功能(多个功能写多个Mixin)不是两者的父类;而汽车直接继承交通工具父类。这样的话,民航飞机、直升飞机、汽车都是交通工具的子类,都能载客,而且还为民航飞机和直升飞机附加了飞行这个属性。满足了什么是什么的思维习惯,三者都是交通工具,尽可能的减少代码的冗余。

# 定义交通工具父类
class Vehicle:
    def carry(self):
        print(‘我是交通工具,世界那么大你想去哪儿都需要我‘)

# 定义一个有分行功能的类,用Mixins规范命名,标识其不是父类,用于混入。
class FlyableMixin:
    def fly(self):
        print(‘我能飞行,我可以上天!‘)

# 民航飞机
class CivilAircraft(FlyableMixin, Vehicle):
    pass

# 直升机
class Helicopter(FlyableMixin, Vehicle):
    pass

# 汽车
class Car(Vehicle):
    pass

civilAircraft_obj = CivilAircraft()
helicopter_obj = Helicopter()
car_obj = Car()

# 三者有载客的属性
civilAircraft_obj.carry()  # 我是交通工具,世界那么大你想去哪儿都需要我
helicopter_obj.carry()  # 我是交通工具,世界那么大你想去哪儿都需要我
car_obj.carry()  # 我是交通工具,世界那么大你想去哪儿都需要我

# 民航飞机和直升机有飞行的功能
civilAircraft_obj.fly()  # 我能飞行,我可以上天!
helicopter_obj.fly()  # 我能飞行,我可以上天!

补充:通常Mixin结果的类放在左边

二、在子类派生的新方法中重用父类功能的方式

方式一:

指名道姓的调用某一类下的函数,不依赖于继承关系

class OldboyPeople:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

class Teacher(OldboyPeople):
    def __init__(self, name, age, sex, level, salary):
        # 指名道姓的向 OldboyPeople类中要.__init__函数
        OldboyPeople.__init__(self, name, age, sex)
        self.level = level
        self.salary = salary

tea_obj = Teacher(‘egon‘, 18, ‘male‘, 10, 3000)
print(tea_obj.__dict__)
# {‘name‘: ‘egon‘, ‘age‘: 18, ‘sex‘: ‘male‘, ‘level‘: 10, ‘salary‘: 3000}

方式二:

super()调用父类提供给直接的方法,严格的依赖继承关系,调用super()会得到一个特殊的对象,该对象会参照发起属性查找的那个类的mro列表去查找,找到列表中当前类的父类,从父类中找属性。

class OldboyPeople:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def f1(self):
        print(f‘你好呀!{self.name}‘)

class Teacher(OldboyPeople):
    def __init__(self, name, age, sex, level, salary):
        # python2中需要传入当前的类名、self
        # super(Teacher,self).__init__(name,age,sex)
        # python3中直接super()调用就可以
        super().__init__(name, age, sex)
        self.level = level
        self.salary = salary
    # def f1(self):
    #     print(f‘hallo,{self.name}‘)

print(Teacher.mro())
# [<class ‘__main__.Teacher‘>, <class ‘__main__.OldboyPeople‘>, <class ‘object‘>]
tea_obj = Teacher(‘egon‘, 18, ‘male‘, 10, 3000)
tea_obj.f1()
# 对象查找f1函数,没有;去对象的类Teacher中找,有执行,结束;
# 没有按照mro列表找到父类,去父类中查找,有执行,打印
# 你好呀!egon
print(tea_obj.__dict__)

super()案例:

class A:
    def test(self):
        print(‘from A‘)
        super().test()
    pass
class B:
    def test(self):
        print(‘from B‘)

class C(A,B):
    pass

obj=C()
print(C.mro())
#[<class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘__main__.B‘>, <class ‘object‘>]
obj.test()
#查找顺序:obj-->C-->A(打印)-->B(打印)
# from A
# from B

三、多态

1、什么是多态

同一个事物有多种形态

例:动物可以使人、猫、猪等形态:

class Animal:
    pass

class People(Animal):
    pass

class Dog(Animal):
    pass

class Pig
	pass

2、为什么要有多态

多态性指的是可以在不考虑对象具体类型的情况下而直接使用对象

例如:不管是什么动物形态,只要是动物都能发出声音

定义父类用继承的方法统一所有子类的方法:

class Animal:  # 统一所有子类的方法
    def say(self):
        print(‘动物基本的发声频率。。。‘, end=‘ ‘)

class People(Animal):
    def say(self):
        super().say()
        print(‘嘤嘤嘤嘤嘤嘤嘤‘)

class Dog(Animal):
    def say(self):
        super().say()
        print(‘汪汪汪‘)

class Pig(Animal):
    def say(self):
        super().say()
        print(‘哼哼哼‘)

obj1 = People()
obj2 = Dog()
obj3 = Pig()

obj1.say()
# 动物基本的发声频率。。。 嘤嘤嘤嘤嘤嘤嘤
obj2.say()
# 动物基本的发声频率。。。 汪汪汪
obj3.say()
# 动物基本的发声频率。。。 哼哼哼

#定义统一的接口,接收传入的动物对象
def animal_say(animal):
    animal.say()

animal_say(obj1)
animal_say(obj2)
animal_say(obj3)

python中一切皆对象,内置方法中也具有多态性

如len:

print(‘hello‘.__len__())  #5
print([1,2,3].__len__())  #3
print({‘a‘:1,‘b‘:2}.__len__())  #2

#自定义一个计算长度的接口
def my_len(val):
    return val.__len__()

print(my_len(‘hello‘))
print(my_len([1,2,3]))
print(my_len({‘a‘:1,‘b‘:2}))
#和len()方法实现的原理

len(‘hello‘)
len([1,2,3])
len({‘a‘:1,‘b‘:2})

但其实我们完全可以不依赖于继承,只需要制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象,这正是Python崇尚的“鸭子类型”(duck typing):“如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子”。比起继承的方式,鸭子类型在某种程度上实现了程序的松耦合度,如下

linux中一切皆文件,看起来像文件,又能像文件那样用,那它就是文件:

class Cpu:
    def read(self):
        print(‘cpu read‘)

    def write(self):
        print(‘cpu write‘)

class Mem:
    def read(self):
        print(‘mem read‘)

    def write(self):
        print(‘mem write‘)

class Txt:
    def read(self):
        print(‘txt read‘)

    def write(self):
        print(‘txt write‘)

obj1=Cpu()
obj2=Mem()
obj3=Txt()

obj1.read()
obj1.write()

obj2.read()
obj2.write()

obj3.read()
obj3.write()

可以通过在父类引入抽象类的概念来硬性限制子类必须有某些方法名

import abc

# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
    def talk(self): # 抽象方法中无需实现具体的功能
        pass

class Cat(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
    def talk(self):
        pass

cat=Cat() # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化

四、绑定方法与非绑定方法

1、绑定方法

特殊之处在于将调用者本身当作第一个参数自动传入

—绑定给对象的方法:调用者是对象,自动传入的是对象

—绑定给类的方法:调用者是类,自动传入的是类

绑定给类的方法:

import settings

‘‘‘
文件settins内容:
IP=‘127.0.0.1‘
PORT=3306‘‘‘

class Mysql:
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

    @classmethod  # 将下面的函数装饰成绑定给类的方法
    def from_conf(cls):
        print(cls)
        return cls(settings.IP, settings.PORT)

obj1 = Mysql(‘1.1.1.1‘, 3306)
print(obj1.ip)  # 1.1.1.1
obj2 = Mysql.from_conf()
print(obj2.ip)  # 127.0.0.1
print(obj2.__dict__)
# {‘ip‘: ‘127.0.0.1‘, ‘port‘: 3306}

2、非绑定方法(静态方法)

没有绑定给任何人:调用者可以是类、对象、没有自动传参的效果

class Mysql:
    def __init__(self, ip, port):
        self.nid = self.create_id()
        self.ip = ip
        self.port = port

    @staticmethod  # 将下述函数装饰成一个静态方法
    def create_id():
        import uuid
        return uuid.uuid4()

    @classmethod
    def f1(cls):
        pass

    def f2(self):
        pass

obj1 = Mysql(‘1.1.1.1‘, 3306)

# print(Mysql.create_id)
# <function Mysql.create_id at 0x000001936877A1F0>
# print(obj1.create_id)
# <function Mysql.create_id at 0x000001936877A1F0>
print(Mysql.create_id())
# 476cad69-a354-418b-a84d-596e5288de8a
print(obj1.create_id())
# f90895c7-cc72-4fd3-9d08-2bfcd8550fdc

# 绑定非绑定对比
print(Mysql.create_id)
print(Mysql.f1)
print(obj1.f2)

原文地址:https://www.cnblogs.com/zhangtieshan/p/12676536.html

时间: 2024-11-10 19:46:26

Mixins、多态、绑定方法与非绑定方法的相关文章

python基础之多态与多态性、绑定方法和非绑定方法

多态与多态性 多态 多态并不是一个新的知识 多态是指一类事物有多种形态,在类里就是指一个抽象类有多个子类,因而多态的概念依赖于继承 举个栗子:动物有多种形态,人.狗.猫.猪等,python的序列数据类型有字符串.列表.元组,文件的类型分为普通文件和可执行文件,人类又有多种形态,男女老少..等等例子 1 import abc 2 class Animal(metaclass=abc.ABCMeta): #模拟动物类 3 @abc.abstractmethod 4 def talk(self): 5

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

多态: 多态指的是一类事物有多种形态:比如 动物有多种形态:人.狗.猪 如下代码: import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstractmethod def talk(self): pass class People(Animal): #动物的形态之一:人 def talk(self): print('say hello') class Dog(Animal): #动物的形态之二:狗 def talk(se

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

1.property property本质就是一个python为你准备好了的--装饰器,那既然他是装饰器,也就意味着他的用法就是我们熟悉的装饰器语法糖用法@+名字,而它的作用就是将装饰的函数(类中定义的方法)伪装成一种属性(类中有两种特质,一是属性你也可以理解为不变的量,二是方法也就是多态变化的函数),那property具体是怎么做到这点呢?先来思考一个问题. 成人的BMI数值: 过轻:低于18.5 正常:18.5-23.9 过重:24-27 肥胖:28-32 非常肥胖, 高于32 体质指数(B

Python学习——02-Python基础——【8-面向对象的程序设计】——封装、绑定方法与非绑定方

十 封装 1引子 从封装本身的意思去理解,封装就好像是拿来一个麻袋,把小猫,小狗,小王八,还有alex一起装进麻袋,然后把麻袋封上口子.照这种逻辑看,封装='隐藏',这种理解是相当片面的 2先看如何隐藏 在python中用双下划线开头的方式将属性隐藏起来(设置成私有的) #其实这仅仅这是一种变形操作且仅仅只在类定义阶段发生变形 #类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式: class A: __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据

python_day7 绑定方法与非绑定方法

在类中定义函数如果 不加装饰器 则默认 为对象作为绑定方法 如果增加 classmethod 是 以 类 作为绑定方法 增加 classmethod 是 非绑定方法,就是不将函数 绑定 ##################### class Foo: def func(self): print(self) @classmethod def func2(cls): print(cls) @staticmethod def sta(): print('非绑定参数') JG=Foo()JG.func(

全面解析python类的绑定方法与非绑定方法

类中的方法有两类: 绑定方法 非绑定方法 一.绑定方法 1.对象的绑定方法 首先我们明确一个知识点,凡是类中的方法或函数,默认情况下都是绑定给对象使用的.下面,我们通过实例,来慢慢解析绑定方法的应用. class People: def __init__(self,name,age): self.name = name self.age = age def talk(self): pass p = People('xiaohua',18) print(p.talk) 输出结果: <bound m

三 面向对象之绑定方法与非绑定方法

一 绑定方法 二 非绑定方法 三 classmethod和staticmethod的区别 一 绑定方法 绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入): 1. 绑定到类的方法:用classmethod装饰器装饰的方法.                 为类量身定制                 类.boud_method(),自动将类当作第一个参数传入               (其实对象也可调用,但仍将类当作第一个参数传入) 2. 绑定到对象的方法:没有被任何装饰器装饰的方

绑定方法和非绑定方法

一:绑定方法 绑定方法有两种,一种是与对象绑定,在类中定义的方法都是都是默认与对象绑定的,另一种是绑定到类的方法,要加上classmethod装饰器: class People: def __init__(self, name, age): self.name = name self.age = age def get_name(self): print("我的名字是:{}".format(self.name)) @classmethod def say_hello(cls): pri

面对对象-绑定方法与非绑定方法

在类内部定义的函数,分为两大类:一:绑定方法:绑定给谁,就应该由谁来调用,谁来调用就会把调用者当做第一个参数自动传入 绑定到对象的方法:在类内定义的没有被任何装饰器来修饰的 邦定到类的方法:在类内定义的被装饰器classmethod修饰的方法 二:非绑定方法:没有自动传值一说了,就是类中的普通工具 非绑定方法:不与类或者对象绑定 staticmethon class Foo: def __init__(self,name): self.name=name def tell(self): # 绑定