【问题标题】:Idiomatic way of processing instances of derived classes?处理派生类实例的惯用方式?
【发布时间】:2017-09-23 02:10:15
【问题描述】:

尽管我有多年的 Python 编程经验,但每次遇到此类问题时,我都会使用内置的 isinstance 函数。但是,我不确定这是否是在 python 中做这些事情的理想方式。

所以,我有一个基类,我的大多数实例都是。

class Base():
  def a(self):
    return 1

我还有一个稍微不同的类,看起来像这样:

class Extended(Base):
  def b(self):
    return 2

现在,第三个类可能具有附加功能,具体取决于接收到的参数,该参数将是先前类之一的实例。

class User():
  def __init__(self, arg):
    ... # do some common work
    if isinstance(arg, Extended):
      ...
      # define more functionality which will call method 'b'
      # at some point during runtime (as event handler or smth)

在这个简单的例子中,这真的是使用 Python 的方式吗,或者我应该考虑将 Base 的接口更改为:

class Base2():
  supports_more_func = False

  def a(self):
    return 1

  def b(self):
    pass

class Extended2(Base2):
  supports_more_func = True

  def b(self):
    return 2

class User():
  def __init__(self, arg):
    ... # do some common work
    if arg.supports_more_func:
      ...
      # define more functionality which will call method 'b'
      # at some point during runtime (as event handler or smth)

您认为哪种方法更好,为什么?

【问题讨论】:

    标签: python inheritance interface


    【解决方案1】:

    一般来说,在进行面向对象编程时,很少使用isinstance,尤其是当您负责设计所使用的类时,因为这会破坏S.O.L.I.D. principles

    相反,您应该简单地将您的类设计为具有通用且定义良好的接口并直接使用它。所以测试类型或成员很少是要走的路。

    我会走的路是:

    class Base2():
      def a(self):
        return 1
    
      def b(self):
        pass
    
    class Extended2(Base2):
      def b(self):
        # all that extra functionality that was in User.__init__()
        return 2
    
    class User():
      def __init__(self, arg):
        ... # do some common work
        arg.b()
    

    现在我猜那部分有:

      # define more functionality which will call method 'b'
      # at some point during runtime (as event handler or smth)
    

    有一些数据和处理与User 紧密耦合,而不是Extended2,但我很确定有一种优雅的方法可以将这些数据作为参数提供给arg.b()

    基本上,当您需要使用isinstance() 来做某事时,我会说 99% 的时间,这意味着您遇到了设计问题,并且有更好的方法来做同样的事情。

    以下是有关该主题的一些网络文学:

    【讨论】:

    • 感谢您的回复!问题是我有一个 UI 应用程序。在用户类中,如果“arg”是扩展的,屏幕上应该会显示一些额外的小部件。然后,如果用户单击该附加小部件,用户会将呼叫转移到扩展。问题是如果'arg'是Base,就不应该显示任何额外的小部件,所以我真的需要一种方法来确定我正在使用哪种类型......有趣的事情是知道一个人如何在 Java 或 C++ 中工作会这样做吗?
    猜你喜欢
    • 1970-01-01
    • 2016-07-06
    • 1970-01-01
    • 2019-07-25
    • 2013-06-15
    • 2018-11-03
    • 2013-02-12
    • 2016-11-14
    • 1970-01-01
    相关资源
    最近更新 更多