发布时间:2018-04-19 20:42:07编辑:Run阅读(3611)
__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'}
上一篇: python3--面向对象的进阶
47605
45985
36909
34469
29080
25713
24566
19714
19245
17756
5565°
6155°
5691°
5737°
6705°
5483°
5484°
5988°
5965°
7295°