User: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
函数时可能会产生困惑。此方法用于支持 len(self)
。该方法必须返回对象的长度,并必须以一个非负的 int
类型来表示。如果返回的并非非负整数,则会报错。
特别的,如果一个对象没有定义 __bool__
方法,而其 __len__
方法返回的值为 0
。则它在布尔运算中,被视为 False
。
operator
模块中,operator.length_hint()
函数所调用的方法。
此方法是为了优化性能而设置的,它必须返回对象长度的估计值——这个估计值并不要求正确无误。返回的估计值必须为一个非负整数。
特别的,返回值也可以为 NotImplemented,这会被视作与 __length_hint__ 方法完全不存在时一样处理。
索引
编辑object.__getitem__(self, key)
编辑此方法用于支持 self[key]
的操作。一般用于键的有三种:
- 整数(用于序列)
- slice 对象(用于序列)
- 字符串或其它不可变对象(主要用于字典)。
此方法的返回值,应当为读者希望 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
语句以及比较运算符 in
和 not in
。
object.__reversed__(self)
编辑该方法用于提升 reversed(self)
的效率和 / 或适用范围。
如果定义了该方法,则该方法必须返回一个新的迭代器对象。它应当返回以逆序逐个迭代容器内所有对象的迭代器对象。
如果未定义该方法,则 reversed(self)
会使用 __len__
方法和 __getitem__
方法,按照类似列表的方式生成一个迭代器。
成员检测
编辑object.__contains__(self, item)
编辑此方法用于支持 item in self
和 item not in self
。它返回一个布尔值。
如果未定义 __contains__
方法。上述运算将尝试通过 __iter__
来迭代 self
中的元素来实现。
泛型
编辑对于类型,我们也有类似索引的操作。泛型就是这种操作的结果。
泛型一般用于函数注释中。具体参见 函数注释#泛型 。
classmethod object.__class_getitem__(cls, key)
编辑获取泛型时调用的方法。这个方法会自动被视为是类方法,因此没必要使用装饰符 @classmethod
来装饰。
此方法一般不由读者定义,而是通过继承的方式自动引入的。具体可以参见Python 文档。