Classes - converting external function to class's method.

Ivan Evstegneev webmailgroups at gmail.com
Sun Dec 14 14:49:54 EST 2014


Dear Steven,

I very appreciate your answer. 
You just explained a lot of background things and you did it in more
explicit and simple way  than it've appeared in the book.
I also agree with you about the fact that there are some advanced topics
spread within a book's text.
It is sometimes hard to a newbie to separate  essential and from non
essential(I mean more advanced) topics.

So I may find myself digging down too much ^_^

In order to assemble the picture I would like to refer to couple of things
you mentioned:

>In this case, it works as you expect. Python looks up "method" on the
instance, and doesn't find anything attached to the instance. It then looks
at the class "rec",
 >which does have something called "method". Because this is a function,
Python knows to provide the instance x as the first argument. So the call

> x.method()

>ends up turning into this:

>rec.method(x)

I saw something similar to this example, but initially didn't understand
what the author meant, so I skipped it ))))

Here is a quote from a book(Please see Pic1.jpg too):
***************************************
Method Calls

If this I2.w reference is a function call, what it really means is "call the
C3.w function to
process I2." That is, Python will automatically map the call I2.w() into the
call
C3.w(I2), passing in the instance as the first argument to the inherited
function.

***************************************
 This was much confusing, till the moment I've read your explanation on live
example. )))


> Looking at this, I can guess you are using Python 3, because that won't
work in
> Python 2. Am I right?

Yes. I downloaded, Python 3.4 from python.org.  Currently working with IDLE.



> The important part to see here is that when you call a method from an
> instance:
> 
>     instance.method()
> 
> Python *automatically* fills in the "self" argument using the instance.
(In your
> case, you called that argument "obj" instead of self, but Python doesn't
care
> what it is called.)
> 
> How does Python know to use x as self? Because it's written right there:
> x.method uses x as the first argument for method. But this is only done
for
> *instances*, not classes.

So, just to summarize all this stuff: 

A class doesn't have method __self__  by itself.

I checked this on some other class provided in the book:

>>> class FirstClass:                               # Define a class object
	def setdata(self, value):        # Define class's methods
		self.data = value     # self is the instance
	def display(self):
		print(self.data)

And then check it with:

>>>dir(FirstClass)

[....Yep no __self__ here....]

On the other side, when an instance created, it does have __self__ method.



> > How does a function "uppername()" looks like, when I apply it to "rec"
> > class, so it becomes  a class's method?
> 
> I don't understand this question.

Well this is an embarrassing moment, it's just shows how lame my English can
be )))))

What I tried to ask here is if there any changes applied by Python to code
of function "uppername()" when it becomes class method (after using this
command: rec.method = uppername)

Never mind, you already answered it here:

> This is almost equivalent to the following:
> 
> class rec:
>     name = 'Bob'
>     age = 40
>     def method(obj):
>         return obj.name.upper()

Moreover, regard to the "rec.method = uppername"
As I can understand, in this case Python does make some changes to the
function, but they are implicit. 
Am I right? 


Sincerely,

Ivan




























