vs 无法解析变量$_25. None、True与False 的故事(解释字面量、关键字与内置变量)...

本文详细探讨了Python中关键字与字面量的区别,解释了为什么None、True和False在Python3中被视为关键字而非字面量。文章还介绍了Python的解析方式,以及内置名称与关键字的不同,讨论了允许给内置名称如None赋值的设计选择及其潜在影响。
摘要由CSDN通过智能技术生成
a6f6a4bb810d38f12189e677454d1198.png

本系列文章译自Python之父 Guido van Rossum 的系列博客“The History of Python”。这个博客系列对我们理解Python及其演变很有帮助,经Guido同意,在这里翻译推荐给大家,希望大家喜欢,也请大家多多指教!

系列地址:http://blog.kantli.com/theme/1


1. 缘起

最近,有人通过邮件向我提了一个有趣的问题:

关键字与字面量的区别何在?为什么 Python 3 中的 True 和 False 是关键字,而不是字面量?我前段时间惊恐地发现,在 Python 2 中,我们可以给 True/False 赋值。

于是我研究了下,发现在 PEP 285 中,True、False 与 None 一样,都是常量(constants)。Python 2.4 之后,禁止用户给 None 赋值,但在 Python 3 之前,对 True/False 的赋值一直是被允许的。

是有什么特殊原因,让 None 一开始就作为变量而不是字面量吗?


2. 关键字 VS 字面量

先来回答第一个问题:关键字与字面量的区别。

在编程句法中,关键字也叫保留字,类似于这门语言中的识别器,或者从解析器的角度看,就像某种 token。识别器由字母、数字及下划线组成,但不能以数字开头(这是 Python 中的定义,其它语言,如 C和 Java 的定义也类似)。

关于关键字,最重要的一点是,它们不可以用作变量名称(方法名、类名等等)。大家比较熟悉的 Python 关键字包括 if、while、for、and、or 等等。

而字面量是一个常量的值的表示,常见的字面量包括数字(如 42,3.14,1.6e-10 等)和字符串(如 “Hello, world”)。解析器可以识别字面量,但识别的具体规则一般会很复杂。比如在 Python 3 中,以下都是数字字面量:

1231.01..01e10.1e+42123.456e-1000xfffe0o755

而以下则不是:

. # 点e10 # 识别器0y12 # 字面量 0 加一个识别器 y120xffe+10 # 字面量 0xffe 加一个加号以及数字 10

注意,字面量并不是常量。我们经常在代码中定义常量,如:

MAX_LEVELS = 15

这里,15 是字面量,而 MAX_LEVEL 则是一个识别器,由于全部都是大写字母,因此,用户可能不会在代码中改变其值,也就是说,可能是一个常量——不过,常量中使用大写字母只是惯例而已,Python 解析器并不会因为变量名由大写字母组成就把它当做常量,也不强制所有常量都用大写字母表示。

但反过来写就会被解析器拒绝:

15 = MAX_LEVELS

因为赋值操作符(=)的左边必须是一个变量,而字面量不可以作为变量名。(变量的准确定义非常复杂,有些看着像表达式的,其实也是变量,比如 d[k],(a, b),foo.bar 等等——不过 f(),() 或 42 就不是变量。在 del 语句中,也使用同样的变量定义。)


3. 解析方式

接下来,我们看 None,True 和 False。

先来看 None,因为它在语言诞生之初就有了。(相对来说,True 和 False 是后期添加的,最初是在 Python 2.2.1 版本。)None 是一个单例对象(即语言中只有一个 None),表示值的缺失。例如,假设 d 是一个字典,如果 d 中有键 k 的话,d.get(k) 会返回 d[k] ,否则就返回 None。

早期版本中,None 只是 Python 的一个“内置名称”,解析器并不知道什么 None,正如它也不知道 int,float,str 等内置类型,或 KeyError 、 ZeroDivisionError 等内置异常。所有这些,对解析器而言都是识别器,在解析用户代码时,查找它们的过程与查找其它名称的过程是一样的(比如用户自己定义的方法或变量)。

在以下代码中,每一行都是同样解析,产生一样的解析树( = ):

x = Nonex = intx = foobar

而下面的代码则会产生另一种解析树( = ):

x = 42x = 'hello'

因为解析器处理数字、字符串等字面量的方式与处理识别器的方式不同。

结合这个例子与之前 MAX_LEVEL 的例子,我们知道,如果左右互换,前面三行代码是可以被解析器接受的( = ),而后面两行则不行( = 不成立)。


4. 内置名称 VS 关键字

这样设计的结果是:如果你想恶心使用你代码的人,可以给内置变量重新赋值,比如:

int = floatdef parse_string(s): return int(s)print(parse_string('42')) # 将打印42.0

有些人可能会说:“这有什么大不了的?正常程序员肯定不会这样写。”而另一些人则完全目瞪口呆:“怎么可能有这种允许赋值给内置名称的傻逼语言?!”

这个问题比较微妙,与一致性的保持和语言的发展历史有关。我相信,如果不查文档,你肯定写不出 Python 中的所有内置名称(至少我做不到),而且我也相信,很多人并不认识每一个内置名称。(想尝试的话,可以用 dir(builtins) 命令)

就以比较奇怪的内置名称 copyright、credits 与 license为例,由于它们的存在,Python 才能在每次打开交互窗口时发出问候语:

Python 3.4.0a4+ (default:0917f6c62c62, Oct 22 2013, 10:55:35)[GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.28)] on darwinType "help
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值