1. 程式人生 > 實用技巧 >我的python學習之路-裝飾器/property/反射

我的python學習之路-裝飾器/property/反射

本節內容:

  一、裝飾器

    1.1裝飾器的原型

    1.2 @語法糖的使用

    1.3 裝飾器的巢狀

    1.4 帶有引數的裝飾器

    1.5 帶有函式返回值的裝飾器

    1.6 類裝飾器

    1.7 帶有引數的裝飾器

    1.8 帶有引數的類裝飾器

  二、類中的方法

    2.1 類中方法的分類

  三、property

    3.1 應用方式1

    3.2 應用方式2

  四、反射

    1、反射類中物件的成員

      4.1.1hasattr()

      4.1.2 getattr()

      4.1.3 setattr()

      4.1.4 delattr()

    2、反射模組中的屬性

一、裝飾器

1. 裝飾器的原型

def kuozhan(_func):
    def newfunc():
        print("有房有車的身份:")
        _func()
        print("到處張揚:")
    return newfunc
    
def func():
    print("我是高富帥")
    
func=kuozhan(func)
func()

2 @語法糖的使用

@符的作用:
(1)自動把@裝飾器下面的函式當成引數傳遞給裝飾器
(2)將裝飾器返回給新的函式替換舊函式,完成拓展功能

def
kuozhan(_func): def newfunc(): print("美麗善良") _func() print("妝容精緻") return newfunc @kuozhan def func(): print("我是白富美") print("------------------") func() # newfunc func = kuozhan(func)= newfunc

3.裝飾器的巢狀

def kuozhan1(_func):
    def newfunc():
        
print("西裝革履1") _func() print("皮鞋鋥亮2") return newfunc def kuozhan2(_func): def newfunc(): print("美麗善良3") _func() print("妝容精緻4") return newfunc @kuozhan2 @kuozhan1 def func(): print("我是屌絲.....5") func() ## 31524

4. 帶有引數的裝飾器

原函式有幾個引數,新函式就有幾個引數;

def kuozhan(_func):
    def newfunc(who,where,do):
        print("結婚之前,一日三餐")
        _func(who,where,do)
        print("結婚之後,一日8碗大米飯,為了家庭,日漸消瘦")
    return newfunc

@kuozhan
def func(who,where,do):
    print("{}在{}吃{}".format(who,where,do))
    
func("李雅琪","電影院","榴蓮")
#結婚之前,一日三餐
#李雅琪在電影院吃榴蓮
#結婚之後,一日8碗大米飯,為了家庭,日漸消瘦

5、帶有函式返回值的裝飾器

引數與返回值與原函式保持一致

 1 def kuozhan(_func):
 2     def func(*args,**kwargs):
 3         print("下面是一線城市建築介紹")
 4         lst=_func(*args,**kwargs)
 5         print("介紹完畢")
 6         return lst
 7     return func
 8 
 9 
10 @kuozhan
11 def func(*args,**kwargs):
12     strvar=""
13     dic={"bj":"北京","sh":"上海","gz":"廣州","sz":"深圳"}
14     lst=[]
15     i=0
16     for k,v in kwargs.items():
17         if k=="bj":
18             strvar=dic[k]+"的地標建築是"+v+""+args[i]
19         elif k=="sh":
20             strvar=dic[k]+"的地標建築是"+v+""+args[i]
21         elif k=="gz":
22             strvar=dic[k]+"的地標建築是"+v+""+args[i]
23         elif k=="sz":
24             strvar=dic[k]+"的地標建築是"+v+"坐落在"+args[i]
25         else:
26             strvar=k+"查無此出"
27         i+=1
28         lst.append(strvar)
29     return lst
30         
31     
32 res=func("皇帝的宮殿","電視訊號塔","中國第一","深圳河",bj="故宮",sh="明珠塔",gz="廣州塔",sz="地王大廈")
33 
34 print(res)
View Code

6、類裝飾器

 1 class KuoZhan():
 2     def kuozhan(_func):
 3         def newfunc():
 4             print("沒有女朋友之前 .. 快樂的,無拘無束的,拖拖拉拉,很頹廢,很狼狽,很自戀")
 5             _func()
 6             print("有女朋友之後....很怕黑,愛自拍,換個iphone18,照片都是他")
 7         return  newfunc
 8     
 9     def __call__(self,_func):
10         return self.kuozhan1(_func)
11 
12     
13     def kuozhan1(delf,_func):
14         def newfunc():
15             print("沒有女朋友之前 .. 快樂的,無拘無束的,拖拖拉拉,很頹廢,很狼狽,很自戀")
16             _func()
17             print("有女朋友之後....很怕黑,愛自拍,換個iphone18,照片都是他")
18         return  newfunc
19     
20         
21 ### 方法一
22 @KuoZhan.kuozhan
23 def func():
24     print("單身進行時....")
25 
26 func()
27 
28 ### 方法二
29 @KuoZhan()
30 def func():
31     print("單身進行時....")
32 
33 func()
View Code

