中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

32面向對象7_reflection

發布時間:2020-04-05 00:36:23 來源:網絡 閱讀:296 作者:chaijowin 欄目:編程語言

?

目錄

reflection相關的內建函數:... 1

反射相關的魔術方法(__getattr__()__setattr__()__delattr__()):... 7

反射相關的魔術方法(__getattribute__):... 9

?

?

?

reflection反射

?

運行時,獲取類型定義信息;運行時通過實例能查出實例及所屬類的類型相關信息;

一個對象能夠在運行時,像照鏡子一樣,反射出它的所有類型信息;

簡單說,在python中,能通過一個對象,找出其typeclassattributemethod的能力,稱為反射或自省;

具有反射能力的函數有:type()isinstance()callable()dir()getattr()

?

注:

運行時,區別于編譯時,指程序被加載到內存中執行的時候;

?

reflection相關的內建函數:

getattr(object,name[,default]),通過name返回object的屬性值,當屬性不存在,將使用default返回,如果沒有default,則拋AttributeErrorname必須為字符串

setattr(object,name,value)object(實例或類)屬性存在則覆蓋,不存在新增;

hasattr(object,name),判斷對象是否有這個名字的屬性,name必須為字符串;

?

動態添加屬性方式,與裝飾器修改一個類、mixin方式的差異?

動態添加屬性,是運行時改變類或者實例的方式,因此反射能力具有更大的靈活性;

裝飾器和mixin,在定義時就決定了;

?

注:

一般運行時動態增,很少刪;

self.__class__,同type(self);即實例a.__class__,同type(a)

?

例:

class Point:

??? def __init__(self,x,y):

??????? self.x = x

??????? self.y = y

?

??? def __str__(self):

??????? return 'Point({},{})'.format(self.x,self.y)

?

??? __repr__ = __str__

?

??? def show(self):

??????? print(self.x,self.y)

?

p = Point(4,5)

print(p.__dict__)

p.__dict__['y'] = 16

print(p.__dict__['y'])?? #通過實例的屬性字典__dict__訪問實例的屬性,本質上是利用反射的能力,這種訪問方式不優雅,python提供了相關的內置函數

p.z = 10

print(p.__dict__)

?

p1 = Point(4,5)

p2 = Point(10,10)

print(repr(p1),repr(p2))

print(p1.__dict__)

setattr(p1,'y',16)

setattr(p1,'z',18)

print(getattr(p1,'__dict__'))

?

if hasattr(p1,'show'):?? #動態調用方法

??? getattr(p1,'show')()

?

if not hasattr(Point,'add'):?? #源碼中常用此方式

??? setattr(Point,'add',lambda self,other: Point(self.x + other.x,self.y + other.y))

?

print(Point.add)

print(p1.add)

print(p1.add(p2))

輸出:

{'x': 4, 'y': 5}

16

{'x': 4, 'y': 16, 'z': 10}

Point(4,5) Point(10,10)

{'x': 4, 'y': 5}

{'x': 4, 'y': 16, 'z': 18}

4 16

<function <lambda> at 0x7f2d82572e18>

<bound method <lambda> of Point(4,16)>

Point(14,26)

?

例:

class A:

??? def __init__(self,x):

??????? self.x = x

?

a = A(5)

setattr(A,'y',10)?? #運行時改變屬性,在類上操作

print(A.__dict__)

print(a.__dict__)

print(getattr(a,'x'))

print(getattr(a,'y'))?? #實例沒有y,向上找自己類的

# print(getattr(a,'z'))?? #X

print(getattr(a,'z',100))

setattr(a,'y',1000)?? #在實例上操作

print(A.__dict__)

print(a.__dict__)

?

# setattr(a,'mtd',lambda self: 1)?? #在實例上定義方法,看似可以,實際不行,未綁定self,若要在調用時不出錯,需把實際名寫上,如a.mtd(a)

# a.mtd()?? #X

# print(a.mtd(a))?? #V

print(a.__dict__)

?

setattr(A,'mtd',lambda self: 2)?? #在類上定義方法沒問題

print(a.mtd())

print(A.__dict__)

輸出:

{'__module__': '__main__', '__init__': <function A.__init__ at 0x7f1061881510>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, 'y': 10}

{'x': 5}

5

10

100

{'__module__': '__main__', '__init__': <function A.__init__ at 0x7f1061881510>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, 'y': 10}

{'x': 5, 'y': 1000}

{'x': 5}

2

{'__module__': '__main__', '__init__': <function A.__init__ at 0x7fde27413510>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, 'mtd': <function <lambda> at 0x7fde274bfe18>}

?

習題:

