QQ登录

只需一步,快速开始

开启左侧

Python学习第六十五天—类和对象14-call、str、repr

[复制链接]
15271953841 发表于 2024-3-29 08:36:08 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
给人看还是给程序看
一、__call__(self[,args…])
在对象中即可以有属性,也可以有方法,Python可以像调用函数一样去调用一个对象噢,要求是:需要这个对象的类去定义一个叫做__call__()魔法方法。演示一下
Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.
>>>class C:
    def __call__(self):
        print("嗨~")

        
>>>c = C()
>>>c()                   (__call__()魔法方法被访问了)
嗨~
>>>class C:
    def __call__(self,*args,**kwargs):       (__call__()支持位置参数和关键字参数的)
        print(f"位置参数->{args}\n关键字参数->{kwargs}")

        
>>>c = C()
>>>c(1,2,3,x=250,y=520)
位置参数->(1, 2, 3)
关键字参数->{'x': 250, 'y': 520}
前面我们学习过闭包的时候,提到过一个例子,定义一个工厂函数,然后根据参数不同,得到不同的生产线
什么是闭包,所谓闭包,有人称之为工厂函数,工厂是指来料加工,批量生产。
>>>def power(exp):      (定义 外部函数(参数))
    def exp_of(base):    (定义 内部函数(参数))
        return base ** exp     (** 表示幂运算)
    return exp_of

>>>square=power(2)
>>>cube=power(3)
>>>square(2)
4
>>>square(5)
25
>>>cube(2)
8
>>>cube(5)
125
>>>power(2)(2)
4
>>>power(2)(5)
25
>>>power(3)(2)
8
>>>power(3)(5)
125
正所谓方法千千万,就看习惯不习惯,如果闭包的实现方案让你觉得太难理解,或者你觉得闭包函数用的烦了,那么我们也可以不用它,我们通过定义__call__()这个魔法方法同样可以实现类似的效果。
>>>class Power:
    def __init__(self,exp):
        self.exp = exp
    def __call__(self,base):
        return base ** self.exp

   
>>>square = Power(2)
>>>square(2)
4
>>>square(5)
25
>>>cube = Power(3)
>>>cube(2)
8
>>>cube(5)                  (与闭包实现效果一样,也更好理解)
125
>>>Power(2)(5)
25
>>>Power(3)(5)
125

二、__str__(self)和__repr__(self)这两个与字符串相关的魔法方法,__str__()响应的是str()内置函数的魔法方法,__repr__()对应的内置函数叫repr(),虽然repr()与str()在多数情况下得到的结果是一样的,都是一个字符串的结果,但是它们设计初衷是不一样的,str()函数是将参数转换对象,是给人看的,repr()函数则是将对象转换为程序可执行的字符串,是给程序看的。
>>>str(123)
'123'
>>>repr(123)
'123'
>>>str(13.14)           (再举一个浮点数)
'13.14'
>>>repr(13.14)
'13.14'
>>>str("FishC")
'FishC'
>>>repr("FishC")           
"'FishC'"              (多穿了一层衣服,这里必须提到另外一个函数eval(),它的作用是将参数去引号后执行,并得到结果。)
>>>eval("1+2")
3
所以我们将str()函数的结果,作为eval()函数的一个参数的话,那么会怎么样?肯定会报错,因为str()函数得到的字符串外面没有引号。
>>>eval(str("FishC"))
Traceback (most recent call last):
  File "<pyshell#33>", line 1, in <module>
    eval(str("FishC"))
  File "<string>", line 1, in <module>
