4

我在课堂上的艰难循环中使用numpy.random.normal函数。

class MyClass(MyBaseClass):   
    def run(self):
        while True:
            ...
            self.L.append(numpy.random.normal(0,1))

我知道在 Python 中使用多个查找非常慢。其中numpy.random.normal有 3 次查找:首先numpy是查找,然后是random,然后是normal

所以我决定通过分配numpy.random.normal一个局部变量来解决这个问题_normal

开始了:

class MyClass(MyBaseClass):
    _normal = numpy.random.normal
    def run(self):
        while True:
            ...
            self.L.append(MyClass._normal(0,1))

我真正关心的是描述符。当访问类中的变量时,会在所有基类中查找具有相同名称的数据描述符。它在这里描述:

检查objectname.__class__.__dict__attrname。如果存在并且是数据描述符,则返回描述符结果。objectname.__class__搜索同一案例的所有基地。

所以,我想,如果我_normal像上面那样放入本地空间,它将查找数据描述符的所有基类。我担心它会成为经济放缓的根源。

我的担忧是否合理?

我是否应该担心在基类中查找描述符所需的时间?

当在类中使用位于模块深处的函数时,是否有更好的方法来加速对其的访问?


在对答案的评论中进行了讨论。

我决定提供一些看起来很重要的额外实施细节(对于我的特殊情况)。

实际上,代码更接近于此(非常非常简化):

class MyClass(MyBaseClass):

    def __iter__(self):
        return self

    def next(self):
        self.L.append(numpy.random.normal(0,1))   

    def run(self):
        while True:
            self.next()
4

2 回答 2

5

如果你必须做这样的事情(函数查找实际上是主要成本吗?随机数生成并不便宜)你应该意识到一个全局 + 一个属性查找(MyClass._normal)并不比一个全局 + 三个属性查找(numpy.random.normal)便宜多少。您真正想要的是在循环内获得全局或 attr 查找,您只能通过_normal 在 function 内部定义来做到这一点。如果您真的非常渴望剃须周期,您还应该预先绑定列表追加调用:

class MyClass(MyBaseClass):
    def run(self):
        _normal = numpy.random.normal
        _Lappend = self.L.append
        while True:
            ...
            _Lappend(_normal(0,1))

对比反汇编输出(仅用于append语句):

  LOAD_FAST                0 (self)
  LOAD_ATTR                1 (L)
  LOAD_ATTR                2 (append)
  LOAD_GLOBAL              3 (numpy)
  LOAD_ATTR                4 (random)
  LOAD_ATTR                5 (normal)
  LOAD_CONST               1 (0)
  LOAD_CONST               2 (1)
  CALL_FUNCTION            2
  CALL_FUNCTION            1
  POP_TOP             

对比

  LOAD_FAST                2 (_Lappend)
  LOAD_FAST                1 (_normal)
  LOAD_CONST               1 (0)
  LOAD_CONST               2 (1)
  CALL_FUNCTION            2
  CALL_FUNCTION            1

更好的是矢量化——生成许多随机的法线偏差并将它们一次性附加到列表中——你可以size使用numpy.random.normal.

于 2011-12-04T18:45:58.810 回答
2

我担心它会成为经济放缓的根源。

我的担忧是否合理?

那要看。对于您心目中的应用程序来说,它已经足够快了吗?如果是这样,请不要担心。CPython、PyPy、NumPy 和摩尔定律的变化可能会在“减速”成为症结之前减轻其幅度。

于 2011-12-04T18:35:54.220 回答