【问题标题】:Class constructor able to init with an instance of the same class object类构造函数能够使用同一类对象的实例进行初始化
【发布时间】:2015-10-14 14:21:52
【问题描述】:

python能否创建一个可以用同一个类对象的实例初始化的类?

我试过了:

class Class(): 

    def __init__(self,**kwargs):

        print self

        self = kwargs.get('obj',self)

        print self

        if not hasattr(self,'attr1'):
            print 'attr1'
            self.attr1  = kwargs.pop('attr1',[])
        if not hasattr(self,'attr2'):
            print 'attr2'
            self.attr2 = kwargs.pop('attr2',[])

        print self

        self.attr1 = kwargs.pop('attr1',self.attr1)
        self.attr2 = kwargs.pop('attr2',self.attr2)
        print self.attr1
        print self.attr2

如果我创建一个新实例没有问题:

inst = Class(attr1=[1,2,3])
print inst
print inst.attr1,inst.attr2

输出是:

<__main__.Class instance at 0x7f2025834cf8>  
<__main__.Class instance at 0x7f2025834cf8>  
attr1  
attr2  
<__main__.Class instance at 0x7f2025834cf8>  
[1, 2, 3]  
[]  
<__main__.Class instance at 0x7f2025834cf8>  
[1, 2, 3]  []

但是如果我用实例inst创建一个新实例:

inst2 = Class(obj=inst)
print inst2
print inst2.attr1,inst2.attr2

输出是:

<__main__.Class instance at 0x7f202584b7e8>  
<__main__.Class instance at 0x7f2025835830>  
<__main__.Class instance at 0x7f2025835830>  
[1, 2, 3]  
[]  
 <__main__.Class instance at 0x7f202584b7e8>  

AttributeError                            Traceback (most recent call last)  
<ipython-input-228-29c9869a9f4d> in <module>()  
       1 inst2 = Class(obj=inst)  
       2 print inst2  
 ----> 3 print inst2.attr1,inst2.attr2  

 AttributeError: Class instance has no attribute 'attr1'  

我处理了这个问题,但我不知道如何解决它:

  • 在第一种情况下,实例地址始终相同(“内部”和“外部”类)
  • 第二种情况:

    • “内部”类:
    • init 调用在新地址创建一个新实例
    • 然后将self设置为前一个实例并更改地址:OK
    • self 已经有属性attr1atrr2:好的

    • 但“在课堂之外”:

    • inst2 有初始化的地址,没有属性!

怎么了?在 Python 中地址影响是如何工作的? 这样做是一种好方法吗?

【问题讨论】:

  • 什么?你到底想实现什么?!
  • 想象一下,如果你得到这个工作。语法会是什么样子?你将如何向其他人解释如何使用你的代码?
  • 投反对票是匿名的,不需要 cmets(参见例如 meta.stackoverflow.com/q/250177/3001761)。更不用说您评论了!如果你不能更明确,那么不要期待答案。你到底想做什么?通过__init__实现奇怪的复制方法?为什么?
  • 什么是“地址影响”
  • 您不必使用继承,我的观点是在 Python 中实现替代构造函数的规范方法是使用 @classmethod。这感觉就像在和墙争吵,所以我不再评论。

标签: python class init self


【解决方案1】:

不确定您要达到的目标,但从技术上讲,您的错误就在这里:

    self = kwargs.get('object',self)

self 没有什么神奇之处,它只是一个函数参数,并且作为一个局部变量,所以在函数内重新绑定它只会使局部名称 self 指向函数范围内的另一个对象 。它绝不会影响当前实例(由方法包装器传递给__init__ 的实例),它只是使self 成为object 的别名。

如果您想要将属性从object 复制到self,您必须明确地这样做:

 other = kwargs.get('object')
 if other is not None:
     self.attrx = other.attrx
     self.attry = other.attry
     # etc

哦,是的:Python 是高级语言,没有什么像“地址矫揉造作”这样的——你所拥有的只是引用对象的名称(实际上,名称=> 对象映射)。名称只是一个名称,对象实际所在的位置与您无关。

【讨论】:

  • 所以如果我理解得很好,它只是局部变量,它是当前实例的别名(由方法包装器传递给 init)?因此,如果我重新绑定它,我会“丢失” init 范围内的当前实例吗? @bruno\ desthuiliers
  • 谢谢@brunodesthuilliers
【解决方案2】:
  • 感谢上面的cmets,我明白了两件事:

    • self 只是一个局部变量,它不是类实例
    • _init_ 是一个类的内置方法,用于从其他对象初始化实例
  • 因此,如果我希望能够从现有实例初始化新类实例,我只需创建一个调用 _init_ 的“初始化程序”方法:

    class Class(): 
    
    
        def __init__(self,**kwargs):
    
            self.attr1 = kwargs.pop('attr1',[])
            self.attr2 = kwargs.pop('attr2',[])
    
        def Class(self,**kwargs):
    
            return Class(attr1 = kwargs.pop('attr1',self.attr1),\
                         attr2 = kwargs.pop('attr2',self.attr2))
    

并像这样使用它:

inst = Class(attr1=[1,2,3])
print inst
print inst.attr1,inst.attr2

输出:

<__main__.Class instance at 0x7eff842d5368>
[1, 2, 3] []

inst2 = inst.Class(attr2=[12,11])
print inst2
print inst2.attr1,inst2.attr2

输出:

<__main__.Class instance at 0x7eff842d56c8>
[1, 2, 3] [12, 11]

【讨论】:

  • "self 只是一个局部变量,它不是类实例" : self 是函数作用域中的一个名称,这个名称最初是指当前实例(方法已被调用)。
猜你喜欢
  • 2012-11-05
  • 2015-11-05
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 2013-12-30
  • 1970-01-01
  • 2016-01-08
  • 1970-01-01
相关资源
最近更新 更多