我有一个由多进程管理器管理的类。我能够公开它的方法,并且看过关于如何公开它的属性的文章
Accessing an attribute of a multiprocessing Proxy of a class
我想知道如何从托管类的子类属性调用方法,如
from multiprocessing.managers import BaseManager
class TestSubClass:
def __init__(self):
self.a = 1
def set_a(self, a):
self.a = a
class TestClass:
def __init__(self):
self.subclass = TestSubClass()
def add_to_a(self, b):
return b + self.subclass.a
class MyManager(BaseManager): pass
MyManager.register('TestClass', TestClass)
if __name__ == '__main__':
with MyManager() as manager:
# Creates classes
t = TestClass()
mt : TestClass = manager.TestClass()
# Runs the Exposed add_to_a method
print (t.add_to_a(2))
print (mt.add_to_a(2))
# Runs the subclass method for the regular class
t.subclass.set_a(2)
print (t.add_to_a(2))
# Runs the subclass method for the proxy class (Fails)
mt.subclass.set_a(2)
print (mt.add_to_a(2))与上述链接问题的主要区别在于,我不是试图将子类返回到主进程,而是简单地调用经理进程中的一个子类方法
发布于 2021-04-18 13:58:53
您需要为您的TestClass定义一个支持属性的代理类。这应该继承NamespaceProxy以支持属性,您必须显式地公开以下方法:
class TestClassProxy(NamespaceProxy):
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'add_to_a')
def add_to_a(self, b):
callmethod = object.__getattribute__(self, '_callmethod')
return callmethod('add_to_a', args=(b,))我还建议将TestSubClass重命名为TestContainedClass。尽管在当前的代码中并不重要,但我会将register语句移到if __name__ == '__main__':块中,以便如果该代码被修改为创建进程,那么如果您碰巧在使用spawn创建这些进程的平台上(例如,Windows),那么新创建的进程就不会不必要地执行register语句。不管怎么说都没什么大不了的。
把这一切结合在一起:
from multiprocessing.managers import BaseManager, NamespaceProxy
class TestContainedClass:
def __init__(self):
self.a = 1
def set_a(self, a):
self.a = a
class TestClass:
def __init__(self):
self.subclass = TestContainedClass()
def add_to_a(self, b):
return b + self.subclass.a
class MyManager(BaseManager): pass
class TestClassProxy(NamespaceProxy):
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'add_to_a')
def add_to_a(self, b):
callmethod = object.__getattribute__(self, '_callmethod')
return callmethod('add_to_a', args=(b,))
if __name__ == '__main__':
MyManager.register('TestClass', TestClass, TestClassProxy)
with MyManager() as manager:
# Creates classes
t = TestClass()
mt : TestClass = manager.TestClass()
# Runs the Exposed add_to_a method
print (t.add_to_a(2))
print (mt.add_to_a(2))
# Runs the subclass method for the regular class
t.subclass.set_a(2)
print (t.add_to_a(2))
# Runs the subclass method for the proxy class (Fails)
mt.subclass.set_a(2)
print (mt.add_to_a(2))指纹:
3
3
4
3但是请注意,最后的结果是3,而不是预期的4。嵌套对象似乎不能很好地与Manager一起工作。见Sharing a complex object between processes?。
要使其工作,两个类都必须由代理来表示:
from multiprocessing.managers import BaseManager, NamespaceProxy
class MyManager(BaseManager): pass
class TestContainedClass:
def __init__(self):
self.a = 1
def set_a(self, a):
self.a = a
class TestContainedClassProxy(NamespaceProxy):
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'set_a')
def set_a(self, a):
callmethod = object.__getattribute__(self, '_callmethod')
return callmethod('set_a', args=(a,))
class TestClass:
def __init__(self, subclass):
self.subclass = subclass
def add_to_a(self, b):
return b + self.subclass.a
class TestClassProxy(NamespaceProxy):
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'add_to_a')
def add_to_a(self, b):
callmethod = object.__getattribute__(self, '_callmethod')
return callmethod('add_to_a', args=(b,))
if __name__ == '__main__':
MyManager.register('TestContainedClass', TestContainedClass, TestContainedClassProxy)
MyManager.register('TestClass', TestClass, TestClassProxy)
with MyManager() as manager:
# Creates classes
testContainedClass = manager.TestContainedClass()
mt : TestClass = manager.TestClass(testContainedClass)
# Runs the Exposed add_to_a method
print (mt.add_to_a(2))
# Runs the subclass method for the proxy class
mt.subclass.set_a(2)
print (mt.add_to_a(2))指纹:
3
4当然,它会更简单,只需重构原始代码:
from multiprocessing.managers import BaseManager, NamespaceProxy
class TestClass:
def __init__(self, a):
self.a = a
def add_to_a(self, b):
return b + self.a
class MyManager(BaseManager): pass
class TestClassProxy(NamespaceProxy):
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'add_to_a')
def add_to_a(self, b):
callmethod = object.__getattribute__(self, '_callmethod')
return callmethod('add_to_a', args=(b,))
if __name__ == '__main__':
MyManager.register('TestClass', TestClass, TestClassProxy)
with MyManager() as manager:
# Creates classes
t = TestClass(1)
mt : TestClass = manager.TestClass(1)
# Runs the Exposed add_to_a method
print (t.add_to_a(2))
print (mt.add_to_a(2))
# Runs the subclass method for the regular class
t.a = 2
print (t.add_to_a(2))
# Runs the subclass method for the proxy class
mt.a = 2
print (mt.add_to_a(2))指纹:
3
3
4
4或者,如果要使用方法a访问属性set_a,则可以使用默认代理:
from multiprocessing.managers import BaseManager, NamespaceProxy
class TestClass:
def __init__(self, a):
self.set_a(a)
def set_a(self, a):
self.a = a
def add_to_a(self, b):
return b + self.a
class MyManager(BaseManager): pass
if __name__ == '__main__':
MyManager.register('TestClass', TestClass)
with MyManager() as manager:
# Creates classes
t = TestClass(1)
mt : TestClass = manager.TestClass(1)
# Runs the Exposed add_to_a method
print (t.add_to_a(2))
print (mt.add_to_a(2))
# Runs the subclass method for the regular class
t.set_a(2)
print (t.add_to_a(2))
# Runs the subclass method for the proxy class
mt.set_a(2)
print (mt.add_to_a(2))https://stackoverflow.com/questions/67012978
复制相似问题