如何设置代理对象的可订阅属性的元素值
How to set the element value of a subscriptable attribute of a proxy object
我用这个 Whosebug question 来尝试实现一个 manager
对象来管理自定义对象属性的写入。我知道我需要通过在代理 class 中定义 _exposed_
来公开 __getattribute__
、__setattr__
和 __delattr__
等魔术方法。但是,当我尝试设置自定义对象的可订阅属性的元素的值时,它保持不变。
查看multiprocessing
文档,我找不到multiprocessing.managers
subclass NamespaceProxy
——前面提到的post——任何地方。我一方面可以导入它;但是,我一直怀疑它没有正确实施。
下面是我如何尝试更改数组元素的值,归因于自定义 class 的对象:
from multiprocessing.managers import BaseManager, NamespaceProxy
import numpy as np
class TestClass(object):
def __init__(self, a):
'''
Args:
a (np.ndarray): the array that needs to be changed
'''
self.a = a
class TestProxy(NamespaceProxy):
# exposes the magic methods for TestProxy objects needed for setting their attributes
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__')
class MyManager(BaseManager):
pass
if __name__ == '__main__':
MyManager.register('test', TestClass, TestProxy)
manager = MyManager()
manager.start()
arr = np.array([0,0,0,0])
managed_obj = manager.test(arr)
managed_obj.a[0] = 1
print(managed_obj.a)
# Console: [0 0 0 0]
# Expected ouput: [1 0 0 0]
编辑: 我可以用
之类的东西更改 a
的实际值
arr2 = np.array([0])
managed_obj.a = arr2
print(managed_obj.a)
# Console : [0]
但是,我还是不知道如何改变a
的一个元素的值。
我还没有弄清楚如何(或是否)可以通过某种通用 __setitem__
方法使其工作——我最初的目标——但这里是如何定义自定义方法(名为 my_setitem()
下面)似乎能够更改数组中索引元素的值。
它不允许您直接更改代理对象的可订阅属性的值,但它确实展示了一种更改它们的方法。
我认为这会在 Python 3.7 中起作用,因为我试图避免做任何只能在 v3.8 中起作用的事情 只有一个例外,即这个 new feature 添加到 f-string 支持对于调试非常方便 — 但如有必要,remove/replace 应该相对容易。
from multiprocessing.managers import BaseManager, NamespaceProxy
import numpy as np
from functools import partial
print = partial(print, flush=True) # Change default.
class TestClass(object):
def __init__(self, a):
'''
Args:
a (np.ndarray): the array that needs to be changed
'''
print(f'TestClass.__init__ called, {a = }')
self.a = a
def my_setitem(self, name, index, value):
print(f'in TestClass.my_setitem()')
attr = getattr(self, name)
attr[index] = value
class TestProxy(NamespaceProxy):
# exposes the magic functions for TestProxy objects needed for setting their attributes
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'my_setitem')
def my_setitem(self, name, index, value):
print(f'in TestProxy.my_setitem()')
callmethod = object.__getattribute__(self, '_callmethod')
return callmethod('my_setitem', (name, index, value))
class MyManager(BaseManager):
pass
if __name__ == '__main__':
MyManager.register('Testclass', TestClass, TestProxy)
manager = MyManager()
manager.start()
arr = np.array([0,0,0,0])
print(f'calling manager.Testclass(arr)')
managed_obj = manager.Testclass(arr)
print(f'result: {managed_obj = }')
print()
# managed_obj.a[0] = 42 # The problem, doesn't work.
name = 'a'
index = 1
# index = slice(0, 2) # slices also work
print(f'executing managed_obj.my_setitem({name=}, {index=}, 42)')
managed_obj.my_setitem(name, index, 42)
print(f'result: {managed_obj.a = }') # -> result: managed_obj.a = array([ 0, 42, 0, 0])
这是它产生的输出(运行 Py 3.8.0 在我的系统上):
calling manager.Testclass(arr)
TestClass.__init__ called, a = array([0, 0, 0, 0])
result: managed_obj = <TestProxy object, typeid 'Testclass' at 0x4b3f520>
executing managed_obj.my_setitem(name='a', index=1, 42)
in TestProxy.my_setitem()
in TestClass.my_setitem()
result: managed_obj.a = array([ 0, 42, 0, 0])
我用这个 Whosebug question 来尝试实现一个 manager
对象来管理自定义对象属性的写入。我知道我需要通过在代理 class 中定义 _exposed_
来公开 __getattribute__
、__setattr__
和 __delattr__
等魔术方法。但是,当我尝试设置自定义对象的可订阅属性的元素的值时,它保持不变。
查看multiprocessing
文档,我找不到multiprocessing.managers
subclass NamespaceProxy
——前面提到的post——任何地方。我一方面可以导入它;但是,我一直怀疑它没有正确实施。
下面是我如何尝试更改数组元素的值,归因于自定义 class 的对象:
from multiprocessing.managers import BaseManager, NamespaceProxy
import numpy as np
class TestClass(object):
def __init__(self, a):
'''
Args:
a (np.ndarray): the array that needs to be changed
'''
self.a = a
class TestProxy(NamespaceProxy):
# exposes the magic methods for TestProxy objects needed for setting their attributes
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__')
class MyManager(BaseManager):
pass
if __name__ == '__main__':
MyManager.register('test', TestClass, TestProxy)
manager = MyManager()
manager.start()
arr = np.array([0,0,0,0])
managed_obj = manager.test(arr)
managed_obj.a[0] = 1
print(managed_obj.a)
# Console: [0 0 0 0]
# Expected ouput: [1 0 0 0]
编辑: 我可以用
之类的东西更改a
的实际值
arr2 = np.array([0])
managed_obj.a = arr2
print(managed_obj.a)
# Console : [0]
但是,我还是不知道如何改变a
的一个元素的值。
我还没有弄清楚如何(或是否)可以通过某种通用 __setitem__
方法使其工作——我最初的目标——但这里是如何定义自定义方法(名为 my_setitem()
下面)似乎能够更改数组中索引元素的值。
它不允许您直接更改代理对象的可订阅属性的值,但它确实展示了一种更改它们的方法。
我认为这会在 Python 3.7 中起作用,因为我试图避免做任何只能在 v3.8 中起作用的事情 只有一个例外,即这个 new feature 添加到 f-string 支持对于调试非常方便 — 但如有必要,remove/replace 应该相对容易。
from multiprocessing.managers import BaseManager, NamespaceProxy
import numpy as np
from functools import partial
print = partial(print, flush=True) # Change default.
class TestClass(object):
def __init__(self, a):
'''
Args:
a (np.ndarray): the array that needs to be changed
'''
print(f'TestClass.__init__ called, {a = }')
self.a = a
def my_setitem(self, name, index, value):
print(f'in TestClass.my_setitem()')
attr = getattr(self, name)
attr[index] = value
class TestProxy(NamespaceProxy):
# exposes the magic functions for TestProxy objects needed for setting their attributes
_exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'my_setitem')
def my_setitem(self, name, index, value):
print(f'in TestProxy.my_setitem()')
callmethod = object.__getattribute__(self, '_callmethod')
return callmethod('my_setitem', (name, index, value))
class MyManager(BaseManager):
pass
if __name__ == '__main__':
MyManager.register('Testclass', TestClass, TestProxy)
manager = MyManager()
manager.start()
arr = np.array([0,0,0,0])
print(f'calling manager.Testclass(arr)')
managed_obj = manager.Testclass(arr)
print(f'result: {managed_obj = }')
print()
# managed_obj.a[0] = 42 # The problem, doesn't work.
name = 'a'
index = 1
# index = slice(0, 2) # slices also work
print(f'executing managed_obj.my_setitem({name=}, {index=}, 42)')
managed_obj.my_setitem(name, index, 42)
print(f'result: {managed_obj.a = }') # -> result: managed_obj.a = array([ 0, 42, 0, 0])
这是它产生的输出(运行 Py 3.8.0 在我的系统上):
calling manager.Testclass(arr)
TestClass.__init__ called, a = array([0, 0, 0, 0])
result: managed_obj = <TestProxy object, typeid 'Testclass' at 0x4b3f520>
executing managed_obj.my_setitem(name='a', index=1, 42)
in TestProxy.my_setitem()
in TestClass.my_setitem()
result: managed_obj.a = array([ 0, 42, 0, 0])