使用__getattr __()按需创建成员方法

时间:2014-06-17 13:34:06

标签: python class oop member getattr

给定一个类MyClass(object),如何使用某个模板和MyClass.__getattr__机制以编程方式定义类成员方法?

我正在考虑的事情
class MyClass(object):
    def __init__(self, defaultmembers, members):
        # defaultmembers is a list
        # members is a dict
        self._defaultmembers = defaultmembers
        self._members = members

    # some magic spell creating a member function factory

    def __getattr__(self):
        # some more magic

def f_MemberB():
    pass

C = MyClass(defaultmembers=["MemberA"], members=dict(MemberB=f_MemberB)
C.MemberA()  # should be a valid statement
C.MemberB()  # should also be a valid statement
C.MemberC()  # should raise an AttributeError

C.MemberA应该是从类中的某个模板机制自动创建的方法,而C.MemberB应该是函数f_MemberB

1 个答案:

答案 0 :(得分:2)

您无需重新定义__getattr__(实际上您通常不应该这样做)。 Python是一种late binding语言。这意味着您可以随时简单地为类中的名称赋值(甚至可以在运行时动态分配),现在它们将存在。

因此,在您的情况下,您可以这样做:

class MyClass(object):
    def __init__(self, defaultmembers, members):
        # defaultmembers is a list
        # members is a dict
        for func in defaultmembers:
            setattr(self, func.__name__, func)
        for name, func in members.items():
            setattr(self, name, func)

请注意,这实际上不会方法绑定到类(它不会将 self 作为其第一个参数)。如果这是你想要的,你需要使用types中的MethodType函数,如下所示:

from types import MethodType

class MyClass(object):
    def __init__(self, defaultmembers, members):
        # defaultmembers is a list
        # members is a dict
        for func in defaultmembers:
            name =  func.__name__
            setattr(self, name , func)
            setattr(self, name , MethodType(getattr(self, name), self))
        for name, func in members.items():
            setattr(self, name, func)
            setattr(self, name , MethodType(getattr(self, name), self))

示例:

def def_member(self):
    return 1

def key_member(self):
    return 2

>>> test = MyClass([def_member], {'named_method':key_member})
>>> test.def_member()
1
>>> test.named_method()
2

使用*args**kwargs也可以使init方法稍微不那么笨拙,因此如果您知道不会有任何其他参数,示例将只是test = MyClass(def_member, named_member = key_member)到这个类的构造函数。

显然我遗漏了defaultmembers的模板创建位,因为我使用了一个函数,而不仅仅是一个名字作为参数。但您应该能够看到如何扩展该示例以满足您的需求,因为模板创建部分有点超出原始问题的范围,即如何将方法动态绑定到类。

重要提示:这只会影响 MyClass 的单个实例。如果您想影响所有实例,请更改问题。虽然我认为在这种情况下使用mixin class会更好。