覆盖内置类型的特殊方法

时间:2015-05-11 04:08:59

标签: python

魔术方法可以在课外重写吗? 当我做这样的事情时

def __int__(x):
    return x + 5

a = 5
print(int(a))

它打印'5'而不是'10'。我做错了什么或者魔术方法不能在课外被覆盖吗?

2 个答案:

答案 0 :(得分:2)

简短回答;不是真的。

你不能随意改变int()内置函数(*内部调用__int__())对int(s)等任意内置类型的行为。

可以但是会更改自定义对象的行为,如下所示:

示例:

class Foo(object):

    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        self.value += other

    def __repr__(self):
        return "<Foo(value={0:d})>".format(self.value)

<强>演示:

>>> x = Foo(5)
>>> x + 5
>>> x
<Foo(value=10)>

这会覆盖两件事,并实现两种特殊方法:

    __repr__() 调用的
  • repr()
  • __add__()+运营商调用。

更新:根据上述评论; techincally你可以重新定义内置函数int;例如:

def int(x):
    return x + 5

int(5)  # returns 10

不建议这样做,并且不会更改对象x的整体行为。

更新#2:您无法更改bultin类型行为的原因(未修改基础来源或使用Cuthonctypes )是因为与Homoiconic Languages参见:Homoiconicity )不同,Python中的内置类型不会向用户公开或变更。 - 即便如此,我还不确定你能用Cython / ctypes;但原因问题是&#34;你为什么要这样做?&#34;

更新#3:请参阅Data Model上的Python文档(例如 object.__complex__ )。

答案 1 :(得分:1)

您可以重新定义顶级__int__功能,但没有人会调用它。

正如Data Model文档中所暗示的,当您撰写int(x)时,会调用x.__int__(),而不是__int__(x)

即使这不是真的。首先,__int__是一种特殊方法,这意味着它可以调用type(x).__int__(x)而不是x.__int__(),但这并不重要。其次,除非你给它一些不是__int__的东西(并用单参数形式称它),否则不需要调用int。所以,它可能就像是这样写的:

def int(x, base=None):
    if base is not None:
        return do_basey_stuff(x, base)
    if isinstance(x, int):
        return x
    return type(x).__int__(x)

所以,没有办法改变int(5)将会做什么......当然,只需用同名的不同内置/全局/本地函数来遮蔽内置int函数。< / p>

但是如果你想改变int(5.5)怎么办?这不是int,所以它会调用float.__int__(5.5)。所以,我们所要做的就是monkeypatch,对吧?

嗯,是的,除了Python允许内置类型是不可变的,并且CPython中的大多数内置类型都是。所以,如果你尝试一下:

>>> _real_float_int = float.__int__
>>> def _float_int(self):
...     return _real_float_int(self) + 5
>>> _float_int(5.5)
10
>>> float.__int__ = _float_int
TypeError: can't set attributes of built-in/extension type 'float'

但是,如果您要定义自己的类型,那就是另一个故事:

>>> class MyFloat(float):
...     def __int__(self):
...         return super().__int__() + 5
>>> f = MyFloat(5.5)
>>> int(f)
10