81、Python之鸭子类型:从魔法函数看对象的字符串呈现

南宫理的日志录 2024-11-07 10:34:12
引言

前面已经介绍了鸭子类型的概念,以及Python中支撑鸭子类型理念的“魔法函数”的体系。Python中的魔法函数分为几大类,本文我们首先从最简单的自定义类型的字符串呈现来切入,逐步理解并掌握Python中的魔法函数的完整架构。

本文的主要内容有:

1、print()函数的内部运行机制

2、对象的字符串表示的默认实现

3、通过魔法函数自定义对象字符串表示的实现

print()函数的内部运行机制

关于print()函数的使用,我们前面已经进行详细的介绍,结合print()函数的定义文档,再来简单回顾一下:

通常情况下,我们只需要将要输出的对象作为位置参数传递给print()函数,即可完成一个对象的打印输出。其实,结合sep、end、file参数,我们可以实现更多的打印效果:

1、sep参数,默认情况下为一个空格,当我们需要输出多个对象,并自定义分隔符时,可以指定该参数。

2、end参数,默认情况下为一个回车,也可以自行指定。

3、file参数,默认情况下其实就是sys.stdout,也可以指定自己的文件流,就变成了往文件中写入数据了,比如日志等。

以上,大概就是我们之前介绍过的关于print()函数的使用了。

但是,为什么有的对象的输出字符串包含了元素、属性等,有些对象的输出就是比较奇怪的一串字符串?要回答这个问题,就要涉及到print()函数的作用机制了,我们直接说结论:

当我们调用print(obj)函数时,Python内部的处理机制是这样的:

1、检查对象是否实现了__str__()方法,如果实现了,则调用__str__()方法,然后输出其返回值。

2、如果对象没有实现__str__()方法,则会检查对象是否实现了__repr__()方法,如果实现了,则调用__repr__()方法,然后输出其返回值。

3、如果对象两个方法都没有实现,则会使用对象的默认字符串表示形式。

需要说明的,Python内置的str类,也是这样类似的实现逻辑,可以从定义中看出:

对象的字符串表示的默认实现

对象的字符串表示的默认实现,其实,只要写过Python代码,应该多少都接触过,我们以实际代码为例,来简单看一下:

执行结果:

这一串看着有些奇怪的字符串,其实是一个固定的表示格式。其中隐含了模块名、类名,以及,大概是这样一个逻辑,我们通过代码直接演示一下:

执行结果:

从执行结果可以看出,我们自定义的my_str()方法的输出内容,与对象的默认字符串表示的输出,是完全一样的。

其实,之所以会有这个默认实现,是由于Python中的新式类,默认都是继承自object这个基类。这种默认的字符串表示是通过object类的__repr__()方法实现的。

通过魔法函数自定义对象字符串表示的实现

从print()函数的内部作用机制,我们已然可以知道,通过魔法函数__str__()和__repr__(),可以实现自定义对象字符串表示的行为。这也是内部类型,比如容器等,等够在print()输出时,呈现出更加人性化的内容,更加便于开发者的使用、调试。

还是先通过代码来看一下吧:

执行结果:

从执行结果可以看出,print(obje)和str(obj),都已经自动调用了我们自定义的__str__()方法。

当然,这里我们换成__repr__()方法,也是可以的。

需要说明的是,大多数情况下,使用__str__()方法或者__repr__()方法的效果都是一样的,但是,二者还是有所区别的,主要在使用场景上:

1、__str__()方法,用于生成面向用户的可读性字符串表示,通常会被用于print()函数或者str()函数(可以理解为是调用方,虽然__repr__也是可以的,只能当做一种约定、习俗)。

2、__repr__()方法,更多地用于生成开发者的详细字符串表示,通常用于调试时使用。比如通过repr()函数调用或者直接在交互式解释器中输入对象等。

感兴趣的同学,可以自行定义__str__()和__repr__()的不同实现,然后对比print()、str()、repr()的输出内容,来看两个方法各自的触发机制。

总结

本文基于对鸭子类型和魔法函数概念的理解的基础上,首先回顾了print()函数的简单使用,介绍了print()等类似的字符串呈现的函数的作用机制,然后介绍了通过__str__()、__repr__()实现自定义类型的对象的字符串表示的自定义实现。

感谢您的拨冗阅读,希望对您有所帮助!

0 阅读:0

南宫理的日志录

简介:深耕IT科技,探索技术与人文的交集