命令分發器,通過名稱找對應的函數執行;

思路:名稱找對象的方法;

?

函數方式實現:

1

def dispatcher():

??? cmds = {}

?

??? def reg(cmd,fn):

??????? if isinstance(cmd,str):

??????????? cmds[cmd] = fn

??????? else:

??????????? print('error')

?

??? def run():

???? ???while True:

??????????? cmd = input('plz input command: ')

??????????? if cmd.strip() == 'quit':

??????????????? return

??????????? print(cmds.get(cmd.strip(),defaultfn)())

?

??? def defaultfn():

??????? return 'default function'

?

??? return reg,run

?

reg,run = dispatcher()

?

reg('cmd1',lambda : 1)

reg('cmd2',lambda : 2)

?

run()

輸出:

plz input command: cmd3

default function

plz input command:? cmd2

2

plz input command: cmd1

1

plz input command: quit

?

2

def cmds_dispatcher():

??? cmds = {}

?

??? def reg(name):

??????? def wrapper(fn):

??????????? cmds[name] = fn

??????????? return fn

??????? return wrapper

?

??? def dispatcher():

??????? while True:

??????????? cmd = input('plz input comd: ')

??????????? if cmd.strip() == 'quit':

??????????????? return

??????????? print(cmds.get(cmd.strip(),defaultfn)())

?

??? def defaultfn():

??????? return 'default function'

?

??? return reg,dispatcher

?

reg,dispatcher = cmds_dispatcher()

?

@reg('cmd1')

def foo1():

??? return 1

?

@reg('cmd2')

def foo2():

??? return 2

?

dispatcher()

?

面向對象方式實現:

使用setattr()getattr()找到對象的屬性(實際是在類上加的,實例找不到逐級往上找),比自己維護一個dict來建立名稱和函數之間的關系要好;

實現1

class Dispatcher:

??? def cmd1(self):

??????? return 1

?

??? def reg(self,cmd,fn):

??????? if isinstance(cmd,str):

??????????? setattr(self.__class__,cmd,fn)?? #放在類上最方便,self.__class__type(self);不要在實例上定義,如果在實例上,setattr(self,cmd,fn),調用時要注意dis.reg('cmd2',lambda : 2)

??????? else:

??????????? print('error')

?

??? def run(self):

??????? while True:

??????????? cmd = input('plz input cmd: ')

??????????? if cmd.strip() == 'quit':

??????????????? return

??????????? print(getattr(self,cmd.strip(),self.defaultfn)())

?

??? def defaultfn(self):

??????? return 'default function'

?

dis = Dispatcher()

dis.reg('cmd2',lambda self: 2)

dis.run()

# print(dis.__class__.__dict__)

# print(dis.__dict__)

輸出:

plz input cmd: cmd1

1

plz input cmd: cmd2

2

plz input cmd: cmd3

default function

plz input cmd: 11

default function

?

實現2

class Dispatcher:

??? def __init__(self):

??????? self._run()

?

??? def cmd1(self):

??????? return 1

?

??? def cmd2(self):

??????? return 2

?

??? def reg(self,cmd,fn):

??????? if isinstance(cmd,str):

??????????? setattr(self.__class__,cmd,fn)

??????? else:

??????????? print('error')

?

??? def _run(self):

??????? while True:

??????????? cmd = input('plz input cmd: ')

??????????? if cmd.strip() == 'quit':

??????????????? return

??????????? print(getattr(self,cmd.strip(),self.defaultfn)())

?

??? def defaultfn(self):

??????? return 'default function'

?

Dispatcher()

輸出:

plz input cmd: cmd1

1

plz input cmd: cmd2

2

plz input cmd: cmd3

default function

plz input cmd: abcd

default function

?

?

?

反射相關的魔術方法(__getattr__()__setattr__()__delattr__()):

__getattr__(),當在實例、實例的類及祖先類中查不到屬性,才調用此方法;

__setattr__()通過點訪問屬性,進行增加、修改都要調用此方法;

__delattr__(),當通過實例來刪除屬性時調用此方法,刪自己有的屬性;

?

一個類的屬性會按照繼承關系找,如果找不到,就是執行__getattr__(),如果沒有這個方法,拋AttributeError

查找屬性順序為:

instance.__dict__-->instance.__class__.__dict__-->繼承的祖先類直到object__dict__-->調用__getattr__(),如果沒有__getattr__()則拋AttributeError異常;

?

__setattr__()__delattr__(),只要有相應的操作(如初始化時self.x = x或運行時a.y = 200觸發__setattr__()del a.m則觸發__delattr__())就會觸發,做攔截用,攔截做增加或修改,屬性要加到__dict__中,要自己完成;

