Замена объекта одним из его методов - PullRequest
2 голосов
/ 10 февраля 2020

Я использую python и у меня есть объект, у этого объекта есть метод. Я ищу простой способ заменить весь объект внутри этой функции.

Например,

class a():
    def b(self):
        self = other_object

Как вы можете это сделать?

Спасибо

Ответы [ 2 ]

1 голос
/ 12 февраля 2020

Вы используете прокси / фасадный объект для хранения ссылки на реальный объект, self, если у вас sh, и этот прокси (более подходящий термин, чем Facade, но не меняющий мой код сейчас) - это то, что остальные ваша кодовая база видит. Однако любой доступ к атрибуту / методу перенаправляется на фактический объект, который можно заменить.

Код ниже должен дать вам приблизительное представление. Обратите внимание, что вы должны быть осторожны с рекурсией вокруг __the_instance, поэтому я назначаю __dict__ напрямую. Немного запутанно, так как уже давно я написал код, который полностью переносит getattr и setattr.

class Facade:
    def __init__(self, instance):
        self.set_obj(instance)

    def set_obj(self, instance):
        self.__dict__["__theinstance"] = instance

    def __getattr__(self, attrname):
        if attrname == "__theinstance":
            return self.__dict__["__theinstance"]                

        return getattr(self.__dict__["__theinstance"], attrname)

    def __setattr__(self, attrname, value):
        if attrname == "__theinstance":
            self.set_obj(value)

        return setattr(self.__dict__["__theinstance"], attrname, value)


class Test:
    def __init__(self, name, cntr):
        self.name = name 
        self.cntr = cntr

    def __repr__(self):
        return "%s[%s]" % (self.__class__.__name__, self.__dict__)

obj1 = Test("first object", 1)

obj2 = Test("second", 2)
obj2.message = "greetings"


def pretend_client_code(facade):
    print(id(facade), facade.name, facade.cntr, getattr(facade, "value", None))


facade = Facade(obj1)

pretend_client_code(facade)

facade.set_obj(obj2)

pretend_client_code(facade)

facade.value = 3

pretend_client_code(facade)

facade.set_obj(obj1)

pretend_client_code(facade)

output:

4467187104 first object 1 None
4467187104 second 2 None
4467187104 second 2 3
4467187104 first object 1 None

Таким образом, по сути, «клиентский код» всегда видит тот же самый фасадный объект, но то, к чему он фактически получает доступ, зависит от того, что сделал ваш эквивалент def b.

Фасад имеет специфическое значение c в терминологии Design Patterns, и он может быть неприменим здесь , но достаточно близко. Возможно, Прокси был бы лучше.

Обратите внимание, что если вы хотите изменить класс на том же объекте, это совсем другое дело, путем присвоения self.__class__. Например, скажем, RPG-игра с EnemyClass, которого после убийства поменяют на DeadEnemyClass: self.__class__ = DeadEnemyClass

0 голосов
/ 10 февраля 2020

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

class A():
    def __init__(self, instance=None):
        self.instance = val or self

    # yes, you can make it a property as well.
    def set_val(self, obj):
        self.instance = obj

    def get_val(self):
        return self.instance

Маловероятно, что замена переменной 'self' приведет к тому, что вы пытаетесь сделать, что не могло быть просто достигается путем сохранения результата fun c (self) в другой переменной. «self» - это локальная переменная, определенная только для продолжительности вызова метода, которая используется для передачи экземпляра класса, с которым выполняется операция. Замена self на самом деле не заменит ссылки на исходный экземпляр класса, хранящийся в других объектах, и не создаст долговременную ссылку на новый экземпляр, который был ему назначен.

Исходный источник: Безопасно ли заменить собственный объект другим объектом того же типа в методе?

...