accessing superclass methods from subclass

B

ben

Why doesn't this work:

class C1:
def f1(self):
print("f1")

class C2(C1):
f1()


It throws this error:

Traceback (most recent call last):
File "./c1.py", line 7, in <module>
class C2(C1):
File "./c1.py", line 8, in C2
f1()
NameError: name 'f1' is not defined


f1() is an attribute of class C1, C2 inherits C1, so why can't it see
it?

thanks!
 
C

Chris Rebert

Why doesn't this work:

class C1:
   def f1(self):
       print("f1")

class C2(C1):
   f1()


It throws this error:

Traceback (most recent call last):
 File "./c1.py", line 7, in <module>
   class C2(C1):
 File "./c1.py", line 8, in C2
   f1()
NameError: name 'f1' is not defined


f1() is an attribute of class C1, C2 inherits C1, so why can't it see
it?

The way classes work in Python, C2 isn't actually created until after
its body suite has been executed, so that's why Python can't find f1.

Additionally, it makes no sense to call an *instance* method such as
f1() in a class context. Or in Java-speak: you can't call a non-static
method in a static context.

Cheers,
Chris
 
M

MRAB

ben said:
Why doesn't this work:

class C1:
def f1(self):
print("f1")

class C2(C1):
f1()


It throws this error:

Traceback (most recent call last):
File "./c1.py", line 7, in <module>
class C2(C1):
File "./c1.py", line 8, in C2
f1()
NameError: name 'f1' is not defined


f1() is an attribute of class C1, C2 inherits C1, so why can't it see
it?
Name lookup works differently from some other languages. You need to be
explicit and tell it where 'f1' is defined:

C1.f1()

However, that will raise a different exception. I don't know what you're
trying to do.
 
B

ben

Ok, thanks for the info.

What would be a better way to do this? What I'm trying to do is treat
things in a reasonable OOP manner (all fairly new to me, esp. in
Python). Here's a made-up example with a little more context. Let's
say you're making a drawing program that can draw various shapes. So
in the interest of not repeating oneself, I want a class Shape that
handles everything that shapes have, such as a color, and a location.
Then I can subclass Shape to create Square, which has code specific to
drawing a square (e.g. 4 equal sides). So, like this:

class Shape:

x = 0
y = 0

def setColor(self,color):
self.color = color

def setLocation(self,x,y):
self.x = x
self.y = y

def getLocation(self):
return [self.x,self.y]

class Square(Shape):

size = 0

def __init__(self,size):
self.size = size

def draw(self):
location = getLocation()
# code to draw shape from location[0],location[1] at size size
# etc...

It seems to me that you would want the location code handled in the
Shape class so that I'm not rewriting it for Circle, Triangle, etc.,
but I'm not allowed to call any of those methods from the subclass. I
must be thinking of this in the wrong way. Help?

thanks!
 
C

Chris Rebert

Ok, thanks for the info.

What would be a better way to do this? What I'm trying to do is treat
things in a reasonable OOP manner (all fairly new to me, esp. in
Python). Here's a made-up example with a little more context. Let's
say you're making a drawing program that can draw various shapes. So
in the interest of not repeating oneself, I want a class Shape that
handles everything that shapes have, such as a color, and a location.
Then I can subclass Shape to create Square, which has code specific to
drawing a square (e.g. 4 equal sides). So, like this:

class Shape:

x = 0
y = 0

def setColor(self,color):
self.color = color

def setLocation(self,x,y):
self.x = x
self.y = y

def getLocation(self):
return [self.x,self.y]

class Square(Shape):

size = 0

def __init__(self,size):
self.size = size

def draw(self):
location = getLocation()
# code to draw shape from location[0],location[1] at size size
# etc...

It seems to me that you would want the location code handled in the
Shape class so that I'm not rewriting it for Circle, Triangle, etc.,
but I'm not allowed to call any of those methods from the subclass. I
must be thinking of this in the wrong way. Help?

Your code suggests you need to read a tutorial on Python's
object-oriented features. The relevant part of Python's official
tutorial is http://docs.python.org/tutorial/classes.html

For starters, Python is not Java and getters/setters are not usually
necessary nor Pythonic; see
http://dirtsimple.org/2004/12/python-is-not-java.html
Secondly, Python does not have instance variable declarations; doing
`x = 0` at the class-level creates a static/class variable, it *does
not* declare an instance variable.
Thirdly, to call an instance method such as getLocation, you need to
specify the receiver, i.e. `self.getLocation()`, not merely
`getLocation()`

Here is how I would rewrite your example:

