Python 将函数绑定到本地作用域中的名称的好处?

Python 将函数绑定到本地作用域中的名称的好处?,python,python-3.x,Python,Python 3.x,大约一天前我读了一些东西,不记得在哪里,文章的作者指出,最好将函数调用绑定到本地空间中的名称,而不是进行访问调用 例如: def foo(): a = math.cos b = math.sin x = a(1) * b(0) vs 现在,这是在性能方面,如果这些调用不止一次,那么我想知道为什么它的性能更好,什么时候应该这样使用它?这样做难道不会让名称空间变得混乱吗?我做了一些分析,以了解它们之间的实际区别。你可以 从timeit导入timeit import math

大约一天前我读了一些东西,不记得在哪里,文章的作者指出,最好将函数调用绑定到本地空间中的名称,而不是进行
访问调用

例如:

def foo():
    a = math.cos
    b = math.sin
    x = a(1) * b(0)
vs


现在,这是在性能方面,如果这些调用不止一次,那么我想知道为什么它的性能更好,什么时候应该这样使用它?这样做难道不会让名称空间变得混乱吗?

我做了一些分析,以了解它们之间的实际区别。你可以 从timeit导入timeit

import math
from math import sin

x = 10_000_000


def from_import():
    for _ in range(x):
        sin(100)


def import_module():
    for _ in range(x):
        math.sin(100)


def local_var():
    s = math.sin
    for _ in range(x):
        s(100)


def local_import():
    from math import sin
    for _ in range(x):
        sin(100)


funcs = (from_import, import_module, local_var, local_import)

for func in funcs:
    print("{:<15} {}".format(
        func.__name__, timeit(
            func.__name__ + '()', number=1, globals=globals())))

我感到惊讶的是,本地名称比全球名称更具表现力。这两种方法都大大优于其他属性查找

在这种特定情况下,不会有性能优势。但是,如果多次调用一个方法(例如在循环中),那么Python中相对较高的方法解析成本可能会对性能产生可测量的影响。注意,不仅解析属性,
x.some_attr
的成本很高,而且如果它是一个函数,那么每次都会重新创建一个绑定方法对象。如果您正在处理一些非常敏感的性能问题,我只会担心这一点。一定要选择好名字。如果您对导入执行此操作,那么您可能应该从math import sin的另一个模块
中导入名称,因为
@juanpa.arrivillaga假设
x
是一个类,并且
x.some_方法
经常被调用。有没有办法提高性能?这个“把戏”比性能更具风格。我有时会在有很长的行的地方使用它,因为它们包含对一个或多个长函数名的调用,我希望通过打断行而不缩写函数名来缩短行。不过,这只是一种风格的东西。@PatrickHaugh我确实是,我可以沿着一个由ECEF点组成的KDTree进行扫描。非常好的小测试,谢谢。现在问题稍微转向“什么时候应该这样做?”。这样的权衡当然不值得在每个函数作用域中为局部变量分配方法调用??对于类实例方法调用,我可以理解为什么,因为它有大量的开销,但对于这一点,似乎需要更多的代码行。
import math
from math import sin

x = 10_000_000


def from_import():
    for _ in range(x):
        sin(100)


def import_module():
    for _ in range(x):
        math.sin(100)


def local_var():
    s = math.sin
    for _ in range(x):
        s(100)


def local_import():
    from math import sin
    for _ in range(x):
        sin(100)


funcs = (from_import, import_module, local_var, local_import)

for func in funcs:
    print("{:<15} {}".format(
        func.__name__, timeit(
            func.__name__ + '()', number=1, globals=globals())))
from_import     4.354339323996101
import_module   5.608195230990532
local_var       3.982630196987884
local_import    3.9956486110022524