Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 类型暗示与duck类型_Python_Type Hinting - Fatal编程技术网

Python 类型暗示与duck类型

Python 类型暗示与duck类型,python,type-hinting,Python,Type Hinting,在Python中使用类型暗示的缺点之一是牺牲Python代码的美 在类型提示之前,我的方法签名是简洁的: def echo(items): for i in items: print(i) 由于我的团队正在使用类型提示,我也在代码中添加了类型提示: def echo(items: Set[str]) -> None: from typing_extensions import Protocol, runtime_checkable @runtime_

在Python中使用类型暗示的缺点之一是牺牲Python代码的美

在类型提示之前,我的方法签名是简洁的:

def echo(items):
    for i in items:
        print(i)
    
由于我的团队正在使用类型提示,我也在代码中添加了类型提示:

def echo(items: Set[str]) -> None:
from typing_extensions import Protocol, runtime_checkable

@runtime_checkable
class Portable(Protocol):
    handles: int

class Mug:
    def __init__(self) -> None:
        self.handles = 1

mug = Mug()
if isinstance(mug, Portable):
   use(mug.handles)  # Works statically and at runtime
还是挺容易走路的。一段时间后,我的代码中对集合集进行操作的其他部分要求我的
项可以散列,而其他部分则不需要。所以我决定也支持
frozenset
,现在我的方法如下:

 def echo(items: Union[Set[str],Frozenset[str]]) -> None:
 
它开始看起来像Java中的方法,尽管在Java中我可以在接口上操作,而忽略了实现细节:

 void echo(Set<String> items) {
void echo(设置项){
Python不支持接口概念,也就是说,我不能说
Set
实现了
Frozenset
。由于duck类型,最初的实现将同时适用于
Set
Frozenset
:两者都表现为Set。然而,我的印象是,显式类型暗示在某种程度上并不适合duck类型平


如何在键入提示和duck键入之间找到一个良好的平衡点?

使用
AbstractSet

from typing import AbstractSet

def echo(items: AbstractSet[str]) -> None:
    ...
AbstractSet
    |
    |
    +--------------+
    |              |
    |              |
MutableSet        FrozenSet
    |
    |
   Set
Set
FrozenSet
都从
AbstractSet
继承(直接或间接):

from typing import AbstractSet

def echo(items: AbstractSet[str]) -> None:
    ...
AbstractSet
    |
    |
    +--------------+
    |              |
    |              |
MutableSet        FrozenSet
    |
    |
   Set

正如@chpner所说的,使用内置类型是一个很好的选择


协议的概念与接口有一些相似之处

如文件所述:

结构子类型可以看作是Python程序员熟知的duck类型的静态等价物。Mypy通过下面描述的协议类提供对结构子类型的支持。有关Python中协议和结构子类型的详细规范,请参阅

还可以定义自定义协议:

from typing import Iterable
from typing_extensions import Protocol

class SupportsClose(Protocol):
    def close(self) -> None:
       ...  # Empty method body (explicit '...')

class Resource:  # No SupportsClose base class!
    # ... some methods ...

    def close(self) -> None:
       self.resource.release()

def close_all(items: Iterable[SupportsClose]) -> None:
    for item in items:
        item.close()

close_all([Resource(), open('some/file')])  # Okay!
虽然协议的主要用途是静态分析,但它们允许检查对象在运行时是否也遵循某些协议:

def echo(items: Set[str]) -> None:
from typing_extensions import Protocol, runtime_checkable

@runtime_checkable
class Portable(Protocol):
    handles: int

class Mug:
    def __init__(self) -> None:
        self.handles = 1

mug = Mug()
if isinstance(mug, Portable):
   use(mug.handles)  # Works statically and at runtime

我会让其他人详细说明,但至少要解决接口问题。duck类型并不是一个真正的问题,duck类型通过
Protocol
s支持。这只是一个使用适当的公共祖先而不是枚举类的问题。你能提供一个到Python代码库的链接,在这里可以解释这种关系吗icitly implemented?Java JDK包含类似于
公共类HashSet implements Set
的内容。查看
类型。Frozenset
我只能看到
Frozenset=\u别名(Frozenset,T\u co,inst=False)
。它是从中明确记录的父类中收集的。因此协议看起来有点像Rust中的traits。我需要更多地了解它。谢谢。traits实际上不是一个新概念。但它们有点不同。Go在方法上使用结构类型来确定类型与接口的兼容性。“协议的概念与接口有一些相似之处。”——不仅仅是相似性。它们是相同的。协议是OO中的一个基本概念。记住,面向对象的基础是消息传递,网络隐喻无处不在。(Alan Kay认识那些在发明Smalltalk的同时发明互联网的人,并且对他们的工作非常感兴趣。object==网络主机,method==隐藏的本地代码,field==隐藏的本地存储,message==公共API的想法在Smalltalk的设计中非常明显。)一开始,Smalltalk的想法协议"虽然是非正式的,但很快就正式集成到SimultAutoDes中。然后研究了第一个SMTALTE类型系统,这些都是基于网络规范和网络协议的思想。当Brad Cox和Tom Love把SimultTalk对象模型放到C上并创建Objto-C时,他们提出了协议PAR的思想。Objective-C是Java设计的主要影响因素,Java中的
interface
关键字直接来自Objective-C协议。因此,我们可以从Smalltalk中的协议到Java中的接口画一条直线。