在python中,为什么pow这样的函数可以直接调用,而floor这样的函数得先导入模块?

python新手,望大神们多指教回复内容:
本来写在 @bhuztez 大大的回答的评论里的。算了还是发到顶层好了。诶这里 @蓝色 大大的回答真的误解一些了, @bhuztez 大大的回答才是完全正解。这个问题,要看最精辟的答案的请看 @flow memory 大大的,要深入到python的内部机制的请看 @bhuztez 大大的,要看点具体代码的请看 @蓝色 大大修正过的答案。python的__builtin___模块完全是个运行时的东西, @蓝色 大大引用的代码其实是在vm初始化的时候把初始的__builtin___模块中的名字与函数指针的对应关系注册好;然而python的(源码到字节码)编译器是不关心这个的。python的pow()跟像gcc的__builtin_powi()不可以相提并论;前者的行为可以在运行时改变,而编译器完全不把它当作特殊的东西看待;后者则是编译器直接支持的intrinsic function。刚初始化好的时候,__builtin__模块里的”pow”映射到的是builtin_pow()函数,后者进一步调用pynumber_power()函数来实现功能;cpython/bltinmodule.c at 2.7 · python/cpython · githubpython的源码编译器会把 ** 运算符编译为binary_power字节码指令,而python的字节码解释器为binary_power的实现则是直接调用pynumber_power()函数(不通过符号解析__builtin__模块里的”pow”的当前绑定)。cpython/ceval.c at 2.7 · python/cpython · github由于在python代码里调用pow()实际上要先经过一次符号解析(load_name)找到目标然后再调用过去,而模块的绑定又是可变的,所以可以做到下面这种事情:

$ python
python 2.7.5 (default, mar 9 2014, 22:15:05)
[gcc 4.2.1 compatible apple llvm 5.0 (clang-500.0.68)] on darwin
type “help”, “copyright”, “credits” or “license” for more information.
>>> 2 ** 5
32
>>> pow(2, 5)
32
>>> __builtins__

>>> dir(__builtins__)
[‘arithmeticerror’, ‘assertionerror’, ‘attributeerror’, ‘baseexception’, ‘buffererror’, ‘byteswarning’, ‘deprecationwarning’, ‘eoferror’, ‘ellipsis’, ‘environmenterror’, ‘exception’, ‘false’, ‘floatingpointerror’, ‘futurewarning’, ‘generatorexit’, ‘ioerror’, ‘importerror’, ‘importwarning’, ‘indentationerror’, ‘indexerror’, ‘keyerror’, ‘keyboardinterrupt’, ‘lookuperror’, ‘memoryerror’, ‘nameerror’, ‘none’, ‘notimplemented’, ‘notimplementederror’, ‘oserror’, ‘overflowerror’, ‘pendingdeprecationwarning’, ‘referenceerror’, ‘runtimeerror’, ‘runtimewarning’, ‘standarderror’, ‘stopiteration’, ‘syntaxerror’, ‘syntaxwarning’, ‘systemerror’, ‘systemexit’, ‘taberror’, ‘true’, ‘typeerror’, ‘unboundlocalerror’, ‘unicodedecodeerror’, ‘unicodeencodeerror’, ‘unicodeerror’, ‘unicodetranslateerror’, ‘unicodewarning’, ‘userwarning’, ‘valueerror’, ‘warning’, ‘zeropisionerror’, ‘_’, ‘__debug__’, ‘__doc__’, ‘__import__’, ‘__name__’, ‘__package__’, ‘abs’, ‘all’, ‘any’, ‘apply’, ‘basestring’, ‘bin’, ‘bool’, ‘buffer’, ‘bytearray’, ‘bytes’, ‘callable’, ‘chr’, ‘classmethod’, ‘cmp’, ‘coerce’, ‘compile’, ‘complex’, ‘copyright’, ‘credits’, ‘delattr’, ‘dict’, ‘dir’, ‘pmod’, ‘enumerate’, ‘eval’, ‘execfile’, ‘exit’, ‘file’, ‘filter’, ‘float’, ‘format’, ‘frozenset’, ‘getattr’, ‘globals’, ‘hasattr’, ‘hash’, ‘help’, ‘hex’, ‘id’, ‘input’, ‘int’, ‘intern’, ‘isinstance’, ‘issubclass’, ‘iter’, ‘len’, ‘license’, ‘list’, ‘locals’, ‘long’, ‘map’, ‘max’, ‘memoryview’, ‘min’, ‘next’, ‘object’, ‘oct’, ‘open’, ‘ord’, ‘pow’, ‘print’, ‘property’, ‘quit’, ‘range’, ‘raw_input’, ‘reduce’, ‘reload’, ‘repr’, ‘reversed’, ’round’, ‘set’, ‘setattr’, ‘slice’, ‘sorted’, ‘staticmethod’, ‘str’, ‘sum’, ‘super’, ‘tuple’, ‘type’, ‘unichr’, ‘unicode’, ‘vars’, ‘xrange’, ‘zip’]
>>> pow

>>> mypow = pow
>>> mypow

>>> __builtins__.pow = lambda x, y: mypow(x, y) – 1
>>> pow(2, 5)
31
>>> 2 ** 5
32

看到蓝色来冒充python专家了,特来批判一番。这里首先是黑魔法,不然有些问题就解释不清楚啦。

>>> __builtins__

>>> pow(2,2)
4
>>> __builtins__ = none
>>> pow(2,2)
traceback (most recent call last):
file “”, line 1, in
nameerror: name ‘pow’ is not defined
>>> __builtins__ = {‘pow’:1}
>>> pow
1
>>>

很多人扯一大堆道理,然而对于本问题并没什么卵用。真正原因在于,这是python设计者的喜好罢了,因为设计者完全可以把floor也做成可以直接调用的嘛。
pow()是built-in function,所以不需要导入.floor()是math module的function,需要import math(from math import floor)后才能用.不过要注意的是math module中也有个pow(),和built-in的pow()有些不同.可以看看官方文档:2. built-in functions以及9.2. math — mathematical functions
——————————-update——————可以看 @rednaxelafx 的解释,我的理解有所偏差,还是放在前面吧,让更多人看到上面说的很清楚,pow是builtin函数,而builtin函数是编译器直接支持的,可以参考这个链接了解built in函数与普通函数的不同:intrinsic function下面我将顺便展开说说python中是如何实现builtin pow的。首先在python中,built in函数定义在了bltinmodules.c这个文件中,具体的代码在:

static pymethoddef builtin_methods[]

pow 貌似比 floor 更常用 更适合作为 build-in 存在
这个问题的实质就是:为什么有的函数在__builtins__,而有的不在?
除了scope原因之外,造成這樣scope的原因,還有一個可能是pow 是int, floor可能是float。雖然python裡面並沒有什麼type。

Posted in 未分类

发表评论