python: 内置函数重定义,参数不同

python: builtin function redefinition, with different arguments

前言:问题是理解python内部结构,所以请不要用'upgrade python'或'import six'

来回答

举个例子,'print'

要替换 'print' 内置函数,我可以编写 python 函数。

python 2.6:在运行时,我得到 语法错误

解决方案

from __future__ import print_function

现在我可以重新定义打印了。 为什么 ? 我想是因为现在我的 print 声明与新的 print 函数相同。

python 2.4:在运行时,我得到 语法错误

没有

from __future__ import print_function

因此,对于 print(或任何其他内置函数):是否可以使用新函数使用不同的声明 - args 和 kwargs 来猴子补丁?


也就是说。

from __future__ import print_function 用函数替换关键字。一般来说,我想了解如何。请不要只关注 print,这是一个方便的示例。

在Python2中,print是关键字。您无法重新定义 print 的原因与您无法重新定义 ifwhiledef 或任何其他语言关键字的原因相同;它们是语言语法的一部分,由解析器处理,而不是通过查找函数处理。

from __future__ import print_function 也由解析器处理。它看起来像一个普通的导入,它确实导入了一个东西,但它导入的东西与语句的主要功能无关,即告诉解析器停止将 print 视为关键字。

禁用关键字后,print 将被视为遵循普通名称查找规则的普通名称。这样的查找会找到 print 内置函数,该函数通常被关键字隐藏。

您不能定义自己的魔法导入;它们必须内置到解释器本身中。由于您无法定义自己的魔法导入,并且由于没有其他 __future__ 导入将关键字转换为非关键字,因此无法进行概括。

(人们有时会说像 listdict 这样的内置函数是关键字。它们不是关键字;那些人错误地使用了 "keyword" 这个词。)


至于使用与原始签名不同的猴子修补内置函数(不是关键字),您可以这样做。这可能是个坏主意,但你可以做到。该过程与您通常对内置程序进行猴子修补的方式相同。

from __future__ import print_function 所做的只是在解析器中切换一个标志,使其停止将 print 视为关键字;一旦完成,对 print 的引用就会无缝地变成对构成合法变量名的任何其他非关键字的引用(它们通过 LEGB 查找,并在 LEGB 的 B 中找到,即内置范围)。这种行为在 Python 解释器中是硬编码的;如果不构建 Python 的自定义版本,或者参与其他超出任何合理问题范围的骇人听闻的黑客行为,就无法对任何其他关键字实现类似的效果。

从 2.6 开始,__builtin__ 有一个 print 函数,所以任何使用 from __future__ import print_function 的模块(因此可以引用 name print 而不是 关键字 print) 将看到 __builtin__.print (如果它没有被本地的某些东西遮蔽,嵌套或全球范围)。对于 every 模块,它仍然 there,但是在没有 __future__ 导入的模块中,对 print 的引用被解析为关键字在编译时替换为实现特殊 print 语句 的原始字节码(与 delreturn 的行为相同;你不能出于同样的原因命名一个变量,它们是关键字),因此没有导入的模块永远没有机会查找 print function.

这不会推广到其他情况,因为 __future__ 没有其他情况,其中一个功能可以将关键字转换为非关键字。对于所有其他实际的内置函数,能够在每个模块的基础上覆盖它们就像在全局范围内分配名称一样简单(为该模块隐藏它),例如:

def abs(x):
    return x  # Who needs absolute value anyway?
# From here on out, references to abs in this module see your override, not the built-in

虽然可以全局重新分配内置函数,但这是一个糟糕的主意(因为使用它的每个其他模块都可能依赖于内置函数的原始行为)。也就是说,这并不难:

import __builtin__

def abs(x):
    return x  # Who needs absolute value anyway?

__builtin__.abs = abs
# *Every* module now sees your terrible monkeypatch, on your own head be it