1

我想创建一个类,其 f 方法取决于已创建类对象的“模式”。

下面的代码不起作用,但希望它能让您了解我想要做什么。我的想法是有一个字典,我在其中定义每种模式的设置(在这种情况下是分配给 self.f 的函数或方法,这样我就不必在 init 函数中使用许多 if elif 语句,而是分配正确的值使用字典。

class A(object):
    _methods_dict={
            'a':A.f1,
            'b':A.f2
            }    

    def __init__(self,mode = 'a'):
        self.f = _methods_dict[mode]


    def f1(self,x):
        return x

    def f2(self,x):
        return x**2

我不知道为什么这不起作用,您将如何解决?还有更好的(和更多的pythonic)方法来获得相同的功能吗?

4

3 回答 3

4

存储两个函数的名称,然后用于getattr()检索绑定的方法__init__

class A(object):
    _methods_dict = {
        'a': 'f1',
        'b': 'f2'
    }    

    def __init__(self, mode='a'):
        self.f = getattr(self, self._methods_dict[mode])

    def f1(self, x):
        return x

    def f2(self, x):
        return x ** 2

或者,只需代理该方法:

class A(object):
    _methods_dict = {
        'a': 'f1',
        'b': 'f2'
    }

    def __init__(self,mode = 'a'):
        self._mode = mode

    @property
    def f(self):
        return getattr(self, self._methods_dict[self._mode])

    def f1(self, x):
        return x

    def f2(self, x):
        return x ** 2

f属性只返回当前模式的正确绑定方法。使用属性简化了调用签名处理,并为用户提供了自省的实际方法,如果他们愿意的话。

任何一种方法都有相同的最终结果:

>>> a1 = A()
>>> a2 = A('b')
>>> a1.f(10)
10
>>> a2.f(10)
100

区别在于实例中存储了什么,第一个方法存储绑定的方法:

>>> vars(a1)
{'f': <bound method A.f1 of <__main__.A object at 0x10aa1ec50>>}
>>> vars(a2)
{'f': <bound method A.f2 of <__main__.A object at 0x10aa1ed50>>}

与其他方法相比:

>>> vars(a1)
{'_mode': 'a'}
>>> vars(a2)
{'_mode': 'b'}

这似乎没有太大区别,但后一种方法创建的实例可以毫无问题地进行腌制和深度复制。

于 2013-04-11T08:45:05.567 回答
0

您可以只创建两个单独的类:

class Base(object):
    # place here all attributes shared in common among the Modes
    pass

class ModeA(Base):
    def f(self, x):
        return x

class ModeB(Base):
    def f(self, x):
        return x**2

def make_mode(mode, *args, **kwargs):
    mode_dict = {'a':ModeA, 'b':ModeB}
    return mode_dict[mode](*args, **kwargs)

a = make_mode('a')
print(a.f(10))
# 10

b = make_mode('b')
print(b.f(10))
# 100
于 2013-04-11T09:07:18.450 回答
0

要回答您的第一个问题(“为什么这不起作用”):类对象“A”仅在整个类语句之后创建并绑定到模块名称“A”(是的,“类”是一个可执行语句)块已结束,因此您不能在此块中引用名称或类对象本身。

于 2013-04-11T09:20:19.683 回答