Python 遵循 EAFP(请求原谅比请求许可更容易)哲学,而不是 LBYL(三思而后行)哲学。Python 的 EAFP 哲学在某种程度上与其“鸭子类型”的编码风格相关联。
当程序员在代码中创建数据时,无论是常量还是变量,一些编程语言需要知道数据的“类型”。 例如,如果您将变量设置为 13,计算机不知道您是想将其用作单词 (“thirteen”) 还是整数(例如 13+12=25 或 13-1=12)。 这就是为什么许多 语言要求程序员在使用数据之前声明数据。
例如,在这段 C++ 代码中,mynumber 变量是整数类型,而 myword 变量是字符串
#include <iostream>
#include <string>
using namespace std;
int mynumber = 13;
string myword = "13";
int main() {
std::cout << 13+2 << endl;
std::cout << "My favourite number is " + myword << endl;
}
然而,Python 很聪明,它使用“鸭子测试”:如果一个变量走起来像鸭子,叫起来也像鸭子,那么它就是鸭子。换句话说,应用于计算机科学,这意味着 Python 检查数据以确定其类型。 Python 知道整数用于数学,单词用于交流,因此程序员不必向 Python 解释如何使用在变量中找到的数据。 Python 使用鸭子类型自行判断,并且不会尝试对字符串进行数学运算或打印数组的内容(不进行迭代)等等。
然而,在我们讨论这些概念之前,让我们先回顾一下基础知识
理解“类型”概念的一个类比
“类型化”的概念在编程语言的上下文中经常被讨论,但通常,更深层的含义让我们难以捉摸。所以,让我尝试用一个类比来解释这个概念。
在计算机程序中,对象和其他项目存储在内存中,它们通常由某些“变量名”引用。因此,当您创建特定类的对象(在任何流行的编程语言中)时,您基本上是在为该对象保留一部分内存以供占用,然后您使用该变量名引用此对象。
因此,作为一个类比,您可以将内存中的这个空间想象成一种容器或盒子。 为了便于理解,我们称之为盒子。 所以现在我们有了两样东西——一个对象和一个包含它的盒子。
为了进一步论证,通常,盒子必须被“设计”成能够容纳它所包含的对象(即,用于装火柴的盒子不适合装鞋子,反之亦然,即使物理上是可能的)。 那么,我们可以同意对象和包含它的盒子都必须是相似的类型吗?
实际上,这就是所谓的“静态类型”。 基本上,这意味着不仅对象必须具有“类型”,而且变量名(又名盒子)也必须具有类型,并且它应该是相同或相似的。(稍后我将解释为什么我说“相似”)。 这就是为什么在 Java/C++ 等静态类型语言中,您需要在创建变量时定义变量的类型。 事实上,您可以创建一个类似于盒子的变量名,即使不创建任何对象来放入其中。 您不能在 Python 中这样做。
然而,像 Python 这样的动态类型语言的工作方式不同。 在这里,您可以将变量名想象成“标签”(有点像商店里的价格标签),而不是盒子。 所以,标签没有类型。 相反,如果您询问标签它的类型是什么,它可能会选择它在那一刻标记的对象。 我之所以说“在那一刻”,是因为就像在现实世界中一样,附加到鞋子的标签也可能在不同的时间附加到其他物品上。 因此,Python 解释器本身不会为变量名分配任何类型。 但是,如果您询问变量名它的类型,那么它将为您提供它当前绑定的对象的类型。 这就是动态类型。
这种动态类型与静态类型直接影响您编写代码的方式。 就像在现实世界中你不能把鞋子放在装火柴的盒子里一样,在静态类型语言中也是如此——你通常不能将一种类型的对象放入为另一种类型的对象创建的变量名中。
强类型语言与弱类型语言
这里还有另一个重要的概念需要讨论,即强类型语言和弱类型语言。“类型化”的“强度”与它是动态类型还是静态类型几乎无关。 它更多地与“类型转换”或将一种类型的对象转换为另一种类型的能力有关。 与流行的看法相反,Python 是一种相当强类型的语言,就像 C++ 或 Java 一样。 因此,例如在 Python 中,您不能将“整数”添加到“字符串”,但是,您可以在像 JavaScript 这样的语言中这样做。 事实上,JavaScript 是臭名昭著的“弱类型”语言之一。 因此,应该清楚的是,强/弱类型与静态/动态类型是完全不同的尺度。 一般来说,像 Python 这样的脚本语言倾向于动态类型,而编译语言倾向于静态类型。
鸭子类型、EAFP 和 LBYL
Python 遵循鸭子类型的编码风格。
让我们再次举一个现实世界的例子。 假设你有一个对象“机器 M”。 现在,你不知道这台机器 M 是否有飞行能力。 下图说明了 LBYL 与 EAFP 的处理方式

让我们用一些 Python 代码(带有虚构的函数)来阐明这个概念
# LBYL:- Look Before You Leap
if can_fly():
fly()
else:
do_something_else()
# EAFP:- Easier to Ask Forgiveness than permission
try:
fly()
except:
clean_up()
鸭子类型如何支持 EAFP
鸭子类型非常适合 EAFP 风格的编码。 这是因为我们不关心对象的“类型”; 我们只关心它的“行为”和“能力”。 “行为”基本上是指它的属性,“能力”是指它的方法。
总结
如果你看到很多 if-else
代码块,那么你就是一个 LBYL 编码者。
但是如果你看到很多 try-except
代码块,你可能就是一个 EAFP 编码者。
9 条评论