跳转到内容

用户:Xyy23330121/Python/类的方法与Python的计算

来自维基学院


学习了“类”之后,我们可以进一步了解 Python 的数据模型:Python 中一切内容、包括计算在内,都是由类和类的实例完成的。

以简单的 len(s) 为例,我们查阅文档,可以发现它实际上是调用了 s 的方法 s.__len__(self),并返回该方法的结果[1]

甚至,连加减法在内,几乎所有的 Python 运算都可以用类的方法来定义、修改。为篇幅起见,本页面的内容被分为多个页面。读者可以在右侧目录中找到对应页面。

可调用类型[编辑 | 编辑源代码]

object.__call__(self[, ...])[编辑 | 编辑源代码]

此方法用于支持把对象当函数使用时的结果。我们看以下示例:

class prt:
    def __call__(self, *arg):
        print(*arg)

a = prt()
a(11,45,14)  #输出:11 45 14

它除了第一个参数会自动传入自身以外,与平常定义的函数基本没有区别。

容器类型[编辑 | 编辑源代码]

长度[编辑 | 编辑源代码]

备注
读者想要让它不返回对象的长度,而是返回其他内容也是可以的,只是这样的话,在使用 len 函数时可能会产生困惑。

object.__len__(self)[1][编辑 | 编辑源代码]

此方法用于支持 len(self)。该方法必须返回对象的长度,并必须以一个非负的 int 类型来表示。如果返回的并非非负整数,则会报错。

特别的,如果一个对象没有定义 __bool__方法,而其 __len__ 方法返回的值为 0。则它在布尔运算中,被视为 False

object.__length_hint__(self)[2][编辑 | 编辑源代码]

operator 模块中,operator.length_hint()函数所调用的方法。

此方法是为了优化性能而设置的,它必须返回对象长度的估计值——这个估计值并不要求正确无误。返回的估计值必须为一个非负整数。

特别的,返回值也可以为 NotImplemented,这会被视作与 __length_hint__ 方法完全不存在时一样处理。

索引[编辑 | 编辑源代码]

object.__getitem__(self, key)[编辑 | 编辑源代码]

此方法用于支持 self[key] 的操作。一般用于键的有三种:

  1. 整数(用于序列)
  2. slice 对象(用于序列)
  3. 字符串或其它不可变对象(主要用于字典)。

此方法的返回值,应当为读者希望 self[key] 所返回的数值。和其它强制进行类型检查的方法不同,此方法实际上可以返回任何值。

object.__setitem__(self, key, value)[编辑 | 编辑源代码]

此方法用于支持 self[key] = value 的操作。在调用此方法时,应直接对 self 进行修改。

object.__delitem__(self, key)[编辑 | 编辑源代码]

此方法用于支持 del self[key] 的操作。

slice 对象[编辑 | 编辑源代码]

在字符串章节,提到过 slice 索引。slice 对象就是用该种索引方式时,向 key 参数传入的对象。

索引与错误处理[编辑 | 编辑源代码]

如果 key 的类型不正确,则应当引发 TypeError。 如果 key 为序列索引集合范围以外的值(在进行任何负数索引的特殊解读之后),则应当引发 IndexError。 对于 mapping 类型,如果 key 找不到(不在容器中),则应当引发 KeyError。

解决 str.format 的问题[编辑 | 编辑源代码]

于是,解决 str.format 中,不支持负数索引和 slice 索引的方式是简单的。使用:

class fixGetitem:
    def __init__(self, obj):
        self.obj = obj
    def __getitem__(self, key):
        if isinstance(key, str):
            if ':' in key:
                key_list = [(int(arg) if arg != "" else None) for arg in key.split(':')]
                if len(key_list) == 2:
                    return self.obj[key_list[0]: key_list[1]]
                return self.obj[key_list[0]: key_list[1]: key_list[2]]
            return self.obj[int(key)]
        return self.obj[key]

在传入 str.format 的参数 s 时,如果有负数索引或 slice 索引的需要(且没有字符串索引的需要时),直接改为传入 fixGetitem(s) 就能解决该问题。读者可以自行拓展此方法。

object.__missing__(self, key)[编辑 | 编辑源代码]

对于 dict 的子类,如果定义了该方法。则在 __getitem__(key) 找不到键 key 时,会尝试调用 __missing__(key) 并返回 __missing__(key) 的值。

迭代[编辑 | 编辑源代码]

object.__iter__(self)[编辑 | 编辑源代码]

该方法应该且必须返回一个新的迭代器对象。如果不返回迭代器,则会报错。

此方法可用于支持 iter 函数、for ... in 语句以及比较运算符 innot in

object.__reversed__(self)[编辑 | 编辑源代码]

该方法用于提升 reversed(self) 的效率和 / 或适用范围。

如果定义了该方法,则该方法必须返回一个新的迭代器对象。它应当返回以逆序逐个迭代容器内所有对象的迭代器对象。

如果未定义该方法,则 reversed(self) 会使用 __len__ 方法和 __getitem__ 方法,按照类似列表的方式生成一个迭代器。

成员检测[编辑 | 编辑源代码]

object.__contains__(self, item)[编辑 | 编辑源代码]

此方法用于支持 item in selfitem not in self。它返回一个布尔值。

如果未定义 __contains__ 方法。上述运算将尝试通过 __iter__ 来迭代 self 中的元素来实现。

泛型[编辑 | 编辑源代码]

对于类型,我们也有类似索引的操作。泛型就是这种操作的结果。

泛型一般用于函数注释中。具体参见 函数注释#泛型

classmethod object.__class_getitem__(cls, key)[编辑 | 编辑源代码]

获取泛型时调用的方法。这个方法会自动被视为是类方法,因此没必要使用装饰符 @classmethod 来装饰。

此方法一般不由读者定义,而是通过继承的方式自动引入的。具体可以参见Python 文档

参考文献[编辑 | 编辑源代码]