在另一个类中创建Python代理类
我正在尝试让一个代理类正常工作,但它似乎不太愿意合作。我想要代理的类如下:
import zmq
class ZmqPublish():
def __init__(self):
self.context = None
self.pub_socket = None
def setup(self, addr):
self.context = zmq.Context()
if isinstance(addr, str):
addr = addr.split(':')
host, port = addr if len(addr) == 2 else (addr[0], None)
self.pub_socket = self.context.socket(zmq.PUB)
self.pub_socket.bind('tcp://%s:%s' % (host, port))
def send(self, msg_type, msg):
self.pub_socket.send_multipart([msg_type, msg])
这个类的功能很简单,就是启动一个发布者,并且能够发送消息。然后我还有另一个类,负责存储数据、发送消息以及处理某种回复:
from multiprocessing import Manager
from multiprocessing.managers import BaseManager
import zmq_publish
class publishManager(BaseManager):
pass
publishManager.register('zmq_publish.ZmqPublish', zmq_publish.ZmqPublish)
class Storage:
def __init__(self):
self.manager = Manager()
self.dict = self.manager.dict()
# Additional variables
self.host = '127.0.0.1'
self.port = 5555
self.bind_addr = (self.host, self.port)
self.publishManager = Storage.publishManager()
self.publishManager.start()
self.publishManager.setup(self.bind_addr)
def setup(self):
# Set up zmq subscriber with callbacks
def add(self, msg):
self.dict[msg] = 0
self.publishManager.send('type', msg)
举个例子,add
函数被用作 zmq 进程的回调,它会添加一些信息。我的想法是,它也可以作为响应发送一条消息。问题是,这条消息从来没有发送出去,我认为这是因为回调进程和创建发布者实例的进程不是同一个。因此,我正在尝试代理这个类,并通过一个管理器让它可用,但到目前为止还没有成功。有人能帮我或者给我一些提示吗?
祝好,
帕特里克
相关问题:
- 暂无相关问题
1 个回答
我不太明白你的问题,不过我可以给你一个提示,希望能帮你完成任务。你可以通过重载 __getattr__
来处理访问未定义属性的情况,或者重载 __getattribute__
来处理访问所有属性的情况。
class Proxy:
def __init__(self, Klass):
self.Klass = Klass # Save/embed original class/object
def __getattr__(self, name): # On undefined attr fetches only
...
return getattr(self.Klass, name) # Delegate to Klass/ could be an obj too
....
这样一来,任何在 Proxy
中未定义的属性都会被 __getattr__
拦截,并转交给 Klass
。这里的 Klass
是一个类对象,所以我们实际上是在代理这个类本身,Klass
也可以是一个类的实际实例。简单来说,Proxy
只会把未定义的属性请求转交给 klass
。因此,当你访问一个在 Proxy
中不存在的属性时,__getattr__
会自动被触发,并将你的请求转交给被包装的对象 klass
。如果你想拦截所有属性的请求,就需要使用 __getattribute__
,而且你可能还需要使用 object.__getattribute__
来避免在 __getattribute__
中出现递归,因为在你的代理方法中使用任何 self.attr
都会触发你类的 __getattribute__
。
编辑:如何使用 Proxy
类:
如果你想代理另一个类的对象,可以这样做:
class Proxy:
# Proxy objects of other classes
def __init__(self, obj):
self.obj = obj
def __getattr__(self, attr):
return getattr(self.obj, attr) # Run only on undefined attribute accesses
class Test:
data = 'some data'
def __init__(self, x, y):
self.x = x
self.y = y
def add(self):
return self.x + self.y
def mul(self):
return self.x * self.y
test_obj = Test(3, 4)
proxied_obj = Proxy(test_obj) # Delegate some operations to test_obj
proxied_obj.add() # Calls Proxy.__getattr__
print(proxied_obj.mul()) # Calls Proxy.__getattr__
如你所见,add
和 mul
方法实际上并不存在于代理其他类实例的 Proxy
类中。proxied_obj
是一个 Proxy
类的实例,里面包装了一个 Test
对象。*注意,__getattr__
就像一个后备选项,只有在找不到属性时,__getattr__
才会被调用。也就是说,如果在 Proxy
实例本身、它的类或父类中找不到某个属性,那么 __getattr__
就会被触发。
你可以在 Proxy
中添加其他方法,以增强被代理对象的接口。在 Python 3.X 和新式类中,如果你的被代理对象需要重载运算符的方法,比如 __add__
用于 +
或 __getitem__
用于索引,你需要在 Proxy
或其父类中重新定义所有重载方法,这样内置操作才能成功:
class Proxy:
def __init__(self, obj):
self.obj = obj
def __getattr__(self, attr):
return getattr(self.obj, attr)
def __add__ (...): ...
def __getitem__(...): ...
如果你还是感到困惑,可以查看这个链接:面向对象编程和委托:“包装器”代理对象
我真的鼓励你打开 Python 解释器,尝试一些小的代码实验。一行代码可能比100句废话更有效,反之亦然。