Python中的魔法方法


1、什么是魔法方法?

     魔法方法就是可以給你的類增加魔力的特殊方法,如果你的對象實現(重載)了這些方法中的某一個,那么這個方法就會在特殊的情況下被 Python 所調用,你可以定義自己想要的行為,而這一切都是自動發生的。它們經常是兩個下划線包圍來命名的(比如 __init__,__lt__),Python的魔法方法是非常強大的,所以了解其使用方法也變得尤為重要!

2、__init__(self[, ...]),__new__(cls[, ...]),__del__(self)

  __init__ 構造器,當一個實例被創建的時候初始化的方法。但是它並不是實例化調用的第一個方法,__new__才是實例化對象調用的第一個方法,它只取下 cls參數,並把其他參數傳給 __init__。 __new__很少使用,但是也有它適合的場景,尤其是當類繼承自一個像元組或者字符串這樣不經常改變的類型的時候。

  __new__ 使用時注意以下四點:

1. __new__ 是在一個對象實例化的時候所調用的第一個方法
2. 它的第一個參數是這個類,其他的參數是用來直接傳遞給 __init__ 方法
3. __new__ 決定是否要使用該 __init__ 方法,因為 __new__ 可以調用其他類的構造方法或者直接返回別的實例對象來作為本類的實例,如果 __new__ 沒有返回實例對象,則 __init__ 不會被調用
4. __new__ 主要是用於繼承一個不可變的類型比如一個 tuple 或者 string
5. __new__ return的是一個構建的實例

  

  __new__實現單例模式:

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,'instance'):
            cls.instance = super(Person,cls).__new__(cls)
        return cls.instance


a = Person('p1',20)
b = Person('p2',21)
print(a == b)
#這里的打印結果是True,可見a,和b都是同一個實例
#單例作用:
#第一、控制資源的使用,通過線程同步來控制資源的並發訪問;
#第二、控制實例產生的數量,達到節約資源的目的。
#第三、作為通信媒介使用,也就是數據共享,它可以在不建立直接關聯的條件下,讓多個不##相關的兩個線程或者進程之間實現通信。
#比如,數據庫連接池的設計一般采用單例模式,數據庫連接是一種數據庫資源。

  __del__ 析構器,當實例被銷毀時調用

3、__call__(self[,args ...]),__getitem__(self,key),__setitem__(self,key,value)

  __call__ 允許一個類的實例像函數一樣被調用

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.instance = add

    def __call__(self,*args):
        return self.instance(*args)

def add(args):
    return args[0] + args[1]

a = Person('p1', 20)
print(a([1,2]))
#這里將打印 3 
#可見當創建a這個對象之后,如果定義了__call__函數則對象是可以像函數一樣調用的

  __getitem__ 定義獲取容器中指定元素的行為,相當於self[key]

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._registry = {
            'name': name,
            'age': age
        }

    def __call__(self, *args):
        return self.instance(*args)

    def __getitem__(self, key):
        if key not in self._registry.keys():
            raise Exception('Please registry the key:%s first !' % (key,))
        return self._registry[key]

a = Person('p1', 20)
print(a['name'],a['age'])
#這里打印的是 'p1' 20 
#可見__getitem__使實例可以像字典一樣訪問

  __setitem__ 設置容器中指定元素的行為,相當於self[key] = value 

4、__getattr__(self,name),__getattribute__(self,name),__setattr__(self,name,value),__delattr__(self,name),__get__(self,instance,owner),__set__(self,instance,value),__delete__(self,instance)

  __getattr__ 定義當用戶試圖訪問一個不存在屬性的時候的行為

  __setattr__ 定義當一個屬性被設置的時候的行為

  __getattribute__ 定義當一個屬性被訪問的時候的行為

  

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._registry = {
            'name': name,
            'age': age
        }

    def __getattr__(self, item):
        print("don't have the attribute ",item)
        return False

    def __setattr__(self, key, value):
        self.__dict__[key] = value

    def __getattribute__(self, item):
        #注意此處不要用 self.__dict__[item]
        #因為self.__dict__依然會被__getattribute__攔截 這樣就會陷入循環
        return object.__getattribute__(self,item)

a = Person('p1', 20)
print(a.hh)        #這里會打印 don't have the attribute hh 以及 False
a.hh = 'fdf'        #這里設置該屬性值為'fdf'
print(a.hh)           #這里將打印出 fdf

  __delattr__ 定義當一個屬性被刪除的時候的行為

  __get__  定義當描述符的值被取得的時候的行為

  __set__ 定義當描述符的值被設置的時候的行為

  __delete__ 定義當描述符的值被刪除的時候的行為

class Descriptor(object):
    def __init__(self):
        self.des = None

    def __get__(self, instance, owner):
        return instance.__dict__.get(self.des,None)

    def __set__(self, instance, value):
        instance.__dict__[self.des] = value


class Person(object):
    des = Descriptor() #這里的Descriptor就是一個描述符類

    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._registry = {
            'name': name,
            'age': age
        }


a = Person('p1', 20)
a.des = 10    #這里會調用Descriptor的__set__方法
print(a.des)   #這里會調用Descriptor的__get__方法

  關於描述符有疑惑的朋友可以自己百度也可參考這篇文章 http://www.geekfan.net/7862/ ,網上也有很多相關的文章,這里的重點不是描述符所以這里不會有關於描述符過多的解釋!

  

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM