Python如何获取实例的基本实例?

11 投票
2 回答
8895 浏览
提问于 2025-04-17 07:26

在C#中,我会这样做:

myObj.base

我有一个日期类,它是从date.datetime这个类继承来的。这个日期类重写了__gt__()__lt__()这两个方法,所以当我使用<>这些符号时,它们会被调用。但是我不想使用这些重写的方法,我想在Date类的实例上使用date.datetime的方法。

2 个回答

4

如果我理解你的问题没错,这在Python中是没有意义的。子类的实例里没有“基础实例”。

在Python中,一个实例就是一个东西,它包含了一些属性(这些属性可能是由它的父类设置或修改的,甚至可能是外部代码设置的)。实际上,你可以在运行时改变一个实例的类,甚至把它移到完全不同的继承结构中(虽然这通常不是个好主意,但这是可以做到的)。无论如何,这个实例始终是一个整体对象,它只知道自己有哪些属性,以及它属于哪个类(实际上这也是一个属性:__class__)。

编辑:如果你想在一个实例上调用被重写的方法,你可以使用super,就像hocl所说的那样。不过从你的评论来看,你似乎并没有完全理解super的作用(这很正常,因为它确实比较复杂)。

super(Date, myObj)并不会返回“底层的datetime.date”实例,因为根本没有这样的东西,只有myObj对象。虽然从你的需求来看,这似乎可以满足你的要求(你可能可以停在这句话)。

它的作用是返回一个神奇的包装器,围绕着myObj,从Date的“后面”开始查找方法;也就是说,它会找到如果Date没有重写的方法会被调用的方法。所以在这种情况下,它会找到所有来自datetime.date的方法,因为你只有单一继承。

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

我还理解到(这有点猜测),因为C#是静态类型的,并且支持从预编译库中定义的类继承,所以当你有类Sub继承自类Base时,在Sub的实例内部,确实存在一个完整的Base实例,你可以访问并调用它的方法。这会影响被遮蔽的字段;我预计(再次强调,我不是C#程序员,只是在猜测)在从Sub实例获取Base实例后,任何直接引用被Sub重写的字段都会访问到Base中的字段,而不是Sub中的字段。

而在Python中,另一方面,没有基础实例,类也不能重写字段。如果Datedatetime.date的构造函数和方法都引用同一个字段,那就是它们共享的同一个字段。因此,使用super不会改变你访问的字段,正如你可能认为的那样,认为它是在获取基础实例。

鉴于你没有使用复杂的多重继承情况,如果你想要简单的语法,你实际上可以直接调用Date.__lt__(myObj, otherObj),虽然这样看起来不太美观,因为你不能使用中缀操作符语法。不过如果考虑普通方法,这样做可能比使用super更简单。

总结一下:我很确定在这种情况下super(Date, myObj)是你想要的。但如果你进入更复杂的情况,你就不应该把super看作是获取“基础实例”的方式,就像在C#中那样。这样的理解会在多重继承时让你困惑(这本来就很复杂),而且在继承层次中使用相同字段时也会出现问题。

10

使用 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)

假设类B是类A的子类,并且类A有一个方法 def f(self):

  • 在Python 2中,你可以通过在类B中使用 super(B, self).f() 来调用类A的方法。
  • 在Python 3中,你可以直接使用 super().f(),不需要写 B, self 这些参数。

撰写回答