名称空间混淆和包装



可能以前有人问过这个问题,但是到目前为止我没有找到任何相关信息。

假设我在一个名为test.py的文件中有一些代码(这是我昨天的问题包装np的结果。数组__pow__方法)

import numpy as np
from functools import wraps, reduce
#Create a subclass of np.ndarray to speed up the power operation
class MyArray(np.ndarray):
  def __pow__(self, other):
    return reduce(lambda x,y: x*y, [self for _ in range(other)])
#Create a wrapper so that arrays are created using my Class instead of the old one.    
def change_ndarray(func):
  @wraps(func)
  def wrapper(*args, **kwargs):
    return func(*args, **kwargs).view(MyArray)
  return wrapper    
np.array = change_ndarray(np.array)
到目前为止,它在我的文件中工作得很好,每个数组都是使用包装的np.array生成的。但随后比较速度增益我很困惑:
>>> import numpy as np
>>> %timeit np.linspace(10,1000,1000000)**3
10 loops, best of 3: 154 ms per loop
>>> import test
>>> %timeit np.linspace(10,1000,1000000)**3
10 loops, best of 3: 40.6 ms per loop

为什么linspace现在与包装的narray一起工作而不是旧的?为什么np.linspace现在呼叫t.np.array ?我以为这是另一个命名空间linspace和np。array有什么关系?

作为一个注释,我通读了https://docs.python.org/3/reference/import.html,但那真的很难读,所以也许我错过了它。如果有人能给我正确的方向,我将很高兴。

test.py中,np.array = change_ndarray(np.array)在您别名为npnumpy模块中重新分配array变量。所有使用numpy.array的代码现在都使用您放入其中的新内容。像from numpy import *这样的操作在本地模块中创建了新的变量,但是import numpy as np只给你一个对模块本身的引用。

考虑python变量是如何工作的。名称空间是存储键(变量名)/值(变量引用的对象)对的python 字典。命名空间与方法和函数(局部变量)、类(类变量)和模块(模块全局变量)相关。当你使用一个变量时,python会在多个命名空间字典中查找该名称并返回其对象。np.array意味着查找一个名为np的变量,获取其命名空间dict,然后查找array。在您的示例中,npnumpy模块,array是那里的变量。