python 面向物件(4)
阿新 • • 發佈:2022-04-11
python 面向物件(4)
反射的實際案例:
# 利用面向物件編寫系統的終端功能 class WinCmd(object): def ls(self): print('windows系統正在執行ls命令') def dir(self): print('windows系統正在執行dir命令') def cd(self): print('windows系統正在執行cd命令') class LinuxCmd(object): def ls(self): print('Linux系統正在執行ls命令') def dir(self): print('Linux系統正在執行dir命令') def cd(self): print('Linux系統正在執行cd命令') obj = WinCmd() obj1 = LinuxCmd() """反射提供了一種不需要考慮程式碼的前提下 操作資料和功能""" def run(obj): while True: cmd = input('請輸入您的指令>>>:') if hasattr(obj, cmd): func_name = getattr(obj, cmd) func_name() else: print('cmd command not found') run(obj1) run(obj)
面向物件雙下方法:
雙下str:
#__str__ 物件被執行列印(print、前端展示)操作的時候自動觸發 該方法必須返回字串型別的資料 很多時候用來更加精準的描述物件 #程式碼示例: class Course(object): def __init__(self, name, price): self.name = name self.price = price def __str__(self): return "func is __str__ ,課程:{},價格:{}".format(self.name, self.price) # python = Course("English", 250) print(python) # func is __str__ ,課程:English,價格:250 print("%s" % (python)) # func is __str__ ,課程:English,價格:250 print([python]) #[<__main__.Course object at 0x0000023A660794E0>]
雙下str和雙下repr區別
# 如果str存在,repr也存在 那麼print(obj)和使用字串格式化format,%s這兩種方式 呼叫的都是__str__ 而repr(obj)和%r格式化字串,都會呼叫__repr__ # 如果str不存在,repr存在 那麼print(obj),字串格式化format,%s,%r 和repr(obj)都呼叫__repr__ # 如果str存在,repr不存在 那麼print(obj)和使用字串格式化format,%s這兩種方式 呼叫的都是__str__ repr(obj)和%r格式化字串 都會打印出記憶體地址
雙下del:
#__del__
物件被執行(被動、主動)刪除操作之後自動執行
# 程式碼示例:
class A(object):
def __init__(self, name,age):
self.name = name
self.age = age
def __del__(self):
print("hhhh")
f = A("jason", 18)
print(f.__dict__) # {'name': 'Tom', 'age': 45}
del f.name
'''只和del obj語法有關係 在執行del obj之前會來執行一下__del__中的內容'''
print(f.__dict__)
#{'age': 18} hhhh
雙下getattr, setattr, delattr, getattribute:
# __getattr__
物件查詢不存在名字的時候自動觸發
#__setattr__
物件在執行新增屬性操作的時候自動觸發 >>> obj.變數名=變數值
#__getattribute__
只要物件查詢名字無論名字是否存在都會執行該方法
如果類中有__getattribute__方法 那麼就不會去執行__getattr__方法
#程式碼示例:
class A(object):
def __setattr__(self, key, value):
print("執行了__setattr__方法")
print(key, value)
def __getattr__(self, item):
print("執行了__getattr__方法")
def __delattr__(self, item):
print("執行了__delattr__方法")
def __getattribute__(self, item):
print("執行了__getattribute__方法")
f = A()
f.name = 'jason' # 將會執行__setattr__
f.name # 將會執行__getattribute__或者__getattr__ 當兩者都存在的時候 先執行__getattribute__ 如果兩者都沒有 報錯
del f.name # 將會執行__delattr__
雙下call:
#__call__
物件被加括號呼叫的時候自動觸發
#程式碼示例:
class A(object):
def __init__(self, name,):
self.name = name
def __call__(self, *args, **kwargs):
print("name " + self.name)
f = A("Tom")
f() # name Tom
A("jason",)() # name Mack
''' 物件+()就會呼叫__call__()方法'''
雙下enter,exit:
#__enter__
物件被執行with上下文管理語法開始自動觸發
該方法返回什麼as後面的變數名就會得到什麼
#__exit__
物件被執行with上下文管理語法結束之後自動觸發
# 程式碼示例:
class A(object):
def __enter__(self):
print("開始的時候觸發")
return 'zz'
def __exit__(self, exc_type, exc_val, exc_tb):
print('結束的時候觸發')
with A() as f:
print('hhaha')
print(f) #f 是__enter__返回的值 沒有返回值預設是None
#輸出結果:
開始的時候觸發
hhaha
結束的時候觸發
zz
雙下方法練習:
1.讓字典具備句點符查詢值得功能
class MyDict(dict):
def __getattr__(self, item):
return self.get(item)
def __setattr__(self, key, value):
self[key] = value
'''要區別是名稱空間的名字還是資料k:v鍵值對'''
obj = MyDict({'name':'jason','age':18})
# 1.具備句點符取v
print(obj.name)
print(obj.age)
# 2.具備句點符設k:v
obj['gender'] = 'male'
obj.pwd = 123 # 給字典名稱空間新增名字 不是資料k:v
print(obj)
2.執行不報錯
#補全程式碼使其不報錯:
class Context:
pass
with Context() as ctx:
ctx.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()
元類
# 元類的介紹
Python當中萬物皆物件,我們用class關鍵字定義的類本身也是一個物件,負責產生該物件的類稱之為元類,元類可以簡稱為類的類
元類的主要目的是為了控制類的建立行為
class MyClass(object):
pass
obj = MyClass()
print(type(obj))
print(type(MyClass)) # <class 'type'>
class Student:
pass
print(type(Student)) # <class 'type'>
class Teacher(MyClass):
pass
print(type(Teacher)) # <class 'type'>
'''type是Python的一個內建元類,用來直接控制生成類,在python當中任何class定義的類其實都是type類例項化的結果。
只有繼承了type類才能稱之為一個元類,否則就是一個普通的自定義類,自定義元類可以控制類的產生過程,類的產生過程其實就是元類
的呼叫過程'''
產生類的兩種形式
一個類由三大組成部分,分別是
1、類名class_name
2、繼承關係class_bases
3、類的名稱空間class_dict
#方式1:使用class關鍵字(python直譯器轉化為第二種)
class A(object):
pass
print(A) # <class '__main__.A'>
#方式2:通過type關鍵字,依次傳入以上三個引數即可
type(類名,父類,類的名稱空間)
res = type('A', (), {})
print(res) # <class '__main__.A'>
'''
學習元類的目的
元類能夠控制類的建立 也就意味著我們可以高度定製類的行為
eg:掌握了物品的生產過程 就可以在過程中做任何的額外操作'''
元組基本使用
#要求類的名字必須首字母大寫
"""元類是不能通過繼承的方式直接指定的"""
需要通過關鍵字引數的形式修改
class C1(metaclass=MyTypeClass):
pass
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 C1(metaclass=MyTypeClass):
school = '清華大學'
元組的進階操作
1.回想__call__方法
物件加括號會自動執行產生該物件的類裡面的__call__,並且該方法返回什麼物件加括號就會得到什麼
推導:類加括號會執行元類的裡面的__call__該方法返回什麼其實類加括號就會得到什麼
"""類裡面的__init__方法和元類裡面的__call__方法執行的先後順序"""
class MyTypeClass(type):
def __call__(self, *args, **kwargs):
print('__call__ run')
super().__call__(*args, **kwargs)
class MyClass(metaclass=MyTypeClass):
def __init__(self, name):
print('__init__ run')
self.name = name
obj = MyClass('jason')
# 定製物件的產生過程
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('jason')
obj2 = MyClass(name='jason')
"""
如果你想高度定製類的產生過程
那麼編寫元類裡面的__init__方法
如果你想高度定製物件的產生過程
那麼編寫元類裡面的__call__方法
"""
雙下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
"""