欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python的代理類實現(xiàn),控制訪問和修改屬性的權(quán)限你都了解嗎

 更新時間:2022年03月21日 16:09:45   作者:Moelimoe  
這篇文章主要為大家詳細(xì)介紹了Python的代理類實現(xiàn),控制訪問和修改屬性的權(quán)限,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

本篇文章主要內(nèi)容

代理類主要功能是將一個類實例的屬性訪問和控制代理到代碼內(nèi)部另外一個實例類,將想對外公布的屬性的訪問和控制權(quán)交給代理類來操作,保留不想對外公布的屬性的訪問或控制權(quán),比如只讀訪問,日志功能

1.代理類實現(xiàn)被代理類的屬性訪問和修改權(quán)限控制

2.異常捕獲代理類的簡化示例

代理類的一個簡單的實現(xiàn)方式示例

目標(biāo):實現(xiàn)類Product的實例屬性讓另一個類Proxy來代理訪問和控制,想將對外公布的屬性交給代理類讓外部訪問和控制,不想對外公布的屬性無法通過代理來訪問和控制,這里不想對外公布的屬性約定用下劃線命名開頭

# proxy_example1.py
# 以下是一個代理類實現(xiàn)只讀訪問的示例
# 目標(biāo):代理后只能訪問和修改Product的公開屬性,私有屬性_current只能查看不能修改
class Product:
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        self._current = 123

# 只暴露代理類Proxy給外部使用
class Proxy:
    def __init__(self, obj):
        self._obj = obj
    def __getattr__(self, item):    # 本實例沒有找到的屬性會執(zhí)行__getattr__方法
        if item.startswith("_"):    # 約定下劃線開頭的方法不能訪問到被代理的類,只會訪問到代理類
            raise Exception(f"{item} not found")    # Product存在的私有屬性也不希望被外部知道
        return getattr(self._obj, item)
    def __setattr__(self, key, value):
        if key.startswith("_"):     # 約定下劃線開頭的方法不能訪問到被代理的類,只會訪問到代理類
            # 注:這里不能raise,這會導(dǎo)致Proxy的實例都無法創(chuàng)建(__dict__等屬性無法創(chuàng)建)
            super(Proxy, self).__setattr__(key, value)   # 避免無限循環(huán)
        else:
            setattr(self._obj, key, value)
    # 要求只能刪除非下劃線開頭的屬性
    def __delattr__(self, item):
        if item.startswith("_"):
            super(Proxy, self).__delattr__(item)    # 避免無限循環(huán)
        else:
            delattr(self._obj, item)

def test_getattr():
    p = Product(10, 1)
    pp = Proxy(p)
    print(pp.price)
    print(pp._curr)

def test_setattr():
    p = Product(10, 2)
    pp = Proxy(p)
    pp.abc = 1
    print(pp.abc, p.abc)
    pp._curr = 10000
    print(pp._curr)  # 私有屬性,設(shè)置給了代理類
    print(p._curr)  # raise an error, 被代理的類Product的屬性沒有設(shè)置成功也無法訪問

def test_delattr():
    p = Product(10, 2)
    pp = Proxy(p)
    pp.abc = 123
    print(pp.abc, p.abc)
    # 刪除公開屬性
    del pp.abc  # 成功
    # print(pp.abc, p.abc)  # 已被刪除
    # # 刪除私有屬性
    # del pp._curr    # 會嘗試刪除Proxy的私有屬性,raise AttributeError: _curr
    # 先創(chuàng)建在刪除
    pp._def = 123   # 這個操作只會設(shè)置Proxy的實例屬性
    print(pp._def)      # 訪問的是Proxy實例屬性,被代理的Product實例沒有創(chuàng)建_def屬性
    # del pp._def     # 刪除的是Proxy的實例屬性
    # print(pp._def)

測試獲取屬性

if __name__ == '__main__':
    test_getattr()

輸出:

10
...
Exception: _curr not found
...

測試設(shè)置屬性

if __name__ == '__main__':
    test_delattr()

輸出

1 1
10000
...
AttributeError: 'Product' object has no attribute '_curr'
...

測試刪除屬性

if __name__ == '__main__':    test_delattr()

輸出

123 123
123

注:以雙下劃線開頭和結(jié)尾的方法無法被代理,想要使用,必須在代理類中定義出這個方法,然后重定向到被代理的類的方法,比如你想使用isinstance()方法就要在Proxy偽造定義__class__屬性,想要使用len()方法就要在Proxy重定向返回到被代理的類的len方法

