子类化内置类型

Python 2.2之后内置类型开始可以子类化了

但是,CPython中的内置类型不会调用用户重写的类的特殊方法。

PyPy的文档中描述了这个问题。subclasses-of-built-in-types

正式情况下,CPython 并没有官方规定内置类型的子类中重写的方法是否会被隐式调用。

基本上,这些用户重写的方法不会被同一对象的其他内置方法调用。

例如,在dict的子类中重写的 `__getitem__()` 方法不会被内置的 `get()` 方法调用。

以上情况在CPython和PyPy中都是一致的。

在内置函数或方法是否会调用另一个对象的重写方法而不是self上,两者会出现差异。

PyPy经常会在Cpython不调用的情况下调用。

两个例子:

ex1:

class D(dict):
    def __getitem__(self, key):
        return "%r from D" % (key,)

class A(object):
    pass

a = A()
a.__dict__ = D()
a.foo = "a's own foo"
print a.foo
# CPython => a's own foo
# PyPy => 'foo' from D

ex2:

glob = D(foo="base item")
loc = {}
exec "print foo" in glob, loc
# CPython => base item
# PyPy => 'foo' from D

原生类型的这种行为违背了面向对象编程的一个基本原则:始终应该从实例(self)所属的类开始搜索方法,即使在超类实现的类中调用也是如此。(不过 __missing__ 方法是个特例。)

在CPython的实现结构中,内建方法大部分会忽略用户重写的特殊方法,所以产生了UserDict,UserString,UserList来解决这个问题。

In : class NewDict(dict):
...:     def __getitem__(self, key):
...:         return 42
...:     
In : d = NewDict(a=1)
In : d
Out: {'a': 42}
In : d2 = {}
In : d2.update(d)       #CPython中的update会忽略NewDict中的__getitem__方法
In : d2
Out: {'a': 1}

因此用户如果自己定义的类应该继承collections模块中的类。而不是子类化内置类。

*《流畅的Python》 12.1

原文地址:https://www.cnblogs.com/leisurelylicht/p/zi-lei-hua-nei-zhi-lei-xing-subclassesofbuiltintyp.html