Python的鸭子类型

作者: steinliber | 来源:发表于2016-08-21 20:52 被阅读835次

‘那只东西呱呱的叫,有扁扁的嘴巴,走起路来还外八,对!它就是只鸭子’

  1. 基本定义
    对于熟悉python的开发者来说,相信对于python的鸭子类型比较熟悉,所谓鸭子类型,在维基百科中的准确定义是‘是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定’。

  2. python中的具体实现
    下面的代码就是一个简单的鸭子类型

class duck():
    def walk(self):
        print('I walk like a duck')
    def swim(self):
        print('i swim like a duck')

class person():
    def walk(self):
        print('this one walk like a duck') 
    def swim(self):
        print('this man swim like a duck')

对于一个鸭子类型来说,我们并不关心这个对象的类型本身或是这个类继承,而是这个类是如何被使用的。我们可以通过下面的代码来调用这些类的方法。

def watch_duck(animal):
    animal.walk()
    animal.swim()

small_duck = duck()
watch_duck(small_duck)

output >> 
I walk like a duck
i swim like a duck


duck_like_man = person()
watch_duck(duck_like_man)

output >> 
this one walk like a duck
this man swim like a duck


class Lame_Foot_Duck():
    def swim(self):
        print('i am lame but i can swim')

lame_duck = Lame_Foot_Duck()
watch_duck(lame_duck)

output >>
AttributeError: Lame_Foot_Duck instance has no attribute 'walk'

watch_duck函数接收这个类的对象,然后并没有检查对象的类型,而是直接调用这个对象的走和游的方法,如果所需要的方法不存在就报错。具体在python中鸭子类型的体现如下面的代码所示

class CollectionClass():
    lists = [1,2,3,4]
    def __getitem__(self, index):
        return self.lists[index]

iter_able_object = CollectionClass()

class Another_iterAbleClass():
    lists=[1,2,3,4]
    list_position = -1

    def __iter__(self):
        return self

    def next(self): #还有更简单的实现,使用生成器或迭代器什么的:)
        self.list_position += 1
        if self.list_position >3:
            raise StopIteration
        return self.lists[self.list_position]

another_iterable_object=Another_iterAbleClass()

print(iter_able_object[1])
print(iter_able_object[1:3])
output>>
2
[2, 3]

another_iterable_object[2]
output>>
Traceback (most recent call last):
  File "/Users/steinliber/a.py", line 32, in <module>
    another_iterable_object[2]
TypeError: 'Another_iterAbleClass' object does not support indexing

print(next(another_iterable_object))
output>>
1
print(next(another_iterable_object))
output>>
2

print(next(iter_able_object))
output>>
Traceback (most recent call last):
  File "/Users/steinliber/a.py", line 29, in <module>
    print(next(iter_able_object))
TypeError: IterAbleClass object is not an iterator

在python把上述代码的实现方法叫做protocol(协议),这些protocol可以看作是通知型的接口,它规定了调用方使用该功能要调用对象的哪些方法,被调用方要实现哪些方法才能完成这个功能。它和java中的接口区别在于java中的接口功能实现需要通过继承,继承的类必须实现接口中的所有的抽象方法,所以在Java中强调的是类型的概念,而python中的protocol更多的是通知性的,一个函数规定要实现某个功能需要调用传入对象的哪些方法,所有实现这些方法的类就可以实现这个功能。

具体从上面两个类来说,第一个类实现了__getitem__方法,那python的解释器就会把它当做一个collection,就可以在这个类的对象上使用切片,获取子项等方法,第二个类实现了__iter__和next方法,python就会认为它是一个iterator,就可以在这个类的对象上通过循环来获取各个子项。一个类可以实现它有能力实现的方法,并只能被用于在它有意义的情况下。

这两个类和上面的鸭子类相比较,其实用于切边的[](它其实调用的是python的slice函数)和用于循环的iter()就相当于watch_duck函数,这些函数都接收任意类的对象,并调用实现功能所需要的对象中的方法来实现功能,若该函数中调用的方法对象里面不存在,就报错。

从上面可以看出,python鸭子类型的灵活性在于它关注的是这个所调用的对象是如何被使用的,而没有关注对象类型的本身是什么。所以在python中使用isinstance来判断传入参数的类型是不提倡的,更pythonic的方法是直接使用传入的参数,通过try,except来处理传入参数不符合要求的情况。我们应该通过传入对象的能力而不是传入对象的类型来使用该对象。

相关文章

  • 符合Python风格的对象

    基于 Python 的数据模型,自定义类型可以实现和内置类型一样自然的行为,实际上靠的是 鸭子类型。 鸭子类型:按...

  • 第四章 深入类和对象

    一. 鸭子类型和多态 鸭子类型与多态文章详解 如果一个对象实现了__getitem__方法,那python的解释器...

  • python鸭子类型

    抽象类,多态与鸭子类型 - 独角兕大王 - 博客园

  • python高级编程第一讲:深入类和对象

    1.鸭子类型和多态 多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚"鸭子类型" 所谓多态:...

  • Python的鸭子类型

    ‘那只东西呱呱的叫,有扁扁的嘴巴,走起路来还外八,对!它就是只鸭子’ 基本定义对于熟悉python的开发者来说,相...

  • python常用类方法(魔法方法)

    在谈论类方法前,我们先理解几个概念: 鸭子类型 协议 鸭子类型 python是动态的面向对象语言,动态意味着只有在...

  • 多态的意义和操作过程

    多态 首先Python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。以下是维基百科中对鸭子...

  • 举例说明什么是Python鸭子类型

    学习python的时候,也知道鸭子类型(ducking typing)这个说法,“当你看到一只鸟走起来像鸭子,游泳...

  • python常用的一些技巧

    1、三目操作符 2、鸭子类型(duck typing) 首先Python不支持多态,也不用支持多态,python是...

  • 语法

    鸭子类型 动态语言中经常提到鸭子类型,所谓鸭子类型就是:如果走起路来像鸭子,叫起来也像鸭子,那么它就是鸭子(If ...

网友评论

  • steinliber:@生命在于折腾已被使用 因为在python中,使用for循环会尝试调用该对象的__iter__方法,生成一个只有next的iterator。再使用iter来逐个获取其中的项。所以说iterable的可迭代,iterator不可迭代,因为iterator没有实现__iter__
  • steinliber:@书记 对,有了__iter__和next只能说明该类是iterable的,只要实现了next 就会被认为是一个iterator,是我的表述有点问题:sweat_smile:
  • 生命在于折腾已被使用:有点难懂啊,还有不可迭代的迭代器

本文标题:Python的鸭子类型

本文链接:https://www.haomeiwen.com/subject/wkitsttx.html