# proxy_example2.py
class Product:
    def __init__(self, price, quantity):
        self.price = price
        self.quantity = quantity
        self._current = 123
    def __len__(self):
        return 111

# 只暴露代理類Proxy給外部使用
class Proxy:
    def __init__(self, obj):
        self._obj = obj
    def __getattr__(self, item):    # 本實例沒有找到的屬性會執(zhí)行__getattr__方法
        if item.startswith("_"):    # 約定下劃線開頭的方法不能訪問到被代理的類,只會訪問到代理類
            raise Exception(f"{item} not found")    # Product存在的私有屬性也不希望被外部知道
        return getattr(self._obj, item)
    def __setattr__(self, key, value):
        if key.startswith("_"):     # 約定下劃線開頭的方法不能訪問到被代理的類,只會訪問到代理類
            # 注:這里不能raise,這會導(dǎo)致Proxy的實例都無法創(chuàng)建(__dict__等屬性無法創(chuàng)建)
            super(Proxy, self).__setattr__(key, value)   # 避免無限循環(huán)
        else:
            setattr(self._obj, key, value)
    # 要求只能刪除非下劃線開頭的屬性
    def __delattr__(self, item):
        if item.startswith("_"):
            super(Proxy, self).__delattr__(item)    # 避免無限循環(huán)
        else:
            delattr(self._obj, item)
    @property
    def __class__(self):    # 偽造類
        return self._obj.__class__
    def __len__(self):
        return len(self._obj)
	def test_instance():
	    p = Product(10, 2)
	    pp = Proxy(p)
	    print(pp.__class__)
	    print(isinstance(pp, Product))      # 如果不偽造__class__,會返回False
	def test_len():
	    p = Product(10, 2)
	    pp = Proxy(p)
	    print(len(pp))  # 如果Proxy實例不定義__len__方法,會報錯TypeError: object of type 'Proxy' has no len()

測試偽造的實例class類型

if __name__ == '__main__':
    test_instance()

輸出

<class '__main__.Product'>
True

測試獲取長度

if __name__ == '__main__':
    test_len()

輸出

111

一個實現(xiàn)日志輸出的代理類的簡化示例

捕獲web server報錯日志并執(zhí)行異常處理的示例

# logger_proxy.py
# -*- coding:utf-8 -*-
from functools import wraps

class DAL:
    @classmethod
    def dm1(cls, req, *args):
        print("dm1...", f"{req=}")
        print(1/0)      # 故意拋出異常
        return "dm1"

class BLL:
    @classmethod
    def bm1(cls, req):
        print("bm1...", f"{req=}")
        return DAL.dm1(req)

class Application:
    def __init__(self, req):
        self.req = req
        self._p = "private attr"
    def hd1(self):
        return BLL.bm1(self.req)

class LoggerProxy:
    def __init__(self, obj):
        self._obj = obj
    def __getattr__(self, item):    # LoggerProxy類實例沒獲取到的屬性會執(zhí)行這個方法
        attr = getattr(self._obj, item)
        if callable(attr):  # 獲取到了方法,則處理異常捕獲
            @wraps(attr)
            def wrapped_method(*args, **kwargs):
                # print(f"Before access to attribute/method: {item}")
                try:
                    method = attr(*args, **kwargs)
                except ZeroDivisionError:
                    # 捕獲異常然后處理...
                    raise Exception(f"{attr.__name__} received a zero division error.")
                # print(f"After attribute/method {item} returned")
                return method
            return wrapped_method
        else:   # 獲取到了屬性,直接返回
            return attr

if __name__ == '__main__':
    lp = LoggerProxy(Application("abc"))
    print(lp.req)
    print(lp._p)
    print(lp.hd1())

運行輸出

abc
private attr
bm1... req='abc'
dm1... req='abc'
Traceback...
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback...
Exception: hd1 received a zero division error.

總結(jié)

本節(jié)主要的內(nèi)容是實現(xiàn)了一個代理類,達(dá)到代理訪問和控制某個類的屬性并避免將私有屬性暴露給外部,需要注意的是,一些特殊方法,也就是python雙下劃線開頭和結(jié)尾的方法,如果想要被代理類訪問和控制,就必須在代理類中也定義對應(yīng)的實際方法,另外,示例中主要是以下劃線開頭的方法作為私有屬性的約定,也可以使用其他約定,這樣在代理方法中的訪問和修改時做出相應(yīng)的判斷即可

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容! 

相關(guān)文章

最新評論