一、什么是特殊方法
Python的官方手册描述
一个类可以通过定义具有特殊名称的方法来实现由特殊语法来发起调用的特定操作(例如算术运算或抽取与切片)。这是 Python 实现 运算符重载 的方式,允许每个类自行定义基于该语言运算符的特定行为。举例来说,如果一个类定义了名为 getitem() 的方法,并且 x 是该类的一个实例,则 x[i] 基本就等价于 type(x).getitem(x, i)。除非有说明例外情况,在没有定义适当方法的时候尝试执行某种操作将引发一个异常 (通常为 AttributeError 或 TypeError)。
二、特殊方法如何使用
特殊方法供 Python 解释器调用,而不是你自己。也就是说,没有my_object.__len__()
这种写法,正确的写法是len(my_object)
。如果 my_object
是用户定义的
类的实例,Python 将调用你实现的 __len__
方法。
特殊方法,在Python中也叫做魔方方法。
很多时候,特殊方法是隐式调用的。例如,for i in x:
语句其实在背后调用 iter(x)
,接着又调用x.__iter__()
(前提是有该方法)或 x.__getitem__()
。
三、都有哪些特殊方法
常用类型如下;但是 最好的解说还是Python的reference手册,官网说明简单明了。
分类 | 方法名称 |
---|---|
字符串(字节)表示形式 | repr__ _str_ _format_ _bytes_ __fspath |
转换为数值 | bool__ _complex_ _int_ _float_ _hash_ __index |
模拟容器 | len__ _getitem_ _setitem_ _delitem_ __contains |
迭代 | iter__ _aiter_ _next_ _anext_ __reversed |
可调用对象或执行协程 | call__ __await |
上下文管理 | enter__ _exit_ _aexit_ __aenter |
构造和析构实例 | new__ _init_ __del |
属性管理 | getattr__ _getattribute_ _setattr_ _delattr_ __dir |
属性描述符 | get__ _set_ _delete_ __set_name |
抽象基类 | instancecheck__ __subclasscheck |
类元编程 | prepare__ _init_subclass_ _class_getitem_ __mro_entries |
字符串表示形式
`str__和__repr`
由
repr()
内置函数调用以输出一个对象的“官方”字符串表示。如果可能,这应类似一个有效的 Python 表达式,能被用来重建具有相同取值的对象(只要有适当的环境)。如果这不可能,则应返回形式如<...some useful description...>
的字符串。返回值必须是一个字符串对象。如果一个类定义了__repr__()
但未定义__str__()
,则在需要该类的实例的“非正式”字符串表示时也会使用__repr__()
。
此方法通常被用于调试,因此确保其表示的内容包含丰富信息且无歧义是很重要的。通过
str(object)
以及内置函数format()
和print()
调用以生成一个对象的“非正式”或格式良好的字符串表示。返回值必须为一个 字符串 对象。
此方法与object.__repr__()
的不同点在于__str__()
并不预期返回一个有效的 Python 表达式:可以使用更方便或更准确的描述信息。
内置类型 object 所定义的默认实现会调用object.__repr__()
。
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'这是__repr__的输出结果: name:{self.name},age:{self.age}'
def __str__(self):
return f'这是__str__的输出结果: name:{self.name},age:{self.age}'
if __name__ == '__main__':
s = Student("Python之家", 20)
# __str__和__repr__都能输出对象信息,但是__str__的优先级比__repr__高
# 同时存在时,优先调用__str__
# __str__不存在时调用__repr__
# 都不存在时,输出的如下:<__main__.Student object at 0x000002607D09B7D0>
print(s)
`format `
当调用format()
的时候,可以根据指定显示样式来具体显示信息
通过
format()
内置函数、扩展、格式化字符串字面值 的求值以及str.format()
方法调用以生成一个对象的“格式化”字符串表示。format_spec 参数为包含所需格式选项描述的字符串。format_spec 参数的解读是由实现__format__()
的类型决定的,不过大多数类或是将格式化委托给某个内置类型,或是使用相似的格式化选项语法。
返回值必须为一个字符串对象。
在 3.4 版更改: _object 本身的__format__
方法如果被传入任何非空字符,将会引发一个TypeError
。在 3.7 版更改: _object.__format__(x, '')
现在等同于 str(x) 而不再是 format(str(x), ”)。
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
# 变量前的双下划线表示真正的私有,实际上的私有,只有内部可以访问,外部不能访问
# 如果变量前是单下划线,表示外部可以访问,但是约定一下,我不想被访问到
__format_dict = {
'N - A': '名字是:{obj.name} - 年龄是:{obj.age}',
'N : A': '名字是:{obj.name} : 年龄是:{obj.age}',
'N / A': '名字是:{obj.name} / 年龄是:{obj.age}',
}
def __format__(self, format_spec):
# 如果模板格式不存在,那就指定一个默认的模板格式
if not format_spec or format_spec not in self.__format_dict:
format_spec = 'N - A'
fmt = self.__format_dict[format_spec]
print(fmt) # {obj.name}:{obj.age}
return fmt.format(obj=self)
if __name__ == '__main__':
s = Student("Python之家", 20)
print(format(s, 'N / A'))
`bytes `
通过
bytes
调用以生成一个对象的字节串表示。这应该返回一个bytes
对象。
依据不同的参数,bytes()
函数的行为也不同。
-
bytes(integer)
:返回一个不可变的字节对象,这个对象包含了给定数量的0x00值
。 -
bytes(string)
:这个版本会将字符串编码为字节。其他的编码和异常处理的参数会定义编码的具体过程。 -
bytes(something)
:这个版本会调用something.bytes()
创建字节对象。这里不用编码或者错误处理参数。
基本的object对象没有定义__bytes__()
。这意味着所有的类在默认情况下都没有提供__bytes__()
方法。
在一些特殊情况下,在写入文件之前,我们需要将一个对象直接编码成字节。通常使用字符串并且使用str类型为我们提供字符串的字节表示会更简单。要注意,当操作字节时,没有什么快捷方式可以解码文件或者接口中的字节。内置的bytes类只能解码字符串,对于我们的自定义对象,是无法解码的。在这种情况下,我们需要解析从字节解码出来的字符串,或者我们可以显式地调用struct模块解析字节,然后基于解析出来的值创建我们的自定义对象。
如果需要定义一个对象底层的字节表示方式,最好使用pickle或者json模块
换为数值
`bool`
调用此方法以实现真值检测以及内置的
bool()
操作;应该返回False
或 True。当未定义此方法时,则在定义了__len__()
的情况下将调用它,如果其结果不为零则该对象将被视为具有真值。如果一个类的__len__()
或__bool__()
均未定义,则其所有实例都将被视为具有真值。
模拟容器
`getitem__ _setitem_ __delitem`
用于索引操作,如字典。以上分别表示获取、设置、删除数据
按照 key 参数指定的类型返回一个表示泛型类的专门化对象。
当在类上定义时,class_getitem() 会自动成为类方法。因此,当它被定义时没有必要使用 @classmethod 来装饰。
class Foo(object):
def __getitem__(self, key):
print ('__getitem__',key)
def __setitem__(self, key, value):
print ('__setitem__',key,value)
def __delitem__(self, key):
print ('__delitem__',key)
obj = Foo()
result = obj['k1'] # 自动触发执行 __getitem__
obj['k2'] = 'Python之家' # 自动触发执行 __setitem__
del obj['k1'] # 自动触发执行 __delitem__
原文始发于微信公众号(Python之家):Python深入-1-特殊方法
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/198439.html