雙下方法,
阿新 • • 發佈:2022-04-11
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就是所有類預設的元類!!!'''
# 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 = '清華大學'
# 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__方法 """
__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 """