【问题标题】:Is it safe to replace a self object by another object of the same type in a method?在方法中用另一个相同类型的对象替换 self 对象是否安全?
【发布时间】:2010-11-16 00:37:03
【问题描述】:

我想用这样的方法中的另一个实例替换一个对象实例:

class A:
    def method1(self):
        self = func(self)

从数据库中检索对象。

【问题讨论】:

标签: python


【解决方案1】:

替换 'self' 变量不太可能完成您想要做的任何事情,这不能仅通过将 func(self) 的结果存储在不同的变量中来完成。 “self”实际上是一个仅在方法调用期间定义的局部变量,用于传递正在操作的类的实例。替换 self 实际上不会替换对其他对象持有的类的原始实例的引用,也不会创建对分配给它的新实例的持久引用。

【讨论】:

  • 你的答案如何与小 7 岁的one 表达得更清楚?你的还“正确”吗?即使我几乎看不出这怎么能被认为是一种好的做法,但看起来“绿色勾号”应该从你的移到 @Nithin 的,你不这么认为吗?
  • 不,我没有。更新__dict__ 的内容并不是用另一个对象替换一个对象。 (例如,如果对象已被实际替换,如果对象是差异类,它将导致is 检查的行为不会像您期望的那样发生变化,等等。)来自@Nithin 的答案既危险又不正确。
  • 最后,我宁愿说@Nithin's 并没有严格解决这个问题。这确实是不“移动刻度”的一个很好的理由。关键是self.__dict__.update 实际上以一种非常方便的方式更改了所有相关的self 的属性。在某些情况下,这样做实际上可能是读者正在寻找的,向他们表明他们甚至不需要更改 self 对象的愿望,即是一种错误的方法。如果有一个例子说明原因就好了你认为这很危险...... 700rep 的答案是值得的......虽然很耗时。
  • @keepAlive 从表面上看,问题是试图用另一个对象实例替换一个对象实例。 @Nithin 的回答破坏了一个对象属性的 子集 与另一个对象的属性。我和@Amber 在一起:这与所要求的行为完全不同,很hacky,甚至可能不会导致2 个具有相同属性的对象。 self 中不在 newObj 中的属性保持不变。依赖于对象引用的操作将不会按预期运行,这可能是一个关键方面......我现在正在查看的代码恰好是这种情况,导致我提出了这个问题.
【解决方案2】:

据我了解,如果您尝试使用成员函数中的另一个相同类型的对象(假设 func 不会更改对象类型)替换当前对象。我认为这将实现这一目标

class A:
    def method1(self):
        newObj = func(self)
        self.__dict__.update(newObj.__dict__)

【讨论】:

  • 请注意,self 上的任何现有属性在使用 update 时都将保留。这对我的应用程序来说是一个额外的好处:-)
【解决方案3】:

这不是问题的直接答案,但在下面的帖子中,有一个解决方案来解决 amirouche 试图做的事情:

这里是工作代码示例 (Python 3.2.5)。

class Men:
    def __init__(self, name):
        self.name = name

    def who_are_you(self):
        print("I'm a men! My name is " + self.name)

    def cast_to(self, sex, name):
        self.__class__ = sex
        self.name = name

    def method_unique_to_men(self):
        print('I made The Matrix')


class Women:
    def __init__(self, name):
        self.name = name

    def who_are_you(self):
        print("I'm a women! My name is " + self.name)

    def cast_to(self, sex, name):
        self.__class__ = sex
        self.name = name

    def method_unique_to_women(self):
        print('I made Cloud Atlas')


men = Men('Larry')
men.who_are_you()
#>>> I'm a men! My name is Larry
men.method_unique_to_men()
#>>> I made The Matrix


men.cast_to(Women, 'Lana')
men.who_are_you()
#>>> I'm a women! My name is Lana
men.method_unique_to_women()
#>>> I made Cloud Atlas

注意self.__class__ 而不是self.__class__.__name__。 IE。这种技术不仅替换了类名,而且实际上转换了一个类的实例(至少它们都具有相同的id())。另外,1)我不知道“在[an object own]方法中用另一个相同类型的对象替换self对象是否安全”; 2)它适用于不同类型的对象,不仅适用于相同类型的对象; 3) 它的工作方式与 amirouche 想要的不完全一样:你不能像 Class(args) 那样初始化类,只能像 Class() 一样(我不是专业人士,无法回答为什么会这样)。

