魔术方法
Posted jiangmingbai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了魔术方法相关的知识,希望对你有一定的参考价值。
- 双下划线开头且结尾的方法我们称之为魔术方法,python底层帮我是实现了很多的魔术方法,在特定场景下自动触发
- 点击跳转Python官网文档
- 点击跳转大佬博客
__int__ 和 __new__ 方法
- __init__ 是在创建对象的时候自动调用,对创建的对象进行初始化设置的
- __new__ 是实力化对象的时候自动调用的
- __new__ 方法在__init__方法之前调用,先实例了对象,在给实例初始化属性
class Mycalss(object):
def __init__(self, name):
print("这个是init方法")
self.name = name
# 重写 __new__方法
def __new__(cls, *args, **kwargs):
print("这个是new方法")
# 创建对象是python底层帮我实现,重写之后需要返回父类的创建对象的方法,不然实例不出对象
return object.__new__(cls)
m = Mycalss("DaBai") # 先进入new方法 在执行init方法
- __init__大家知道用,不做研究
- __new__方法的应用场景:重写new方法可以实现单例模式
- 所有实例化操作都是实例一个对象,节约内存
- 对象属性共用,全局化
方式一:类中重写new方法实现
class Mycalss(object):
instance = None
# 重写 __new__方法
def __new__(cls, *args, **kwargs):
# 如果 instance 为None 实例化对象,否则用第一次实例的对象
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
else:
return cls.instance
m1 = Mycalss()
m2 = Mycalss()
# id 一样 同一个对象
print(id(m1))
print(id(m2))
# 所以m1创建的属性,m2一样有
m1.name="DaBai"
print(m2.name)
方式二:单例装饰器
# 装饰器单例模式
def class_one_case(cls):
# 空字典储存 类 和 类实例(key:value)
instace = {}
def inner(*args, **kwargs):
# 如果类不在字典中实例化对象储存,否者用字典中的对象
if cls not in instace:
instace[cls] = cls(*args, **kwargs)
return instace[cls]
else:
return instace[cls]
return inner
@class_one_case
class TestClass(object): # TestClass=class_one_case(TestClass) 调用的时候执行的装饰器内部inner方法,返回实例
name = ""
def run(self):
print(self.name)
t1 = TestClass()
t2 = TestClass()
print(id(t1))
print(id(t2))
t1.name="Dabai"
# t2 就是t1 name 属性也都公共也变成"DaBai"
t2.run()
__srt__方法和__repr__方法
- __srt__ 输出的内容可以理解为是给用户看的,用户不关心是说明数据类型,只关心内容
- __repr__ 可以理解为是给开发看的,开发看到这个一眼就能确认是字符转类型
- 交互环境代码演示
>>> a = "1"
>>> print(a)
1
>>> a
'1'
>>>
- 问题思考:交互环境下print打印内容和直接输入变量,返回的内容为什么会不一样?
- 因为底层触发的魔术方法不一样
- print方法触发的__srt__方法
- 直接输出是触发的__repr__方法
- Pycharm演示
a = "123"
print(str(a)) # 123
print(format(a)) # 123
print(repr(a)) # '123'
- 重写__srt__方法和__repr__方法
- 一定要有return
- 一定要返回字符串类型
class MyStrRepr(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def __str__(self):
print("出发__str__方法")
return self.name # 不返回 或者返回的类型不是字符串的时候会报错
def __repr__(self):
print("出发__repr__方法")
return "MySrtRepr.object.name-%s" % self.gender
s = MyStrRepr("DaBai", "男")
print(s) # print 触发__str方法
str(s) # srt 触发__srt__
format(s) # format 触发__srt__
res = repr(s) # repr 触发__repr__ 程序员输出方式
print(res)
- 注意
- 1、如果__srt__方法没有重写,print、str、format方法会去触发__repr__,__repr__没有就去招父类的__srt__方法
- 2、使用repr方法时,会先找自身__repr__方法,如果没有就直接去父类里找
- 可以理解为__repr__是__str__备胎-见下图
__call__方法
- 问题一:在Python中万物皆对象,函数也是对象,为什么函数可以调用,而其他的对象不行呢?
- 如果想让类创建出来的对象,可以像函数一样被调用可以实现么?
- 那么我们只需要在类中定义__call__方法即可
# __call__ 可以被调用的方法 像函数一样加() 可以被调用,
# 实例不能被调用是因为 实例和函数底层实现的方法不一样
# 函数底层实现的call方法
def fun():
print("函数")
class My(object):
def __init__(self, name):
print("这个是init方法")
self.name = name
print("函数内部实现的方法", dir(fun)) # 实现了'__call__'
m1 = My("DaBai")
print("实例实现的方法", dir(m1)) # 没有实现__call
m1() # 被执行会报错
class My(object):
def __call__(self, *args, **kwargs):
print("__实例被执行了__")
m = My()
m() # 不会报错 会执行类中__call__方法内的代码块
- __call__方法应用小案例:利用类实现装饰器
# 类装饰器
class MyCall(object):
def __init__(self, fun_cls):
# print("这个是init方法")
self.fun_cls = fun_cls
def __call__(self, *args, **kwargs):
print("call方法")
return self.fun_cls(*args, **kwargs)
@MyCall
def fun(a): # fun = Mycall(fun) 此时的fun 是 Mycall的实例对象了,被调用时执行call方法
print("函数%s" % a)
@MyCall
class My(object): # My = Mycall(My) 此时的My 是 Mycall的实例对象了,被调用时执行call方法
def __init__(self, name):
self.name = name
print(fun) # <__main__.MyCall object at 0x0000022ECE480320> MyCall的实例对象
fun(1) # 实例被执行 执行的call方法,call方法里面执行了run()函数
print(My) # <__main__.MyCall object at 0x0000012B8FDB03C8> MyCall的实例对象
m = My("DaBai") # MyCall的实例对象执行call方法 返回 My类的实例对象
print(m) # <__main__.My object at 0x0000012B8FDB0470> My的实例对象
以上是关于魔术方法的主要内容,如果未能解决你的问题,请参考以下文章