首页 > 解决方案 > @staticmethod 是否在 CPython 或 Micropython 中保存任何 ram?

问题描述

在回答最近的一个问题时,我重复了我的假设,即使用的一个原因@staticmethod是为了节省 ram,因为静态方法只实例化一次。这个断言可以很容易地在网上找到(例如这里),我不知道我第一次遇到它的地方。

我的推理基于两个假设,一个是错误的:那个python在实例化一个类时实例化了所有方法(事实并非如此,正如一点点的想法会表明,哎呀)和b。staticmethods 没有在访问时实例化,而是直接调用。因此我认为这段代码:

import asyncio

class Test:
    async def meth1():
        await asyncio.sleep(10)
        return 78
t1= Test()
t2 = Test()
loop = asyncio.get_event_loop
loop.create_task(t1)
loop.create_task(t2)

def main():
    for _ in range(10):
        await asyncio.sleep(2)

loop.run(main())

将使用比我这样定义类更多的内存:

class Test:
    @staticmethod
    async def meth1():
        await asyncio.sleep(10)
        return 78

是这样吗?静态方法是否在访问时被实例化?类方法是否在访问时被实例化?我知道它t1.meth1 is t2.meth1True在第二种情况和第一种情况下返回False,但那是因为pythonmeth1第一次实例化然后第二次查找它,或者因为在这两种情况下它只是查找它,或者因为在这两种情况下它都得到了静态方法的副本,它在某种程度上是相同的(我想不是吗?)id静态方法的 似乎没有改变:但我不确定我对它的访问在做什么。

如果是这样,是否有任何现实世界的理由关心?我在 micropython 代码中看到了大量的静态方法,其中异步代码中同时存在多个实例。我以为这是为了节省内存,但我怀疑我错了。我很想知道这里的 micropython 和 Cpython 实现之间是否有任何区别。

编辑 我认为调用t1.meth1()并将在第一个实例中t2.meth1()绑定该方法两次,第二个实例中绑定该方法是正确的?

标签: pythonstatic-methodsmicropython

解决方案


方法不会被“实例化”,它们会被绑定——这是“他们的self/cls参数被填充”的一个花哨的词,类似于partial参数绑定。的全部要点staticmethod是没有self/cls参数,因此不需要绑定。

事实上,获取 astaticmethod根本没有任何作用——它只是返回未更改的函数:

>>> class Test:
...     @staticmethod
...     async def meth1():
...         await asyncio.sleep(10)
...         return 78
...
>>> Test.meth1
<function __main__.Test.meth1()>

由于方法是按需绑定的,因此它们通常不以其绑定形式存在。因此,没有任何内存成本可以为仅拥有方法而无需支付任何费用staticmethod来弥补。由于staticmethod在查找期间是一个实际的层¹——即使它什么都不做——从(不)使用staticmethod.

In [40]: class Test:
    ...:     @staticmethod
    ...:     def s_method():
    ...:         pass
    ...:     def i_method(self):
    ...:         pass
    ...: 

In [41]: %timeit Test.s_method
42.1 ns ± 0.576 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [42]: %timeit Test.i_method
40.9 ns ± 0.202 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

请注意,这些时间可能会因实施和测试设置而略有不同。要点是这两种方法都相当快,并且性能与选择其中一种方法无关。


¹staticmethod用作每次查找方法时运行的描述符。


推荐阅读