Какие побочные эффекты следует ожидать, когда метод decorator заменяет собой? - PullRequest
0 голосов
/ 23 января 2010

Я хочу выполнить метод с копией оригинала self, переданной во время выполнения.

Вот код, о котором я говорю:

def protect_self(func):
    from copy import copy
    from functools import wraps
    @wraps(func)
    def decorated(self, *args, **kwargs):
        self_copy = copy(self)
        return func(self_copy, *args, **kwargs)
    return decorated

В моем понимании функция копирования создает новый объект того же типа и копирует __dict__ старого в новый объект (используя ссылки, так изменения в реальных экземплярах объекта в __dict__ все равно будут влиять на исходный объект).

Означает ли это, что я могу быть уверен, что декорированный метод не может изменить __dict__ из оригинальный экземпляр?

Просто чтобы убедиться: мне не нужно безопасное поведение в песочнице. Моя цель просто чтобы создать экземпляр одного объекта, который я буду использовать как фабрику. Защищенный метод должен иметь возможность изменить переданный self, но он должен быть сброшены впоследствии.

Ответы [ 2 ]

2 голосов
/ 23 января 2010

Копия делает его таким, чтобы «я», переданное в декорированную функцию, было мелкой копией оригинала. Декорированная функция не может изменять исходное «я» напрямую, хотя, конечно, она может изменять его другими способами (если у нее есть косвенный доступ к ней.) Если какой-либо из атрибутов объекта изменчив, он может эффективно изменить оригинальное «я» путем изменения атрибутов.

Кроме того, любой фрагмент (произвольного) кода Python имеет косвенный доступ практически ко всем объектам в программе. Декорированная функция может получить доступ к исходному «я» через проверку стека или, например, через модуль gc. Ваш случай использования кажется немного запутанным; Вы уверены, что должны использовать экземпляр класса для этого?

1 голос
/ 23 января 2010

Как ОП пояснил в комментарии, что цель состоит в том, чтобы быть потокобезопасными, тогда есть очевидная проблема - copy.copy сам не потокобезопасен, в дополнение к уже упомянутой проблеме, что copy.copy создает мелкую копию и, таким образом (хотя само self.__dict__ не будет изменено), изменяемые объекты вполне могут быть изменены. Использование copy.deepcopy имеет дело с этим (с потенциально высокой ценой с точки зрения производительности), но в некотором смысле даже ухудшает проблему безопасности потоков (поскольку глубокое копирование может занять гораздо больше времени, чем мелкое копирование, риск гонки фактически возникающее состояние растет как на дрожжах - не то, чтобы я каким-либо образом, ни в какой форме, ни в форме не рекомендовал иметь расовые условия, которые возникают "очень редко", ум! -).

Если вам нужно сделать изначально небезопасные методы потокобезопасными, вам придется кусать пули и использовать блокировки (или очередь и вспомогательный поток для сериализации операций) - я полагаю, что если вам в дальнейшем понадобится молча игнорируя попытки методов изменить объекты, вам, кроме того, придется deepcopy все (зачем останавливаться на self - что если эти методы изменяют globals , например?! -). Мне кажется, очень сомнительное предложение.

...