简体   繁体   English

使用其他一些类定义,使用不同的默认参数创建一个新的类定义?

[英]Create a new class definition with different default arguments, using some other class definition?

Say I have the following class in Python 2.7: 说我在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

I want to use the class definition to create another class definition with different default arguments, eg something like: 我想使用类定义来创建另一个具有不同默认参数的类定义,例如:

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

or 要么

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

which should be equivalent to: 应该等于:

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

Is it possible to do something like this in Python 2.7 (or 3?)? 是否可以在Python 2.7(或3)中做类似的事情?

(I know you can use the functools.partial to do the equivalent for functions; so I was wondering if there was anything similar for classes) (我知道您可以使用functools.partial对功能进行等效操作;因此,我想知道类是否存在类似的功能)

You can write a function that creates classes for you: 您可以编写一个为您创建类的函数:

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

This can be done, but it's a bit messy. 可以做到,但是有点混乱。

This code: 这段代码:

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

...is equivalent to this code, though I'm not sure this is correct if Foo is a classic class: ...相当于此代码,但是如果Foo是经典类,我不确定这是否正确:

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

So we can create classes on the fly, and attach custom method objects to them. 因此,我们可以即时创建类,并将自定义方法对象附加到它们。

For your specific case, we need to make these calls (assuming you convert X into a new-style class by inheriting from object ). 对于您的特定情况,我们需要进行这些调用(假设您通过从object继承将X转换为新样式的类)。 First, we extract methods from X and apply functools.partial : 首先,我们从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)

The im_func attribute grabs the underlying function out of the unbound method object. im_func属性im_func绑定的方法对象中获取底层函数。 In Python 3, there's no such thing as an unbound method, so we don't need to use this attribute; 在Python 3中,没有诸如未绑定方法之类的东西,因此我们不需要使用此属性。 X.__init__ is just the function itself. X.__init__只是函数本身。

Next, we create the class: 接下来,我们创建类:

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

Unfortunately, we don't have any reasonable way of getting a list of the functions we need to redefine here. 不幸的是,我们没有任何合理的方法来获取我们需要在此处重新定义的功能列表。 If we use dir() we'll get a lot of irrelevant special attributes. 如果使用dir()我们将获得许多不相关的特殊属性。 We could use the class's __dict__ , but that won't include any inherited methods. 我们可以使用该类的__dict__ ,但这将不包括任何继承的方法。 I think we may need to search X.__mro__ for a fully correct listing of methods: 我认为我们可能需要搜索X.__mro__以获取方法的完全正确列表:

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

We also need to figure out which arguments to override in each case; 我们还需要弄清楚每种情况下要覆盖哪些参数。 inspect.getargspec() is a good starting point for this, but it will not help much if any of the methods are variadic (ie if they take *args or **kwargs arguments). inspect.getargspec()是一个很好的起点,但是,如果任何方法都是可变参数的(例如,它们采用*args**kwargs参数),它都无济于事。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM