关于python:能够使用相同类对象的实例初始化的类构造函数

Class constructor able to init with an instance of the same class object

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

我试过了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

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

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

输出为:

1
2
3
4
5
6
7
8
9
<__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创建一个新实例:

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

输出为:

1
2
3
4
5
6
<__main__.Class instance at 0x7f202584b7e8>  
<__main__.Class instance at 0x7f2025835830>  
<__main__.Class instance at 0x7f2025835830>  
[1, 2, 3]  
[]  
 <__main__.Class instance at 0x7f202584b7e8>
1
2
3
4
5
6
7
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设置为上一个实例并更改地址:确定
    • self已经有了attr1atrr2的属性:好的。

    • 但在课堂之外:

    • inst2有init的地址,没有属性!

怎么了?在Python中,如何处理矫揉造作?这是一种很好的方式吗?


不知道你想达到什么样的目标,但从技术上讲,你的错误是:

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

self没有什么魔力,它只是一个函数参数,因此在函数中重新绑定它只会使本地名称self指向函数范围内的另一个对象。它不会影响当前实例(方法包装器传递给__init__的实例),它只是使self成为object的别名。

如果您想要将属性从object复制到self,则必须明确地执行以下操作:

1
2
3
4
5
 other = kwargs.get('object')
 if other is not None:
     self.attrx = other.attrx
     self.attry = other.attry
     # etc

哦,是的:Python是高级语言,没有什么比"地址矫揉造作"更像的了——您所拥有的只是引用对象的名称(实际上,名称=>对象映射)。名称只是一个名称,而对象实际生活的地方并不是您关心的问题。


  • 感谢以上评论,我了解两件事:

    • self只是一个局部变量,而不是类实例
    • _init_是一个类内置方法,用于从其他对象初始化实例。
  • 因此,如果我想从现有实例初始化一个新的类实例,我只需要创建一个"initializer"方法来调用_init_

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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))

像这样使用:

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

输出:

1
2
<__main__.Class instance at 0x7eff842d5368>
[1, 2, 3] []
1
2
3
inst2 = inst.Class(attr2=[12,11])
print inst2
print inst2.attr1,inst2.attr2

输出:

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