魔术方法

Posted jiangmingbai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了魔术方法相关的知识,希望对你有一定的参考价值。


__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的实例对象

以上是关于魔术方法的主要内容,如果未能解决你的问题,请参考以下文章

PHP中的常见魔术方法功能作用及用法实例

object基础魔术方法使用代码

object基础魔术方法使用代码

python魔术方法

Python 魔术方法笔记

D15内置函数和魔术方法