Пересвязать объект Python (т.е. передать по ссылке) - PullRequest
1 голос
/ 23 июня 2011

У меня есть функция, которую я хочу использовать для управления входным параметром, однако в процессе я должен скопировать входной параметр. Я не хочу возвращать измененный объект (потому что многопроцессорность может или не может быть вовлечена). Как переназначить входной параметр скопированному значению? Вот представление функции:

from copy import deepcopy, copy

def myFunc(myObj,i):
    myObj.x = 'start'
    # I can't avoid this step:
    modObj = deepcopy(myObj)
    modObj.x = 'modified'
    if i == 0:
        myObj.x = modObj.x
    elif i == 1:
        myObj = modObj
    elif i == 2:
        myObj = copy(modObj)
    elif i == 3:
        myObj.__dict__ = modObj.__dict__

class MyClass(object):
   def __init__(self):
       self.x = "construct"

for i in range(4):
   temp = MyClass()
   myFunc(temp,i)
   print i,temp.x

А вот и вывод:

0 modified
1 start
2 start
3 modified

Поскольку вариант № 3 очень близок к тому, что я хочу сделать, есть ли «официальный» способ сделать это? Э.Г.

myObj.shallowcopy(modObj)

, где эта мелкая копия ведет себя так же, как мелкая копия в копии. Одной из альтернатив может быть внедрение MyClass в качестве члена какого-то другого класса и передача этого класса в функцию ... но если я могу это сделать, почему Python не может просто сохранить этот шаг, скопировав данные члена? Я прочитал это , но, похоже, они не нашли ответ для меня.

1 Ответ

1 голос
/ 23 июня 2011

Обновление : Хорошо, теперь, когда я больше понимаю проблему, я бы предложил комбинацию вариантов 1 и 4: создать общедоступные методы update() и dictify(). Эти могут быть обертками вокруг варианта 4 или некоторого варианта, например myObj.__dict__.update(modObj.__dict__), оба из которых несколько хакерские.

Или это могут быть элегантные, читаемые, самодокументируемые методы, которые принимают и возвращают (соответственно) соответствующее словарное представление self, которое может совпадать или не совпадать с self.__dict__. Я думаю, что причина того, что Python не имеет никакой встроенной функциональности для подобных вещей, заключается в том, что не существует по-настоящему общего способа его реализации, потому что не все объекты имеют __dict__. Этот тип поведения имеет для настраиваемой реализации.

Если манипулирования __dict__ достаточно для ваших нужд, хорошо, но вы избавите себя от некоторых неприятностей, если скрываете эти манипуляции за абстракцией, которую можно изменить позже, если решите, что хотите реализовать __slots__ или что-то подобное .

(оставляя ниже для исторических целей)


Это смущает меня: «Я не хочу возвращать измененный объект (потому что многопроцессорная обработка может или не может быть задействована)». Если вы имеете в виду модуль multiprocessing, то даже параметры 0 и 3 не будут выполнены, поскольку процессы не разделяют память.

>>> for i in range(4):
...     temp = MyClass()
...     p = Process(target=myFunc, args=(temp, i))
...     p.start()
...     p.join()
...     print i,temp.x
... 
0 construct
1 construct
2 construct
3 construct

См? Если вы хотите передавать данные между процессами, вы должны использовать один из встроенных типов multiprocessing.

>>> from multiprocessing import Process, Queue
>>> 
>>> def myFuncQ(myObj, i, return_queue):
...     myObj.x = 'start'
...     modObj = deepcopy(myObj)
...     modObj.x = 'modified'
...     return_queue.put(modObj)
... 
>>> return_queue = Queue()
>>> for i in range(4):
...     temp = MyClass()
...     p = Process(target=myFuncQ, args=(temp, i, return_queue))
...     p.start()
...     p.join()
...     temp = return_queue.get()
...     print i,temp.x
... 
0 modified
1 modified
2 modified
3 modified

Если вы не используете multiprocessing, тогда Queue будет служить, как и любой другой изменяемый контейнер для этой цели. Это самый близкий к "официальному" способ передачи по ссылке в Python.

...