使用其他类定义创建具有不同默认参数的新类定义?

时间:2015-07-09 14:31:30

标签: python class

假设我在Python 2.7中有以下类:

class X():
    def __init__(self, alpha=1):
        self.alpha = alpha
        print self.alpha

    def beta(self, gamma=1):
        self.gamma = gamma
        self.omega = self.alpha + self.gamma
        print self.omega

我想使用类定义来创建具有不同默认参数的另一个类定义,例如类似的东西:

Y = f(X, alpha=2, gamma=2)

Y = f(X, __init__.alpha=2, beta.gamma=2)

应该相当于:

class Y():
    def __init__(self, alpha=2):
        self.alpha = alpha
        print self.alpha

    def beta(self, gamma=2):
        self.gamma = gamma
        self.omega = self.alpha + self.gamma
        print self.omega

是否可以在Python 2.7(或3?)中执行类似的操作?

(我知道你可以使用functools.partial来完成函数的等价物;所以我想知道类中是否有类似的东西)

2 个答案:

答案 0 :(得分:2)

您可以编写一个为您创建类的函数:

def makeclass(alpha, gamma):
    class C():
        def __init__(self, alpha=alpha):
            self.alpha = alpha
            print self.alpha

        def beta(self, gamma=gamma):
            self.gamma = gamma
            self.omega = self.alpha + self.gamma
            print self.omega

    return C
>>> X = makeclass(1, 1)
>>> Y = makeclass(2, 2)
>>> x = X() # X is the class, x is an instance
1
>>> x.beta()
2
>>> y = Y()
2
>>> y.beta()
4

答案 1 :(得分:0)

这个可以完成,但它有点乱。

此代码:

class Foo(base1, base2, ...):
    bar = something
    baz = something_else
    def qux(self):
        ...

...等同于此代码,但如果Foo是经典类,我不确定这是否正确:

Foo = type('Foo', (base1, base2, ...), {'bar': something, 'baz': something_else,
                                        'qux': lambda self: ...})

因此我们可以动态创建类,并将自定义方法对象附加到它们。

对于您的具体情况,我们需要进行这些调用(假设您通过继承object将X转换为新式类)。首先,我们从X中提取方法并应用functools.partial

new_init = functools.partial(X.__init__.im_func, # Just X.__init__ in 3.x
                             alpha=2)
new_beta = functools.partial(X.beta.im_func, # Just X.beta in 3.x
                             gamma=2)

im_func属性从未绑定的方法对象中获取基础函数。在Python 3中,没有非绑定方法,所以我们不需要使用这个属性; X.__init__只是函数本身。

接下来,我们创建类:

Y = type('Y', (object,), {'__init__': new_init, 'beta': new_beta})

不幸的是,我们没有任何合理的方法来获取我们需要重新定义的函数列表。如果我们使用dir(),我们将获得许多不相关的特殊属性。我们可以使用类的__dict__,但不包括任何继承的方法。我想我们可能需要在X.__mro__中搜索完整正确的方法列表:

result = {}
for class_ in X.__mro__:
    for name, value in class_.__dict__.items():
        if name not in result:
            result[name] = value

我们还需要确定在每种情况下要覆盖哪些参数; inspect.getargspec()是一个很好的起点,但是如果任何方法都是可变参数(例如,如果它们采用*args**kwargs参数),它将无济于事。