class Shape(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y

@property
def location(self):
return (self.x, self.y)

@location.setter
def location(self, val):
self.x, self.y = val

class Square(Shape):
def __init__(self,size):
super(Square, self).__init__()
self.size = size

def draw(self):
x, y = self.location
# code to draw shape from location[0],location[1] at size size
# etc...


This uses some minor magic involving property(), see
http://docs.python.org/library/functions.html#property for how that
works.

Cheers,
Chris
 
T

TFH

Why doesn't this work:

class C1:
def f1(self):
print("f1")

class C2(C1):
f1()


It throws this error:

Traceback (most recent call last):
File "./c1.py", line 7, in <module>
class C2(C1):
File "./c1.py", line 8, in C2
f1()
NameError: name 'f1' is not defined


f1() is an attribute of class C1, C2 inherits C1, so why can't it see
it?

thanks!

Try this:

class C1:
def f1(self):
return "From C1: f1"

class C2(C1):
def f2(self):
return self.f1()

c2 = C2()

print c2.f2()

regards

Trevor
 
L

Lie Ryan

Additionally, it makes no sense to call an *instance* method such as
f1() in a class context. Or in Java-speak: you can't call a non-static
method in a static context.

<nit>Actually, in python it does make sense, with a caveat that you have
to provide the instance as the first argument (i.e. as 'self'). The
semantic of "instance method" in python is a class method whose first
argument is curried/bound to a specific instance.</nit>

I think it's better not to confuse OP even further by drawing comparison
with Java; as Python and Java has a confusingly similar name but wholly
different "static method". Also python has nothing similar to "static
context".
The way classes work in Python, C2 isn't actually created until after
its body suite has been executed, so that's why Python can't find f1.

That isn't the reason why OP's code doesn't work. Python cannot find f1
because there is no f1 in the current scope. Class definition in Python
is done by *execution of class body*; the class body is executed in *a
new scope*, which will later become the class' scope. (btw, a "scope" in
python is nothing but sugar for a dictionary (waves a limb airily)).

An instance's scope is a shadow of the class' scope [with respect to
descriptor protocol] + __dict__ + the rest of __mro__; and this __mro__
is not known until the class body execution is finished and type() is
called to create the class. That's why f1() is not in the class' scope
at class declaration time.

In fact, the whole class declaration syntax is more or less sugar for:

class_scope = {}
exec "pass" in globals(), class_scope
Foo = type("Foo", (Parent1, Parent2), class_scope)
# class Foo(Parent1, Parent2):
# pass

the exec statement cannot access its Parent scope, except by explicit
reference through globals() (e.g. Parent1.foo).
 
J

Jean-Michel Pichavant

ben said:
Ok, thanks for the info.

What would be a better way to do this? What I'm trying to do is treat
things in a reasonable OOP manner (all fairly new to me, esp. in
Python). Here's a made-up example with a little more context. Let's
say you're making a drawing program that can draw various shapes. So
in the interest of not repeating oneself, I want a class Shape that
handles everything that shapes have, such as a color, and a location.
Then I can subclass Shape to create Square, which has code specific to
drawing a square (e.g. 4 equal sides). So, like this:

class Shape:

x = 0
y = 0

def setColor(self,color):
self.color = color

def setLocation(self,x,y):
self.x = x
self.y = y

def getLocation(self):
return [self.x,self.y]

class Square(Shape):

size = 0

def __init__(self,size):
self.size = size

def draw(self):
location = getLocation()
# code to draw shape from location[0],location[1] at size size
# etc...

It seems to me that you would want the location code handled in the
Shape class so that I'm not rewriting it for Circle, Triangle, etc.,
but I'm not allowed to call any of those methods from the subclass. I
must be thinking of this in the wrong way. Help?

thanks!

Hi Ben,

Please do not top post.
You already been given good advices, especially the one suggesting to go
through the tutorial. You're making basic mistakes here.

Here is a very simple version of your code.

class Shape:

def __init__(self, x=0, y=0):
self.x = 0
self.y = 0
self.color = None

def draw(self):
print 'drawing %s' % self


class Square(Shape):

def __init__(self,size):
self.size = size

def draw(self):
Shape.draw(self) # this is one way to call the base class method
location = (self.x, self.y)
# code to draw shape from self.x, self.y at size self.size
# etc...


mySquare = Square(5,2)
mySquare.color = 'red'
print mySquare.x
Since your attributes are flagged as public, you don't really need
setters & getters.


JM
 
B

Bruno Desthuilliers

Chris Rebert a écrit :
(snip)
Here is how I would rewrite your example:

class Shape(object):
def __init__(self, x=0, y=0):
self.x = x
self.y = y

@property
def location(self):
return (self.x, self.y)

@location.setter
def location(self, val):
self.x, self.y = val

Not necessary but helps documenting the expected interface:

def draw(self):
raise NotImplementedError("Abstract method")
class Square(Shape):
def __init__(self,size):
super(Square, self).__init__()
self.size = size

Why can't I specify a Square location ??? This looks rather inconsistant
and inconveniant to me...

def __init__(self, x=0, y=0, size=0):
super(Square, self).__init__(x, y)
self.size = size

def draw(self):
x, y = self.location
# code to draw shape from location[0],location[1] at size size
# etc...
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top