1. 程式人生 > 其它 >雙下方法,

雙下方法,

1. 面向物件的雙下方法

  1. __str__方法

class MyClass(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def __str__(self):
        """
        物件被執行列印(print、前端展示)操作的時候自動觸發
            該方法必須返回字串型別的資料
        很多時候用來更加精準的描述物件
        """
        print('我到底什麼時候觸發')
        
return '物件:%s' % self.name obj = MyClass('dragon') print(obj)

 

 

   

  2. __del__方法

class MyClass(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def __del__(self):
        """物件被執行(被動、主動)刪除操作之後自動執行"""
        print("del啥時候執行")
        pass


obj = MyClass('
dragon') del obj

  

  3. __getattr__方法

class MyClass(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def __getattr__(self, item):
        """物件查詢不存在名字的時候自動觸發"""
        print('__getattr__方法', item)
        return '不好意思 沒有%s這個名字' % item

obj = MyClass('
dragon') print(obj.age)

 

 

  

  4. __setattr

class MyClass(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def __setattr__(self, key, value):
        """物件在執行新增屬性操作的時候自動觸發>>>obj.變數名=變數值"""
        print('__setattr__方法')
        print(key, value)
        if key == 'age':
            raise Exception('你沒有資格擁有age')
        if not key.islower():
            raise Exception('名字只能小寫')
        super().__setattr__(key, value)

obj = MyClass('dragon')
obj.age = 18

 

 

   

  5.__call__方法

class MyClass(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def __call__(self, *args, **kwargs):
        """物件被加括號呼叫的時候自動觸發"""
        print('__call__方法', args, kwargs)
        return '嘿嘿嘿'

obj = MyClass('dragon')
obj(123, age=123)

 

 

  6.__enter__與__exit__方法

class MyClass(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def __enter__(self):
        """物件被執行with上下文管理語法自動觸發"""
        print('__enter__方法')

    def __exit__(self, exc_type, exc_val, exc_tb):
        """物件被執行with上下文管理語法結束之後自動觸發"""
        print('__exit__方法')

obj = MyClass('dragon')
with obj as f:
    print(222)

 

 

  8.__getattribute__

class MyClass(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def __getattribute__(self, item):
        """
        只要物件查詢名字無論名字是否存在都會執行該方法
            如果類中有__getattribute__方法 那麼就不會去執行__getattr__方法
        """
        print('__getattribute__方法', item)
        return item

obj = MyClass('dragon')
print(obj.name)
print(obj.age)

 

 

2. 筆試題講解

補全下列程式碼 使其執行不報錯
    """
    class Context:
            pass
    with Context() as ctx:
            ctx.do_something()
    """

1. 使用到with方法,那麼類中必須有__enter__此方法
2. 使用到__enter__方法就需要配套使用__exit__方法
 class Context:
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

with Context() as ctx:
    ctx.do_something()
執行:報錯
錯誤資訊:
Traceback (most recent call last):
  File "D:/pycharm project/pythonProject/1.py", line 11, in <module>
    ctx.do_something()
AttributeError: 'Context' object has no attribute 'do_something'

檢視錯誤資訊發現,物件中沒有do_something方法,那麼我們就需要增加do_something方法
最後結果為

class Context():
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

    def do_something(self):
        pass


with Context() as ctx:
    ctx.do_something()

 

3. 元類簡介

 

# 元類
# 元類其實就是產生類的類


print(type(123))
print(type([12, 33, 44]))
print(type({'name': 'jason', 'pwd': 123}))


# type檢視的其實是當前物件所屬的類名稱
class MyClass(object):
    pass


obj = MyClass()
print(type(obj))
print(type(MyClass))


class Student:
    pass


print(type(Student))


class Teacher(MyClass):
    pass


print(type(Teacher))
'''type就是所有類預設的元類!!!'''

 

 

4. 產生類的兩種表現形式

# 1.class關鍵字
class C1(object):
    pass

print(C1)

# 2.type元類
# type(類名, 父類, 類的名稱空間)
res = type('C2', (), {})
print(res)

"""
學習元類的目的
    元類能夠控制類的建立 也就意味著我們可以高度定製類的行為

    類的產生過程目前還比較懵       元類裡面的__init__方法
    物件的產生過程呢               類裡面的__init__方法
"""

 

 

5. 元類的基本使用

"""元類是不能通過繼承的方式直接指定的"""
# 需要通過關鍵字引數的形式修改


class MyTypeClass(type):
    def __init__(cls, cls_name, cls_bases, cls_dict):
        print(cls, cls_name, cls_bases, cls_dict)
        if not cls_name.istitle():
            raise Exception("類名的首字母必須大寫 你個SD")
        super().__init__(cls_name, cls_bases, cls_dict)


class School1(metaclass=MyTypeClass):
    school = '清華大學'


class School2(metaclass=MyTypeClass):
    school = '清華大學'

 

 

6. 元類進階操作

# 1.回想__call__方法
#     物件加括號會自動執行產生該物件的類裡面的__call__,並且該方法返回什麼物件加括號就會得到什麼
#   推導:類加括號會執行元類的裡面的__call__該方法返回什麼其實類加括號就會得到什麼
"""類裡面的__init__方法和元類裡面的__call__方法執行的先後順序"""

# 定製物件的產生過程
class MyTypeClass(type):
    def __call__(self, *args, **kwargs):
        print('__call__ run')
        print(args,kwargs)
        if args:
            raise Exception('必須全部採用關鍵字引數')
        super().__call__(*args, **kwargs)


class MyClass(metaclass=MyTypeClass):
    def __init__(self, name):
        print('__init__ run')
        self.name = name

    """強制規定:類在例項化產生物件的時候 物件的獨有資料必須採用關鍵字引數"""


obj1 = MyClass('dragon')
obj2 = MyClass(name='dragon')
"""
如果你想高度定製類的產生過程
    那麼編寫元類裡面的__init__方法
如果你想高度定製物件的產生過程
    那麼編寫元類裡面的__call__方法
"""

 

 

7. 雙下new方法

__new__用於產生空物件(類)            骨架
__init__用於例項化物件(類)        血肉

"""
注意:並不是所有的地方都可以直接呼叫__new__ 該方法過於底層
如果是在元類的__new__裡面 可以直接呼叫
class Meta(type):
      def __new__(cls, *args, **kwargs):
          obj = type.__new__(cls,*args,**kwargs)
          return obj

如果是在元類的__call__裡面 需要間接呼叫
class Mate(type):
    def __call__(self, *args, **kwargs):
         obj = object.__new__(self) # 建立一個空物件
         self.__init__(obj,*args,**kwargs) # 讓物件去初始化
         return obj
"""