Python语言基础
Python语言进阶
Python数据结构

Python 多态

搞懂Python类的多态性
Python中多态是指对象有多种形态。比如动物有多种形态,狗,猫,牛,马等等。

什么是多态性?

多态性是指在不考虑实例类型的情况下使用实例,多态性分为静态多态性和动态多态性
静态多态性:如任何类型都可以用运算符+进行运算
动态多态性:如下
import abc
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def color(self):
        pass

class Dog(Animal):
    def color(self):
        print("Dog is black")

class Cat(Animal):
    def color(self):
        print("Cat is blue")

dog = Dog()
cat = Cat()
dog.color()
cat.color()

# 定义一个统一的接口来访问
def func(object):
    object.color()

func(dog)
执行结果:
Dog is black
Cat is blue
Dog is black

为什么要用多态性?

增加了程序的灵活性:以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal) 增加了程序额可扩展性:通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
import abc
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def color(self):
        pass

class Dog(Animal):
    def color(self):
        print("Dog is black")

class Cat(Animal):
    def color(self):
        print("Cat is blue")

class Pig(Animal): # 属于动物的另外一种形态:猪
    def color(self):
        print("Pig is white")

dog = Dog()
cat = Cat()
pig = Pig()

# 统一接口,对于使用者来说,自己的代码根本无需改动
def func(object):
    object.color()

# 甚至连调用方式都无需改变,就能调用出pig的talk功能
func(pig)
执行结果:
Pig is white

鸭子类型

在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。
例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为"鸭子"的对象,并调用它的"走"和"叫"方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的"走"和"叫"方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的"走"和"叫"方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。
鸭子类型通常得益于不测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。
class Duck():
    def speak(self):
        print("Duck speaking like a duck")

    def swim(self):
        print("Duck swim like a duck")

class Person():
    def speak(self):
        print("this people speaking like a duck")

    def swim(self):
        print("this people swim like a duck")

可以很明显的看出,Person类拥有跟Duck类一样的方法,当有一个函数调用Duck类,并利用到了两个方法speak()和swim()。我们传入Person类也一样可以运行,函数并不会检查对象的类型是不是Duck,只要他拥有speak()和swim()方法,就可以正确的被调用。
和其它面向对象语言相比,Python不支持方法重载,主要原因是函数功能相同,但是参数类型不同,Python不需要处理,因为 python可以接受任何类型的参数,如果函数的功能相同,那么不同的参数类型在 python中很可能是相同的代码,没有必要做成两个不同函数。而函数功能相同,但参数个数不同,python就是缺省参数。对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。

运算符重载

运算符重载是让自定义的类生成的对象(实例)能够使用运算符进行操作
1、算术运算符的重载:
                                                                                   
方法名运算符和表达式说明
__add__(self,rhs)self + rhs加法
__sub__(self,rhs)self - rhs减法
__mul__(self,rhs)self * rhs乘法
__truediv__(self,rhs)self / rhs除法
__floordiv__(self,rhs)self //rhs地板除
__mod__(self,rhs)self % rhs取模(求余)
__pow__(self,rhs)self **rhs幂运算
具体事例如下:
class Number():
    def __init__(self,v):
        self.data = v

    def __repr__(self):
        return "Number(%d)"%self.data

    def __add__(self,other):
        v = self.data + other.data
        return Number(v)

    def __sub__(self,other):
        v = self.data - other.data
        return Number(v)

n1 = Number(100)
n2 = Number(200)
n3 = n1 + n2
print(n3)
n4 = n2 - n1
print(n4)
print(n1.__add__(n2))
print(n2.__sub__(n1))
执行结果:
Number(300)
Number(100)
Number(300)
Number(100)
2、反向算术运算符的重载
                                                                                               
方法名运算符和表达式说明
__radd__(self,lhs)lhs + self加法
__rsub__(self,lhs)lhs - self减法
__rmul__(self,lhs)lhs * self乘法
__rtruediv__(self,lhs)lhs / self
__rfloordiv__(self,lhs)lhs // self地板除
__rmod__(self,lhs)lhs % self取模(求余)
__rpow__(self,lhs)lhs ** self幂运算
3、复合赋值算术运算符的重载
                                                       
方法名运算符和表达式说明
__iadd__(self,rhs)self += rhs加法
__isub__(self,rhs)self -= rhs减法
__imul__(self,rhs)self *= rhs乘法
__itruediv__(self,rhs)self /= rhs除法
__ifloordiv__(self,rhs)self //=rhs地板除
__imod__(self,rhs)self %= rhs取模(求余)
__ipow__(self,rhs)self **=rhs幂运算
   
4、比较算术运算符的重载
                                                   
方法名运算符和表达式说明
__lt__(self,rhs)self < rhs小于
__le__(self,rhs)self <= rhs小于等于
__gt__(self,rhs)self > rhs大于
__ge__(self,rhs)self >= rhs大于等于
__eq__(self,rhs)self == rhs等于
__ne__(self,rhs)self != rhs不等于
            
5、位运算符重载
                                           
方法名运算符和表达式说明
__and__(self,rhs)self & rhs位与
__or__(self,rhs)self | rhs位或
__xor__(self,rhs) self ^ rhs位异或
__lshift__(self,rhs)self <<rhs左移
__rshift__(self,rhs)self >>rhs右移
   
6、反向位运算符重载
                                                     
方法名运算符和表达式说明
__and__(self,lhs)lhs & rhs位与
__or__(self,lhs)lhs | rhs位或
__xor__(self,lhs)lhs ^ rhs位异或
__lshift__(self,lhs)lhs <<rhs左移
__rshift__(self,lhs)lhs >>rhs右移
   
7、复合赋值位相关运算符重载
                                                   
方法名运算符和表达式说明
__iand__(self,rhs)self & rhs位与
__ior__(self,rhs)self | rhs位或
__ixor__(self,rhs)self ^ rhs位异或
__ilshift__(self,rhs)self <<rhs左移
__irshift__(self,rhs)self >>rhs右移
            
8、一元运算符的重载
                       
方法名运算符和表达式说明
__neg__(self)- self负号
__pos__(self)+ self正号
__invert__(self)~ self取反
9、索引和切片运算符重载方法
                               
方法名运算符和表达式说明
__getitem__(self,i)x = self(i)索引/切片取值
__setitem__(self,i,v)self[i] = v索引/切片赋值
__delitem__(self,i)del self[i]del语句删除索引/切片
昵称: 邮箱:
Copyright © 2022 立地货 All Rights Reserved.
备案号:京ICP备14037608号-4