__str__和__repr__
改变对象的字符串显示__str__, __repr__
示例
class List:
def __init__(self, *args):
self.l = list(args)
l = List(1,2,3,4,5)
print(l)
执行结果
打印的是对象的内存地址,如果想要print(对象)显示字符串怎么办?
定制一个内置的方法__str__即可
class List:
def __init__(self, *args):
self.l = list(args)
def __str__(self):
return '[%s]' % (','.join([str(i) for i in self.l]))
l = List(1,2,3,4,5)
# 每一个对象, 都有__str__方法
print(l)
print(str(l))
print('%s' % l)
执行结果
[1,2,3,4,5]
[1,2,3,4,5]
[1,2,3,4,5]
例2
class Teacher:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return "Teacher's object %s" % self.name
def __repr__(self):
return 'repr function %s' % self.name
a = Teacher('Sam', 80)
b = Teacher('Tom', 80)
print(a) # 相当于 str(a)的返回值
print(b) # 相当于 str(b)的返回值
print(repr(a)) # 函数 打印repr的返回值
print(repr(b)) # 函数 打印repr的返回值
print(a.__repr__()) # repr(obj)的结果和obj.__repr__()是一样的
执行结果
Teacher's object Sam
Teacher's object Tom
repr function Sam
repr function Tom
repr function Sam
print执行时,是去内部寻找__str__方法,所以print没有输出不了的数据,因为每一个对象都有__str__方法
当一个对象,没有指定属性和方法时,则打印出内存地址
class List:
def __init__(self, *args):
self.l = list(args)
# def __str__(self):
# return '[%s]' % (','.join([str(i) for i in self.l]))
#
# def __repr__(self):
# return '[%s]' % (','.join([str(i) for i in self.l]))
l = List(1,2,3,4,5) #注释掉上面的__str__方法,和__repr__方法
print(str(l))
print(repr(l))
执行结果
重定义内置方法,是为了个性化输出而已
class List:
def __init__(self, *args):
self.l = list(args)
def __str__(self):
return '[__str__:%s]' % (','.join([str(i) for i in self.l]))
def __repr__(self):
return '[__repr__:%s]' % (','.join([str(i) for i in self.l]))
l = List(1,2,3,4,5)
print(str(l))
print(repr(l))
执行结果
[__str__:1,2,3,4,5]
[__repr__:1,2,3,4,5]
总结
当需要使用__str__的场景时找不到__str__就找__repr__
当需要使用__repr__的场景时找不到__repr__的时候就找父类的__repr__
__repr__是__str__的备胎
归一化设计
format()
__format__内部调用了这个方法
class A:
def __init__(self, name, school, addr):
self.name = name
self.school = school
self.addr = addr
a = A('Sam', '北大', '徐汇')
print(format(a))
执行结果
对象之所以能用format,是因为object有这个方法
源码
def __format__(self, *args, **kwargs): # real signature unknown
""" default object formatter """
pass
自定义格式化输出,format_spec参数必须要有默认参数,否则报错
class A:
def __init__(self, name, school, addr):
self.name = name
self.school = school
self.addr = addr
def __format__(self, format_spec):
return '{obj.name}-{obj.addr}-{obj.school}'.format(obj=self)
a = A('Sam', '北大', '徐汇')
format_spec = '{obj.name}-{obj.addr}-{obj.school}'
print(format(a, format_spec))
执行结果
Sam-徐汇-北大
所谓的自定义,就是添加一些个性化的输出,例如
class A:
def __init__(self, name, school, addr):
self.name = name
self.school = school
self.addr = addr
def __format__(self, format_spec):
return format_spec.format(obj=self)
a = A('Sam', '北大', '徐汇')
b = A('Tom', '清华', '松江')
# 只需要更改,就可以自定义个性化了
format_spec = '{obj.name}-{obj.addr}魔都!-{obj.school}很牛!'
print(format(a, format_spec))
print(format(b, format_spec))
执行结果
Sam-徐汇魔都!-北大很牛!
Tom-松江魔都!-清华很牛!
__str__和__repr__加上__format__的例子
改变对象的字符串显示__str__, __repr__,自定制格式化字符串__format__
format_dict = {
'nat': '{obj.name}-{obj.addr}-{obj.sex}', # 姓名,地址,性别
'tna': '{obj.addr}:{obj.name}:{obj.sex}', # 地址,姓名,性别
'tan': '{obj.sex}:{obj.name}:{obj.addr}', # 性别,姓名,地址
}
class School:
def __init__(self, name, addr, sex):
self.name = name
self.addr = addr
self.sex = sex
def __repr__(self):
return '__repr__(%s,%s)' % (self.name, self.addr)
def __str__(self):
return '__str__(%s,%s)' % (self.name, self.addr)
def __format__(self, format_spec):
if not format_spec or format_spec not in format_dict:
format_spec = 'nat'
fmt = format_dict[format_spec]
return fmt.format(obj=self)
s1 = School('张三', '武汉', '男')
s2 = School('李四', '上海', '男')
s3 = School('王五', '北京', '男')
"""
str函数或者print函数----> obj.__str__()
repr或者交互式解释器----> obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这两方法的返回值必须是字符串,否则抛出异常
"""
print('from repr:', repr(s1))
print('from str:', str(s2))
print('from format:', format(s3))
执行结果
from repr: __repr__(张三,武汉)
from str: __str__(李四,上海)
from format: 王五-北京-男
__call__
对象后面加括号,触发执行
注:构造方法的执行是由创建对象触发的,即:对象=类名();而对于__call__方法的执行是由对象后加括号触发的,即:对象()或者类()()
object默认没有__call__方法
class Teacher():
def __call__(self, *args, **kwargs):
print(123)
t = Teacher()
t() # 对象名() 执行__call__
Teacher()() # 类名()() 执行__call__
执行结果
123
123
一个对象是否可调用,完全取决于这个对象对应的类是否实现了__call__
callable判断一个对象是否可以调用
class Teacher():
def __call__(self, *args, **kwargs):
print('执行__call__方法')
def call(self):
print('执行call方法')
t = Teacher()
Teacher()() # 类名()() 执行__call__
print(callable(t)) # 返回值True或False
t.call() # 对象名.方法名() 执行call
t() # 对象名() 执行__call__
执行结果
执行__call__方法
True
执行call方法
执行__call__方法
解释:
call()是人为调用,太麻烦了
Teacher()()其实是调用了类的__call__方法,有些源码会出现类名()()
__eq__
==实际是调用了__eq__方法,它是判断内存地址是否一致
class A:pass
a = A()
b = A()
print(a)
print(b)
print(a == b)
执行结果
<__main__.A object at 0x00000231F5EB22E8>
<__main__.A object at 0x00000231F5EB2208>
False
在来看看__eq__的使用方法
class B:
def __init__(self):
self.a = 1
self.b = 2
def __eq__(self, other):
if self.a == other.a and self.b == other.b:
return True # 这里改成什么就返回什么
a = B()
b = B()
print(a == b)
执行结果
True
==是由__eq__的返回值来决定的
__del__析构方法:析构方法,当对象在内存中被释放时,自动触发执行
注:此方法一般无需定义,因为python是一门高级语言。程序员在使用时无需关心内存的分配和释放,因为此工作都是交给python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
在删除一个对象的时候做一些收尾工作
class A:
def __init__(self):
pass
def __del__(self):
print('执行我啦')
a = A()
print('aaa')
执行结果
aaa
执行我啦
对象执行结束之后,就会执行析构方法
例2
class A:
def __init__(self):
self.f = open('123.txt', 'w')
def __del__(self):
self.f.close() # 在最后会执行关闭文件的操作
a = A()
print('aaa')
执行结果
aaa
__new__构造方法,这个很重要
实例化的时候
创建对象的过程 __new__
init 初始化
__new__的源码
@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
""" Create and return a new object. See help(type) for accurate signature. """
pass
__new__是一个静态方法,也叫单例模式,先有对象,才能初始化,也就是说__new__要在 __init__之前。
单例模式就是一个类,只能有一个实例
错误示例,下面这个例子不属于单例模式
class A:pass
a = A()
b = A()
print(a)
print(b)
执行结果
<__main__.A object at 0x000001594118E630>
<__main__.A object at 0x00000159415D2240>
单例模式就是一个类,只能有一个实例
真正的单例模式
class B:
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
obj = object.__new__(cls)
cls.__instance = obj
return cls.__instance
a = B()
b = B()
print(a)
print(b)
执行结果
<__main__.B object at 0x00000204BC4922E8>
<__main__.B object at 0x00000204BC4922E8>
内存地址是一样的,单例模式
例2
class B:
__instance = None
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
obj = object.__new__(cls)
cls.__instance = obj
return cls.__instance
def __init__(self, name, age):
self.name = name
self.age = age
a = B('Sam', 40)
b = B('Tom', 28)
print(a)
print(b)
print(a.name)
print(b.name) # 打印的都是Tom
执行结果
<__main__.B object at 0x0000024BEFC59710>
<__main__.B object at 0x0000024BEFC59710>
Tom
Tom
相当于重新赋值了,单例模式,只能有一个实例,后面的会覆盖前面的
item系列
__getitem__ __setitem__ __delitem__
class Foo:
def __init__(self, name):
self.name = name
def __getitem__(self, item): # __getitme__只能有一个参数
print(self.__dict__[item])
def __setitem__(self, key, value): # __setitme__ 能接收2个参数,一个是等号左边,一个是等号右边
self.__dict__[key] = value
def __delitem__(self, key):
print('del obj[key]时,我执行')
self.__dict__.pop(key)
def __delattr__(self, item):
print('del obj.key时,我执行')
self.__dict__.pop(item)
f1 = Foo('sb')
f1['age'] = 18
f1['age1'] = 19
del f1.age1
del f1['age']
f1['name'] = 'Sam'
print(f1.__dict__)
执行结果
del obj.key时,我执行
del obj[key]时,我执行
{'name': 'Sam'}