简体   繁体   English

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

[英]Does @staticmethod save any ram in CPython or Micropython?

When answering a recent question I repeated my assumption that one reason for using @staticmethod was to save ram, since a static method was only ever instantised once.在回答最近的一个问题时,我重复了我的假设,即使用@staticmethod一个原因是为了节省 ram,因为静态方法只实例化一次。 This assertion can be found fairly easily online, (eg here ) and I don't know where I first encountered it.这个断言可以很容易地在网上找到,(例如这里),我不知道我第一次遇到它的地方。

My reasoning was based on two assumptions, one false: a.我的推理基于两个假设,一个是错误的: that python instantised all methods when instantising a class (which is not the case, as a little thought would have shown, oops) and b.在实例化一个类时,python 实例化了所有方法(事实并非如此,正如一点点想法所示,哎呀)和 b。 that staticmethods were not instantised on access, but just called directly.静态方法没有在访问时实例化,而只是直接调用。 Thus I thought that this code:因此我认为这段代码:

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())

would use more ram than if I defined the class like this:会比我这样定义类使用更多的内存:

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

Is this the case?是这种情况吗? Do staticmethods get instantised on access?静态方法是否在访问时实例化? Do classmethods get instantised on access?类方法是否在访问时实例化? I know that t1.meth1 is t2.meth1 will return True in the second case and False in the first, but is that because python is instantising meth1 the first time and then looking it up the second, or because in both cases it merely looks it up, or because in both cases it gets a copy of the static method which is somehow the same (I presume not that?) The id of a staticmethod appears not to change: but I'm not sure what my access to it is doing.我知道t1.meth1 is t2.meth1在第二种情况下会返回True而在第一种情况下会返回False ,但这是因为 python 第一次实例化meth1然后第二次查找它,或者因为在这两种情况下它只是看起来它起来,或者因为在这两种情况下它都获得了静态方法的副本,该副本在某种程度上是相同的(我认为不是?)静态方法的id似乎没有改变:但我不确定我对它的访问权限是什么正在做。

Is there any real world reason to care if so?如果是这样,是否有任何现实世界的理由需要关心? I've seen an abundance of staticmethods in micropython code where multiple instances exist in asynchronous code at once.我在 micropython 代码中看到了大量的静态方法,其中异步代码中同时存在多个实例。 I assumed this was for ram saving, but I suspect I'm wrong.我认为这是为了节省内存,但我怀疑我错了。 I'd be interested to know if there is any difference between the micropython and Cpython implementations here.我很想知道这里的 micropython 和 Cpython 实现之间是否有任何区别。

Edit I am correct in thinking that the calling t1.meth1() and t2.meth1() will bind the method twice in the first instance and once in the second?编辑我认为调用t1.meth1()t2.meth1()将在第一个实例中绑定该方法两次,在第二个实例中绑定一次是正确的吗?

Methods do not get "instantiated", they get bound – that is a fancy word for "their self / cls parameter is filled", similar tp partial parameter binding .方法不会被“实例化”,它们会被绑定——这是“他们的self / cls参数被填充”的花哨词,类似于 tp partial参数绑定 The entire point of staticmethod is that there is no self / cls parameter and thus no binding is needed. staticmethod的全部意义在于没有self / cls参数,因此不需要绑定。

In fact, fetching a staticmethod does nothing at all - it just returns the function unchanged:事实上,获取一个staticmethod什么都不做——它只是返回不变的函数:

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

Since methods are bound on-demand, they don't usually exist in their bound form.由于方法是按需绑定的,因此它们通常不以绑定形式存在。 As such, there is no memory cost to pay for just having methods and nothing for staticmethod to recoup.因此,仅拥有方法无需支付内存成本,而无需为staticmethod方法进行补偿。 Since staticmethod is an actual layer during lookup¹ – even if it does nothing – there is no performance gain either way from (not) using 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 works as descriptor that runs everytime the method is looked up. ¹ staticmethod用作描述符,每次查找该方法时都会运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM