31.Python面向对象str和repr原理魔法方法__call__和__new__方法单例模式
Posted 孤寒者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了31.Python面向对象str和repr原理魔法方法__call__和__new__方法单例模式相关的知识,希望对你有一定的参考价值。
目录:
每篇前言:
🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者
- 🔥🔥本文已收录于Python全栈系列专栏:《Python全栈基础教程》
- 🔥🔥热门专栏推荐:《Django框架从入门到实战》、《爬虫从入门到精通系列教程》、《爬虫高级》、《前端系列教程》、《tornado一条龙+一个完整版项目》。
- 📝📝本专栏面向广大程序猿,为的是大家都做到Python从入门到精通,同时穿插有很多很多习题,巩固学习。
- 🎉🎉订阅专栏后可私聊进一千多人Python全栈交流群(手把手教学,问题解答); 进群可领取Python全栈教程视频 + 多得数不过来的计算机书籍:基础、Web、爬虫、数据分析、可视化、机器学习、深度学习、人工智能、算法、面试题等。
- 🚀🚀加入我一起学习进步,一个人可以走的很快,一群人才能走的更远!
Python面向对象(四)
1.1 str和repr原理
不知道大家学到现在有没有注意到一个问题:
- 在交互模式下输出的交互信息与直接print的信息有些不同
这背后的原理是什么嘞?
其实这就涉及到了str和repr原理(有跟着我的Django专栏学习的童鞋可能发现在django中创建模型时用过这玩意,但是大家只是知道要那样用,会有那样的效果,而没有深究,所以这里就来好好探讨探讨!)。
- return返回的必须是字符串。
- print打印实例对象的时候(没有重写__repr__方法,直接是pass)显示的是 地址;
- 如果重写了__repr__方法,那么打印的就是__repr__方法里面的东西;
- 如果同时重写了__repr__和__str__方法,打印实例对象的时候,只会显示__str__里面的内容。
例一:
# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Person:
def __repr__(self):
return '这是一个repr方法'
def __str__(self):
return '这是一个str方法'
p = Person()
print(p)
- %s 使用的是__str__方法; %r 使用的是__repr__方法。
例二:
# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Person:
def __repr__(self):
return '这是一个repr方法'
def __str__(self):
return '这是一个str方法'
p = Person()
print(' %s' % p)
# 输出为:这是一个str方法
print(' %r' % p)
# 输出为:这是一个repr方法
在python中,str和repr方法在处理对象的时候,分别调用的是对象的__str__和__repr__方法;
print打印对象,调用str函数,如果对象没有定义__str__方法,则调用__repr__方法处理;
在交互模式下,直接输出对象,显示__repr__
的返回值。
1.2 魔术方法__call__
方法
正常情况下,实例是不能像函数一样被调用的,要想实例能够被调用,就需要定义 __call__
方法
# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Person:
def a(self):
print('this is a ')
# 实例对象加上括号就会自动调用call方法
def __call__(self, *args, **kwargs):
print('this is call')
p = Person()
p() # 输出为: this is call
- 拓展:
类中的一些查询相关信息的方法(了解既可,而且我其实大都在前面讲过了,再讲一遍加深印象~)
-
__class__
查看类名格式: 实例.
__class__
-
__dict__
查看全部属性,返回属性和属性值键值对形式格式:实例.
__dict__
-
__doc__
查看对象文档,即类中(用三个引号引起来的部分)格式:类名.
__dict__
-
__bases__
查看父类格式:类名.
__base__
-
__mro__
查看多继承的情况下,子类调用父类方法时,搜索顺序格式:子类名.
__mro__
实例.__class__.__mro__
下来再来深入看一个魔法方法:
1.3 魔法方法__new__方法
类每次实例化的时候都会创建一个新的对象,如果要求类只能被实例化一次该怎么做呢?
__new__方法
举个例子:
# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Person:
#初始化
def __init__(self):
print('this is init')
def __new__(cls, *args , **kwargs):
print('这new方法在init之前就进行了调用')
#重写new方法
#new方法是最先被调用的
#new 必须返回父类的new方法,程序才能继续往下运行,如果不返回,即没有下面这行程序就不会往下运行。
return super().__new__(cls)
guhanzhe= Person()
四个点理解__new__
方法:
__new__
方法是在类创建实例的时候自动调用的。- 实例是通过类里面的
__new__
方法是在 类 创建出来的。 - 先调用
__new__
方法创建实例,再调用__init__
方法初始化实例。 __new__
方法,后面括号里的cls代表的是类本身
在上面的例子中,我们可以看到创建实例的时候,自动调用了__new__方法和__init__方法,并且
是先调用的__new__(__new__方法会在内存当中开辟一个空间)再调用的__init__方法,打印 cls 的时候显示的这个Person类
下一个知识点引入:
new方法会开辟空间
每次实例化,这个new方法都会开辟一个新的空间
那就有个问题——可不可以让这new方法只开辟一个空间?
- 这就涉及到了伟大的单例模式!
1.4 单例模式
提前引入一些小知识点(前面也讲过了,怕大家忘了,再来温习一遍):
hasattr() #has attribute
hasattr() 函数用于判断对象是否包含对应的属性
hasattr(object(对象),name(“字符串,属性名”))
返回True(有);False(没有)
直接结合范式代码讲解:
# -*- coding: utf-8 -*-
"""
__author__ = 孤寒者
"""
class Person:
#范式:固定的公式;固定的写法
def __new__(cls,*args,**kwargs):
#hasattr 判断类里面有没有这个方法
#如果类没有instance这个属性
if not hasattr(cls,'instance'): #cls就是Person这个类本身
#没有instance这个属性就会执行下面这句
#创建instance这个属性,等于父类的new方法
#new返回父类的new方法,和返回instance都可以
cls.instance = super().__new__(cls) #上面说如果类没有instance这个属性就执行这句,把父类的new方法添加为类本身的属性
#在下一句再return这个类本身的这个instance属性,这样在第二次实例化的时候,return
#的仍然是第一次实例化的cls.instance,就没有返回父类的new方法,也就没有创建新的内存
#空间,而是仍然指向第一次创建的内存空间
return cls.instance #如果把返回的改为 super().__new__(cls),直接返回父类的new方法,这就不是单例模式,因为每次实例化都会返回父类
#的new方法,即创建一个新的内存空间。
def __init__(self,name):
self.name = name
a = Person('孤寒者')
b = Person('新的孤寒者')
print(id(a))
print(id(b))
会发现两次的id都一样了,即两次指向同一片内存空间,相当于a被b覆盖了。
意味着这两个其实引用的是同一个实例,是一个实例的不同名字
以上是关于31.Python面向对象str和repr原理魔法方法__call__和__new__方法单例模式的主要内容,如果未能解决你的问题,请参考以下文章
31.Python面向对象str和repr原理魔法方法__call__和__new__方法单例模式
python_魔法方法:__str__()和__repr__()