NameError: name 'FishC' is not defined
报错:原因是参数去引号的结果,是裸的FishC,Python自然把它当变量名来应用,结果是找不到FishC的定义,但如果我们把str()换成repr(),那结果就ok了。
>>>eval(repr("FishC"))
'FishC'                       (因为repr()多了一层外衣,脱了还是一个字符串吗,所以有人说eval()函数是repr()函数的反函数,因为repr()函数返回的字符串作为参数传递给eval()函数的话,那么,所得到的结果,必定是repr()函数的参数。
>>>eval(repr(12345))
12345
再来讲讲,它们对应的魔法方法__str__(self)和__repr__(self),这两个魔法方法必须是返回字符串的类型,其次,__repr__(self)这个魔法方法是可以对__str__(self)魔法方法进行代偿的,也就是说,我们只定义__repr__()方法,那么调用str()函数也可以被相应到的。举个例子给大家演示一下吧。
>>>class C:
    def __repr__(self):
        return "I love FishC"

   
>>>c = C()
>>>repr(c)
'I love FishC'
>>>str(c)            (类中没有定义str对应的魔法方法,所以它会自动去调__repr__()这个魔法方法代偿,但是如果反过来就不行了)
'I love FishC'
>>>class C:
    def __str__(self):
        return "I love FishC"

   
>>>c = C()
>>>str(c)
'I love FishC'
>>>repr(c)                  (它得不到I love Fish C了
'<__main__.C object at 0x000002575D550C20>'
然后,还有一点大家需要注意的:__str__()魔法方法定义的只能应用于对象出现在打印操作的顶层,也就是说,我们把多个对象放到一个列表中,然后把这个列表打印出来的话,那么我们就没办法去访问到这个对应的字符串了
>>>c = C()
>>>print(c)
I love FishC
>>>cs = [C(),C(),C()]            (创建一个列表给cs,列表中三个类C的实例对象)
>>>for each in cs:              (通过迭代把列表中的每个元素(每个对象)打印出来,print(cs)应该是print(each))
    print(cs)

   
[<__main__.C object at 0x000002575D550C20>, <__main__.C object at 0x000002575D552930>, <__main__.C object at 0x000002575D552900>]
[<__main__.C object at 0x000002575D550C20>, <__main__.C object at 0x000002575D552930>, <__main__.C object at 0x000002575D552900>]
[<__main__.C object at 0x000002575D550C20>, <__main__.C object at 0x000002575D552930>, <__main__.C object at 0x000002575D552900>]
>>>for each in cs:          (通过迭代把列表中的每个元素(每个对象)打印出来)

    print(each)

   
I love FishC
I love FishC
I love FishC                   (这个没问题,可以打印,就是一个一个的打印没问题)
>>>print(cs)               (但是我们试图去打印整个列表的话,就不能打印了,得到的是这么一个内容"类名 + object at + 内存地址",它不能得到三个I love FishC的字符串)
[<__main__.C object at 0x000002575D550C20>, <__main__.C object at 0x000002575D552930>, <__main__.C object at 0x000002575D552900>]
但是我们如果定义的是__repr__():
>>>class C:
    def __repr__(self):
        return "I love FishC"

   
>>>cs = [C(),C(),C()]
>>>for each in cs:
    print(each)

   
I love FishC
I love FishC
I love FishC
>>>print(cs)          (去打印整个列表的话,定义这个__repr__()则没有这个困扰,说明__repr__()魔法方法适用的场景更多,更稳。)
[I love FishC, I love FishC, I love FishC]
不过,通过同时定义两个方法实现,我们可以让对象在不同场景下支持不同的显示效果,还是举例说明。(这个可以百度一下“Python同时定义__str__()和__repr__()”)
>>>class C:
    def __init__(self,data):
        self.data = data
    def __str__(self):
        return f"data = {self.data}"
    def __repr__(self):
        return f"C({self.data})"
    def __add__(self,other):
        self.data += other

        
>>>c = C(250)
>>>print(c)                (调用print方法打印一个实例对象,就会调用该对象的str()的方法,如果没有定义该方法,就会打印对像的内存地址。str()只有在调用print打印的时候才会触发,直接输出则不会,如果同时定义了__str__()和__repr__(),print会优先触发__str__()方法)
data = 250
>>>c
C(250)
>>>c + 250
>>>print(c)
data = 500
>>>c
C(500)
Python中每个类都包含repr()方法,因为object类包含repr()的方法,而Python中所有的类都是直接或间接继承自object类。__str__()和__repr__()的区别是:只要类中重构了__repr__()方法,不管是直接输出,还是通过print打印,都会触发__repr__()方法。
>>>class C:
    def __init__(self,data):
        self.data = data
    def __repr__(self):
        return f"C({self.data})"
    def __add__(self,other):
        self.data += other

        
>>>c = C(250)
>>>c
C(250)
>>>print(c)
C(250)
>>>c + 250
>>>c
C(500)
>>>print(c)
C(500)
调用print方法打印一个实例对象,就会调用该对象的str()的方法,如果没有定义该方法,就会打印对像的内存地址。str()只有在调用print打印的时候才会触发,直接输出则不会,如果同时定义了__str__()和__repr__(),print会优先触发__str__()方法
>>>class C:
    def __init__(self,data):
        self.data = data
    def __str__(self):
        return f"data = {self.data}"
    def __add__(self,other):
        self.data += other

        
>>>c = C(250)
>>>print(c)
data = 250
>>>c
<__main__.C object at 0x000002575D553830>

客服热线
400-1234-888 周一至周日:09:00 - 21:00
公司地址:襄阳市樊城区长虹路现代城5号楼188

创客帮MAKER.BAND青少年创客创意社区是一个融教育、科技、体育资讯为一体的综合服务平台,专注于教育创新、专注于科技体育、专注于教育资讯。

Powered by Discuz! X3.4 © 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表