ChatGPT解决这个技术问题 Extra ChatGPT

为什么 Python 类会继承对象?

为什么以下类声明继承自 object

class MyClass(object):
    ...
这将创建一个 new-style class
这个问题的答案(虽然很简单)很难找到。谷歌搜索“python 对象基类”或类似的东西会出现一页又一页的面向对象编程的教程。赞成,因为这是第一个让我找到搜索词“旧式与新式 python 对象”的链接
对于“如何搜索这个问题”部分,SymbolHound 是一个选项。

W
Werner Faruk

类声明是否有任何理由从对象继承?

在 Python 3 中,除了 Python 2 和 3 之间的兼容性之外,没有任何原因。在 Python 2 中,有很多原因。

Python 2.x 故事:

在 Python 2.x(从 2.2 开始)中,有两种样式的类取决于是否存在 object 作为基类:

“经典”样式类:它们没有对象作为基类:>>> 类 ClassicSpam:# 没有基类 ...通过 >>> ClassicSpam.__bases__ () “新”样式类:它们直接或间接(例如从内置类型继承),对象作为基类: >>> class NewSpam(object): # 直接从对象继承 ... pass >>> NewSpam.__bases__ (, ) >>> class IntSpam(int): # 间接继承自对象... ... pass >>> IntSpam.__bases__ (,) >>> IntSpam.__bases__[0].__bases__ # . .. 因为 int 继承自 object (,)

毫无疑问,在编写课程时,您总是想上新式课程。这样做的好处很多,列出其中一些:

支持描述符。具体来说,使用描述符可以实现以下构造: classmethod:接收类作为隐式参数而不是实例的方法。 staticmethod:不接收隐式参数 self 作为第一个参数的方法。带有属性的属性:创建用于管理属性的获取、设置和删除的函数。 __slots__:节省类的内存消耗,也可以更快地访问属性。当然,它确实施加了限制。

classmethod:接收类作为隐式参数而不是实例的方法。

staticmethod:不接收隐式参数 self 作为第一个参数的方法。

带有属性的属性:创建用于管理属性的获取、设置和删除的函数。

__slots__:节省类的内存消耗,也可以更快地访问属性。当然,它确实施加了限制。

__new__ 静态方法:允许您自定义创建新类实例的方式。

方法解析顺序 (MRO):在尝试解析要调用的方法时,将按照什么顺序搜索类的基类。

与MRO、super call相关。另请参阅, super() 被认为是超级的。

如果您不从 object 继承,请忘记这些。可以在 here 中找到对前面的要点以及“新”样式类的其他好处的更详尽的描述。

新型类的缺点之一是类本身对内存的要求更高。但是,除非您要创建许多类对象,否则我怀疑这将是一个问题,并且它是在积极海洋中的消极沉没。

Python 3.x 故事:

在 Python 3 中,事情被简化了。只存在新样式的类(简单地称为类),因此添加 object 的唯一区别是要求您再输入 8 个字符。这个:

class ClassicSpam:
    pass

与此完全等效(除了他们的名字:-):

class NewSpam(object):
     pass

对此:

class Spam():
    pass

所有的 __bases__ 中都有 object

>>> [object in cls.__bases__ for cls in {Spam, NewSpam, ClassicSpam}]
[True, True, True]

那你该怎么办?

在 Python 2 中: 总是从 object 显式继承。获得福利。

在 Python 3 中:如果您编写的代码尝试与 Python 无关,即它需要在 Python 2 和 Python 3 中工作,则从 object 继承。否则,不要这样做真的没有什么区别,因为 Python 在幕后为您插入了它。


“取决于是否存在作为基类的内置类型”=>实际上,这与“作为基类的内置类型是否存在或不存在”无关,而是该类是否直接或间接object 继承。 IIRC 有一个时间点,并非所有内置类型都移植到新式类。
@brunodesthuilliers 我的印象是所有内置类型都继承自 object。我确实有一个 Python 2.2.3,经过快速检查后我找不到违规者,但是,我稍后会改写答案以使其更清楚。如果你能找到一个例子,我会很感兴趣,我的好奇心被激起了。
老实说(参见我之前评论中的“IIRC”)我不是 101% 确定这一点(当引入新式类时,所有内置类型是否已经转换为新式类) - 我可能只是简单错了,或者这可能只涉及一些标准库的(但不是内置的)类型。但是,我认为最好澄清一下构成新型类的原因是其基础中有 object
staticmethodclassmethod 即使在老式类上也能正常工作。 property sorta 适用于旧式类的读取,它只是无法拦截写入(因此,如果您分配给名称,实例将获得一个给定名称的属性,该属性会影响该属性)。另请注意,__slots__ 对属性访问速度的改进主要是为了消除新式类属性访问所带来的损失,因此它并不是新式类的真正卖点(虽然节省内存是一个卖点) .
A
Arsen Khachaturyan

蟒蛇 3

class MyClass(object): = 新式类

class MyClass: = 新式类(隐式继承自对象)

蟒蛇2

