【问题标题】:Python how to get the base instance of an instance?Python如何获取实例的基本实例?
【发布时间】:2011-12-01 02:38:14
【问题描述】:

在 C# 中我会去:

myObj.base

我有一个继承自 date.datetime 的 Date 类。 Date 类会覆盖 __gt__()__lt__(),因此在使用 <> 运算符时会调用它们。我不想使用这些覆盖 - 我想在 Date 的实例上使用 date.datetime 方法。

【问题讨论】:

  • 也许你可以解释一下“基本实例”的真正含义,因为不是每个人都会说 C#。
  • .basemyObj 继承自的类吗?还是myObj的类名?
  • 我想要实例而不是名称

标签: python python-2.6


【解决方案1】:

使用super() 获取超类对象。在 Python 命令提示符中键入 help(super)

来自手册:

class super(object)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super(C, self).meth(arg)

【讨论】:

  • 这看起来像我想要的,但我无法从帮助中看出我要提供什么 - 是“类型”我想要的类型或我给出的类型 - 是“obj”我想要的实例它来自??如何获取基础实例并在其上调用方法?
  • TypeError: super() 参数 1 必须是类型,而不是日期
  • 我通过反复试验发现“类型”是您传递的类型。所以大概 super 会返回直接的父母。例如super(Date, myObj) 返回 datetime.date
  • @Feanor 我在我的答案中添加了更多关于这一点的信息(它不适合这里)。请让我知道它是否有帮助(或没有)。
【解决方案2】:

如果我正确理解您的问题,这在 Python 中没有意义。子类的实例中没有“基础实例”。

一个 Python 实例只是一个东西,它包含一组属性(其中任何一个都可能被它的任何基类设置​​/修改,或者实际上是从它的任何类之外的代码中设置/修改的)。实际上,可以在运行时更改实例的类,甚至可以将其移植到完全不同的继承层次结构中(这通常不是一个好主意,但它是明确定义的)。无论如何,实例仍然是一个单一的单一对象,它只知道它具有哪些属性以及它是哪个类的实例(实际上这只是一个属性:__class__)。

编辑:如果您想要的是能够在实例上调用被覆盖的方法,那么您可以使用super 来实现,正如 hocl 回答的那样。但是,从您的 cmets 看来,您并没有完全理解 super 正在做什么(这是很自然的,因为它非常复杂)。

super(Date, myObj) 不返回“底层datetime.date”实例,因为没有这样的东西,只有myObj 对象。尽管出于您的目的,这听起来会满足您的需求(您可能会停在这句话上)。

它的作用是 return 是一个围绕 myObj 的神奇包装器,它查找从“后面”Date 开始的方法;即,如果Date 没有覆盖它,它会找到将调用的方法。所以在 this 的情况下,它会找到来自 datetime.date 的所有方法,因为你只进行了单一继承。

一个关键的区别是它支持多重继承。如果有人创建了另一个继承自 Date 的类,并且还通过另一条路径从 datetime.date 继承,那么 super(Date, instanceOfThatClass) 可能实际上不会命中 datetime.date 的方法。这取决于该继承层次结构的详细信息。这实际上是super 设计的情况;它使复杂的多重继承层次结构中的类能够协作地调用彼此的实现,确保每个类只被调用一次,并且以合理的顺序调用(尽管每个最终叶类的顺序可能不同,所以中间的类实际上不知道他们调用的是哪个超类实现)。我的理解是这种复杂的情况不会出现在 C# 中,因此它可以提供一个简单的.base 语法。

我的理解也是(这有点猜测),因为 C# 是静态类型的并且支持从预编译库中定义的类继承,所以当你有类 Sub 继承自类 Base ,在Sub 的一个实例中,确实有一个完整的Base 实例,您可以获取它然后调用方法。这将影响阴影场;我希望(再次,作为一个非 C# 程序员猜测一下)从 Sub 实例获取 Base 实例后,任何直接引用被 Sub 覆盖的 field 都会来自Base 的领域,而不是来自Sub 的领域。

在 Python OTOH 中,没有基实例,并且类不能覆盖字段。如果Datedatetime.date 的构造函数和方法都引用同一个字段,那么这只是它们共享的实例中的一个字段。因此,使用 super 不会改变您将访问的字段,如果您将其视为获取基本实例,您可能会期望它。

鉴于您没有使用复杂的多重继承情况,如果您想要一个简单的语法,您实际上可以直接调用Date.__lt__(myObj, otherObj),尽管它看起来很丑,因为您在这样做时不会使用中缀运算符语法就这样。如果您正在考虑普通方法,那就没那么可怕了;在这种情况下,它可能比使用super 更简单。

带回家的信息:我很确定super(Date, myObj) 是您在这种情况下想要的。但是,如果您遇到更复杂的情况,您不想像在 C# 中那样将super 视为获取“基本实例”的方式。这种理解会让你在多重继承中感到困惑(无论如何这可能会让你感到困惑),而且当你在继承层次结构中有多个层使用相同的字段时也是如此。

【讨论】:

  • 所以如果基类方法被派生方法覆盖,就没有办法调用它了?
  • 明白了,感谢您的澄清! super() 现在就足够了,因为我只需要调用基类上的方法
  • 非常有趣的答案,但我期待一些 cmets 在 mro 上了解它与所有这些的关系
  • @artu-hnrq 我相信我决定不故意谈论 MRO(10 年前!)。 MRO 的全部细节是我谈到的属性的实现策略(例如“复杂的多重继承层次结构中的类[可以] 协作调用彼此的实现,确保每个只调用一次,并以合理的顺序”)。您不需要知道有任何诸如 MRO 之类的东西可以理解和使用super。当然,您也可以更深入地了解实现,但我并没有在这个特定的答案中去那里。
  • 感谢您的回复,本!我完全同意范围判断。但对于那些到这里的人,我将引用一个complementary answer,它也会在 mro 中查看
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-08
  • 2013-01-13
  • 2010-10-12
  • 2019-07-08
  • 2021-03-28
  • 1970-01-01
相关资源
最近更新 更多