A question about Python Classes

C

chad

Let's say I have the following....

class BaseHandler:
def foo(self):
print "Hello"

class HomeHandler(BaseHandler):
pass


Then I do the following...

test = HomeHandler()
test.foo()

How can HomeHandler call foo() when I never created an instance of
BaseHandler?

Chad
 
J

Jean-Michel Pichavant

chad said:
Let's say I have the following....

class BaseHandler:
def foo(self):
print "Hello"

class HomeHandler(BaseHandler):
pass


Then I do the following...

test = HomeHandler()
test.foo()

How can HomeHandler call foo() when I never created an instance of
BaseHandler?

Chad
you did, test is an instance of BaseHandler.
isinstance(test, HomeHandler)
< True
isinstance(test, BaseHandler)
< True

JM
 
C

chad

you did, test is an instance of BaseHandler.

 > isinstance(test, HomeHandler)
< True

 > isinstance(test, BaseHandler)
< True

So it just just creates an instance of every class that it inherits?

Chad
 
P

Pascal J. Bourguignon

chad said:
Let's say I have the following....

class BaseHandler:
def foo(self):
print "Hello"

class HomeHandler(BaseHandler):
pass


Then I do the following...

test = HomeHandler()
test.foo()

How can HomeHandler call foo() when I never created an instance of
BaseHandler?

But you created one!

test is an instance of HomeHandler, which is a subclass of BaseHandler,
so test is also an instance of BaseHandler.

A subclass represents a subset of the instances of its super class.
 
T

Terry Reedy

Let's say I have the following....

class BaseHandler:
def foo(self):
print "Hello"

class HomeHandler(BaseHandler):
pass


Then I do the following...

test = HomeHandler()
test.foo()

How can HomeHandler call foo() when I never created an instance of
BaseHandler?

When you ask for an attribute of an instance of a class, the attribute
lookup first looks at the instance; if not there, then the class; if not
there, then superclass(es); and so on back to class 'object'.
<method-wrapper '__hash__' of C object at 0x00FCB5D0>

# how does this happen when C has no __hash__ method?
<slot wrapper '__hash__' of 'object' objects>

# C inherits __hash__ and other special methods from 'object'
1035101

# uses the default, inherited method.

Most syntactic operations and builtins are ultimately converted to a
special method call, often inherited like this. In fact, c.x is
converted to object.__getattribute__(c, 'x').
<method-wrapper '__hash__' of C object at 0x00FCB5D0>

You do need to understand inheritance. On the other hand, do not worry
about behind-the-scenes implementation details like 'method_wrapper' and
'slot_wrapper' classes, which may be CPython specific.
 
M

MRAB

But you created one!
No, he didn't, he created an instance of HomeHandler.
test is an instance of HomeHandler, which is a subclass of BaseHandler,
so test is also an instance of BaseHandler.
test isn't really an instance of BaseHandler, it's an instance of
HomeHandler, which is a subclass of BaseHandler.

If you do this:

class BaseHandler(object):
def foo(self):
print "Hello"

class HomeHandler(BaseHandler):
pass

test = HomeHandler()

then you'll find:
True

but:
<class '__main__.HomeHandler'>
 
E

Ethan Furman

chad said:
Let's say I have the following....

class BaseHandler:
def foo(self):
print "Hello"

class HomeHandler(BaseHandler):
pass


Then I do the following...

test = HomeHandler()
test.foo()

How can HomeHandler call foo() when I never created an instance of
BaseHandler?

You don't need to create an instance of BaseHandler. You have the
class, Python knows you have the class -- Python will look there if the
subclasses lack an attribute.

~Ethan~
 
S

Steven D'Aprano

No, he didn't, he created an instance of HomeHandler.

test isn't really an instance of BaseHandler, it's an instance of
HomeHandler, which is a subclass of BaseHandler.

Which *also* makes it an instance of BaseHandler. You are a human being,
which also makes you a mammal. It would be *wrong* to say that you're not
a mammal, just because you're a human being.

But to answer the Original Poster's question... you don't need a formal
BaseHandler instance because that's how inheritance is designed to work.
Each class knows its own parent classes, and when you call test.foo(),
Python walks the chain of:

instance
instance's class
each of the parent class(es) (if any)

looking for a match for foo, and then calls it appropriately. This is
called inheritance: HomeHandler inherits behaviour from BaseHandler.

(The details are a little more complex than the sketch above, but broadly
equivalent.)
 
J

Jean-Michel Pichavant

MRAB said:
No, he didn't, he created an instance of HomeHandler.
I think this is really wrong within the OP question context. This is a
key concept about OOP and inheritance, any object of class HomeHandler
is an object of class BaseHandler and also an object of any other base
class.

However it is true that for convenience, there are some language abuses
around this terms that we're all using, for instance:
- class refers to the lowest class of the object (like the python
__class__ attribute)
- "instance of" means sometimes "created using the constructor of"
when stating for example that you cannot create an instance of a
virtual class. From a formal OO POV, anyone can create an instance of a
virtual class, you just need to create an instance of one of its
subclass. What you cannot, is create a instance of a virtual class using
the constructor of that virtual class.

Also note that
isinstance(test, BaseHandler)
returns True. And this is no Python trick to trigger some magic, this is
what OO is about.


JM
 
K

Kyle T. Jones

Ethan said:
You don't need to create an instance of BaseHandler. You have the
class, Python knows you have the class -- Python will look there if the
subclasses lack an attribute.

~Ethan~

Really? That's not at all how I thought it worked in Python
(post-instantiation referencing of class and superclass code...)

Cheers.
 
E

Ethan Furman

Kyle said:
Really? That's not at all how I thought it worked in Python
(post-instantiation referencing of class and superclass code...)

I'm not sure exactly what you're asking/stating, but does this help?

8<---Py 3.2 code------------------------------------------
class BaseClass():
def bFoo(self):
print("Base foo here!")

class NormalClass(BaseClass):
def nFoo(self):
print("Normal foo here.")

class EnhancedClass(NormalClass):
def eFoo(self):
print("Enhanced foo comin' at ya!")

class EnrichedClass(EnhancedClass):
def rFoo(self):
print("Am I glowing yet?")

test = EnrichedClass()
test.bFoo()
test.nFoo()
test.eFoo()
test.rFoo()

def newFoo(self):
print("Ha! You've been replaced!")

BaseClass.bFoo = newFoo

test.bFoo()
8<----------------------------------------------------------
 
I

Ian Kelly

Really?  That's not at all how I thought it worked in Python
(post-instantiation referencing of class and superclass code...)

Yes, it looks up the attribute in the superclass tree at the time that
it's referenced, not at the time it's instantiated or at the time the
class is created. So:
.... x = 5
........ pass
....7

Or were you talking about something else?
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top