为什么以下类声明继承自 object
?
class MyClass(object):
...
类声明是否有任何理由从对象继承?
在 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__ (
毫无疑问,在编写课程时,您总是想上新式课程。这样做的好处很多,列出其中一些:
支持描述符。具体来说,使用描述符可以实现以下构造: 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 在幕后为您插入了它。
蟒蛇 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 开发人员的眼泪。
__metaclass__ = type
放在模块的顶部(在 from __future__ import absolute_import, division, print_function
行之后:-));它是 Py2 中的一个兼容性黑客,默认情况下使模块中所有后续定义的类都是新样式的,而在 Py3 中,它被完全忽略(只是一个随机的全局变量),所以它是无害的。
是的,这是一个“新风格”的对象。这是python2.2中引入的一个特性。
新样式对象与经典对象具有不同的对象模型,并且某些内容不适用于旧样式对象,例如 super()
、@property
和描述符。有关什么是新样式类的详细说明,请参阅 this article。
差异描述的 SO 链接:What is the difference between old style and new style classes in Python?
object
继承即可。
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。
是的,它是 historical。没有它,它会创建一个老式的类。
如果您在旧式对象上使用 type()
,您只会得到“实例”。在一个新样式的对象上,你会得到它的类。
type()
,您会得到“classobj”而不是“type”。
类创建语句的语法:
class <ClassName>(superclass):
#code follows
如果没有您特别想要继承的任何其他超类,则 superclass
应始终为 object
,它是 Python 中所有类的根。
object
在技术上是 Python 中“新式”类的根源。但是今天的新式班就像是唯一的班式一样好。
但是,如果您在创建类时没有显式使用 object
一词,那么正如其他人所提到的,Python 3.x 隐式继承自 object
超类。但我猜显式总是比隐式好(地狱)
不定期副业成功案例分享
object
继承。 IIRC 有一个时间点,并非所有内置类型都移植到新式类。object
。我确实有一个 Python 2.2.3,经过快速检查后我找不到违规者,但是,我稍后会改写答案以使其更清楚。如果你能找到一个例子,我会很感兴趣,我的好奇心被激起了。object
。staticmethod
和classmethod
即使在老式类上也能正常工作。property
sorta 适用于旧式类的读取,它只是无法拦截写入(因此,如果您分配给名称,实例将获得一个给定名称的属性,该属性会影响该属性)。另请注意,__slots__
对属性访问速度的改进主要是为了消除新式类属性访问所带来的损失,因此它并不是新式类的真正卖点(虽然节省内存是一个卖点) .