关于python鸭子类型和白鹅类型

1,白鹅类型

白鹅类型对接口有明确定义,比如不可变序列(Sequence),需要实现__contains__,__iter__,__len__,__getitem__,__reversed__,index,count
对于其中的抽象方法,子类在继承时必须具体化,其余非抽象方法在继承时可以自动获得,Sequence序列必须具体化的抽象方法是__len__和__getitem__

from collections import abc

class Foo(abc.Sequence):

    def __init__(self, components):
        self._components = components

    def __getitem__(self, item):
        return self._components[item]

    def __len__(self):
        return len(self._components)

f = Foo(list(‘abcde‘))

# f就是正式的Sequence类了
print(isinstance(f, abc.Sequence)) # 结果True

# 可以使用自己创建的抽象方法,或者继承来的方法
print(f[0])   # ‘a‘,__getitem__
print(len(f))   # 4,__len__
print(‘b‘ in f)   # True,__contains __
for i in f:    # __iter__
  print(f)
print(list(reversed(f)))   # [‘e‘, ‘d‘, ‘c‘, ‘b‘, ‘a‘], __reversed__
print(f.count(‘a‘))     # 1, count
print(f.index(‘a‘))   # 0, index

 

2,鸭子类型

鸭子类型没有明确的接口,只是遵循了一定的协议,比如python序列协议只需要实现__len__和__getitem__方法
对于序列,这点鸭子类型和白鹅类型中Sequence抽象基类的要求完全相同,只是白鹅类型Sequence继承后能够自动获得抽象基类的方法,而鸭子类型没有这些方法,比如不继承abc.Sequence的Foo:
# 下面2个方法可以使用,因为自己实现了:
print(f[0]) # ‘a‘,__getitem__
print(len(f)) # 4,__len__

# 下面2个方法也可以使用,原因是python发现某些特殊方法没有实现时,会自动尝试调用其他特殊方法
print(‘b‘ in f) # 可以用,in测试会依次尝试调用__contains__,__iter__,__getitem__
for i in f: # 可以用,迭代会依次尝试调用__iter__,__getitem__
  print(i)

#下面3个方法就无法使用了:
print(list(reversed(f)))
print(f.count(‘a‘))
print(f.index(‘a‘))

# 另外isinstance检测无法通过:
print(isinstance(f, abc.Sequence)) # 结果False

对于抽象基类,如果子类没有基础Sequence,但是自己实现了Sequence明确要求的接口,可以注册为Sequence的虚拟子类,然后Sequence也能“认出来”,例如:

from collections import abc

@abc.Sequence.register
class Foo:

    def __init__(self, components):
        self._components = components

    def __getitem__(self, item):
        return self._components[item]

    def __len__(self):
        return len(self._components)

    def __contains__(self, item):
        return item in self._components

    def __iter__(self):
        for i in self._components:
            yield i

    def __reversed__(self):
        return reversed(self._components)

    def count(self, v):
        return self._components.count(v)

    def index(self, v):
        return self._components.index(v)

# 所有接口都已经实现,并注册为虚拟子类后,isinstance检测顺利通过:

f = Foo(list(‘abcde‘))
print(isinstance(f, abc.Sequence))   #  True

如果少了一样,python解释器会提示AttributeError

备注:例子Foo类非常简单,多此一举,只为演示,相关方法全部委托给components序列处理

原文地址:https://www.cnblogs.com/guxh/p/10206630.html

时间: 2024-11-06 03:55:47

关于python鸭子类型和白鹅类型的相关文章

python 鸭子类型

以前写过一篇文章讲了一下python中的多态,最后得出结论python不支持多态,随着对python理解得加深,对python中得多态又有了一些看法. 首先Python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型.以下是维基百科中对鸭子类型得论述: 在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格.在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定.这个概念的名字来源于由James Whitco

python脚本实现自动为png类型图片添加@2x后缀

@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css); @import url(/css/cuteeditor.css); @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css); @import url(/css/cuteeditor.css); 美术们总是忘记或者因为其它

简单的python爬虫 爬的乌云漏洞类型

import urllib.request import re starturl="http://wooyun.org/searchbug.php?q=%E9%87%91%E8%9E%8D" def get_html_response(url): html_response = urllib.request.urlopen(url).read().decode('utf-8') return html_response def geturl(starturl): a=get_html_

python有哪些变量类型?以及变量类型的总结

python有哪些变量类型?以及变量类型的总结[数值]Number:float.int.long.complex [字符串]:str注意没有string,这里的str就是string的缩写. 创建方式:str() a='abcdef' 方法: 1.截取:a[头下标:尾下标:每步值] 每步值默认是:1 2.增加:a + a 等同 a*2 3.合并:a + a 4.S.lower() #小写 5.S.upper() #大写 6.S.swapcase() #大小写互换 7.S.capitalize()

简介Python的collections模块中defaultdict类型

这里我们来简介Python的collections模块中defaultdict类型的用法,与内置的字典类最大的不同在于初始化上,一起来看一下: defaultdict 主要用来需要对 value 做初始化的情形.对于字典来说,key 必须是 hashable,immutable,unique 的数据,而 value 可以是任意的数据类型.如果 value 是 list,dict 等数据类型,在使用之前必须初始化为空,有些情况需要把 value 初始化为特殊值,比如 0 或者 ''. from c

python基础(1) 变量类型

变量赋值: python中的变量不需要类型声明 每个变量在使用前必须赋值,变量赋值以后才会被创建 变量在内存中创建时,包括变量的标识.名称和数据这些信息. EX: 1 #!/usr/bin/python 2 # -*- coding: UTF-8 -*- 3 4 counter = 100 # 赋值整型变量 5 miles = 1000.0 # 浮点型 6 name = "John" # 字符串 7 8 print counter 9 print miles 10 print name

python可变类型和不可变类型

原文地址:http://www.cnblogs.com/huamingao/p/5809936.html 可变类型 Vs 不可变类型 可变类型(mutable):列表,字典 不可变类型(unmutable):数字,字符串,元组 这里的可变不可变,是指内存中的那块内容(value)是否可以被改变 代码: name1='wupeiqi' name2=name1 print("name1:%s\nname2:%s" %(name1,name2)) name1='alex' print(&qu

【Python系统学习03】错误类型整理(一)

错误类型与可能原因分析 A.语法错误: 1.syntaxError:invalid syntax 无效的语法 print(2019小石头) # print(2019小石头) # ^ # SyntaxError: invalid syntax 2.syntaxError:invalid character in identifier 标识符中有无效的字符 print('我左边的引号是中文的符号') # print('我左边的引号是中文的符号') # ^ # SyntaxError: invalid

python限定方法参数类型、返回值类型、变量类型等

typing模块的作用 自python3.5开始,PEP484为python引入了类型注解(type hints) 类型检查,防止运行时出现参数和返回值类型.变量类型不符合. 作为开发文档附加说明,方便使用者调用时传入和返回参数类型. 该模块加入后并不会影响程序的运行,不会报正式的错误,只有提醒pycharm目前支持typing检查,参数类型错误会黄色提示 常用类型 int,long,float: 整型,长整形,浮点型 bool,str: 布尔型,字符串类型 List, Tuple, Dict,