Python 部分魔术方法Magit Method

魔术方法不过是一种特殊的方法,它不需要人工调用,在特定的时刻会自动执行。
比如像a-b其实"魔术"般地执行了a.__sub__(b),像__sub__这样的以"__"双下划线包起来的方法,都统称魔术方法。

魔术方法的分类

魔法方法大致可以分为两类:与运算符相关以及与运算符无关的,而两大类下还有很多小类
1、与运算符相关的魔术方法很简单,即触发条件为运算符
Python 部分魔术方法Magit Method_第1张图片
2、而与运算符无关的才是我们需要着重关心的地方,也就是说以下才是你能秀起来的魔术方法
Python 部分魔术方法Magit Method_第2张图片

实例创建和销毁

  • Python中构造一个实例其实分为两步:__new__用来创建类并返回这个类的实例, 然后__init__将传入的参数来初始化该实例,可以说这两个方法共同构成了"构造函数"

1、__init__通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后,所以不需要返回值。它是实例级别的方法。
2、__new__通常用于控制生成一个新实例的过程,所以必须要有返回值。它是类级别的方法

使用__new____init__来实现单例模式:

import threading
class Singleton(object):
    _instance_lock = threading.Lock()

	#初始化实例
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

	#创建类实例
    def __new__(cls, arg1, arg2):
        with Singleton._instance_lock:
            if not hasattr(Singleton, "_instance"):
				#由于重写了__new__所以要调用父类的方法达到原本的效果
                Singleton._instance = object.__new__(cls) 
        return Singleton._instance

obj1 = Singleton(1,1)
obj2 = Singleton(2,2)  #会覆盖obj1初始化的属性
print(obj1 is obj2)    #true
  • 在对象生命周期调用结束时,__del__方法会被调用,可以理解为“构析函数” :del obj <-> obj.__del__()

属性管理

  • __getattr__(self,name):获取一个不存在的属性时执行的方法。

  • __setattr__(self,name,value):设置一个属性时执行的方法。

  • __delattr__(self,name):删除一个属性时执行的方法。

  • __getattribute__(self,name):当该类的属性被访问时执行的方法。

class A(object):
    def __getattr__(self,name):
        print('__getattr__')   #没有在父类中进行定义
    def __setattr__(self,name,value):
        print('__setattr__')   
        super(A).__setattr__(name,value)  
    def __delattr__(self,name):
        print('__delattr__')
        return super(A).__delattr__(name)
    def __getattribute__(self,name):
        print('__getattribute__')
        return super(A).__getattribute__(name)
>>> a = A()
>>> a.name
__getattribute__       #只要访问属性就会先调用 __getattribute__ 
__getattr__            #由于当前没有name属性,则调用__getattr__
>>> a.name = 'jod'     
__setattr__
>>> a.name
__getattribute__
'jod'
>>> del a.name
__delattr__
>>> a.name
__getattribute__   
__getattr__ 
  • __dict__:返回一个字典,存放了实例或类相关的属性或方法

注意:在__setattr__时,不能直接使用self.name = value ,会造成死循环,因为在执行self.name = value的时候又会调用本身,无限循环下去,可以调用父类的方法,或者使用__dict__实现:

    def __setattr__(self,name,value):
        print('__setattr__')
        self.__dict__[name] = value

实例的__dict__仅存储与该实例相关的实例属性,正是因为实例的__dict__属性,每个实例的实例属性才会互不影响。

类的__dict__存储所有实例共享的变量和函数(类属性,方法等),类的__dict__并不包含其父类的属性。

dir()是Python提供的一个API函数,dir()函数会自动寻找一个对象的所有属性(包括从父类中继承的属性);__dict__是dir()的子集,dir()包含__dict__中的属性

属性描述符

  • __set__(self,instance,value):当作一个描述符(属性)被赋值时执行的方法

  • __get__(self,instance,owner):当作一个描述符(属性)被获取时执行的方法

  • __delete__(self,instance):当作一个描述符(属性)被删除时执行的方法

这一部分涉及到描述器的知识,在这里稍作介绍,一个类中只要定义了__get____set____delete__中的一个或几个,这个类的实例就可以叫做一个描述器。链接

描述器是是@property、super、静态方法、类方法、甚至属性、实例背后的实现机制。其实是定义了一些查找规则。

class A(object):
    def __get__(self, instance, owner):
        print('__get__', 'self:', self, 'instance:', instance, 'owner:', owner)

    def __set__(self, instance, value):
        print('__set__', 'self:', self, 'instance:', instance, 'value:', value)

    def __delete__(self, instance):
        print('__delete__', 'self:', self, 'instance:', instance)

class B(object):
    # 一个函数在实例化的时候调用了其他类的对象
    # 把A类的对象在B实例化的时候当作描述符(属性)进行赋值,这个name就是一个描述器的实例
    def __init__(self,name):
    	self.name = A()
>>> b = B()
>>> b.name
__get__ self: <__main__.A object at 0x1134247f0> instance: <__main__.B object at 0x113411d68> owner: 
>>> b.name = 'abc'
__set__ self: <__main__.A object at 0x1134247f0> instance: <__main__.B object at 0x113411d68> value: abc
>>> del b.name
__delete__ self: <__main__.A object at 0x1134247f0> instance: <__main__.B object at 0x113411d68>
>>>

集合相关

这一部分的魔术方法提供了自定义容器的"接口规范"

  • __getitem__:获取容器中的元素,比如mylist[1]

  • __setitem__:设置容器中的元素,比如mylist[2] = ‘hello’

  • __delitem__:删除容器中的某个元素,比如 del mylist[2]

  • __len__:获取集合的长度,len()时被调用

  • __contains__:查询是否包含指定元素,如mylist.contains(1)

在collections模块中已经有了很多如Counter、OrderedDict这样的高级集合,必要时可以结合业务特性自定义容器

上下文管理

  • __enter__(self)
    定义当使用 with 语句时的初始化行为__enter__ 的返回值被 with 语句的目标或者 as 后的名字绑定

  • __exit__(self, exc_type, exc_value, traceback)
    定义当一个代码块被执行或者终止后上下文管理器应该做什么
    一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作

with所求值的对象必须要有这两个方法

紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。

class Sample(object):
    def __enter__(self):
        print "In __enter__()"
        return "Foo"

    def __exit__(self, type, value, trace):
        print "In __exit__()"

def get_sample():
    return Sample()

with get_sample() as sample:
    print "sample:", sample
    
'''
流程:
1、enter__()方法被执行
2、enter__()方法返回的值 - 这个例子中是"Foo",赋值给变量'sample'
3、执行代码块,打印变量"sample"的值为 "Foo"
4、exit__()方法被调用
'''
In __enter__()
sample: Foo
In __exit__()

你可能感兴趣的:(python)