class MyClass(object): = 新式类

类 MyClass: = OLD-STYLE CLASS

解释:

在 Python 3.x 中定义基类时,您可以从定义中删除 object。但是,这可能会为严重难以跟踪的问题打开大门……

Python 在 Python 2.2 中引入了新样式的类,而现在旧样式的类已经很老了。旧式类的讨论是 buried in the 2.x docs,并且在 3.x 文档中不存在。

问题是,Python 2.x 中旧式类的语法与 Python 3.x 中新式类的替代语法相同。 Python 2.x 仍然被广泛使用(例如 GAE、Web2Py),任何不经意间将 3.x 风格的类定义引入 2.x 代码的代码(或编码器)最终都会导致一些严重过时的基础对象。而且由于旧式课程不在任何人的视线范围内,他们可能不知道是什么击中了他们。

所以只要把它拼出来,就可以省去一些 2.x 开发人员的眼泪。


“在 Python 3.x 中定义基类时,您可以从定义中删除对象。但是,这可能会为严重难以跟踪的问题打开大门……”您指的是什么问题?
@Aidis:我认为他们的意思是,在 Py2 和 Py3 上运行的代码在 Py3 上都可以,但如果 Py2 依赖于新型类特性,则在 Py2 上会被破坏。就个人而言,如果我正在编写这样的代码,我会省略显式继承,而只是将 __metaclass__ = type 放在模块的顶部(在 from __future__ import absolute_import, division, print_function 行之后:-));它是 Py2 中的一个兼容性黑客,默认情况下使模块中所有后续定义的类都是新样式的,而在 Py3 中,它被完全忽略(只是一个随机的全局变量),所以它是无害的。
既然 Python 2 已经过时了,那么将它们从轨道上击落?
D
Dimitris Fasarakis Hilliard

是的,这是一个“新风格”的对象。这是python2.2中引入的一个特性。

新样式对象与经典对象具有不同的对象模型,并且某些内容不适用于旧样式对象,例如 super()@property 和描述符。有关什么是新样式类的详细说明,请参阅 this article

差异描述的 SO 链接:What is the difference between old style and new style classes in Python?


+1 这个。请注意,旧式类在 Python 3 中已不存在,因此您只需要从 Python 2 中的 object 继承即可。
这不是一个真正的答案。我只是参考其他文章。我认为 Yarin 的回答应该被接受为这个问题的答案。
@alwbtc:这个答案也有一些新的东西。例如,提到“super()”让我想到了另一个重要的 [here](stackoverflow.com/questions/576169/…)。
D
Dimitris Fasarakis Hilliard

Learn Python the Hard Way 的历史记录:

Python 对一个类的原始演绎在许多方面都被严重破坏了。等到发现这个故障已经太晚了,他们不得不支持它。为了解决这个问题,他们需要一些“新类”样式,以便“旧类”可以继续工作,但您可以使用新的更正确的版本。他们决定将使用小写的“对象”一词作为您继承的“类”来创建一个类。这很令人困惑,但是一个类从名为“object”的类继承来创建一个类,但它不是一个对象,它实际上是一个类,但不要忘记从对象继承。

也只是为了让您知道新式类和旧式类之间的区别是,新式类总是继承自 object 类或继承自 object 的另一个类:

class NewStyle(object):
    pass

另一个例子是:

class AnotherExampleOfNewStyle(NewStyle):
    pass

虽然旧式基类看起来像这样:

class OldStyle():
    pass

一个老式的子类看起来像这样:

class OldStyleSubclass(OldStyle):
    pass

您可以看到 Old Style 基类不会从任何其他类继承,但是,Old Style 类当然可以相互继承。从对象继承保证了某些功能在每个 Python 类中都可用。 Python 2.2 中引入了新的样式类


调用根类 object 并没有那么令人困惑,事实上它是相当标准的。 Smalltalk 有一个名为 Object 的根类和一个名为 Class 的根元类。为什么?因为,正如 Dog 是狗的类,Object 是对象的类,Class 是类的类。 Java、C#、ObjC、Ruby 以及人们今天使用的大多数其他具有根类的基于类的 OO 语言都使用 Object 的一些变体作为名称,而不仅仅是 Python。
D
Dimitris Fasarakis Hilliard

是的,它是 historical。没有它,它会创建一个老式的类。

如果您在旧式对象上使用 type(),您只会得到“实例”。在一个新样式的对象上,你会得到它的类。


此外,如果您在旧式类上使用 type(),您会得到“classobj”而不是“type”。
k
kmario23

类创建语句的语法:

class <ClassName>(superclass):
    #code follows

如果没有您特别想要继承的任何其他超类,则 superclass 应始终为 object,它是 Python 中所有类的根。

object 在技术上是 Python 中“新式”类的根源。但是今天的新式班就像是唯一的班式一样好。

但是,如果您在创建类时没有显式使用 object 一词,那么正如其他人所提到的,Python 3.x 隐式继承自 object 超类。但我猜显式总是比隐式好(地狱)

Reference