• 技术文章 >后端开发 >Python教程

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

    2016-06-06 16:23:12原创752
    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。
    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:python
    Web大前端开发直播班

    相关文章推荐

    • python常用机器学习及深度学习库介绍(总结分享)• 归纳整理Python正则表达式知识点• 带你搞懂Python反序列化• Python数据结构与算法学习之双端队列• Python详细解析之容器、可迭代对象、迭代器以及生成器

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网