最近一下子学了很多的知识点,导致我有点没反应过来,粗略的在草稿纸记了点自己的想法,趁休息的时间将它敲到博客里面去,免得丢失,这一篇写的挺废话的,有点啰嗦,本篇的重点是第二段程序后开始的总结和后面的几个细节问题。

关于__repr__和__str__这连个东西,我最开始就感觉有点难以理解,百度来的东西看了很多遍,定义都能背下来了,随口一说就是一个给机器看的一个给人看的,但是感觉只理解了最表面,当然不是网上大佬给的答案不够好,而是某些东西还是需要自己去思考,然后有一番自己的理解,然后写点程序验证下,这才是最好的。

首先,我把这两个的东西对实例对象的操作称为“渲染”,可能不太准确,但是我觉这么叫方便我去理解。

第一步先写一个简单的类:MyNumber,先来理解下在输出实例的时候,str和repr的操作方式

class MyNumber:
        def __init__(self,value):
            self.data = value
        def __str__(self):
            print('正在调用__str__方法,转换为普通字符串')
            s = '自定义数据%d'%self.data
            return s
        def __repr__(self):

print('正在调用__str__方法,转换为普通字符串')
             s = 'MyNumber(%d)'%self.data

return s

n1 = MyNumber(100),

这个类里面除了init方法还有str和repr,首先,我们在用print输出任何东西的时候,都会有一个渲染步骤,而且默认的就是用str进行渲染,因为任何一样东西都可以看做一个对象,那么它必有一个类型,如果它的类里面没有定义str和repr也没关系,object里面定义了str和repr,object是一切类的父类,所以输出的对象一定会是渲染过的。这个类里面自己写了str和repr,它覆盖了object里面的str和repr,相当于print的重定向。

接下来就是输出了,print(n1)和print(str(n1))是一样的效果的,因为他们都会调用类里面的str方法,其中print(n1)是默认调用str的。print(repr(n1))的结果就不一样了,它会调用这个类里面的repr方法。

接下来再弄一段来记下repr的用法和两者的区别。

class MyInteger:
        def __init__(self,v):
            self.data = v
        def __repr__(self):
            return 'MyInteger(%d)'%self.data
        def __abs__(self): 
        '''此方法用于制定abs(obj)函数取值时返回的结果'''
            if self.data < 0:
                return MyInteger(-self.data) #用-self.data创建一个新的对象返回回去
            return MyInteger(-self.data)
    i1 = MyInteger(-100)
    print(i1)  #等同与print(str(i1))
    n = abs(i1)

print(n)

这一段程序比较有意思,先来配合第一段程序来总结下str和repr的调用规则。