> -----Original Message-----
> From: Python-list [mailto:python-list-
> bounces+webmailgroups=gmail.com at python.org] On Behalf Of Steven
> D'Aprano
> Sent: Sunday, December 14, 2014 19:28
> To: python-list at python.org
> Subject: Re: Classes - converting external function to class's method.
> 
> Ivan Evstegneev wrote:
> 
> > Hello Everyone,
> >
> > I have stuck a bit with this example(took this one from the book).
> 
> The example you are working on (adding external functions as methods) is
> actually a bit more complicated than it seems, as you have discovered. You
have
> this:
> 
> class rec: pass
> rec.name = 'Bob'
> rec.age = 40
> 
> x= rec()
> 
> def uppername(obj):
>     return obj.name.upper()
> 
> rec.method = uppername
> 
> 
> This is almost equivalent to the following:
> 
> class rec:
>     name = 'Bob'
>     age = 40
>     def method(obj):
>         return obj.name.upper()
> 
> 
> You then try to use this new method, by calling it from the instance:
> 
> x.method()
> --> returns 'BOB' as you expected
> 
> 
> In this case, it works as you expect. Python looks up "method" on the
instance,
> and doesn't find anything attached to the instance. It then looks at the
class
> "rec", which does have something called "method". Because this is a
function,
> Python knows to provide the instance x as the first argument. So the call
> 
>     x.method()
> 
> ends up turning into this:
> 
>    rec.method(x)
> 
> Your function uppername() receives x as the argument "obj", it looks up
> obj.name (x.name) and returns it as uppercase.
> 
> The important part to see here is that when you call a method from an
> instance:
> 
>     instance.method()
> 
> Python *automatically* fills in the "self" argument using the instance.
(In your
> case, you called that argument "obj" instead of self, but Python doesn't
care
> what it is called.)
> 
> How does Python know to use x as self? Because it's written right there:
> x.method uses x as the first argument for method. But this is only done
for
> *instances*, not classes.
> 
> 
> Now you move on to calling the method from the class itself:
> 
> rec.method()
> --> raises TypeError
> 
> rec.method(rec)
> --> returns 'BOB'
> 
> Looking at this, I can guess you are using Python 3, because that won't
work in
> Python 2. Am I right?
> 
> When you call a method from the class, Python cannot fill in the "self"
> argument because it doesn't know what instance to use. This is called an
> "unbound method" in Python 2, but in Python 3 it is just a regular
function.
> 
> The important thing here are these two rules:
> 
> * when you call a method from an instance, Python automatically binds
>   that instance to the first argument (usually called "self") of the
>   method:
> 
>   instance.method() --> method gets instance as the "self" argument
> 
> * when you call a method from the class, Python cannot bind an
>   instance to "self", so you have to do it:
> 
>   Class.method()  --> no argument is given!
> 
>   Class.method(instance)  --> method gets instance as "self"
> 
> 
> In your example, you didn't actually pass an instance, you just passed the
class
> itself:
> 
>     rec.method(rec)
> 
> But that's okay, because in *this case* the class has a "name" attribute,
so it all
> works out alright. But normally this would fail.
> 
> The actual mechanism for how Python does this is called the descriptor
protocol,
> and if you look it up you can find some explanations for it, but be warned
that it
> is quite technical and it is only for very advanced work that you need to
care
> about it.
> 
> 
> > Keeping it in mind, I wrote this code:
> >
> > class myclass:
> >     def __init__(self, value):
> >         self.name = value
> >     def myupper(self):
> >         return self.name.upper()
> >
> > And then:
> >
> > b = myclass('bob')
> > b.myupper()
> > 'BOB'
> >
> > I made an assumption that this is what happens(roughly speaking) when
> > I write this:
> >
> > rec.method = uppername
> >
> > Am I right? (close enough maybe?)
> 
> Close enough.
> 
> 
> 
> > On the other hand, when I checked further:
> >
> >>>>dir(x.method)
> > [........, '__self__',.......]
> 
> That is because you are looking the method up on the instance, x. If you
look it
> up on rec, there is no instance so Python cannot give it an __self__
attribute.
> 
> 
> > but
> >>>>dir(rec.method)
> > [.... list of method and  '__self__'  wasn't there.....]
> 
> Exactly!
> 
> You are looking at a complicated part of Object Oriented Programming, as
done
> by Python, so it is not surprising if it takes a while to understand this.
Please feel
> free to ask more questions if anything is unclear.
> 
> 
> > I got a "bit" confused.
> >
> > Why  actually in instance "x"
> >>>>x.method()
> > can auto-assign an "x" to uppername() function argument, but it
> > doesn't work in a class "rec" itself?
> 
> When you have an instance
> 
>     x.method
> 
> then Python knows which instance to use, because it is right there: x.
> 
> But if you have no instance, only the class:
> 
>     rec.method
> 
> how does Python know which instance to use? There could be a million
> instances, or none.
> 
> Let us look at some strings: the class is called "str", and we can have
many, many
> different instances:
> 
> "hello".upper()
> --> returns "HELLO"
> 
> "goodbye".upper()
> --> returns "GOODBYE"
> 
> 
> But if I call the method from the class, which instance should it use?
> 
> str.upper()
> ???? return "HELLO" or "GOODBYE" or "1234" or "ABCD" or ... ????
> 
> The only way is for you to tell Python which instance to use:
> 
> str.upper("hello")  # just like "hello".upper()
> --> returns "HELLO"
> 
> 
> 
> > So  I need to write down an "obj" argument manually.
> > Why '__self__' exists only in instance "x"? (maybe because "rec",
> > initially was created as an empty class?)
> 
> No. __self__ exists when you call the method from x, because __self__ is
set to
> x. If you call it from the class rec, there is no instance so __self__
cannot be set
> to an instance.
> 
> 
> > How does a function "uppername()" looks like, when I apply it to "rec"
> > class, so it becomes  a class's method?
> 
> I don't understand this question.
> 
> 
> > So in such a case, when instance "x" receives an "update" it reads the
> > new method as I described above(I mean the code of "myclass")?
> 
> Or this question. Can you explain what you mean?
> 
> 
> 
> 
> --
> Steven
> 
> --
> https://mail.python.org/mailman/listinfo/python-list
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pic1.jpg
Type: image/jpeg
Size: 33382 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/python-list/attachments/20141214/2f9271ae/attachment.jpg>


More information about the Python-list mailing list