PY => Python__黑魔法__

類的繼承

類繼承有三種調用方式,實際上是 有區別 的,聽我慢慢道來
class A:
    def say(self, name):
        print(f'Im {name}')
class B(A):
    def say(self, name):
    # 第一種:父類.方法(self, 參數) 直接調用
        A.say(self, name)    
        
    def say(self, name):
    # 第二種:super().方法(參數)    直接調用
    # 在誰的類下調用super,就找此類對應 mro()的下一個,就是要繼承的
         super().say(name)
         
    def say(self, name):
    # 第三種:super(B, self).方法(參數)
    # 找類名 對應的 mro()的下一個,就是 繼承的,通常寫自己的類名
        super(B, self).say(name)

B().say('Tom')

上下文管理器

"""
    上下文管理器能夠用兩種方式實現:
"""
     方式1:經過類來實現
        主要實現兩種協議
            1. __enter__(self)
            2. __exit__(self, *args, **kwargs)
                
        class A():
            def __init__(self, name):
                self.name = name
            def __enter__(self):
                print('進入')
                return self
            def __exit__(self, *args, **kwargs):
                print('退出')
                return True
        
        with A('Tom') as a:
            print(a.name)

    方式2:經過函數來實現
        from contextlib import contextmanager
        @contextmanager
        def f():
            print('開始')    # yield 以前 對應 with f()
            yield '中間'     # yield 的值 就是    as 以後的值
            print('結束')    # yield 以後 對應 print(str1) 這個語句體
        
        with f() as str1:
            print(str1)
        ------------------Output----------------------
        開始
        中間
        結束

屬性描述符-property-setter

class A:
@property
def name(self):
    return '123'
@name.setter
def name(self, value):
    self.age=value

a = A()
print(a.name)
a.name = '456'
print(a.age)

__init__()

實例化對象時自動調用,這裏先賣個關子,見下面 __new__()

__call__()

"""
   對象當作函數執行的時候會自動調用 __call__()
"""
class A():
    pass
a = A()    # 此處自動調用了 __init__()
a()        # 此處自動調用了 __call__()

__str__()

"""
    對對象進行print操做的時候 會自動調用 __str__()
"""
class A:
    def __str__(self):
        return '5'
a = A()
print(a)  # 此處自動調用了 __str__()

__new__()

"""
    上面說過 __init__()是實例化對象的時候自動調用,在它以前還隱式調用了 __new__()
    __new__返回的是什麼,對象就是什麼
"""
In [2]: class A:
   ...:   def __new__(self):
   ...:     print('__new__')    # 初始化對象只調用 __new__ 而不調用 __init__
   ...:     return 1
   ...:   def __init__(self):
   ...:     print(2)
   ...: print(A())
    __new__
    1

__setattr__() 和 __getattr__() 和 __delattr__()

"""
    __setattr__():=號 屬性賦值 會自動調用此方法 
    __getattr__():.號 屬性取值 會自動調用此方法    # 注:找不到屬性纔會調用此方法
    __delattr__():del 屬性刪除 會自動調用此方法
"""
class A:

    def __init__(self, name):
        self.name = name        # 賦值操做就會調用 __setattr__()
    
    def __setattr__(self, name, value):
        print(f'{name}:{value}')
    def __getattr__(self, name):
        print(name)
    def __delattr__(self,name):
        print('del了')
        
a = A('Jack')    # 調用了 __init__
a.name = 'Tom'   # 賦值操做再次調用 __setattr__()
a.name           # 取值操做調用 __getattr__()
---------------------output---------------------
name:Jack
name:Tom
name
del了

__getattribute__()

"""
    和 __getattr__() 同樣,只不過 __getattribute__最早調用,並攔截了 __getattr__()
"""
class A:
    def __init__(self):
        self.name = 1
    def __getattr__(self,x,*args, **kwargs):
        print(456)
    def __getattribute__(self, x):
        print(123)

a = A()
a.aaaaaa
-----------output---------------
123

__getitem__()

"""
    對對象進行 切片、索引、遍歷 等 會自動調用此方法
"""
class A:
def __getitem__(self,x,*args, **kwargs):
    return x

a = A()
觸發方式1: 若是直接索引此對象,那麼索引值就會傳遞到上面 x 看成參數
    print(a[5])
    >> 5
觸發方式2: 若是直接切片此對象,那麼slice對象 就會傳遞到上面 x 看成參數
    print(a[1:5])
    >> slice(1, 5, None)
觸發方式3: 若是for循環迭代此對象,那麼 上面的 x 每次將會被賦予從零開始 自增1的天然整數
    for x in a:
        print(x)
    >> 0,1,2,3,4....................

__init_subclass__()

"""
    被繼承的類 會自動調用__init_subclass__ 
"""
class A:
    def __init_subclass__(self):
        print('我被繼承了')

class B(A):
    pass

__base__()

"""
    查看基類
"""
class A:
    pass
class B(A):
    pass
print(B.__base__)
-----------output---------------
<class '__main__.A'>

__contains__()

"""
    xx in xx 就會自動調用  __contains__()
"""
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息