Python静态方法是否比实例方法占用更少的内存?

9

我有几个实例方法在其中使用了self,但只有少数几个地方需要这样做。

我可以直接将这些对象传递给这些方法,并使它们成为staticmethod。这会消耗更少的内存吗?

1个回答

17

您在这里进行微观优化,但没有任何好处。

是的,常规方法涉及创建一个新的method对象来处理函数和实例之间的绑定,但那只是一点点内存(2个指针加上一些Python元数据),仅在调用期间或者如果您存储了绑定方法时使用*。一个staticmethod对象不会创建新的方法对象,但这被需要大约相同数量的内存来存储staticmethod对象抵消:

>>> import sys
>>> class Foo:
...     def bar(self): pass
...     @staticmethod
...     def staticbar(): pass
...
>>> sys.getsizeof(Foo().bar)   # bound method object size
64
>>> sys.getsizeof(Foo.__dict__['staticbar'])  # staticmethod size
56

使用staticmethod对象可以节省8个字节(在Mac OS X上,在其他操作系统上字节数可能略有不同),但通常你不会保留绑定方法(你会使用instance.method(),这样会创建方法对象,然后在调用之后将其丢弃)。

因此,除非你需要存储大量的绑定方法,否则这不足以证明通过手动在代码中传递实例使代码难以阅读。


* 注意,从Python 3.7开始,对于常见情况,Python甚至不再创建方法对象。请参阅3.7 What's New 说明书 中的 优化 部分:

由于字节码更改避免创建绑定方法实例,因此方法调用现在快了多达20%。

这适用于<expr>.attribute_name(...)调用序列,即在同一整体表达式中直接跟随属性名称查找和调用,并且仅使用位置参数。生成特殊的字节码以验证attribute_name是否解析为类上的方法名称,然后直接使用<expr>之前的结果调用底层函数。 Python使用LOAD_METHOD后跟CALL_METHOD操作码,而不是LOAD_ATTRCALL_FUNCTION操作码,但如果优化不适用,则回退到后两者的行为。


1
但就我所尝试的而言,绑定方法是为每个实例创建的,这不是为每个实例额外占用了内存吗? - Ekrem Dinçel
1
@EkremDİNÇEL:我在我的回答中已经解决了这个问题:只在调用期间使用或者如果你存储了绑定方法. 如果你没有为每个实例存储绑定方法,那么就不会使用内存,方法对象通常只存在很短的时间。在现代 Python 版本中,对于常见情况,Python 甚至不会创建该对象 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接