调用 print(i1)  (#等同与print(str(i1)))的时候,解释器第一个寻找的就是i1这个类的方法里面有没有重新定义str,如果没有,那么它第二步会去寻找这个类里面有没有重新定义repr,如果有则会用类方法的repr,如果还没有,那么解释器会找这个类的上一层父类,按同样的规则进行寻找,直到最后找到了object,然后用object的str方法,将该对象的内容转成字符串,最后输出到终端。

调用print(repr(i1))的时候就不一样了,repr只会调用repr方法,当自定义的类中没有重写repr方法的时候,它会直接找上一级的父类中有没有repr方法,而不会考虑调用str方法。

总的来说,repr方法比较傲娇,而str方法就比较随意,所以repr的用法就会像这一段程序一样,当我要输出一个需要自己加工的数据的时候,用object的str和repr显然不够,那么就需要在自己的类中重新写一个repr的方法,这样,调用print(XXX)的时候,这个类里面的repr方法就会被调用,这段程序里面,repr调用的意义就输输出了一个段字符串用做提示,这一是一般比较常见的用法。

最后再来总结一些东西,除了顺序之外还有一些细节。

1.几乎所有的函数重构会遵循一些返回值规则,str和repr也不例外,自己重构这个函数的时候写得返回值必须是字符串类型,这个规则被写在了解释器的骨子里,试想下,object里定义这两个东西就是为了输出字符串给人或机器看,结果自己重构了一遍返回了个int型的值,解释器也会很苦恼怎么把int的值显示在终端上,干脆就报错了。

2.所谓给人看和给机器看的意思最直观的就是用eval函数进行测试,eval函数里是需要一个表达式,经过测试就能明白,str返回的是个字符串,而repr返回一个能代表此对象的表达式字符串,这个表达式会被eval翻译,结果就是调用repr时传入的对象,eval(repr(obj))=obj。而str这么做就会报错。

3.以前经常会有'hello %s'%word  一类的写法,这里%s就是代表了str的类型,其实repr类型对应的是%r,但是都用%s貌似也不会出错,不过还是区分一下,显得更专业一些。

4.一个小细节,算是比较容易出问题的细节,以第二段程序为例,如果我把print(i1)写成print(i1.data)会怎么样,结果是会直接输出这个实例的属性的值,而且不会调用这个类里面的str和repr方法,因为print里面放的不是一个实例对象,而是该实例的一个属性,所以解释器会直接调用object里面的str,将值转成字符串并输出到了终端,所以一般自己写的类里面重构的repr,一般都是用来自定义的去描述一个实例对象的,如果需要带上实例属性,那就像这一段程序一样,在返回的时候把实例属性插进字符串里面好了。
---------------------
作者:汐陌夏初
来源:CSDN
原文:https://blog.csdn.net/qq_36272641/article/details/80875222
版权声明:本文为博主原创文章,转载请附上博文链接!

__rept__和__str__的更多相关文章

  1. python 的特殊方法 __str__和__repr__

    __str__和__repr__ 如果要把一个类的实例变成 str,就需要实现特殊方法__str__(): class Person(object): def __init__(self, name, ...

  2. python的class的__str__()和__repr__()函数

    repr(object) 返回一个可以用来表示对象的可打印字符串首先,尝试生成这样一个字符串,将其传给 eval()可重新生成同样的对象 否则,生成用尖括号包住的字符串,包含类型名和额外的信息(比如地 ...

  3. python __str__ & __repr__ & __cmp__

    For ( __str__ ),we going to see a example ... and find who is working for ... #!/usr/bin/python clas ...

  4. __str__

    __str__是被print函数调用的,一般都是return一个什么东西.这个东西应该是以字符串的形式表现的.如果不是要用str()函数转换.当你打印一个类的时候,那么print首先调用的就是类里面的 ...

  5. python面对对象编程------4:类基本的特殊方法__str__,__repr__,__hash__,__new__,__bool__,6大比较方法

    一:string相关:__str__(),__repr__(),__format__() str方法更面向人类阅读,print()使用的就是str repr方法更面对python,目标是希望生成一个放 ...

  6. Django rest framework:__str__ returned non-string (type NoneType) 真正原因

    出错原因: 用户表是Django中核心的表,当这个表类字段中有一个这样的函数 def __str__(self): return self.name 在Django用户表设计时候有个字段容易犯这个失误 ...

  7. python __str__ 和__repr__方法

    看下面的例子就明白了 class Test(object): def __init__(self, value='hello, world!'): self.data = value >> ...

  8. python3全栈开发-内置函数补充,反射,元类,__str__,__del__,exec,type,__call__方法

    一.内置函数补充 1.isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(object): pass obj = Foo() print(isinstan ...

  9. __str__与__repr__

    在讲解之前,我们先来了解下str和repr的区别:两者都是用来将数字,列表等类型的数据转化为字符串的形式.不同之处在于str更加类似于C语言中使用printf输出的内容,而repr输出的内容会直接将变 ...

随机推荐

  1. 【剑指Offer】10- I. 斐波那契数列 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人微信公众号:负雪明烛 目录 题目描述 解题方法 递归 动态规划 日期 题目地址:htt ...

  2. 【LeetCode】424. 替换后的最长重复字符 Longest Repeating Character Replacement(Python)

    作者: 负雪明烛 id: fuxuemingzhu 公众号:每日算法题 本文关键词:LeetCode,力扣,算法,算法题,字符串,双指针,刷题群 目录 题目描述 题目大意 解题方法 双指针 代码 欢迎 ...

  3. Windows服务注册(需要指定config文件的情况下)

    最近,遇到一个问题:需要将telegraf在Win平台下注册为windows服务(避免误操作关闭CMD窗口): 尝试了网上的几种注册Windows服务的方法,发现无法将telegraf这种需要在CMD ...

  4. 【嵌入式】keil不识别野火高速dap的问题

    解决方法:https://www.firebbs.cn/thread-28093-1-1.html

  5. [opencv]Rect集合象限法分类聚合 函数

    /** * 矩形拟合 * @param mats * @return */ vector<Rect> PublicCardFrameDetection::RectContainFit(ve ...

  6. <数据结构>拓扑排序

    有向无环图 有向无环图(Directed Acycilc Graph, DAG):从任意顶点出发都无法回到自身的有向图. 拓扑排序 定义 任一两个顶点u,v间,如果存在边u->v,则排序后u一定 ...

  7. Java EE数据持久化框架 • 【第2章 MyBatis实现DML操作】

    全部章节   >>>> 本章目录 2.1 标签 2.1.1 标签简单应用 2.1.2 使用JDBC方式返回主键自增的值 2.1.3 使用标签返回普通主键的值 2.1.4 实践练 ...

  8. Python两处容易理解错误的设计

    函数内部修改可变类型的变量时不会视作局部变量(除非函数内有该变量的赋值运算符),因为如果做局部变量处理则修改语句势必报错,此处的理解不会有歧义: s = 'test' d = {True:1,2:'S ...

  9. 在 GitHub 复活 80 年代的游戏代码,它们出自第一本售出百万册的计算机书籍

    今儿我在 GitHub 看到了一个很眼熟的名字和头像,但是第一时间没想起来他是谁.算了先看看是个什么神仙开源项目,竟然能登上今天的 GitHub 趋势榜首. 该项目是把<BASIC Comput ...

  10. 【计项02组01号】Java版图形界面计算器

    Java版图形界面计算器1.0版本 项目分析[1.0] 组成部分 代码结构 (1)窗口的创建 在<JDK 核心 API>中我们提到,创建一个窗口需要使用 JFrame 类.在本实验中,我们 ...