反射,雙下方法

一. 反射

反射的概念是由Smith在1982年首次提出的,主要是指程序能夠訪問、檢測和修改它自己狀態或行爲的一種能力(自省)。這一律唸的提出很快引起了計算機科學領域關於應用反射性的研究。它首先被程序語言的設計領域所採用,並在Lisp和麪向對象方面取得了成績。python

python面向對象中的反射:經過字符串的形式操做對象相關的屬性。python中的一切事物都是對象(均可以使用反射)程序員

四個能夠實現自省的函數面試

下列方法適用於類和對象(一切皆對象,類自己也是一個對象)設計模式

class Foo:
    f = '類的靜態變量'
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say_hi(self):
        print('hi,%s'%self.name)

obj=Foo('egon',73)

#檢測是否含有某屬性
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))

#獲取屬性
n=getattr(obj,'name')
print(n)
func=getattr(obj,'say_hi')
func()

print(getattr(obj,'aaaaaaaa','不存在啊')) #報錯

#設置屬性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
print(obj.__dict__)
print(obj.show_name(obj))

#刪除屬性
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show_name111')#不存在,則報錯

print(obj.__dict__)

對實例化對象的示例

對對象的反射瀏覽器

class Foo(object):
 
    staticField = "old boy"
 
    def __init__(self):
        self.name = 'wupeiqi'
 
    def func(self):
        return 'func'
 
    @staticmethod
    def bar():
        return 'bar'
 
print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')

對類的反射函數

import sys


def s1():
    print 's1'


def s2():
    print 's2'


this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')

當前模塊的反射工具

#一個模塊中的代碼
def test():
    print('from the test')
"""
程序目錄:
    module_test.py
    index.py
 
當前文件:
    index.py
"""
# 另外一個模塊中的代碼
import module_test as obj

#obj.test()

print(hasattr(obj,'test'))

getattr(obj,'test')()

其餘模塊的示例

其餘模塊的反射學習

反射的應用:網站

瞭解了反射的四個函數。那麼反射到底有什麼用呢?它的應用場景是什麼呢?this

如今讓咱們打開瀏覽器,訪問一個網站,你單擊登陸就跳轉到登陸界面,你單擊註冊就跳轉到註冊界面,等等,其實你單擊的實際上是一個個的連接,每個連接都會有一個函數或者方法來處理。

class User:
    def login(self):
        print('歡迎來到登陸頁面')
    
    def register(self):
        print('歡迎來到註冊頁面')
    
    def save(self):
        print('歡迎來到存儲頁面')


while 1:
    choose = input('>>>').strip()
    if choose == 'login':
        obj = User()
        obj.login()
    
    elif choose == 'register':
        obj = User()
        obj.register()
        
    elif choose == 'save':
        obj = User()
        obj.save()

沒學反射以前的解決方式

class User:
    def login(self):
        print('歡迎來到登陸頁面')
    
    def register(self):
        print('歡迎來到註冊頁面')
    
    def save(self):
        print('歡迎來到存儲頁面')

user = User()
while 1:
    choose = input('>>>').strip()
    if hasattr(user,choose):
        func = getattr(user,choose)
        func()
    else:
        print('輸入錯誤。。。。')

學了反射以後解決方式

有多簡單,一目瞭然。

二. 函數 vs 方法

學到這裏,我終於能回答你一直以來可能有的一個疑問。那就是,以前的學習中咱們稱len()爲函數(口誤時稱爲方法)卻稱如str的strip爲方法,那它到底叫什麼?函數和方法有什麼區別和相同之處?我在這裏就正式的解釋一下。

2.1 經過打印函數(方法)名肯定

def func():
    pass

print(func)  # <function func at 0x00000260A2E690D0>


class A:
    def func(self):
        pass
    
print(A.func)  # <function A.func at 0x0000026E65AE9C80>
obj = A()
print(obj.func)  # <bound method A.func of <__main__.A object at 0x00000230BAD4C9E8>>

View Code

2.2 經過types模塊驗證

from types import FunctionType
from types import MethodType

def func():
    pass


class A:
    def func(self):
        pass

obj = A()


print(isinstance(func,FunctionType))  # True
print(isinstance(A.func,FunctionType))  # True
print(isinstance(obj.func,FunctionType))  # False
print(isinstance(obj.func,MethodType))  # True

View Code

2.3 靜態方法是函數

from types import FunctionType
from types import MethodType

class A:
    
    def func(self):
        pass
    
    @classmethod
    def func1(self):
        pass
    
    @staticmethod
    def func2(self):
        pass
obj = A()

# 靜態方法實際上是函數
# print(isinstance(A.func2,FunctionType))  # True
# print(isinstance(obj.func2,FunctionType))  # True

