-2

Can python create a class that can be initialised with an instance of the same class object?

I've tried this:

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

If I create a new instance there is no problem:

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

The output is:

<__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]  []

But if I create a new instance with the instance inst:

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

The output is:

<__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'  

I handle the problem but i dont know how to solve it:

  • in the 1st case the instance address is always the same ("inside" and "outside" the class)
  • in the 2nd case:

    • "inside" the class:
    • the init call create a new instance at a new address
    • then self is set to the previous instance and change address: OK
    • self already has attributes attr1 and atrr2 : OK

    • but "outside" the class:

    • inst2 has the address from the init and has no attributes!

What is wrong ? How does address affectation work in Python? Is it a good manner of doing this?

G.S
  • 392
  • 2
  • 13
  • 1
    What? What are you actually trying to *achieve*?! – jonrsharpe Oct 14 '15 at 14:24
  • Imagine if you get this working. What will the syntax look like? How will you explain to others how to use your code? – Peter Wood Oct 14 '15 at 14:26
  • 1
    Downvotes are anonymous and don't require comments (see e.g. http://meta.stackoverflow.com/q/250177/3001761). Not to mention that you **have had** a comment! If you can't be more explicit, then don't expect an answer. What are you actually trying to do? Implement a weird copying method via `__init__`? Why? – jonrsharpe Oct 14 '15 at 14:26
  • And what is *"address affectation"*? – jonrsharpe Oct 14 '15 at 14:32
  • @PeterWood This syntax will permit to a second instance to inherite of all attributes of a first instance except the ones that are re-initialize – G.S Oct 14 '15 at 14:33
  • @G.S **edit the question** to clarify what you're trying to achieve. Why not a `from_existing_instance` class method, rather than complicating the `__init__`? – jonrsharpe Oct 14 '15 at 14:34
  • @jonrsharpe I say i cant be more explicit because i wrote my whole procedure! _Implement a weird copying method via __init__? Why?_ I say in my question that there is maybe a better/right manner, so can you explain whats this is the same of a copying method and how to do this – G.S Oct 14 '15 at 14:37
  • @G.S but your *"whole procedure"* neither works nor makes much sense. Either give a [mcve], a prose clear explanation, or (preferably) both. Maybe you want something like http://stackoverflow.com/q/19305296/3001761? – jonrsharpe Oct 14 '15 at 14:38
  • My example works I dont write the output by myself! If it doest make sense explain why ! Even I implement a `from_existing_instance` method i will have the same problem (except if i peel all the attributes of the existing instance). I see your proposed link, and it not correspond of what i m doing because it use inheritance – G.S Oct 14 '15 at 14:50
  • @jonrsharpe Thanks for formatiing and you were right the example dont work because i change object to obj – G.S Oct 14 '15 at 15:10
  • 3
    You don't have to use inheritance, my point is that the canonical way to implement alternate constructors in Python is with a `@classmethod`. This feels like arguing with a wall, so I won't comment further. – jonrsharpe Oct 14 '15 at 15:12
  • @jonrsharpe I dont know a lot of wall that answers and takes in considerations arguments from others, I just want to be clear about what you say and what im answering.. Thanks for your help i will see the `@classmethod` – G.S Oct 14 '15 at 15:43

2 Answers2

1

Not sure what you're trying to achieve, but technically your error is here:

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

There's nothing magic with self, it's just a function argument, and as such a local variable, so rebinding it within the function will only make the local name self points to another object within the function's scope. It's in no way affecting the current instance (the one that was passed to __init__ by the method wrapper), it just makes self an alias for object.

If what you want is to copy attributes from object to self, you have to do it explicitly:

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

Oh and yes: Python is high-level language, there's nothing like "address affectation" - all you have are names refering to objects (really, name=>object mapping). A name is just a name, and where the object actually lives is none of your concerns.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • So if i understand well, self it just local variable which is an alias of the current instance (passed to _init_ by the method wrapper) ? and so if i rebinding it i "lose" the current instance within the _init_ scope ? @bruno\ desthuiliers – G.S Oct 14 '15 at 15:32
  • Thanks @brunodesthuilliers – G.S Oct 15 '15 at 09:15
-1
  • Thanks to the comments above I understand 2 things:

    • self is just a local variable and it s not the class instance
    • _init_ it s an class built-in method for initialize the instance from other object
  • So if I want to be able to initialize a new class instance from an existing instance, I have just to create an "initializer" method which call the _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))
    

And use it like this:

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

Output:

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

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

Output:

<__main__.Class instance at 0x7eff842d56c8>
[1, 2, 3] [12, 11]
G.S
  • 392
  • 2
  • 13
  • "self is just a local variable and it s not the class instance" : `self` is a name in the function's scope, and this name initially refers to the current instance (the one on which the method has been called). – bruno desthuilliers Oct 15 '15 at 09:08