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()
正确的做法是先有一个Instrument
class,然后是三个Piano
、Guitar
和Trumpet
classes 继承自 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层次结构,您可以在enum
class中定义所有可能的类型,然后选择正确的方法。为了避免 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
设 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()
正确的做法是先有一个Instrument
class,然后是三个Piano
、Guitar
和Trumpet
classes 继承自 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层次结构,您可以在enum
class中定义所有可能的类型,然后选择正确的方法。为了避免 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