View Code

2.4 函數與方法的區別

那麼,函數和方法除了上述的不一樣之處,咱們還總結了一下幾點區別。

(1)函數的是顯式傳遞數據的。如咱們要指明爲len()函數傳遞一些要處理數據。

(2)函數則跟對象無關。

(3)方法中的數據則是隱式傳遞的。

(4)方法能夠操做類內部的數據。

(5)方法跟對象是關聯的。如咱們在用strip()方法是,是否是都是要經過str對象調用,好比咱們有字符串s,而後s.strip()這樣調用。是的,strip()方法屬於str對象。

咱們或許在平常中會口語化稱呼函數和方法時不嚴謹,可是咱們心中要知道兩者之間的區別。

在其餘語言中,如Java中只有方法,C中只有函數,C++麼,則取決因而否在類中。

三. 雙下方法

定義:雙下方法是特殊方法,他是解釋器提供的 由爽下劃線加方法名加雙下劃線 __方法名__的具備特殊意義的方法,雙下方法主要是python源碼程序員使用的,咱們在開發中儘可能不要使用雙下方法,可是深刻研究雙下方法,更有益於咱們閱讀源碼。

調用:不一樣的雙下方法有不一樣的觸發方式,就比如盜墓時觸發的機關同樣,不知不覺就觸發了雙下方法,例如:init

3.01 __len

class B:
    def __len__(self):
        print(666)

b = B()
len(b) # len 一個對象就會觸發 __len__方法。

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))

View Code

3.02 __hash

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))

View Code

3.03 str

若是一個類中定義了__str__方法,那麼在打印 對象 時,默認輸出該方法的返回值。

class A:
    def __init__(self):
        pass
    def __str__(self):
        return '太白'
a = A()
print(a)
print('%s' % a)

View Code

3.04 repr

若是一個類中定義了__repr__方法,那麼在repr(對象) 時,默認輸出該方法的返回值。

class A:
    def __init__(self):
        pass
    def __repr__(self):
        return '太白'
a = A()
print(repr(a))
print('%r'%a)

View Code

3.05 call

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

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

class Foo:

    def __init__(self):
        pass
    
    def __call__(self, *args, **kwargs):

        print('__call__')


obj = Foo() # 執行 __init__
obj()       # 執行 __call__

View Code

3.06 __eq

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        if  self.a == obj.a and self.b == obj.b:
            return True
a = A()
b = A()
print(a == b)

View Code

3.07 del

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

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

3.08__new

class A:
    def __init__(self):
        self.x = 1
        print('in init function')
    def __new__(cls, *args, **kwargs):
        print('in new function')
        return object.__new__(A, *args, **kwargs)

a = A()
print(a.x)

View Code

class A:
    __instance = None
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            obj = object.__new__(cls)
            cls.__instance = obj
        return cls.__instance

單例模式

單例模式具體分析

單例模式是一種經常使用的軟件設計模式。在它的核心結構中只包含一個被稱爲單例類的特殊類。經過單例模式能夠保證系統中一個類只有一個實例並且該實例易於外界訪問,從而方便對實例個數的控制並節約系統資源。若是但願在系統中某個類的對象只能存在一個,單例模式是最好的解決方案。
【採用單例模式動機、緣由】
對於系統中的某些類來講,只有一個實例很重要,例如,一個系統中能夠存在多個打印任務,可是隻能有一個正在工做的任務;一個系統只能有一個窗口管理器或文件系統;一個系統只能有一個計時工具或ID(序號)生成器。如在Windows中就只能打開一個任務管理器。若是不使用機制對窗口對象進行惟一化,將彈出多個窗口,若是這些窗口顯示的內容徹底一致,則是重複對象,浪費內存資源;若是這些窗口顯示的內容不一致,則意味着在某一瞬間系統有多個狀態,與實際不符,也會給用戶帶來誤解,不知道哪個纔是真實的狀態。所以有時確保系統中某個對象的惟一性即一個類只能有一個實例很是重要。
如何保證一個類只有一個實例而且這個實例易於被訪問呢?定義一個全局變量能夠確保對象隨時均可以被訪問,但不能防止咱們實例化多個對象。一個更好的解決辦法是讓類自身負責保存它的惟一實例。這個類能夠保證沒有其餘實例被建立,而且它能夠提供一個訪問該實例的方法。這就是單例模式的模式動機。
【單例模式優缺點】
【優勢】
1、實例控制
單例模式會阻止其餘對象實例化其本身的單例對象的副本,從而確保全部對象都訪問惟一實例。
2、靈活性
由於類控制了實例化過程,因此類能夠靈活更改實例化過程。
【缺點】
1、開銷
雖然數量不多,但若是每次對象請求引用時都要檢查是否存在類的實例,將仍然須要一些開銷。能夠經過使用靜態初始化解決此問題。
2、可能的開發混淆
使用單例對象(尤爲在類庫中定義的對象)時,開發人員必須記住本身不能使用new關鍵字實例化對象。由於可能沒法訪問庫源代碼,所以應用程序開發人員可能會意外發現本身沒法直接實例化此類。
3、對象生存期
不能解決刪除單個對象的問題。在提供內存管理的語言中(例如基於.NET Framework的語言),只有單例類可以致使實例被取消分配,由於它包含對該實例的私有引用。在某些語言中(如 C++),其餘類能夠刪除對象實例,但這樣會致使單例類中出現懸浮引用

