函数在类和实例上的行为不同

我希望一个特定的函数可以作为类方法来调用,并且在实例上被调用时表现不同。


例如,如果我有一个class Thing,我既要Thing.get_other_thing()工作,又要thing = Thing(); thing.get_other_thing()表现得与众不同。


我认为get_other_thing在初始化时覆盖该方法应该可以工作(请参阅下文),但这似乎有点不客气。有没有更好的办法?


class Thing:


    def __init__(self):

        self.get_other_thing = self._get_other_thing_inst()


    @classmethod

    def get_other_thing(cls):

        # do something...


    def _get_other_thing_inst(self):

        # do something else


翻过高山走不出你
浏览 145回答 2
2回答

莫回无

好问题!您可以使用描述符轻松地完成查找。描述符是实现描述符协议的Python对象,通常以开头__get__()。它们大多存在于不同类的类属性中。访问它们后,将__get__()调用它们的方法,并传入实例和所有者类。class DifferentFunc:&nbsp; &nbsp; """Deploys a different function accroding to attribute access&nbsp; &nbsp; I am a descriptor.&nbsp; &nbsp; """&nbsp; &nbsp; def __init__(self, clsfunc, instfunc):&nbsp; &nbsp; &nbsp; &nbsp; # Set our functions&nbsp; &nbsp; &nbsp; &nbsp; self.clsfunc = clsfunc&nbsp; &nbsp; &nbsp; &nbsp; self.instfunc = instfunc&nbsp; &nbsp; def __get__(self, inst, owner):&nbsp; &nbsp; &nbsp; &nbsp; # Accessed from class&nbsp; &nbsp; &nbsp; &nbsp; if inst is None:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return self.clsfunc.__get__(None, owner)&nbsp; &nbsp; &nbsp; &nbsp; # Accessed from instance&nbsp; &nbsp; &nbsp; &nbsp; return self.instfunc.__get__(inst, owner)class Test:&nbsp; &nbsp; @classmethod&nbsp; &nbsp; def _get_other_thing(cls):&nbsp; &nbsp; &nbsp; &nbsp; print("Accessed through class")&nbsp; &nbsp; def _get_other_thing_inst(inst):&nbsp; &nbsp; &nbsp; &nbsp; print("Accessed through instance")&nbsp; &nbsp; get_other_thing = DifferentFunc(_get_other_thing,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _get_other_thing_inst)现在来看结果:>>> Test.get_other_thing()Accessed through class>>> Test().get_other_thing()Accessed through instance那很简单!顺便说一句,您是否注意到我__get__在类和实例函数上使用过?你猜怎么着?函数也是描述符,这就是它们的工作方式!>>> def func(self):...&nbsp; &nbsp;pass...>>> func.__get__(object(), object)<bound method func of <object object at 0x000000000046E100>>访问函数属性后,将__get__调用它,这就是获取函数绑定的方式。有关更多信息,我强烈建议阅读Python手册和上面链接的“操作方法”。描述符是Python最强大的功能之一,甚至鲜为人知。为什么不设置实例化功能?还是为什么不设置self.func = self._func在里面__init__?将函数设置为实例化会带来很多问题:self.func = self._func导致循环引用。实例存储在由返回的函数对象中self._func。另一方面,这是在分配期间存储在实例上的。最终结果是该实例引用了自己,并且将以慢得多,更沉重的方式进行清理。与您的类进行交互的其他代码可能会尝试将该函数直接带出该类,并使用__get__(),这是通常的预期方法来对其进行绑定。他们将收到错误的功能。将无法使用__slots__。尽管使用描述符需要了解机制,但将其设置__init__为不干净,需要将多个功能设置为__init__。占用更多内存。您不必为每个实例存储一个绑定函数,而不必存储一个函数。将无法使用属性。随着列表的不断进行,我没有添加更多内容。

饮歌长啸

这是一个有点棘手的解决方案:class Thing(object):&nbsp; &nbsp; @staticmethod&nbsp; &nbsp; def get_other_thing():&nbsp; &nbsp; &nbsp; &nbsp; return 1&nbsp; &nbsp; def __getattribute__(self, name):&nbsp; &nbsp; &nbsp; &nbsp; if name == 'get_other_thing':&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return lambda: 2&nbsp; &nbsp; &nbsp; &nbsp; return super(Thing, self).__getattribute__(name)print Thing.get_other_thing()&nbsp; # 1print Thing().get_other_thing()&nbsp; # 2如果我们在上课,则执行staticmethod。如果我们在实例上,__getattribute__首先要执行,那么我们就不能返回Thing.get_other_thing其他函数(lambda在我的情况下)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python