1. 程式人生 > >Python系列之 - 反射

Python系列之 - 反射

function 一道 好的 HA BE python n) method lis

一、靜態方法(staticmethod)和類方法(classmethod)

類方法:有個默認參數cls,並且可以直接用類名去調用,可以與類屬性交互(也就是可以使用類屬性)

靜態方法:讓類裏的方法直接被類調用,就像正常調用函數一樣

類方法和靜態方法的相同點:都可以直接被類調用,不需要實例化

類方法和靜態方法的不同點:

  類方法必須有一個cls參數表示這個類,可以使用類屬性

  靜態方法不需要參數

綁定方法:分為普通方法和類方法

     普通方法:默認有一個self對象傳進來,並且只能被對象調用-------綁定到對象

      類方法:默認有一個cls對象傳進來,並且可以被類和對象(不推薦)調用-----綁定到類

非綁定方法:靜態方法:沒有設置默認參數,並且可以被類和對象(不推薦)調用-----非綁定

class Student:
    f = open(student, encoding=utf-8)
    def __init__(self):
        pass
    @classmethod #類方法 :有個默認參數cls,並且可以直接使用類名去
                 #調用,還可以與類屬性交互(也就是可以使用類屬性)
    def show_student_info_class(cls):
        # f = open(‘student‘, encoding=‘utf-8‘)
for line in cls.f: name,sex = line.strip().split(,) print(name,sex) @staticmethod #靜態方法:可以直接使用類名去調用,就像正常的函數調用一樣 def show_student_info_static(): #不用傳self f = open(student,encoding=utf-8) for line in f: name,sex = line.strip().split(
,) print(name,sex) # egon = Student() # egon.show_student_info_static() #也可以這樣調,但是還是推薦用類名去調 # egon.show_student_info_class() Student.show_student_info_class()#類名.方法名() print(-------------------) Student.show_student_info_static()#類名.方法名() staticmethod和classmethod

一、isinstance 和 issubclass

isinstance(obj,cls):檢查obj是不是cls的對象(傳兩個參數,一個是對象,一個是類)

issubclass(sub,super):檢查sub是不是super的子類(傳兩個參數,一個是子類,一個是父類)

class Foo:
    pass
class Son(Foo):
    pass
s = Son()
print(isinstance(s,Son))  #判斷s是不是Son的對象
print(type(s) is Son)
print(isinstance(s,Foo))  #判斷s是不是Foo的對象  不精準
print(type(s) is Foo)  #type比較精準

print(issubclass(Son,Foo)) #判斷Son是不是Foo的子類
print(issubclass(Son,object))
print(issubclass(Foo,object))
print(issubclass(int,object))

二、反射

反射:可以用字符串的方式去訪問對象的屬性,調用對象的方法(但是不能去訪問方法),python中一切皆對象,都可以使用反射。

反射有四種方法:

hasattr:hasattr(object,name)判斷一個對象是否有name屬性或者name方法。有就返回True,沒有就返回False

getattr:獲取對象的屬性或者方法,如果存在則打印出來。hasattr和getattr配套使用

    需要註意的是,如果返回的是對象的方法,返回出來的是對象的內存地址,如果需要運行這個方法,可以在後面添加一對()

setattr:給對象的屬性賦值,若屬性不存在,先創建後賦值

delattr:刪除該對象指定的一個屬性

class Foo:
    def __init__(self):
        self.name = egon
        self.age = 51
    def func(self):
        print(hello)
egg = Foo()
setattr(egg,sex,)
print(egg.sex)
# 2.
def show_name(self):
    print(self.name+sb)
setattr(egg,sh_name,show_name)
egg.sh_name(egg)
show_name(egg)
delattr(egg,‘name‘)
print(egg.name)

1.對象應用反射

class Foo:
def __init__(self):
self.name = ‘egon‘
self.age = 51
def func(self):
print(‘hello‘)
egg = Foo()
print(hasattr(egg,‘name‘)) #先判斷name在egg裏面存在不存在
print(getattr(egg,‘name‘)) #如果為True它才去得到
print(hasattr(egg,‘func‘))
print(getattr(egg,‘func‘)) #得到的是地址
# getattr(egg,‘func‘)() #在這裏加括號才能得到,因為func是方法
if hasattr(egg,‘func‘):
getattr(egg,‘func‘)()
else:
print(‘沒找到‘)

