日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python中代理模式分为几种_通俗 Python 设计模式——代理模式

發(fā)布時(shí)間:2025/3/8 python 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python中代理模式分为几种_通俗 Python 设计模式——代理模式 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

今天來說一說代理模式。

代理模式顧名思義,是對資源進(jìn)行代理訪問的一種模式,這里的資源是泛指在程序中會(huì)使用到的數(shù)據(jù)、操作、過程、對象等等。當(dāng)然,針對不同的資源,代理進(jìn)行的操作不盡相同,根據(jù)前人的總結(jié),有四種常見且知名的代理模式:

遠(yuǎn)程代理,即在物理上的遠(yuǎn)程資源(如服務(wù)器)在本地的代理

虛擬代理,即不是真實(shí)的代理,是對一些可以不在第一時(shí)間執(zhí)行的操作進(jìn)行的代理,他可以將比如復(fù)雜耗時(shí)的操作推遲到真正需要的時(shí)候再進(jìn)行,所謂的惰性加載即是典型的虛擬代理模式

保護(hù)代理,即對敏感資源進(jìn)行保護(hù),在實(shí)際訪問前,進(jìn)行相應(yīng)安全性控制的代理

智能代理,即引用代理,在資源被訪問時(shí),執(zhí)行一些額外的預(yù)操作,如檢查引用計(jì)數(shù)或線程安全之類的

書中提供了一個(gè)惰性加載的實(shí)例,來講解虛擬代理,這里我們摘錄于此。

首先我們編寫一個(gè)名為 LazyProperty 的裝飾器,他的作用在于,將他裝飾的對象的執(zhí)行時(shí)機(jī)從聲明之時(shí)推后到被調(diào)用之時(shí)。LazyProperty 裝飾器代碼如下:

class LazyProperty(object):

def __init__(self, method):

self.method = method

self.method_name = method.__name__

print('function overriden: {}'.format(self.method))

print("function's name: {}".format(self.method_name))

def __get__(self, obj, cls):

if not obj:

return None

value = self.method(obj)

print('value {}'.format(value))

setattr(obj, self.method_name, value)

return value

這里我們?yōu)?LazyProperty 重寫了 __get__ 方法,從代碼中可以看出,__get__ 方法其實(shí)本質(zhì)上是代理了被 LazyProperty 所修飾的對象的訪問操作。也就是說,要訪問被 LazyProperty 所修飾的對象,在實(shí)際返回其值之前,會(huì)先執(zhí)行 LazyProperty.__get__ 方法。下面我們來驗(yàn)證一下。

編寫一個(gè) Test 類,假設(shè)其中 resource 操作會(huì)花費(fèi)較長時(shí)間,代碼如下:

class Test:

def __init__(self, x, y):

self.x = x

self.y = y

self._resource = None

def resource(self):

print('initializing self._resource which is: {}'.format(self._resource))

self._resource = tuple(range(x, y)) # 假設(shè)這一行的計(jì)算成本比較大

return self._resource

如果我們只是這樣編寫代碼,那么每次在遇到需要使用 self._resource 時(shí),調(diào)用 Test.resource 方法,都會(huì)需要重新執(zhí)行一遍其中復(fù)雜的操作。如下代碼所示:

def main():

t1 = Test(1,5)

t2 = Test(10,15)

print(t1.x)

print(t1.y)

print(t1._resource)

print(t2.x)

print(t2.y)

print(t2._resource)

# 做更多的事情……

print(t1.resource())

print(t2.resource())

print(t1._resource)

print(t2._resource)

print(t1.resource())

print(t2.resource())

main()

這段代碼的輸出是:

1

5

None

10

15

None

initializing self._resource which is: None

(1, 2, 3, 4)

initializing self._resource which is: None

(10, 11, 12, 13, 14)

(1, 2, 3, 4)

(10, 11, 12, 13, 14)

initializing self._resource which is: (1, 2, 3, 4)

(1, 2, 3, 4)

initializing self._resource which is: (10, 11, 12, 13, 14)

(10, 11, 12, 13, 14)

請注意其中兩次出現(xiàn)的 initializing self._resource which is: 內(nèi)容,這表明,每次調(diào)用 t.resource(),都重新執(zhí)行了一次賦值操作。

然而當(dāng)我們使用 LazyProperty 裝飾器 & 描述符來修飾 Test.resource 方法時(shí),修改 Test.resource 方法代碼如下:

@LazyProperty

def resource(self):

print('initializing self._resource which is: {}'.format(self._resource))

self._resource = tuple(range(self.x, self.y)) # 假設(shè)這一行的計(jì)算成本比較大

return self._resource

如此一來,我們再將 main() 方法中,各處調(diào)用 t.resource() 改為 t.resource (因?yàn)檫@里 LazyProperty 已經(jīng)充當(dāng)了描述符,使得 t.resource 可以像訪問屬性一樣直接訪問),會(huì)發(fā)現(xiàn)輸出內(nèi)容有所改變,具體如下:

function overriden:

function's name: resource

1

5

None

10

15

None

initializing self._resource which is: None

value (1, 2, 3, 4)

(1, 2, 3, 4)

initializing self._resource which is: None

value (10, 11, 12, 13, 14)

(10, 11, 12, 13, 14)

(1, 2, 3, 4)

(10, 11, 12, 13, 14)

(1, 2, 3, 4)

(10, 11, 12, 13, 14)

除開最上面部分有一些之前沒有見過的內(nèi)容,我們可以明顯的看到,初始化操作只執(zhí)行了一次,之后的每次調(diào)用,都是直接獲取已經(jīng)初始化好的 Test._resource 屬性。也就是說,本例中的虛擬代理 LazyProperty,一方面幫我們完成了惰性加載的操作,另一方面也充當(dāng)了資源的描述符,方便其之后的獲取其值。當(dāng)然,根據(jù)需要,也可以在 LazyProperty 中實(shí)現(xiàn) __set__ 等其他相關(guān)描述符操作。

