@staticmethod 是否在 CPython 或 Micropython 中保存任何 ram?
Does @staticmethod save any ram in CPython or Micropython?
在回答最近的一个问题时,我重复了我的假设,即使用 @staticmethod
的一个原因是为了节省 ram,因为静态方法只被实例化一次。这个断言可以很容易地在网上找到,(例如 here),我不知道我第一次遇到它的地方。
我的推理基于两个假设,一个是错误的:a。 python 在实例化 a class 时实例化了所有方法(事实并非如此,稍加思考就会表明,哎呀)和 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 使用更多的内存:
class Test:
@staticmethod
async def meth1():
await asyncio.sleep(10)
return 78
是这样吗?静态方法是否在访问时实例化? classmethods 是否在访问时实例化?我知道 t1.meth1 is t2.meth1
在第二种情况下会 return True
而在第一种情况下会 False
,但那是因为 python 正在实例化 meth1
第一次然后第二次查找它,或者因为在这两种情况下它只是查找它,或者因为在这两种情况下它都获得静态方法的副本,它在某种程度上是相同的(我想不是那样?) id
的静态方法似乎没有改变:但我不确定我对它的访问是做什么的。
是否有任何现实世界的理由关心是否如此?我在 micropython 代码中看到了大量静态方法,其中异步代码中同时存在多个实例。我以为这是为了节省内存,但我怀疑我错了。我很想知道这里的 micropython 和 Cpython 实现之间是否有任何区别。
编辑
我认为调用 t1.meth1()
和 t2.meth1()
将在第一个实例中绑定方法 twice 和 once 是正确的在第二个?
方法不会被“实例化”,它们会被绑定——这是“它们的 self
/cls
参数已填充”的奇特词,类似于 partial
parameter binding。 staticmethod
的全部要点是没有 self
/cls
参数,因此不需要绑定。
事实上,获取 staticmethod
什么都不做 - 它只是 returns 函数不变:
>>> 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
与每次查找方法时运行的 descriptor 一样工作。
在回答最近的一个问题时,我重复了我的假设,即使用 @staticmethod
的一个原因是为了节省 ram,因为静态方法只被实例化一次。这个断言可以很容易地在网上找到,(例如 here),我不知道我第一次遇到它的地方。
我的推理基于两个假设,一个是错误的:a。 python 在实例化 a class 时实例化了所有方法(事实并非如此,稍加思考就会表明,哎呀)和 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 使用更多的内存:
class Test:
@staticmethod
async def meth1():
await asyncio.sleep(10)
return 78
是这样吗?静态方法是否在访问时实例化? classmethods 是否在访问时实例化?我知道 t1.meth1 is t2.meth1
在第二种情况下会 return True
而在第一种情况下会 False
,但那是因为 python 正在实例化 meth1
第一次然后第二次查找它,或者因为在这两种情况下它只是查找它,或者因为在这两种情况下它都获得静态方法的副本,它在某种程度上是相同的(我想不是那样?) id
的静态方法似乎没有改变:但我不确定我对它的访问是做什么的。
是否有任何现实世界的理由关心是否如此?我在 micropython 代码中看到了大量静态方法,其中异步代码中同时存在多个实例。我以为这是为了节省内存,但我怀疑我错了。我很想知道这里的 micropython 和 Cpython 实现之间是否有任何区别。
编辑
我认为调用 t1.meth1()
和 t2.meth1()
将在第一个实例中绑定方法 twice 和 once 是正确的在第二个?
方法不会被“实例化”,它们会被绑定——这是“它们的 self
/cls
参数已填充”的奇特词,类似于 partial
parameter binding。 staticmethod
的全部要点是没有 self
/cls
参数,因此不需要绑定。
事实上,获取 staticmethod
什么都不做 - 它只是 returns 函数不变:
>>> 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
与每次查找方法时运行的 descriptor 一样工作。