Python 中的可变函数调用

Variable function calling in Python

Instrument 为具有三个函数 piano(self)guitar(self)trumpet(self) 的 class。 class 还有一个 play(self) 函数,它将根据 class.

中表示的仪器调用适当的方法

有没有办法,只用一个classInstrument(即没有其他抽象class),定义什么时候应该调用的方法调用 play 方法?

换句话说,有没有办法做到以下几点:

my_piano = Instrument(piano)
my_piano.play() # calls piano(self) method

my_guitar = Instrument(guitar)
my_guitar.play() # calls guitar(self) method

my_trumpet = Instrument(trumpet)
my_trumpet.play() # calls trumpet(self) method

一种相当简单但代码不太干净的方法是在构造函数中放置一个变量,然后在 play 方法中放置很多条件,如下所示:

def Instrument(object):
    def __init__(self, instrument_type):
        self.instrument_type = instrument_type

    def play(self):
        if instrument_type == 0:
            self.piano()
        elif instrument_type == 1:
            self.guitar()
        elif instrument_type == 2:
            self.trumpet()

正确的做法是先有一个Instrumentclass,然后是三个PianoGuitarTrumpetclasses 继承自 Instrument。但是对于我的需要,这不会使事情复杂化。

编辑

根据要求,我解释了我的实际问题,这几乎是相同的。 我有一个 class ComputeSth 可以使用五种不同的方法来计算那个东西。它可以用 a(self)b(self)、...、f(self) 的方式计算它。 例如,有时我想根据 a 计算,有时我想根据 c 计算。如果我这样做就很容易:

my_computer = ComputeSth()
my_computer.a()
my_computer.c()

但后来我注意到,为了在代码的其他部分轻松使用此 class,我更愿意使用 my_computer.compute()。所以,我认为在调用compute(self)时用实际方法构造实例会很方便。我不想写其他五个 classes,因为它们实际上不会代表五个不同的对象,而是代表相同的五种方式。我无法将函数 a,...,f 作为构造函数的输入传递,因为需要 self.
换句话说,与 Instrument 的示例相同,但少了 "real world inheritance".

这就是多态性的作用

class Instrument:

  def play(self):
    pass

class Guitar(Instrument):

  def play(self):
    print 'brau dau'

class Drum(Instrument):

  def play(self):
    print 'dum dum'


guitar = Guitar()
guitar.play()

drum = Drum()
drum.play()

这肯定是错误的设计,但绝对可行:

class Instrument:
    def __init__(self, method):
        self.method = method

    def play(self):
        self.method(self)

    def piano(self):
        print("I am a piano")

    def trumpet(self):
        print("I am a trumpet")

    def guitar(self):
        print("I am a guitar")

piano = Instrument.piano
trumpet = Instrument.trumpet
guitar = Instrument.guitar

my_piano = Instrument(piano)
my_piano.play()
#... and others

您将未绑定的 class 方法传递给 instrument 的 __init__,然后在 play 中在 self 上调用该方法。

您甚至可以通过创建独立函数来扩展可用工具

def violin(self):
    print("I am playing a violin")

my_violin = Instrument(violin)
my_violin.play()

但是上面显示的整个方法在 python 世界中确实用处很小。

如果您真的不想创建class层次结构,您可以在enumclass中定义所有可能的类型,然后选择正确的方法。为了避免 if 语句,您可以使用字典:

In [1]: import enum

In [2]: class InstrumentType(enum.Enum):
   ...:     PIANO = 0
   ...:     GUITAR = 1
   ...:     TRUMPET = 2
   ...:     

In [3]: class Instrument:
   ...:     def __init__(self, type):
   ...:         self.type = type
   ...:     def piano(self):
   ...:         print('Piano')
   ...:     def guitar(self):
   ...:         print('Guitar')
   ...:     def trumpet(self):
   ...:         print('Trumpet')
   ...:     def play(self):
   ...:         return {
   ...:             InstrumentType.PIANO: self.piano,
   ...:             InstrumentType.GUITAR: self.guitar,
   ...:             InstrumentType.TRUMPET: self.trumpet
   ...:         }.get(self.type, lambda: print('Not an instrument'))()
   ...:     

In [4]: guitar = Instrument(InstrumentType.GUITAR)

In [5]: guitar.play()
Guitar

In [6]: unknown = Instrument('UNKNOWN')

In [7]: unknown.play()
Not an instrument