Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python内部函数是否已编译?_Python - Fatal编程技术网

Python内部函数是否已编译?

Python内部函数是否已编译?,python,Python,因此,在CPython中,函数定义在解析时被编译成函数对象。但是内部功能呢?它们是在解析时被编译成函数对象,还是在每次调用函数时被编译(或解释)?内部函数是否会导致任何性能损失 >>> import dis >>> def foo(): ... def bar(): ... print "stuff" ... return bar ... >>> b = foo() >>> dis.

因此,在CPython中,函数定义在解析时被编译成函数对象。但是内部功能呢?它们是在解析时被编译成函数对象,还是在每次调用函数时被编译(或解释)?内部函数是否会导致任何性能损失

>>> import dis
>>> def foo():
...     def bar():
...             print "stuff"
...     return bar
... 
>>> b = foo()
>>> dis.dis(foo)
  2           0 LOAD_CONST               1 (<code object bar at 0x20bf738, file "<stdin>", line 2>)
              3 MAKE_FUNCTION            0
              6 STORE_FAST               0 (bar)

  4           9 LOAD_FAST                0 (bar)
             12 RETURN_VALUE        
>>> dis.dis(b)
  3           0 LOAD_CONST               1 ('stuff')
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE        

因此,我们可以得出结论,它们是经过编译的。至于它们的性能特征,请使用它们。如果您开始出现性能问题,请配置文件。我知道这不是一个真正的答案,但它几乎从来都不重要,当它发生时,一般的答案并不能解决它。函数调用会产生一些开销,看起来内部函数就像函数一样。

简单测试:函数的默认参数在定义时调用一次

>>> def foo():
...     def bar(arg=count()):
...             pass
...     pass
...
>>> def count():
...     print "defined"
...
>>> foo()
defined
>>> foo()
defined

是的:这是一个很小的(非常非常小的)性能损失。

为了扩展nmichaels answer,内部函数是在编译时编译的,正如他猜测的那样,字节码保存在
foo.func\u code.co\u consts
中,并且可以使用操作码加载常量来访问它们,正如您在函数的反汇编中看到的那样

例如:

>>> def foo():
...     def inner():
...         pass
>>> print foo.func_code.co_consts
(None, <code object inner at 0x249c6c0, file "<ipython console>", line 2>)
>>def foo():
...     def inner():
...         通过
>>>打印foo.func_code.co_常量
(无,<0x249c6c0处的代码对象内部,文件“ipython控制台”,第2行>)

给出一般解释-假设模块中有以下代码:

def outer(x=1):
    def inner(y=2):
        return x+y
当python通过
compile()
解析文件时,上面的文本将转换为字节码,说明如何执行模块。在字节码模块中,有两个“代码对象”,一个用于
outer()
的字节码,另一个用于
inner()的字节码。请注意,我说的是代码对象,而不是函数-代码对象只包含函数使用的字节码,以及编译时可能知道的任何信息-例如
outer()
的字节码,其中包含对
inner()
字节码的引用

当模块实际加载时,通过评估与模块关联的代码对象,发生的一件事是为
outer()
创建一个实际的“函数对象”,并存储在模块的
outer
属性中。函数对象充当字节码和调用函数所需的所有上下文相关内容的集合(例如,它应该从哪些全局dict中提取,等等),这些在编译时是未知的。在某种程度上,代码对象是一个函数的模板,它是一个用于执行实际字节码并填充所有变量的模板


所有这些都不涉及
internal()
-作为一个函数-每次您真正开始调用
outer()
,都会为调用outer创建一个新的
internal()
函数对象,它将已经创建的内部字节码对象绑定到一个全局变量列表,包括传递给外部调用的
x
的值。您可以想象,这非常快,因为不需要解析,只需使用指向其他现有对象的指针填充一个快速结构。

我对此有点晚,但作为这些彻底答案的一个小实验补充:您可以使用来验证是否创建了一个新对象:

In []: # inner version
       def foo():
           def bar():
               return id(bar)
           return bar()

       foo(), foo()

Out[]: (4352951432, 4352952752)
实际数字可能不同,但它们的差异表明确实创建了两个不同的
bar
实例

In []: # outer version
       def bar():
           return id(bar)

       def foo():
           return bar()

       foo(), foo()

Out[]: (4352950952, 4352950952)
这一次,正如预期的那样,两个
id
s是相同的

现在进行一些
timeit
测量。内第一,外第二:

100000 loops, best of 3: 1.93 µs per loop
1000000 loops, best of 3: 1.25 µs per loop

因此,在我的机器上,内部版本似乎慢了50%(Python 2.7,IPython笔记本)。

您是否有机会提供一个您所指的内部函数类型的示例?我倾向于说,如果你在另一个函数体中定义一个函数,性能会下降,主要是因为我希望它在外部函数的每次调用中都会被重新定义,但我想确保我完全理解你的问题。另外,
timeit
模块将是测试它的一个很好的方法。非常清晰的答案与上述实验的结果一致。谢谢!有关详细信息,请参阅:
100000 loops, best of 3: 1.93 µs per loop
1000000 loops, best of 3: 1.25 µs per loop