【讨论】:

    【解决方案4】:

    是的,将会发生的只是您将无法引用您的类的当前实例A(除非您在更改之前将另一个变量设置为self。)我不会推荐它但是,它会导致代码的可读性降低。

    请注意,您只是在更改一个变量,就像其他任何变量一样。执行self = 123 与执行abc = 123 相同。 self 只是对方法中当前实例的引用。您无法通过设置 self 来更改您的实例。

    func(self) 应该做的是更改实例的变量:

    def func(obj):
        obj.var_a = 123
        obj.var_b = 'abc'
    

    然后这样做:

    class A:
        def method1(self):
            func(self) # No need to assign self here
    

    【讨论】:

      【解决方案5】:

      在许多情况下,实现您想要的一个好方法是再次调用__init__。例如:

      class MyList(list):
          def trim(self,n):
              self.__init__(self[:-n])
      
      x = MyList([1,2,3,4])
      x.trim(2)
      assert type(x) == MyList
      assert x == [1,2]
      

      请注意,这带有一些假设,例如您想要更改的关于在__init__ 中设置的对象的所有内容。另请注意,这可能会导致继承以不兼容方式重新定义 __init__ 的类出现问题。

      【讨论】:

        【解决方案6】:

        是的,这没有什么问题。愤世嫉俗的人看什么都不顺眼。 (看着你的 Pycharm 和你的 in most cases imaginable, there's no point in such reassignment and it indicates an error)。

        您可以这样做的情况是:

        some_method(self, ...):
        
            ...
        
            if(some_condition):
                self = self.some_other_method()
        
            ...
        
            return ...
        

        当然,您可以通过将self 重新分配给其他变量来启动方法主体,但如果您通常不会对其他参数执行此操作,那么为什么要使用self

        【讨论】:

          【解决方案7】:

          可以在方法中使用自赋值,将实例的类更改为派生类。

          当然可以将它分配给一个新对象,但随后对新对象的使用会影响方法中的其余代码。将其重新分配给自己,保持方法的其余部分不变。

          class aclass:
          
              def methodA(self):
                  ...
                  if condition:
                      self = replace_by_derived(self)
                      # self is now referencing to an instance of a derived class
                      # with probably the same values for its data attributes
          
                  # all code here remains untouched
                  ...
                  self.methodB() # calls the methodB of derivedclass is condition is True
                  ...
          
              def methodB(self):
                  # methodB of class aclass
                  ...
          
          class derivedclass(aclass):
              def methodB(self):
                  #methodB of class derivedclass
                  ...
          

          但是除了这种特殊的用例之外,我看不出替换 self 有什么好处。

          【讨论】:

          • 正如其他人所说,self 只是本地的,所以无论如何它都不起作用。
          【解决方案8】:

          您可以使实例成为类的单例元素 并用@classmethod标记方法。

          from enum import IntEnum
          from collections import namedtuple
          
          class kind(IntEnum):
              circle = 1
              square = 2
          
          def attr(y): return [getattr(y, x) for x in 'k l b u r'.split()]
          
          class Shape(namedtuple('Shape', 'k,l,b,u,r')):
              self = None
          
              @classmethod
              def __repr__(cls):
                  return "<Shape({},{},{},{},{}) object at {}>".format(
                      *(attr(cls.self)+[id(cls.self)]))
          
              @classmethod
              def transform(cls, func):
                  cls.self = cls.self._replace(**func(cls.self))
          
          Shape.self = Shape(k=1, l=2, b=3, u=4, r=5)
          s = Shape.self
          
          def nextkind(self):
              return {'k': self.k+1}
          
          print(repr(s))  # <Shape(1,2,3,4,5) object at 139766656561792>
          s.transform(nextkind)
          print(repr(s))  # <Shape(2,2,3,4,5) object at 139766656561888>
          
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-11-29
            • 1970-01-01
            • 2012-12-05
            • 1970-01-01
            • 1970-01-01
            • 2022-06-27
            相关资源
            最近更新 更多