@staticmethod 在 CPython 或 Micropython 中保存任何内存吗?

2e0*_*byo 4 python static-methods micropython

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

我的推理基于两个假设,其中一个是错误的:python在实例化一个类时实例化了所有方法(事实并非如此,稍加思考就会发现,哎呀)和b。静态方法没有在访问时实例化,而是直接调用。因此我认为这段代码:

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())
Run Code Online (Sandbox Code Playgroud)

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

class Test:
    @staticmethod
    async def meth1():
        await asyncio.sleep(10)
        return 78
Run Code Online (Sandbox Code Playgroud)

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

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

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

Mis*_*agi 8

方法不会被“实例化”,它们会被绑定 \xe2\x80\x93 ,这是“它们的self/cls参数已填充”的花哨词,类似于partial参数绑定。整个要点staticmethod是没有self/cls参数,因此不需要绑定。

\n

事实上,获取 astaticmethod根本不执行任何操作 - 它只是返回函数不变:

\n
>>> class Test:\n...     @staticmethod\n...     async def meth1():\n...         await asyncio.sleep(10)\n...         return 78\n...\n>>> Test.meth1\n<function __main__.Test.meth1()>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

由于方法是按需绑定的,因此它们通常不以绑定形式存在。因此,仅仅拥有方法就不需要支付任何内存成本,也不需要staticmethod补偿。由于staticmethod是查找期间的实际层\xc2\xb9 \xe2\x80\x93,即使它不执行任何操作,\xe2\x80\x93 也不会从(不)使用staticmethod.

\n
In [40]: class Test:\n    ...:     @staticmethod\n    ...:     def s_method():\n    ...:         pass\n    ...:     def i_method(self):\n    ...:         pass\n    ...: \n\nIn [41]: %timeit Test.s_method\n42.1 ns \xc2\xb1 0.576 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 10000000 loops each)\n\nIn [42]: %timeit Test.i_method\n40.9 ns \xc2\xb1 0.202 ns per loop (mean \xc2\xb1 std. dev. of 7 runs, 10000000 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
\n

\xc2\xb9staticmethod作为每次查找方法时运行的描述符。

\n

  • 请注意,在我的环境中,无论是在 ipython 中使用 `%timeit` 还是直接运行 `timeit.timeit` 时,我都始终获得 micropython 和 python 的反 timeit 结果,静态方法稍微快一些。我会明白这最终并不重要,并且不再担心它 (3认同)
  • @2e0byo ``staticmethod`` *永远不会被绑定。发生的情况是它的描述符“__get__”被调用——这对于*每个*访问的常规方法和“staticmethod”都会发生。 (2认同)