文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

python3--面向对象进阶之内置方法

2023-01-30 21:59

关注

__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__的备胎


归一化设计

blob.png


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'}


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