?

這三個魔術方法的第一個參數為self,則如果用類名.屬性操作時,則這三個魔術方法管不著;

?

例:

class A:

??? m = 6

??? def __init__(self,x):

??????? self.x = x

?

??? def __getattr__(self, item):?? #對象的屬性按搜索順序逐級找,找到祖先類object上也沒有對應屬性,則最后找__getattr__(),如有定義__getattr__()返回該函數返回值,如果沒有此方法,則報錯AttributeError: 'A' object has no attribute 'y'

??????? print('__getattr__',item)

?

print(A(10).x)

print(A(8).y)

輸出:

10

__getattr__ y

None

?

例:

class A:

??? m = 6

??? def __init__(self,x):

??????? self.x = x?? #__init__()中的self.x = x也調用__setattr__()

?

??? def __getattr__(self, item):

??????? print('__getattr__',item)

??????? # self.__dict__[item] = 'default_value'

?

??? def __setattr__(self, key, value):

??????? print('__setattr__',key,value)

??????? # self.__dict__[key] = value

?

??? def __delattr__(self, item):

??????? print('__delattr__')

?

a = A(8)?? #初始化時的self.x = x也調用__setattr__()

a.x?? #調用__getattr__()

a.x = 100 ??#調用__setattr__(),實例的__dict__為空沒有x屬性,雖有觸發__setattr__(),但沒寫到__dict__中,要自己寫

a.x

a.y

a.y = 200

a.y

print(a.__dict__)?? #__getattr__()__setattr__()都有,實例的__dict__為空,用a.x訪問屬性時按順序都沒找到最終調用__getattr__()

print(A.__dict__)

?

del a.m

輸出:

__setattr__ x 8

__getattr__ x

__setattr__ x 100

__getattr__ x

__getattr__ y

__setattr__ y 200

__getattr__ y

{}

{'__module__': '__main__', 'm': 6, '__init__': <function A.__init__ at 0x7ffdacaa80d0>, '__getattr__': <function A.__getattr__ at 0x7ffdacaa8158>, '__setattr__': <function A.__setattr__ at 0x7ffdacaa8488>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

__delattr__

?

?

?

反射相關的魔術方法(__getattribute__):

?

__getattribute__(),實例所有屬性調用,都從這個方法開始;

實例的所有屬性訪問,第一個都會調用__getattribute__()方法,它阻止了屬性的查找,該方法應該返回(計算后的)值或拋AttributeError,它的return值將作為屬性查找的結果,如果拋AttributeError則直接調用__getattr__(),表示屬性沒有找到;

為了避免在該方法中無限的遞歸,它的實現應該永遠調用基類的同名方法以訪問需要的任何屬性,如object.__getattribute__(self,name)

除非明確知道__getattribute__()方法用來做什么,否則不要使用它,攔截面太大;

?

屬性查找順序:

實例調用__getattribute__()-->instance.__dict__-->instance.__class__.__dict__-->繼承的祖先類直到object__dict__-->調用__getattr__()

?

例:

class A:

??? m = 6

??? def __init__(self,x):

??????? self.x = x

?

??? def __getattr__(self, item):

??????? print('__getattr__',item)

??????? # self.__dict__[item] = 'default_value'

?

??? def __setattr__(self, key, value):

??????? print('__setattr__',key,value)

??????? # self.__dict__[key] = value

?

??? def __delattr__(self, item):

??????? print('__delattr__')

?

??? def __getattribute__(self, item):

??????? print('__getattribute__',item)

??????? raise AttributeError(item)?? #如果拋AttributeError則直接調用__getattr__(),表示屬性沒找到

??????? # return self.__dict__[item]?? #遞歸調用

??????? # return object.__getattribute__(self,item) ??#繼續向后找,這樣做沒意義

?

a = A(8)

a.x

a.y

a.z

輸出:

__setattr__ x 8

__getattribute__ x

__getattr__ x

__getattribute__ y

__getattr__ y

__getattribute__ z

__getattr__ z

?


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

汽车| 清丰县| 沂水县| 东源县| 武隆县| 儋州市| 密山市| 友谊县| 水城县| 如东县| 石门县| 盐山县| 宁陵县| 昌都县| 晋城| 莲花县| 仁布县| 潞城市| 肇庆市| 庄浪县| 天镇县| 乳源| 青冈县| 贵溪市| 盘山县| 金华市| 满洲里市| 岱山县| 阳曲县| 抚松县| 台安县| 沽源县| 石河子市| 青河县| 平昌县| 济阳县| 德惠市| 兴业县| 深泽县| 霍邱县| 灵山县|