本例完整代碼如下:

class LazyProperty(object):

def __init__(self, method):

self.method = method

self.method_name = method.__name__

print('function overriden: {}'.format(self.method))

print("function's name: {}".format(self.method_name))

def __get__(self, obj, cls):

if not obj:

return None

value = self.method(obj)

print('value {}'.format(value))

setattr(obj, self.method_name, value)

return value

class Test(object):

def __init__(self, x, y):

self.x = x

self.y = y

self._resource = None

@LazyProperty

def resource(self):

print('initializing self._resource which is: {}'.format(self._resource))

self._resource = tuple(range(self.x, self.y)) # 假設(shè)這一行的計(jì)算成本比較大

return self._resource

def main():

t1 = Test(1,5)

t2 = Test(10,15)

print(t1.x)

print(t1.y)

print(t1._resource)

print(t2.x)

print(t2.y)

print(t2._resource)

# 做更多的事情……

print(t1.resource)

print(t2.resource)

print(t1._resource)

print(t2._resource)

print(t1.resource)

print(t2.resource)

main()

下面再將書中一個(gè)關(guān)于保護(hù)代理的實(shí)例摘錄于此。

我們首先有一個(gè)需要訪問的類,SensitiveInfo,其中包含了列表信息,一個(gè)讀取列表信息的方法以及一個(gè)修改列表內(nèi)容的方法:

class SensitiveInfo(object):

def __init__(self):

self.users = ['nick', 'tom', 'ben', 'mike']

def read(self):

print('There are {} users: {}'.format(len(self.users), ' '.join(self.users)))

def add(self, user):

self.users.append(user)

print('Added user {}'.format(user))

這里我們假設(shè)他的列表信息是需要保密訪問的,只有獲取密碼后才能訪問相應(yīng)內(nèi)容,那么我們在不修改這個(gè)類本身的情況下,要實(shí)現(xiàn)訪問控制,就需要通過代理的方式來進(jìn)行。增加一個(gè) Info 類作為保護(hù)代理,他包含有與被保護(hù)對象 SensitiveInfo 相同的方法。代碼如下:

class Info(object):

def __init__(self):

self.protected = SensitiveInfo()

self.secret = '0xdeadbeef'

def read(self):

self.protected.read()

def add(self, user):

sec = input('what is the secret? ')

self.protected.add(user) if sec == self.secret else print("That's wrong!")

這里的 Info 中,將被保護(hù)對象作為一個(gè)屬性代理了起來,在要進(jìn)行敏感操作(這里是修改被保護(hù)對象列表值)時(shí),設(shè)定一系列驗(yàn)證等檢測,來確保對被訪問對象的操作時(shí)安全或者符合要求的。

我們依舊編寫一個(gè) main() 函數(shù)進(jìn)行測試:

def main():

info = Info()

while True:

print('1. read list |==| 2. add user |==| 3. quit')

key = input('choose option: ')

if key == '1':

info.read()

elif key == '2':

name = input('choose username: ')

info.add(name)

elif key == '3':

exit()

else:

print('unknown option: {}'.format(key))

通過運(yùn)行這個(gè)實(shí)例,可以看到保護(hù)代理是怎樣實(shí)現(xiàn)保護(hù)這一核心操作的。

同時(shí),書上還留了幾道思考題,我摘錄最有價(jià)值的一題于此。其實(shí)現(xiàn)代碼將在本文最下方給出。

該示例有一個(gè)非常大的安全缺陷。沒有什么能阻止客戶端代碼通過直接創(chuàng)建一個(gè)SensitveInfo實(shí)例來繞過應(yīng)用的安全設(shè)置。優(yōu)化示例來阻止這種情況。一種方式是使用abc模塊來禁止直接實(shí)例化SensitiveInfo。在這種情況下,會(huì)要求進(jìn)行其他哪些代碼變更呢?

答案:

from abc import ABCMeta, abstractmethod

# 將類聲明為抽象類,并為用 @abstractmethod 修飾相應(yīng)的需要成為抽象方法的方法

# 如此一來,即無法直接將此類實(shí)例化,避免開發(fā)中的失誤導(dǎo)致繞過代理,出現(xiàn)不安全的情況

class SensitiveInfo(metaclass=ABCMeta):

def __init__(self):

self.users = ['nick', 'tom', 'ben', 'mike']

@abstractmethod

def read(self):

'''read'''

pass

@abstractmethod

def add(self, user):

'''add'''

pass

class Info(SensitiveInfo):

'''SensitiveInfo的保護(hù)代理'''

def __init__(self):

# 通過這種方式,調(diào)用 SensitiveInfo.__init__() 獲得 users 列表

super().__init__()

self.secret = '0xdeadbeef'

def read(self):

print('There are {} users: {}'.format(len(self.users), ' '.join(self.users)))

def add(self, user):

sec = input('what is the secret? ')

# 此時(shí)的操作全部基于從 SensitiveInfo 繼承來的 users 進(jìn)行

self.users.append(user) if sec == self.secret else print("That's wrong!")

def main():

info = Info()

while True:

print('1. read list |==| 2. add user |==| 3. quit')

key = input('choose option: ')

if key == '1':

info.read()

elif key == '2':

name = input('choose username: ')

info.add(name)

elif key == '3':

exit()

else:

print('unknown option: {}'.format(key))

if __name__ == '__main__':

main()

總結(jié)

以上是生活随笔為你收集整理的python中代理模式分为几种_通俗 Python 设计模式——代理模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。