gpt4 book ai didi

python - 将用户选择的方法添加到 python 中的元基类中

转载 作者:行者123 更新时间:2023-12-01 02:25:00 27 4
gpt4 key购买 nike

我有无法实例化的基类(在我的简化示例中为BaseFruit)和一些派生类(例如在我的示例中的Apple),它们都应该共享一个相同的方法(printfuture)。然而,它们有很多可能的变体,我想让用户选择应该使用什么变体(例如 sadfuturesaddestfuture)。

由于我的 printfuture 方法对于所有派生类都是通用的,因此我认为适合使用我的 __new__ 方法来捕获变体的用户参数。基类并将方法分配给基类本身。如下例所示:

# my custom methods

def sadfuture(self):
"""A sad future"""
print 'It looks {}!'.format(self.aspect)
print 'Mmm yummy !'

def saddestfuture(self):
"""A saddest future"""
print 'It looks {}'.format(self.aspect)
print 'Garbage !'

# my base class

class BaseFruit(object):
"""Fruit base class"""
def __new__(cls, *args, **kwargs):
setattr(cls, 'printfuture', kwargs['usermethod'])
return object.__new__(cls)

# My class

class Apple(BaseFruit):
"""An apple class"""
def __init__(self, aspect, usermethod=sadfuture):
self.aspect = aspect


if __name__ == '__main__':
goodapple = Apple(aspect='delicious', usermethod=sadfuture)
goodapple.printfuture() # ==> ok
badapple = Apple(aspect='rotten', usermethod=saddestfuture)
goodapple.printfuture() # ==> not ok anymore
badapple.printfuture() # ==> ok

打印内容:

It looks delicious!
Mmm yummy !
It looks delicious
Garbage !
It looks rotten
Garbage !

而不是预期的行为:

It looks delicious!
Mmm yummy !
It looks delicious!
Mmm yummy !
It looks rotten
Garbage !

我确实知道我已经覆盖了我的基类,并且我的第一个对象已经改变了它的行为。所以,我的主要问题是:如何在将自定义方法保留在基类之外的同时实现预期行为?

也欢迎对此类问题的最佳实践和正确设计发表评论。

最佳答案

“预期”行为确实是实际打印的。所以,这种行为并不是“你所期望的”,这是另一回事。让我们看看为什么:

每次创建 Apple 的新实例时,您所做的就是在实例化类(在本例中为 Apple )上创建一个新方法。专线setattr(cls, 'printfuture', kwargs['usermethod'])每次创建 BaseFruit 的新实例时,都会执行此操作。或其任何子类。 (顺便说一句,这一行可以简单地是 cls.printfuture = kwargs['usermethod'] ,如果属性名称是硬编码的,则不需要 setattr )。

因此,当您创建 Apple 的第二个实例时,调用badapple = Apple(aspect='rotten', usermethod=saddestfuture)只需制作 saddestfuture printfuture对于Apple类(class)为saddestfuture ,不仅仅是 badapple 的方法,但适用于 Apple 的任何实例。

修复不需要元类 - 您可以使用 __new__ 中的代码本身创建一个“伪方法”,附加到实例 - 正如您所希望的那样。但是,您必须在实例上执行此操作,在创建实例之后,当您拥有对实例的引用时,而不是在实例化之前,当您仅拥有对类本身的引用时。

由于在实例化类之前没有需要运行的实际代码,因此您也可以在__init__中绑定(bind)类似方法的函数。 ,并离开定制__new__只在真正需要的时候使用。同时,使用 super 也没什么坏处。而不是对父类(super class)的调用进行硬编码:

...
# my base class

class BaseFruit(object):
"""Fruit base class"""
def __init__(self, *args, **kwargs):
printfuture = kwargs.pop('usermethod')
super(BaseFruit, self).__init__(*args, **kwargs)
# Wrap the call to the passed method in a function
# that captures "self" from here, since Python do not
# insert "self" in calls to functions
# attributed to instances.
self.printfuture = lambda: printfuture(self)


# My class

class Apple(BaseFruit):
"""An apple class"""
def __init__(self, aspect, usermethod=sadfuture):
super(Apple, self).__init__(usermethod)
self.aspect = aspect

至于元类,这不需要它们 - 相反,您必须在创建每个实例时对其进行自定义。当我们必须自定义类本身时,我们通常会使用元类。您的原始代码正在执行此操作(自定义类本身),但该代码在创建每个实例时运行,这导致了您不期望的行为。如果代码创建printfuture元类 __new__ 上的方法方法,与在父类(super class)中不同的是,当声明每个子类时,这种情况只会发生一次(并且该子类的所有实例将共享相同的 printifuture 方法)。

现在,一旦您掌握了它的工作原理,请转到 Python 3 继续学习这些内容。 Python 2 将在 2 年内完全退出历史舞台,并且在任何项目中都将毫无用处。一件事是必须在 Python 2 中保留遗留代码,另一件事是学习或启动新项目 - 为此您应该只使用 Python 3。

关于python - 将用户选择的方法添加到 python 中的元基类中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47500101/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com