技術分享圖片
 1 class Foo:
 2     def __init__(self):
 3         self.name = ‘egon‘
 4         self.age = 51
 5     def func(self):
 6         print(‘hello‘)
 7 egg = Foo()
 8 print(hasattr(egg,‘name‘))  #先判斷name在egg裏面存在不存在
 9 print(getattr(egg,‘name‘)) #如果為True它才去得到
10 print(hasattr(egg,‘func‘))
11 print(getattr(egg,‘func‘))  #得到的是地址
12 # getattr(egg,‘func‘)()  #在這裏加括號才能得到,因為func是方法
13 if hasattr(egg,‘func‘):
14     getattr(egg,‘func‘)()
15 else:
16     print(‘沒找到‘)
技術分享圖片

2.類應用反射

class Foo:
f = 123
@classmethod
def class_method_dome(cls):
print(‘class_method_dome‘)

@staticmethod
def static_method_dome():
print(‘static_method_dome‘)
print(hasattr(Foo,‘class_method_dome‘))
method = getattr(Foo,‘class_method_dome‘)
method()
print(‘------------‘)
print(hasattr(Foo,‘static_method_dome‘))
method1 = getattr(Foo,‘static_method_dome‘)
method1()

技術分享圖片
 1 class Foo:
 2     f = 123
 3     @classmethod
 4     def class_method_dome(cls):
 5         print(‘class_method_dome‘)
 6 
 7     @staticmethod
 8     def static_method_dome():
 9         print(‘static_method_dome‘)
10 print(hasattr(Foo,‘class_method_dome‘))
11 method = getattr(Foo,‘class_method_dome‘)
12 method()
13 print(‘------------‘)
14 print(hasattr(Foo,‘static_method_dome‘))
15 method1 = getattr(Foo,‘static_method_dome‘)
16 method1()
技術分享圖片

3.模塊應用反射

 模塊的應用又分為導入其他模塊反射和在本模塊中反射

# 1.導入其他模塊引用
import mymodule
print(hasattr(mymodule,‘test‘))
getattr(mymodule,‘test‘)()

# # 這裏的getattr(mymodule,‘test‘)()這一句相當於
# p = getattr(mymodule,‘test‘)
# p()

技術分享圖片
1 # 1.導入其他模塊引用
2 import mymodule
3 print(hasattr(mymodule,‘test‘))
4 getattr(mymodule,‘test‘)()
5 
6 # # 這裏的getattr(mymodule,‘test‘)()這一句相當於
7 # p = getattr(mymodule,‘test‘)
8 # p()
技術分享圖片

# 2.在本模塊中應用反射
def demo1():
print(‘wwww‘)
import sys
# print(sys.modules)
module_obj = sys.modules[__name__] #相當於‘__main__‘
print(module_obj)
print(hasattr(module_obj,‘demo1‘))
getattr(module_obj,‘demo1‘)()

# 舉例
def 註冊():
    print(regiester)
def 登錄():
    print(login)
def 購物():
    pass
print(註冊,登錄,購物)
ret = input(請輸入你要做的操作:)
import sys
my_module = sys.modules[__name__]  #利用sys模塊導入一個自己的模塊
if hasattr(my_module,ret):
    getattr(my_module,ret)()

導入自己的模塊的一個簡單小例子

反射補充:

db.mysql

class MySQlHelper(object):
    print(‘MySQlHelper1111111‘)
    def fetchone(self):
        print(‘你好‘)

db.pool

class PoolHelper(object):
    print(‘PoolHelper‘)

settings.py

DB_PATH = db.mysql.MySQlHelper

#吧字符串切割
module_name,cls_name = DB_PATH.rsplit(.,maxsplit=1)
# print(module_name,cls_name)  #db.mysql    MySQlHelper
#導入模塊
# from db.mysql import MySQlHelper
import importlib
moudel_obj = importlib.import_module(module_name)
print(moudel_obj,type(moudel_obj))
#導入模塊中的類
cls = getattr(moudel_obj,cls_name)
print(cls)
#對類進行實例化
obj = cls()
obj.fetchone()
# getattr()

三、內置方法

1.__str__和__repr__

改變對象的字符串顯示

class Foo:
    def __init__(self,name):
        self.name = name
    def __repr__(self):
        return obj in str  #這裏只能是return
    # def __str__(self):
    #     return ‘%s obj in str‘%self.name