@KuoZhan() 先去執行KuoZhan() 返回物件之後,使用@符發動技能
obj = 類() # 例項化物件

@obj
def func():
  pass

@符傳送技能
  (1) 把func當成引數傳遞給obj => obj(func)
  (2) 把返回的新函式替換舊函式

把物件當成函式呼叫時,自動觸發魔術方法__call__

7、帶有引數的裝飾器

 1 def outer(num):
 2     def kuozhan(_func):
 3         def newfunc1(self):
 4             print("廁所前,蓬頭垢面")
 5             _func(self)
 6             print("廁所後,光彩亮麗")
 7         def newfunc2(self):
 8             print("遊戲前,瘋狂送人頭")
 9             _func(self)
10             print("遊戲後,大殺特殺..")
11         if num ==1:
12             return newfunc1
13         elif num ==2:
14             return newfunc1
15         elif num==3:
16             return "我是最強王者"
17     return kuozhan
18     
19 class MyClass():
20     @outer(1)
21     def func1(self):
22         print("上廁所,來也匆匆,去也匆匆")
23     @outer(2)
24     def func2(self):
25         print("上廁所,上前一小步,文明一大步")
26     @outer(3)
27     def func3(self):
28         print("尿不到坑裡,說明你短")
29 
30         
31 obj =MyClass()
32 obj.func1()
33 obj.func1()
34 ##把方法變屬性
35 print(obj.func3)
View Code

8 、帶有引數類裝飾器

1.當引數為1時,為MyClass 新增屬性和方法
2.當引數為2時,為MyClass 中的run方法變成屬性

 1 class KuoZhan():
 2     ad="程式設計師,我們不生產程式碼,我們只做程式碼的搬運工"
 3     def money(self):
 4         print("程式設計師,基本工資12000,一行程式碼一塊錢")
 5     def __init__(self,num):
 6         self.num = num
 7     def __call__(self,cls):
 8         if self.num==1:
 9             return self.kuozhan1(cls)
10         elif self.num==2:
11             return self.kuozhan2(cls)
12     def kuozhan1(self,cls):
13         def newfunc():
14             cls.ad=self.ad
15             cls.money=self.money
16             return cls()
17         return newfunc
18     def kuozhan2(self,cls):
19         def newfunc():
20             if "run" in cls.__dict__:
21                 cls.run=cls.run()                
22                 return cls()
23         
24         return newfunc
25 
26 @KuoZhan(1)
27 class  MyClass():
28     def run():
29         return "亢龍有悔"
30 
31 obj =MyClass()
32 print(obj.ad)
33 obj.money()
34 
35 @KuoZhan(2)
36 class  MyClass():
37     def run():
38         return "亢龍有悔"
39 
40 
41 obj =MyClass()
42 print(obj.run)
View Code

二、類中的方法

1、類中的方法的分類

  1. 無參方法:類中的無參方法只能用類來呼叫
  2. 繫結方法:(1) 繫結到物件,物件呼叫類中成員方法時,自動傳遞物件引數
  3. 繫結方法 (2) 繫結到類,物件或者類呼叫類中的成員方法時,自動傳遞類引數
  4. 靜態方法:無論物件還是引數,系統都不會傳遞任何引數
 1 class Cat():
 2     ###無參方法:類中的無參方法只能用類來呼叫
 3     def patree():
 4         print("小貓會爬樹")
 5     ### 繫結方法:(1) 繫結到物件,物件呼叫類中成員方法時,自動傳遞物件引數
 6     def eatfish(self):
 7         print("小貓喜歡吃魚")
 8     ### 繫結方法 (2) 繫結到類,物件或者類呼叫類中的成員方法時,自動傳遞類引數
 9     @classmethod
10     def sleep(cls):
11         print(cls,type(cls))
12         print("小貓愛睡覺")
13     ## 靜態方法:無論物件還是引數,系統都不會傳遞任何引數
14     @staticmethod
15     def zhualaoshu():
16         print("小貓愛抓老鼠")
17     
18 
19 obj = Cat()
20 
21 ## 無參方法
22 # obj.patree() # error
23 Cat.patree()
24 
25 ###繫結方法: 繫結到物件
26 obj.eatfish()
27 Cat.eatfish(obj)
28 
29 ###繫結方法: 繫結到類
30 obj.sleep() # print(obj.__class__)
31 Cat.sleep() # 推薦
32 
33 ## 靜態方法
34 obj.zhualaoshu()
35 Cat.zhualaoshu()
View Code

