好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

在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 · GitHub
Python的源码编译器会把 ** 运算符编译为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__ 
   module   '__builtin__'   (  built  -  in  )  > 
 >>>   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'  ,   'ZeroDivisionError'  ,   '_'  ,   '__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'  ,   'divmod'  ,   '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 
   built  -  in   function   pow  > 
 >>>   mypow   =   pow 
 >>>   mypow 
   built  -  in   function   pow  > 
 >>>   __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。

查看更多关于在Python中,为什么pow这样的函数可以直接调用,而floor这样的函数得先导入模块?的详细内容...

  阅读:43次