Как установить значение элемента подписываемого атрибута прокси-объекта - PullRequest
1 голос
/ 09 ноября 2019

Я использовал этот вопрос stackoverflow , чтобы попытаться реализовать manager объект, который будет управлять записью атрибутов пользовательского объекта. Я знаю, что мне нужно раскрыть магические методы, такие как __getattribute__, __setattr__ и __delattr__, определив _exposed_ в моем прокси-классе. Однако, когда я пытаюсь установить значение элемента подписного атрибута пользовательского объекта, оно остается неизменным.

При просмотре документации multiprocessing я не могу найти подкласс multiprocessing.managers NamespaceProxy - упомянуто в вышеупомянутом посте - где угодно. Я могу импортировать его с одной стороны;однако у меня есть ноющее сомнение, что оно не реализовано правильно.

Вот как я пытался изменить значение элемента массива, относящегося к объекту пользовательского класса:

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.

1 Ответ

1 голос
/ 09 ноября 2019

Я не выяснил, как (или если) это можно сделать с помощью какого-то общего __setitem__ метода - моей первоначальной цели - но вот как определить пользовательский метод (с именем my_setitem() ниже), которыйпохоже, что он может изменять значение индексированных элементов в массиве.

Это не позволит вам изменить значение подписываемого атрибута прокси-объекта напрямую подобноВы хотите, но это показывает способ их изменения.

Я думаю, что это будет работать в Python 3.7, так как я пытался избегать всего, что работало бы только в v3.8 с одним исключением , а именно эта новая функция , которая была добавлена ​​в поддержку f-строки, очень удобна для отладки, но при необходимости ее относительно легко удалить / заменить.

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])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...