newbie: copy base class fields

T

tmp123

Hello,

Thanks for your time.

The following small program gives an error:

#!/usr/bin/python
#

class A:
def __init__(self):
self.v1=1

def __repr__(self):
return "v1=%d\n" % self.v1

class B(A):
def __init__(self,a):
self=a
self.v2=2

def __repr__(self):
return A.__repr__(self) + ("v2=%d\n" % self.v2)

x=A()
print x

y=B(x)
print y



$ ./prueba.pl
v1=1

Traceback (most recent call last):
File "./prueba.pl", line 23, in <module>
print y
File "./prueba.pl", line 17, in __repr__
return A.__repr__(self) + ("v2=%d\n" % self.v2)
File "./prueba.pl", line 9, in __repr__
return "v1=%d\n" % self.v1
AttributeError: B instance has no attribute 'v1'


It seems that the statement "self=a" is not the correct way to copy
all the fields of the base class from the __init__ argument to the new
object.

Of course, it is not an option to copy one by one all the fields of
class A inside the __init__ of B.

Several variants of the program produces similar results.

Please, could someone explain which way is the correct way?

Thanks a lot.
 
M

Marc 'BlackJack' Rintsch

The following small program gives an error:

#!/usr/bin/python
#

class A:
def __init__(self):
self.v1=1

def __repr__(self):
return "v1=%d\n" % self.v1

class B(A):
def __init__(self,a):
self=a
self.v2=2

def __repr__(self):
return A.__repr__(self) + ("v2=%d\n" % self.v2)

x=A()
print x

y=B(x)
print y



$ ./prueba.pl
v1=1

Traceback (most recent call last):
File "./prueba.pl", line 23, in <module>
print y
File "./prueba.pl", line 17, in __repr__
return A.__repr__(self) + ("v2=%d\n" % self.v2)
File "./prueba.pl", line 9, in __repr__
return "v1=%d\n" % self.v1
AttributeError: B instance has no attribute 'v1'


It seems that the statement "self=a" is not the correct way to copy
all the fields of the base class from the __init__ argument to the new
object.

This binds the local name `self` to the same object that is bound to `a`.
Now you have lost the reference to the instance, so the next line sets the
attribute `v2` on the object passed to the constructor of the `B` object.
Of course, it is not an option to copy one by one all the fields of
class A inside the __init__ of B.

Several variants of the program produces similar results.

Please, could someone explain which way is the correct way?

Call the `__init__()` of `A`:

class B(A):
def __init__(self, a):
A.__init__(self)
self.v2 = 2

Ciao,
Marc 'BlackJack' Rintsch
 
T

tmp123

Hello Marc,

Thanks for your help.

I'm sorry, I've not correctly explained the subject. It is need to
init class B with the current value of the A instance, not with the
initial ones. A best example is:

x=A()
print x

x.v1=3

y=B(x)
print y

at the end, y.v1 must be equal to 3.

Sorry again.
 
A

Alex Martelli

tmp123 said:
It seems that the statement "self=a" is not the correct way to copy
all the fields of the base class from the __init__ argument to the new
object.

Indeed, it isn't. Assigning to self just rebinds the name 'self' as a
local variable of method B.__init__ -- really useless.
Of course, it is not an option to copy one by one all the fields of
class A inside the __init__ of B.

Several variants of the program produces similar results.

Please, could someone explain which way is the correct way?

Somebody else suggested you call A.__init__ from inside B.__init__, and
that is correct if what you want to do is "freshly initialize the B
instance as an A". However, from the fact that you pass to B.__init__
an argument 'a', it looks as if what you're trying to do is indeed copy
each of a's instance variables to self (it's hard to read your mind from
the code you've posted, but if I had to guess that would be by guess),
where a is an instance of A that's not necessarily "freshly
initialized".

In this case, you might for example start B.__init__ with:
self.__dict__.update(a.__dict__)

This is not very elegant or solid, but at least it's short and fast:).

A better way would require having _somewhere_ a list or tuple with the
names of all the instance variables you know you want to copy; if that
list of names was for example B._names_to_copy,
for name in self._names_to_copy:
value = getattr(a, name)
setattr(self, name, value)
IS elegant and robust. The advantages of explicitly controlling what
names you're copying (rather than blindly taking whatever happens to be
there) are similar to those of avoiding "from wherever import *": you
avoid accidental name pollution. The advantages of using getattr and
setattr (rather than blindly working on the __dict__s) are those of
working correctly and transparently with properties and other similar
kinds of descriptors, rather than just "raw" instance variables.


Alex
 
J

Jerry Hill

Of course, it is not an option to copy one by one all the fields of
class A inside the __init__ of B.

Is it okay to copy them all at once? Like this:

class B(A):
def __init__(self, a):
self.__dict__.update(a.__dict__)
self.v2 = 2

That will copy all of the attributes of instance a into the new instance.
 
T

tmp123

Is it okay to copy them all at once? Like this:

class B(A):
def __init__(self, a):
self.__dict__.update(a.__dict__)
self.v2 = 2

Thanks a lot for the answers, they seem to agree with the requested
funcitionality.

Kind regards.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top