f = Foo(egon)
print(f)  #優先執行__str__裏面的內容
# 那麽你是不是據地__repr__沒用呢?
# print(‘%s‘%f)  #執行的是__str__裏面的返回值
# print(‘%r‘%f)  #執行的是__repr__裏面的返回值
print(==============)
print(str(f))  #當執行str(f)時,會去找__str__這個方法,如果找不到的時候,__repr__這個方法就給替補了
print(repr(f))
#1.當打印一個對象的時候,如果實現了__str__方法,打印__str__中的返回值
# 2.當__str__沒有被實現的時候,就會調用__repr__方法
# 3.但是當你用字符串格式化的時候,%s和%r會分別調用__str__和__repr__方法
# 4.不管是在字符串格式化的時候還是在打印對象的時候,
# __repr__方法都可以作為__str__方法的替補,但反之則不行
# 5.用於友好的表示對象。如果__str__和__repr__方法你只能實現一個:先實現__repr__

 __str__和__repr__

2.__del__

析構方法,當對象在內存中被釋放時,自動觸發執行。

註:此方法一般無須定義,因為Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。

class Foo:
    def __del__(self):
        print(執行我啦)

f= Foo()
print(123)
print(123)
print(123)
print(123)

3.item系列

分別有__getitem__ ,__setitem__ ,__delitem__

class Foo:
    def __init__(self):
        self.name = egon
        self.age = 73
        self.l=[1,2,3]
    def __getitem__(self, item):  #得到
        # return  self.l[item]
        # return self.__dict__[item]
        # print(Foo.__dict__)
        return 123
    def __setitem__(self, key, value):  #修改
        print(key,value)
        self.__dict__[key] = value
    def __delitem__(self, key):  #刪除
        del self.__dict__[key]
f = Foo()
print(f[qqq])  #不管裏面放的啥值,它都會得到返回值的內容,調用的是__getitem__方法
f[name]=alex #修改egon的值為alex,調用 __setitem__方法
# del f[‘name‘] #刪除name,就會報錯了,說明在調用__delitem__方法調用成功了,就已經刪了,就會報錯了
print(f.name) 
f1 = Foo()
print(f == f1)
# print(f.name)
# print(f[0])  #一開始不能這樣取值,但是提供了一個__getitem__方法,這樣就可以用了
# print(f[1])
# print(f[2])

三個方法的使用

4.__new__(創建)

# 4.__new__方法
# 單例模式:是一種設計模式
class Singleton:
    def __new__(cls, *args, **kw):
        if not hasattr(cls, _instance):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance

one = Singleton()
two = Singleton()
print(one,two)   #他們兩個的地址一樣

one.name = alex
print(two.name) 

單例模式
# class A:
#     def __init__(self):  #有一個方法在幫你創造self
#         print(‘in init function‘)
#         self.x = 1
#
#     def __new__(cls, *args, **kwargs):
#         print(‘in new function‘)
#         return object.__new__(A, *args, **kwargs)
# a = A()
# b = A()
# c = A()
# d = A()
# print(a,b,c,d)

__new__

5.__call__

對象後面加括號,觸發執行

註:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()

class Foo:
2     def __call__(self, *args, **kwargs):
3         print(123)
4 # f = Foo()
5 # f() #如果不寫上面的__call__方法,就不會調用。如果加上,就正確了
6 Foo()() #也可以這樣表示

6.__hash__

class Foo:
    def __hash__(self):
        print(aaaaaaaaaa)
        return hash(self.name)
        # print(‘aaas‘)
f = Foo()
f.name = egon
print(hash(f))  #hash方法是可以重寫的

__hash__

7.__eq__

class A:
    def __eq__(self, other):
        return True
a = A()
b = A()
print(a==b) #不加方法的時候返回的是False,加了個__eq__方法就返回了個True
# ‘==‘內部就調用了__eq__方法
print(a is b)

__eq__

一道面試題

from collections import namedtuple
Card = namedtuple(Card,[rank,suit])  #兩個屬性:一個是數,一個是花色(每一個card的對象就是一張紙牌)
class FranchDeck: #紙牌數據類型
    ranks = [str(n) for n in range(2,11)] + list(JQKA)
    suits = [紅心,方板,梅花,黑桃]

    def __init__(self):
        self._cards = [Card(rank,suit) for rank in FranchDeck.ranks #先循環這個,在循環下面的那個循環
                                        for suit in FranchDeck.suits]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, item):
        return self._cards[item]

    def __setitem__(self, key, value):
        self._cards[key] = value

deck = FranchDeck()
# print(deck[0])
# print(deck[0])
# print(deck[0])
# print(deck[0])
from random import choice
print(choice(deck))
print(choice(deck))

from random import shuffle
shuffle(deck)
print(deck[:5])

紙牌遊戲

Python系列之 - 反射