为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

翻过高山走不出你 2021-04-16 18:15:16
我希望一个特定的函数可以作为类方法来调用,并且在实例上被调用时表现不同。例如,如果我有一个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
查看完整描述

2 回答

?
莫回无

TA贡献1865条经验 获得超7个赞

好问题!您可以使用描述符轻松地完成查找。


描述符是实现描述符协议的Python对象,通常以开头__get__()。


它们大多存在于不同类的类属性中。访问它们后,将__get__()调用它们的方法,并传入实例和所有者类。


class DifferentFunc:

    """Deploys a different function accroding to attribute access


    I am a descriptor.

    """


    def __init__(self, clsfunc, instfunc):

        # Set our functions

        self.clsfunc = clsfunc

        self.instfunc = instfunc


    def __get__(self, inst, owner):

        # Accessed from class

        if inst is None:

            return self.clsfunc.__get__(None, owner)


        # Accessed from instance

        return self.instfunc.__get__(inst, owner)



class Test:

    @classmethod

    def _get_other_thing(cls):

        print("Accessed through class")


    def _get_other_thing_inst(inst):

        print("Accessed through instance")


    get_other_thing = DifferentFunc(_get_other_thing,

                                    _get_other_thing_inst)

现在来看结果:


>>> Test.get_other_thing()

Accessed through class

>>> Test().get_other_thing()

Accessed through instance

那很简单!


顺便说一句,您是否注意到我__get__在类和实例函数上使用过?你猜怎么着?函数也是描述符,这就是它们的工作方式!


>>> def func(self):

...   pass

...

>>> func.__get__(object(), object)

<bound method func of <object object at 0x000000000046E100>>

访问函数属性后,将__get__调用它,这就是获取函数绑定的方式。


有关更多信息,我强烈建议阅读Python手册和上面链接的“操作方法”。描述符是Python最强大的功能之一,甚至鲜为人知。

为什么不设置实例化功能?

还是为什么不设置self.func = self._func在里面__init__

将函数设置为实例化会带来很多问题:

  1. self.func = self._func导致循环引用。实例存储在由返回的函数对象中self._func。另一方面,这是在分配期间存储在实例上的。最终结果是该实例引用了自己,并且将以慢得多,更沉重的方式进行清理。

  2. 与您的类进行交互的其他代码可能会尝试将该函数直接带出该类,并使用__get__(),这是通常的预期方法来对其进行绑定。他们将收到错误的功能。

  3. 将无法使用__slots__

  4. 尽管使用描述符需要了解机制,但将其设置__init__为不干净,需要将多个功能设置为__init__

  5. 占用更多内存。您不必为每个实例存储一个绑定函数,而不必存储一个函数。

  6. 将无法使用属性。

随着列表的不断进行,我没有添加更多内容。


查看完整回答
反对 回复 2021-04-20
?
饮歌长啸

TA贡献1951条经验 获得超3个赞

这是一个有点棘手的解决方案:


class Thing(object):

    @staticmethod

    def get_other_thing():

        return 1


    def __getattribute__(self, name):

        if name == 'get_other_thing':

            return lambda: 2

        return super(Thing, self).__getattribute__(name)


print Thing.get_other_thing()  # 1

print Thing().get_other_thing()  # 2

如果我们在上课,则执行staticmethod。如果我们在实例上,__getattribute__首先要执行,那么我们就不能返回Thing.get_other_thing其他函数(lambda在我的情况下)


查看完整回答
反对 回复 2021-04-20
  • 2 回答
  • 0 关注
  • 144 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号