三、property

作用:可以把方法變成屬性,動態的控制了該屬性的獲取,設定,刪除三個操作

獲取屬性時自動觸發裝飾器@property
設定屬性時自動觸發裝飾器@username.setter
刪除屬性時自動觸發裝飾器@username.deleter

要求:使用username時,獲取 設定 刪除 函式名必須一致
在函式中去做相應操作

1、應用方式1

 1 class MyClass():
 2     def __init__(self,name):
 3         self.name = name
 4 
 5     @property
 6     def username(self):
 7         return self.name
 8     
 9     @username.setter
10     def username(self,val):
11         self.name=val
12         
13     @username.deleter
14     def username(self):
15         pass
16         # del self.name
17             
18         
19 obj = MyClass("張銀")
20 
21 # 獲取元素
22 print(obj.username)
23 
24 # 設定元素
25 obj.username="家營和"
26 print(obj.name)
27 print(obj.username)
28 
29 ## 刪除元素
30 del obj.username
31 print(obj.username)
View Code

2、應用方式2

 1 class MyClass():
 2     def __init__(self,name):
 3         self.name=name
 4     ## 獲取元素
 5     def get_username(self):
 6         return self.name
 7         
 8     ## 設定元素
 9     def set_username(self,val):
10         self.name=val
11         
12     ## 刪除元素    
13     
14     def del_username(self):
15         del self.name
16     
17     #順序必須按照:獲取方法 -> 設定方法 ->刪除方法
18     username= property( get_username,set_username,del_username)    
19         
20     
21 # 例項化物件 
22 obj = MyClass("黃常見")
23 print(obj.name)
24 
25 ### 獲取元素username 觸發 get_username方法
26 print(obj.username)
27 
28 ### 設定成員usern 觸發set_username方法
29 obj.username ="耿澤師"
30 print(obj.username)
31 
32 ### 刪除成員username 觸發del_username
33 del obj.username
34 # print(obj.username)
View Code

四、反射

概念: 通過字串去操作類物件 或者 模組中的屬性方法

1、反射類中物件的成員

class Children():
    age=1
    def __init__(self,name):
        self.name=name
        
    def skin(self):
        print("孩子面板的顏色取決於人的父母")
    def eye(self):
        print("小孩眼睛的顏色是血輪眼")
    def weight(self):
        print("小孩的體重不超過一百斤")
    def __eat(self):
        print("小孩只能喝奶")
        
obj= Children("小明")

1)、hasattr() 檢測物件/類是否有指定的成員

 判斷的依據:檢視是否可以被呼叫,返回True與False

res = hasattr(obj,"name")
res  = hasattr(obj,"skin")
print(res)
res = hasattr(Children,"name") # False
res =hasattr(Children,"skin") # True
print(res)

(2) getattr() 獲取物件/類成員的值

res = getattr(obj,"name")
##getattr(類/物件,成員.'預設值防止報錯')
res = getattr(obj,"name11","設定友好提示,防止報錯")
print(res)
## 通過類來反射[反射出來的是普通函式]
func= getattr(Children,"skin")
print(func,type(func))
func(obj)
### 通過物件反射[反射出來的是繫結方法]
func= getattr(obj,"skin")
print(func,type(func))
func()

(3)setattr() 設定物件/類成員的值

setattr(obj,"sex","男性")
print(obj.sex)

setattr(Children,"school","清華大學")
print(obj.school)
print(Children.school)


setattr(Children,"school", lambda self :print("名牌大學"))
obj.school()
Children.school(obj)

# setattr(obj,"school", lambda :print("名牌大學1"))
# obj.school()

(4) delattr() 刪除類/物件的值

delattr(Children,"school")
# obj.school()
delattr(obj,"name")
# print(obj.name)

小例子 : 通過字串操作物件/類中的成員

strvar= input("請告訴我,你想要呼叫的方法是:")
if hasattr(obj,strvar):
    func= getattr(obj,strvar)
    func()
    
else:
    print("抱歉 該方法不存在")

2、反射模組中的成員

import sys
""" sys.modules 返回的是系統的模組字典"""
# print(sys.modules)
""" 通過__main__ 字典的鍵,獲取的是當前檔案的模組物件"""
# print(sys.modules["__main__"])
modules = sys.modules["__main__"]
print(modules)

def func1():
    print("我是func1")
def func2():
    print("我是func2")
def func3():
    print("我是func3")

## 反射模組成員的小例子

while True:
    func_name = input("請輸入你要使用的方法名>>>")
    if hasattr(modules,func_name):
        func = getattr(modules,func_name)
        func()
    elif func_name.upper()=="Q":
        break        
    else:
        print("沒有該方法")