【问题标题】:Python criteria based dynamic function adding to class基于 Python 标准的动态函数添加到类
【发布时间】:2012-02-28 09:16:59
【问题描述】:

如何根据某些条件动态地向类添加函数。

对于前我有一个类如下:

class A(object):
     def __init__(self,type):
         self.type = type

现在基于“类型”值,我想将 B 类或 C 类的函数添加到 A 类。

例如

lass B(object):
    def fun1(self):
        print 'fun1'
    def fun2(self):
        print 'fun2'

class C(object):
    def fun3(self):
        print 'fun3'
    def fun4(self):
        print 'fun4'

如果 A 类的 'type' 属性值为 'B' 则将 B 类的函数(即 fun1 和 fun2)动态添加到 A 类,否则如果 'type' 属性值为 'C' 则添加 C 类的函数到 A 类(即 fun3 和 fun4)到 A 类,这样在我的代码中,我可以访问这些函数作为 A.fun1() 或 A.fun3。

我猜元编程可能会在这方面对我有所帮助,但我不知道如何去做。请指导。

此外,我必须创建 A 类的对象,并能够通过 A 类的那些对象使用这些功能。

a = class A(type='B')
a.fun1()  #should work

请帮忙,因为我无法弄清楚这一点。

这是我的代码的一部分。

class Group(object):
    def __init__(self,type):
        if type == 'source'
            self.mgr = SManager(self)             #grp_mgr
        elif type == 'target'
            self.mgr = TManager(self)

    def __getattr__(self,name):
        if hasattr(self.mgr,name):
            return getattr(self.mgr,name)
        return AttributeError

class SManager(object):
    def __init__(self,groupobj):
        self.some_list = []
        self.groupobj = groupobj

    def doProcess(self):
        #this function accesses self.groupobj
        pass

    def get_valid_list(self):
        #this function accesses self.groupobj
        pass

但是这样我得到了以下错误。

    if hasattr(self.mgr,name):
  File "c:\workspace\project\dev.py", line 27, in __ge
tattr__
    if hasattr(self.mgr,name):
  File "c:\workspace\project\dev.py", line 27, in __ge
tattr__
    if hasattr(self.mgr,name):
  File "c:\workspace\project\dev.py", line 27, in __ge
tattr__
    if hasattr(self.mgr,name):
  File "c:\workspace\project\dev.py", line 27, in __ge
tattr__
    if hasattr(self.mgr,name):
  File "c:\workspace\project\dev.py", line 27, in __ge
tattr__
    if hasattr(self.mgr,name):
RuntimeError: maximum recursion depth exceeded while calling a Python object

我无法弄清楚我在哪里犯了错误。在合并这个之前,我用一个简单的 sn-p 尝试了这个例子,但是当我在实际代码中做同样的事情时,它会抛出错误。 请帮忙

【问题讨论】:

  • “元类是比 99% 的用户所担心的更深层次的魔法。如果你想知道是否需要它们,其实你不需要。 - TP。您愿意解释一下为什么需要这种行为吗?也许有更好的设计可以帮助您。

标签: python metaprogramming python-2.7 python-2.6 python-2.x


【解决方案1】:

好像你的问题是XY Problem,而你原来的问题“X”的解决方案是多重继承,比如:

class A(B, C):
    pass

所以现在您可以使用A().fun1()A().fun3()

【讨论】:

  • 我实际上已经想到了这一点。但在我的情况下,我需要 B 类或 C 类的功能,但从不需要两者。
  • @PyBegginer:如果你需要 A 或 B 的功能而不是两者,那么只继承其中一个;然后,您可以将适当的类传递给需要实例化此类对象的任何代码。
【解决方案2】:

正如我在问题评论中已经说过的那样:您可能根本不需要元类。

但由于您没有提供更多信息,这就是您所要求的如何使用元类来完成:

class MetaX(type):

    def __add__(cls, other):
        name = '{}+{}'.format(cls.__name__, other.__name__)
        return type(cls)(name, (cls, other), dict())


class X(object):    # metaclass=MetaX in py3k

    __metaclass__ = MetaX

    def __add__(self, other):
        cls = type(self) + type(other)
        return cls

就是这样,你只需要从X继承。

例子:

class A(X):
    def func_a(self):
        print "I'm in func_a"

class B(X):
    def func_b(self):
        print "I'm in func_b"

class C(X):
    def func_c(self):
        print "I'm in func_c"

L = A + B
l = L()
l.func_a()  # -> I'm in func_a
l.func_b()  # -> I'm in func_b

P = A + C
p = P()
p.func_a()  # -> I'm in func_a
p.func_c()  # -> I'm in func_c

编辑:您真正需要的取决于您的实际代码的样子。

您在问题中描述的是动态继承,如果这是您真正需要的,那么 IMO 元类是正确的工具,而覆盖 __getattr__ 将只是一个 hack。

如果您不想构建整个元类,您可以使用某种类工厂来构建:

def get_enhanced_A(typ)   # you can't use type as a keyword here
    dct = {'B': B, 'C': C}
    return type('A+{}'.format(typ), (A,dct[typ]), dict())

我不知道这两个选项中哪个更好看。

【讨论】:

  • 谢谢。 zeekay 提到的 getattr 覆盖似乎比你的更容易,但即使这样也很有帮助。这将是我的第二个赌注。谢谢:)
  • 另外,您还需要更多信息。请让我知道您需要关于我的问题的更多信息,我将在这里传达相同的信息。谢谢
  • @PyBegginer:您在问题中描述的内容听起来像 动态继承,这样做覆盖 __getattr__ 看起来像一个 hack。但重点是你是否真的需要这种动态行为?找不到更好的设计吗?你没有展示你的代码,所以我们有点不知所措。
  • 我已经编辑了我的问题并添加了我的代码 sn-p。请看一下
【解决方案3】:

Roman 的回答可能是最明智的方法。但是,嘿,让我们忽略这一点,想想你可以做的一些疯狂的事情!

你可以只使用一个函数,但这太简单了:

def A(type):
    if type == 'B':
        return B()
    elif type == 'C':
        return C

您可以覆盖__getattr__,以便在所选类的实例上查找缺失的属性:

class A(object):
    def __init__(self, type):
        if type == 'B':
            self.type = B()
        if type == 'C':
            self.type = C()

    def __getattr__(self, name):
        if hasattr(self.type, name):
            return getattr(self.type, name)
        return AttributeError

或者你可以覆盖__new__,并返回一个疯狂的新类,或者你感兴趣的类的一个实例:

class A(object):
    bases = {'B': B, 'C': C}

    def __new__(cls, type):
        class Cls(A.bases[type]):
            pass
        return Cls()

可能还有很多其他被误导的事情!

【讨论】:

  • getattr 的想法对我的目的来说已经足够了。谢谢:)
  • 我使用此方法收到以下错误。 'if hasattr(self.grp_mgr,name): 文件 "c:\workspace\project\trial.py",第 27 行,在 getattr if hasattr(self.type,name): RuntimeError: maximum调用 Python 对象时超出递归深度'
  • 我已经编辑了我的问题,添加了我的代码 sn-p。请看一看。
猜你喜欢
  • 2011-02-16
  • 2016-06-15
  • 2017-10-16
  • 2019-01-28
  • 2015-01-20
  • 2023-03-28
  • 1970-01-01
  • 2019-03-22
  • 2023-03-05
相关资源
最近更新 更多