3.09 __item__系列

class Foo:
    def __init__(self,name):
        self.name=name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key]=value
    def __delitem__(self, key):
        print('del obj[key]時,我執行')
        self.__dict__.pop(key)
    def __delattr__(self, item):
        print('del obj.key時,我執行')
        self.__dict__.pop(item)

f1=Foo('sb')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__)

View Code

3.10 上下文管理器相關

enter __exit

# 若是想要對一個類的對象進行with  as 的操做 不行。
class A:
    def __init__(self, text):
        self.text = text

with A('大爺') as f1:
    print(f1.text)

沒他們不能夠這樣操做

class A:
    
    def __init__(self, text):
        self.text = text
    
    def __enter__(self):  # 開啓上下文管理器對象時觸發此方法
        self.text = self.text + '您來啦'
        return self  # 將實例化的對象返回f1
    
    def __exit__(self, exc_type, exc_val, exc_tb):  # 執行完上下文管理器對象f1時觸發此方法
        self.text = self.text + '這就走啦'
        
with A('大爺') as f1:
    print(f1.text)
print(f1.text)

有他們能夠這樣操做

class Diycontextor:
    def __init__(self,name,mode):
        self.name = name
        self.mode = mode
 
    def __enter__(self):
        print "Hi enter here!!"
        self.filehander = open(self.name,self.mode)
        return self.filehander
 
    def __exit__(self,*para):
        print "Hi exit here"
        self.filehander.close()
 
 
with Diycontextor('py_ana.py','r') as f:
    for i in f:
        print i

自定義文件管理器

相關面試題:

class StarkConfig:
    def __init__(self,num):
        self.num = num
    
    def run(self):
        self()
    
    def __call__(self, *args, **kwargs):
        print(self.num)

class RoleConfig(StarkConfig):
    def __call__(self, *args, **kwargs):
        print(345)
    def __getitem__(self, item):
        return self.num[item]

v1 = RoleConfig('alex')
v2 = StarkConfig('太白金星')
# print(v1[1])
# print(v2[2])
v1.run()

-------
class UserInfo:
    pass


class Department:
    pass


class StarkConfig:
    def __init__(self, num):
        self.num = num
    
    def changelist(self, request):
        print(self.num, request)
    
    def run(self):
        self.changelist(999)


class RoleConfig(StarkConfig):
    def changelist(self, request):
        print(666, self.num)


class AdminSite:
    
    def __init__(self):
        self._registry = {}
    
    def register(self, k, v):
        self._registry[k] = v


site = AdminSite()
site.register(UserInfo, StarkConfig)
# 1 
# obj = site._registry[UserInfo]()

# 2
obj = site._registry[UserInfo](100)
obj.run()

-------
class UserInfo:
    pass

class Department:
    pass

class StarkConfig:
    def __init__(self,num):
        self.num = num

    def changelist(self,request):
        print(self.num,request)

    def run(self):
        self.changelist(999)

class RoleConfig(StarkConfig):
    def changelist(self,request):
        print(666,self.num)


class AdminSite:

    def __init__(self):
        self._registry = {}

    def register(self,k,v):
        self._registry[k] = v(k)

site = AdminSite()
site.register(UserInfo,StarkConfig)
site.register(Department,RoleConfig)

for k,row in site._registry.items():
    row.run()

-------
class A:
    list_display = []
    
    def get_list(self):
        self.list_display.insert(0,33)
        return self.list_display

s1 = A()
print(s1.get_list())

-------
class A:
    list_display = [1, 2, 3]
    def __init__(self):
        self.list_display = []
    def get_list(self):
        self.list_display.insert(0, 33)
        return self.list_display


s1 = A()
print(s1.get_list())

------
class A:
    list_display = []

    def get_list(self):
        self.list_display.insert(0,33)
        return self.list_display

class B(A):
    list_display = [11,22]


s1 = A()
s2 = B()
print(s1.get_list())
print(s2.get_list())

View Code

相關文章
相關標籤/搜索