【问题标题】:Variable function calling in PythonPython中的变量函数调用
【发布时间】:2015-11-16 13:44:58
【问题描述】:

Instrument 是一个具有三个函数piano(self)guitar(self)trumpet(self) 的类。该类还有一个play(self) 函数,它将根据类中表示的工具调用正确的方法。

有没有一种方法,只有一个类Instrument(即没有其他抽象类)来定义调用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,然后是三个PianoGuitarTrumpet 继承自Instrument 的类。但是对于我的需要,这不会太复杂。

编辑

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

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

但后来我注意到,为了在我的代码的其他部分轻松使用这个类,我更愿意使用my_computer.compute()。因此,我认为在调用compute(self) 时使用实际计算方法构造实例会很方便。我不想写其他五个类,因为它们实际上不会代表五个不同的对象,而是五种做同样事情的方式。我无法将函数 a,...,f 作为构造函数的输入传递,因为它需要 self
换句话说,与Instrument 的示例相同,但“现实世界继承”较少。

【问题讨论】:

  • 这就是任何面向对象语言中的多态性。您应该为从基类 Instrument 继承的 Piano/Guitar 创建单独的类
  • 您可以查看single dispatch,但我不能 100% 确定它适用于方法,我相信这比仅仅玩继承更麻烦。
  • @lejlot 是的,我知道我可以按照您在回答中提出的建议(请参阅我的最后一段)。购买 我想也许可以有一种更简单的方法,就像我提出的那种丑陋但简单且有效的方法。在仪器示例中,通过继承实现了更多逻辑,但在我的实际问题中,它看起来很重,也更复杂。
  • 那么你应该描述你的实际问题,否则我们无法给你任何合理的答案。
  • 这实际上仍然是继承的“路要走”,因为它们是不同类型的计算。在 python 中,具有多重继承和“mixins”,只有一个方法的子类是可以的

标签: python call


【解决方案1】:

这就是多态性的意义

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()

【讨论】:

  • 请考虑编辑您的帖子,以添加更多关于您的代码的作用以及它为何能解决问题的说明。大部分只包含代码的答案(即使它正在工作)通常不会帮助 OP 理解他们的问题。
  • 还有Instrument.play应该raise NotImplementedError
【解决方案2】:

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

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

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

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

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

my_violin = Instrument(violin)
my_violin.play()

但上面显示的整个方法在 python 世界中确实没有什么用处。

【讨论】:

    【解决方案3】:

    如果您真的不想创建类层次结构,您可以在enum 类中定义所有可能的类型,然后选择正确的方法。为了避免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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-06
      • 1970-01-01
      • 2015-09-04
      • 1970-01-01
      • 2021-09-26
      • 1970-01-01
      • 2013-07-16
      • 2019-10-05
      相关资源
      最近更新 更多