【问题标题】:Replacing the object from one of its methods从其方法之一替换对象
【发布时间】:2020-02-10 08:31:48
【问题描述】:

我正在使用 python 并且有一个对象,该对象有一个方法。我正在寻找一种简单的方法,从该函数中替换整个对象。

例如

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

你怎么能做到这一点?

谢谢

【问题讨论】:

  • 这是不可能的,而且闻起来像 XY problem。为什么你认为你需要这样做?
  • selfa 的实例,我不认为你可以替换它。你为什么还要这样做?
  • 你有什么问题?
  • 您可以有一个类变量来存储other 对象并实现__getattr____setattr__ 以显式使用other 对象来获取和设置属性。
  • 你不需要它的方法。您只需在代码的任何部分执行obj = other_obj。如果你仍然认为你需要它,那是不可能的。

标签: python python-3.x oop metaprogramming


【解决方案1】:

您使用代理/外观对象来保存对实际对象的引用,如果您愿意,可以使用 self,并且该代理(比外观更好,但现在不更改我的代码)是您代码库的其余部分所看到的.但是,任何属性/方法访问都会转发到可交换的实际对象。

下面的代码应该给你一个粗略的想法。请注意,您需要小心围绕__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)

输出:

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

所以基本上,“客户端代码”总是看到相同的外观对象,但它实际访问的内容取决于您的 def b 等效项所做的工作。

Facade 在设计模式术语中具有特定的含义,在这里它可能并不真正适用,但足够接近。也许代理会更好。

请注意,如果您想更改 same 对象上的类,那是另一回事,通过分配 self.__class__ 来完成。例如,假设一个 RPG 游戏的 EnemyClass 一旦被杀死就会被换成 DeadEnemyClassself.__class__ = DeadEnemyClass

【讨论】:

  • @kaya3 是的,你可以。这是否是一个好主意是一个不同的问题,但是有很多代码可以做到这一点。例如,它是构建状态机的一种方法。如果你走那条路,只使用设计为以这种方式使用的类 - 始终具有相同的方法名称和属性名称,只是内容不同。
  • 我的错;我过去出于好奇尝试过它并看到了一个错误,但显然如果原始类和新类都是没有__slots__的用户定义类,则有可能。
  • 啊,看,我们都学到了一些东西。我没有意识到__slots__ 会干扰,但我不能说我很惊讶他们这样做。应该非常谨慎地处理它,但它可以替代相当多的工厂设计模式样板,但代价是当他们的实例动态更改类时,代码的用户可能会非常惊讶。绝对要注意 Liskov 替换原则 - 理想情况下,它们都将共享相同的直系祖先类 - 并且仅在适当时使用。
  • 我认为只有当新类是旧类的子类,或者不存在对实例的其他引用时,它才是安全的。否则例如List[A] 可能会发现自己包含非 A 类型的东西,这不是它自己的错误。
【解决方案2】:

你不能直接这样做。您可以将其保存为实例变量。

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”变量不太可能完成 无论您尝试做什么,都无法通过以下方式完成 将 func(self) 的结果存储在不同的变量中。 “自我”是 实际上是一个仅在持续时间内定义的局部变量 方法调用,用于传入正在被调用的类的实例 操作。替换 self 实际上不会替换对 其他对象持有的类的原始实例,也不会 创建对分配给的新实例的持久引用 它。

原文来源:Is it safe to replace a self object by another object of the same type in a method?

【讨论】:

    猜你喜欢
    • 2013-10-25
    • 2012-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-26
    • 1970-01-01
    • 2015-06-23
    相关资源
    最近更新 更多