第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

多處理代理:讓 getters 返回代理本身

多處理代理:讓 getters 返回代理本身

德瑪西亞99 2023-12-26 17:05:23
我有一個(gè)復(fù)雜的不可選取對(duì)象,它的屬性(通過 getter 和 setter 定義)也是復(fù)雜且不可選取類型的。我想為對(duì)象創(chuàng)建一個(gè)多處理代理來并行執(zhí)行一些任務(wù)。問題:雖然我成功地使 getter 方法可用于代理對(duì)象,但我無法使 getter 返回不可選取的返回對(duì)象的代理。我的設(shè)置類似于以下內(nèi)容:from multiprocessing.managers import BaseManager, NamespaceProxyclass A():    @property    def a(self):        return B()    @property    def b(self):        return 2# unpickable classclass B():    def __init__(self, *args):        self.f = lambda: 1    class ProxyBase(NamespaceProxy):    _exposed_ = ('__getattribute__', '__setattr__', '__delattr__')class AProxy(ProxyBase): passclass BProxy(ProxyBase): passclass MyManager(BaseManager):passMyManager.register('A', A, AProxy)if __name__ == '__main__':    with MyManager() as manager:        myA = manager.A()        print(myA.b) # works great        print(myA.a) # raises error, because the object B is not pickable我知道我可以在向管理器注冊(cè)方法時(shí)指定方法的結(jié)果類型。也就是說,我可以做MyManager.register('A', A, AProxy, method_to_typeid={'__getattribute__':'B'})MyManager.register('B', B, BProxy)if __name__ == '__main__':    with MyManager() as manager:        myA = manager.A()        print(myA.a) # works great!        print(myA.b) # returns the same as myA.a ?!我很清楚,我的解決方案不起作用,因?yàn)樵摲椒ㄟm用于所有屬性,而我只希望它在訪問屬性時(shí)__getattr__返回代理。我怎樣才能做到這一點(diǎn)?Ba作為一個(gè)附帶問題:如果我*args從 __init__的方法中刪除參數(shù)B,我會(huì)收到一個(gè)錯(cuò)誤,表明它被調(diào)用時(shí)參數(shù)數(shù)量錯(cuò)誤。為什么?我該如何解決這個(gè)問題?
查看完整描述

1 回答

?
DIEA

TA貢獻(xiàn)1820條經(jīng)驗(yàn) 獲得超2個(gè)贊

如果沒有一些技巧,這是不可能的,因?yàn)榉祷刂祷虼淼倪x擇是僅基于方法名稱而不是返回值的類型(來自Server.serve_client):


try:

    res = function(*args, **kwds)

except Exception as e:

    msg = ('#ERROR', e)

else:

    typeid = gettypeid and gettypeid.get(methodname, None)

    if typeid:

        rident, rexposed = self.create(conn, typeid, res)

        token = Token(typeid, self.address, rident)

        msg = ('#PROXY', (rexposed, token))

    else:

        msg = ('#RETURN', res)

另請(qǐng)記住,__getattribute__在調(diào)用方法時(shí),在不可挑選的類的代理中公開基本上會(huì)破壞代理功能。


但如果你愿意破解它并且只需要屬性訪問,這里有一個(gè)可行的解決方案(注意調(diào)用myA.a.f()仍然不起作用,lambda 是一個(gè)屬性并且沒有被代理,只有方法可以,但這是一個(gè)不同的問題)。


import os

from multiprocessing.managers import BaseManager, NamespaceProxy, Server


class A():

    @property

    def a(self):

        return B()

    @property

    def b(self):

        return 2


# unpickable class

class B():

    def __init__(self, *args):

        self.f = lambda: 1

        self.pid = os.getpid()


class HackedObj:

    def __init__(self, obj, gettypeid):

        self.obj = obj

        self.gettypeid = gettypeid


    def __getattribute__(self, attr):

        if attr == '__getattribute__':

            return object.__getattribute__(self, attr)

            

        obj = object.__getattribute__(self, 'obj')

        result = object.__getattribute__(obj, attr)

        if isinstance(result, B):

            gettypeid = object.__getattribute__(self, 'gettypeid')

            # This tells the server that the return value of this method is

            # B, for which we've registered a proxy.

            gettypeid['__getattribute__'] = 'B'



        return result


class HackedDict:

    def __init__(self, data):

        self.data = data


    def __setitem__(self, key, value):

        self.data[key] = value


    def __getitem__(self, key):

        obj, exposed, gettypeid = self.data[key]

        if isinstance(obj, A):

            gettypeid = gettypeid.copy() if gettypeid else {}

            # Now we need getattr to update gettypeid based on the result

            # luckily BaseManager queries the typeid info after the function

            # has been invoked

            obj = HackedObj(obj, gettypeid)


        return (obj, exposed, gettypeid)


class HackedServer(Server):

    def __init__(self, registry, address, authkey, serializer):

        super().__init__(registry, address, authkey, serializer)

        self.id_to_obj = HackedDict(self.id_to_obj)


class MyManager(BaseManager):

    _Server = HackedServer


class ProxyBase(NamespaceProxy):

    _exposed_ = ('__getattribute__', '__setattr__', '__delattr__')

class AProxy(ProxyBase): pass

class BProxy(ProxyBase): pass


MyManager.register('A', callable=A, proxytype=AProxy)

MyManager.register('B', callable=B, proxytype=BProxy)


if __name__ == '__main__':

    print("This process: ", os.getpid())

    with MyManager() as manager:

        myB = manager.B()

        print("Proxy process, using B directly: ", myB.pid)

        

        myA = manager.A()

        print('myA.b', myA.b)

        

        print("Proxy process, via A: ", myA.a.pid)


解決方案的關(guān)鍵是替換_Server我們管理器中的 ,然后將id_to_obj字典包裝為針對(duì)我們需要的特定方法執(zhí)行 hack 的字典。


該黑客方法包括填充gettypeid該方法的字典,但只有在它被評(píng)估并且我們知道返回類型是我們需要代理的類型之后。幸運(yùn)的是,我們的評(píng)估順序gettypeid是在調(diào)用該方法之后訪問的。


幸運(yùn)的是,gettypeid它在方法中用作本地變量serve_client,因此我們可以返回它的副本并對(duì)其進(jìn)行修改,并且不會(huì)引入任何并發(fā)問題。


雖然這是一個(gè)有趣的練習(xí),但我不得不說我真的建議不要使用此解決方案,如果您正在處理無法修改的外部代碼,您應(yīng)該簡(jiǎn)單地創(chuàng)建自己的包裝類,該包裝類具有顯式方法而不是訪問@property器,代理您自己的類代替,并使用method_to_typeid.


查看完整回答
反對(duì) 回復(fù) 2023-12-26
  • 1 回答
  • 0 關(guān)注
  • 176 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)