19

Duck-typing Programming

 4 years ago
source link: https://sikasjc.github.io/2019/11/13/duck_typing/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Duck-typing Programming

2019年11月13日

翻译自Duck Typing

duck.png

Duck Typing是一种编程方式,其中传递给函数或方法的对象,期望在运行时,该对象满足函数或方法所需对象的所有方法签名和属性。 即只关注行为,而不关注类型

对象的类型本身并不重要。相反,该对象应该支持所有函数或方法在其上调用的所有方法签名/属性。

出于这个原因,Duck typing 有时被视为“一种思考方式而不是一种类型系统”。

在Duck typing中,我们不在函数原型或方法中声明参数类型。 这意味着编译器无法进行类型检查。

真正重要的是这种编程方式认为对象在运行时具有特定的方法/属性。

因此,动态语言通常支持Duck typing。 然而,一些静态语言开始通过结构类型“模仿”这种编程范式。

SAMPLE CODE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Source: Wikipedia, 2017.
class Sparrow:
def fly(self):
print("Sparrow flying")
class Airplane:
def fly(self):
print("Airplane flying")
class Whale:
def swim(self):
print("Whale swimming")

# The type of entity is not specified
# We expect entity to have a callable named fly at run time
def lift_off(entity):
entity.fly()

sparrow = Sparrow()
airplane = Airplane()
whale = Whale()

lift_off(sparrow) # prints `Sparrow flying`
lift_off(airplane) # prints `Airplane flying`
lift_off(whale) # Throws the error `'Whale' object has no attribute 'fly'`

如果它像鸭子一样走路,像鸭子一样游泳,像鸭子一样嘎嘎叫,那么它就是一只鸭子。

If it walks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.

即像鸭子一样的非鸭子实体也可以被视为鸭子,因为重点在于行为

因此通过类比,只要对象的行为符合预期,对象的类型就不重要了

例如,Book类具有属性numPages和方法getPage(number),其中number是整数。假设函数searchPhrase(book, phrase)用于搜索书中的给定短语。这个函数会调用给定book中的numPages和getPage()。

Newspaper显然不是Book,但是对于Duck typing这不重要。如果Newspaper已经实现了numPages和getPage(number),那么它就可以传递给searchPhrase(book, phrase)。

Duck-typing 优势

img

便捷 > 类型安全

Duck-typing 不是类型系统,它为程序员提供了巨大的灵活性,常见于动态类型语言。 例如,在Python中,许多地方都容易编码。

一般而言,动态类型(dynamic typing)通常会缩短开发时间。 更少的冗余而又不得不写的代码,并且代码也更容易理解。 使用静态类型,编译时的类型检查降低了开发速度,但是在之后使用静态类型可以获得更好的性能。 因此有些人推荐建议Duck-typing仅用于原型设计,而不用于生产。

虽然编译时检查对于尽早发现潜在问题很有用,不过Duck-typing也可以通过强制执行编码约定,文档和测试驱动方法来确保代码的健壮。

Duck typing 和 Late binding

Late binding 是指在运行时将对象或方法绑定到指定的名字上。Duck typing看起来类似于Late binding,但是有一个微妙的差别,Duck typing基于行为而不是声明的类型。

Duck typing 和 Structural typing

img

Duck typing 可以分为静态Duck typing和动态Duck typing,对于后者,跳过编译时检查,这就是一般提及Duck typing时的含义。

静态Duck typing和一些静态类型语言(Scala,F#)支持的Structural typing很相似。 Structural typing允许进行一些编译时检查,注意检测的不是类型,而是支持的方法/属性。 Structural typing可以看作是由编译器保证的Duck typing的子集。 但是,我们还应该注意Structural typing基本上是静态类型,而Duck typing是动态的。

Duck typing 和 implied interfaces

静态类型语言使用显式接口。 在C#中,可以使用interface:任何实现interface的类型都可以传递给接受该接口的方法/函数。 这就是如何将灵活性构建到静态类型语言中,但这需要接口声明。

Python则没有显式接口:隐含接口。 对于Python,隐式接口与Duck typing没有什么不同。

但是,对于C++,在其STL库中支持隐含接口。 鉴于C++进行编译时检查,我们通常不能说隐含的接口与Duck typing相同。 请注意,当接口为隐式时,没有正式的接口定义,一般而言只有接口文档。

Duck typing 与 LBYL, EAFP

LBYL: Look Before You Leap

EAFP: Easy to Ask for Forgiveness than Permission

这是两个相反的概念,都可以用Python来讨论,虽然Python更喜欢EAFP方法。

对于LBYL,我们通常在对象执行操作之前检查对象是否是可兼容类型,例如调用其方法。Python有一个内置函数isinstance()来做到这一点。

对于EAFP,我们只需调用对象的方法,期望该方法存在。如果不存在,则Python解释器将抛出异常,代码应该处理该异常。

在Python的Duck typing中,验证对象的类型的行为很不Pythonic。 因此,尽管可以使用hasattr()来验证对象是否含有某个属性,但Python更喜欢EAFP,这也正好和Duck typing的思想一致。

Reference

DEVOPEDIA Duck Typing


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK