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