前言:问题是要了解python的内部原理,所以请不要回答“升级python”或“导入六个”
以“打印”为例
要替换内置的“ print”,我可以编写python函数。
python 2.6:在运行时,出现语法错误
解决方案
from __future__ import print_function
现在我可以重新定义打印了。 为什么呢 我想是因为现在我的打印声明与新的打印功能相同。
python 2.4:在运行时,出现语法错误
没有
from __future__ import print_function
因此,对于print
(或任何其他内置函数):是否可以用带有不同声明args和kwargs的新函数来猴子补丁?
换句话说。
from __future__ import print_function
用功能代替关键字。总的来说,我想了解如何。请不要只关注print
,这是一个方便的示例。
答案 0 :(得分:3)
在Python 2中,print
是一个关键字。出于无法重新定义print
,if
,while
或任何其他语言关键字的相同原因,您无法重新定义def
;它们是语言语法的一部分,并且由解析器处理,而不是通过查找函数来处理。
from __future__ import print_function
也由解析器处理。看起来像是正常的导入,实际上确实导入了一个东西,但是它导入的东西与语句的主要功能无关,后者是告诉解析器停止将print
当作关键字。>
在禁用关键字的情况下,print
被视为遵循普通名称查找规则的普通名称。这样的查找会找到print
内置函数,该函数通常被关键字隐藏。
您不能定义自己的魔术导入;它们必须内置在解释器中。由于您无法定义自己的魔术导入,并且由于没有其他__future__
导入将关键字转换为非关键字,因此无需进行一般化。
(人们有时会说list
或dict
之类的内置关键字是关键字。它们不是关键字;那些人错误地使用了“关键字”一词。)
对于猴子补丁内置功能(不是关键字),其签名与原始签名不同,您可以执行此操作。这可能是个坏主意,但您可以做到。该过程与您正常修补内置猴子的方式相同。
答案 1 :(得分:3)
from __future__ import print_function
所做的全部工作就是在解析器中切换一个标志,以使其停止将print
视为关键字;完成此操作后,对print
的引用将无缝地类似于对构成合法变量名称的任何其他非关键字的引用(它们将通过LEGB查找,并在LEGB的B中被找到,内置作用域)。此行为在Python解释器中进行了硬编码。如果没有构建Python的自定义版本,或者没有进行超出任何合理问题范围的其他骇人听闻的骇客活动,就无法获得其他任何关键字的类似效果。
从2.6开始,__builtin__
上具有print
函数,因此任何使用from __future__ import print_function
的模块(因此可以引用 name {{1 }}(而不是关键字 print
)将看到print
(如果尚未被本地,嵌套或全局范围内的某些内容所遮盖)。它仍然是每个模块的那里,但是在没有__builtin__.print
导入的模块中,对__future__
的引用在编译时被解析为关键字并被替换原始字节码实现了特殊的print
语句(print
和del
的行为方式相同;对于相同的原因,它们是关键字),因此没有导入的模块将永远没有机会查找return
函数。
这不会推广到其他情况,因为print
在其他情况下,其功能之一会将关键字转换为非关键字。对于所有其他实际的内置函数,能够在每个模块的基础上覆盖它们就像在全局范围内分配名称(为该模块着色)一样简单,例如:
__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