Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #82509 > unrolled thread

Classes - converting external function to class's method.

Started by"Ivan Evstegneev" <webmailgroups@gmail.com>
First post2014-12-14 18:20 +0200
Last post2014-12-15 21:13 +0200
Articles 8 — 4 participants

Back to article view | Back to comp.lang.python


Contents

  Classes - converting external function to class's method. "Ivan Evstegneev" <webmailgroups@gmail.com> - 2014-12-14 18:20 +0200
    Re: Classes - converting external function to class's method. Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-12-15 04:28 +1100
      RE: Classes - converting external function to class's method. "Ivan Evstegneev" <webmailgroups@gmail.com> - 2014-12-14 21:49 +0200
    Re: Classes - converting external function to class's method. Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2014-12-15 00:15 +0100
      Re: Classes - converting external function to class's method. Terry Reedy <tjreedy@udel.edu> - 2014-12-14 19:11 -0500
        Re: Classes - converting external function to class's method. Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2014-12-15 01:32 +0100
      Re: Classes - converting external function to class's method. Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-12-15 13:01 +1100
        RE: Classes - converting external function to class's method. "Ivan Evstegneev" <webmailgroups@gmail.com> - 2014-12-15 21:13 +0200

#82509 — Classes - converting external function to class's method.

From"Ivan Evstegneev" <webmailgroups@gmail.com>
Date2014-12-14 18:20 +0200
SubjectClasses - converting external function to class's method.
Message-ID<mailman.16949.1418574125.18130.python-list@python.org>
Hello Everyone,

I have stuck a bit with this example(took this one from the book).

Here are a description steps of what I've done till now:
 

Step 1 - creating an empty namespace:

>>>class rec: pass

Step 2 - adding some attributes:

>>>rec.name = 'Bob' 
>>>rec.age = 40

Step 3 - Creating an instance:

>>>x= rec()

Step 4 - write down external function: 

>>>def uppername(obj):
	return obj.name.upper()

Step 5 - applying this function on x:

>>>uppername(x)
'BOB'

Till this moment its Ok.

But:

Step 6 - Creating a class method:


>>>rec.method = uppername

Then using the "help" function I  get (just checking what happened):

>>>help(rec)
class rec(builtins.object)
 |  Methods defined here:
 |  
 |  method = uppername(obj)
 |  
 |  ----------------------------------------------------------------------
 |omitted text......

 |------------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  age = 40
 |  
 |  name = 'Bob'


Then the same about x:

>>>help(x)
class rec(builtins.object)
 |  Methods defined here:
 |  
 |  method = uppername(obj)
 | -------------------------------------------------------------------
 omitted text .....
|---------------------------------------------------------------------


The last check I've made:

>>> help(x.method)
Help on method uppername in module __main__:

uppername() method of __main__.rec instance

>>> help(rec.method)
Help on function uppername in module __main__:

uppername(obj)

and now to the Step 7 - using this new "method" on x:

>>>x.method()
'BOB'

>>>rec.method()
.....
.....
TypeError: uppername() missing 1 required positional argument: 'obj'

and then:

>>>rec.method(rec)
'BOB'

So my the question is: what is going on here? How this actually works?

According to the book's downside note:
****************************************************************************
******
In fact, this is one of the reasons the self argument must always be
explicit in Python methods-because
methods can be created as simple functions independent of a class, they need
to make the implied instance
argument explicit. They can be called as either functions or methods, and
Python can neither guess nor
assume that a simple function might eventually become a class's method. The
main reason for the explicit
self argument, though, is to make the meanings of names more obvious: names
not referenced through
self are simple variables mapped to scopes, while names referenced through
self with attribute notation
are obviously instance attributes.
****************************************************************************
*****

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?)


On the other hand, when I checked further:

>>>dir(x.method)
[........, '__self__',.......]

but 
>>>dir(rec.method)
[.... list of method and  '__self__'  wasn't there.....]

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?

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?)

How does a function "uppername()" looks like, when I apply it to "rec"
class, so it becomes  a class's method?

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")?


Thanks a  lot in advance,

Ivan. 



[toc] | [next] | [standalone]


#82519

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-12-15 04:28 +1100
Message-ID<548dc8a1$0$12982$c3e8da3$5496439d@news.astraweb.com>
In reply to#82509
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

[toc] | [prev] | [next] | [standalone]


#82529

From"Ivan Evstegneev" <webmailgroups@gmail.com>
Date2014-12-14 21:49 +0200
Message-ID<mailman.16958.1418594531.18130.python-list@python.org>
In reply to#82519

[Multipart message — attachments visible in raw view] — view raw

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@python.org] On Behalf Of Steven
> D'Aprano
> Sent: Sunday, December 14, 2014 19:28
> To: python-list@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

[toc] | [prev] | [next] | [standalone]


#82531

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2014-12-15 00:15 +0100
Message-ID<2082416.uXDKvNnAXg@PointedEars.de>
In reply to#82509
Ivan Evstegneev wrote:

> I have stuck a bit with this example(took this one from the book).
> 
> Here are a description steps of what I've done till now:
>  
> 
> Step 1 - creating an empty namespace:
> 
>>>>class rec: pass

IMHO that is not actually creating a namespace; it is just 
declaring/defining an empty class.

The equivalent of a namespace in Python is a module; the file path starting 
from an entry in the PYTHONPATH works like a namespace (the module is 
considered to be in a package if the directory contains an __init__.py 
file).  (One can assume that this was derived from Java.)

BTW, the recommended Python 3.x way is

class Rec (object):
    pass

(whereas “pass” is a placeholder statement, a bit like the yada-yada 
operator of Python) and you should start class identifiers uppercase 
(therefore, “Rec” instead) in order to avoid name collisions with built-in 
class identifiers (“str”, “int” etc.) and make it easier to tell apart 
instantiations from function/method calls.  This recommendation applies to 
other similar OOPLs too, but ISTM is especially important in Python code 
where there is no “new” keyword used in instantiation.

> Step 4 - write down external function: 
> 
> >>>def uppername(obj):
>         return obj.name.upper()
> 
> […]
> Step 6 - Creating a class method:
> 
>>>rec.method = uppername
> […]
>>>>x.method()
> 'BOB'
> 
>>>>rec.method()
> .....
> .....
> TypeError: uppername() missing 1 required positional argument: 'obj'
> 
> and then:
> 
>>>>rec.method(rec)
> 'BOB'
> 
> So my the question is: what is going on here? How this actually works?

Short answer: Calling rec.method(x) is equivalent to calling x.method() if 
type(x) == rec.

| >>> class C (object): pass
| >>> def foo (self):
| ...     print(self)
| >>> C.foo = foo
| >>> C.foo()
| Traceback (most recent call last):
| File "<stdin>", line 1, in <module>
| TypeError: foo() missing 1 required positional argument: 'self'
| >>> o = C()
| >>> C.foo(o)
| <__main__.C object at 0x7f64a7458be0>
| >>> o.foo()
| <__main__.C object at 0x7f64a7458be0>

Long answer:

If you call that method as the method of a class (object), you need to pass 
an argument for the first parameter because you have made it positional, not 
optional (it has no default value).  If you pass (a reference to) the class 
as first argument of that method, the class is the object whose attribute is 
accessed.  Classes are objects (this, too, was probably derived from Java).  
(In fact, AFAIK almost everything is an object in Python; there are no 
primitive data types at all.)

If instead you call that method as the method of an instance, the first 
argument is a reference to that instance implicitly, so the signature of the 
method is met implicitly and there is no error.  (See below for an 
explanation as to why “self.name” still works.)  Any arguments that you pass 
then in the argument list are passed as second, third aso. argument to the 
method.  To this method, then, you MUST NOT pass other arguments because it 
does not take any more than already supplied implicitly.

[Fixed comb-quote; please keep to at most 80 characters per line, best 72]

> According to the book's downside note:
> 
> ************************************************************************
> In fact, this is one of the reasons the self argument must always be
> explicit in Python methods-because methods can be created as simple 
> functions independent of a class, they need to make the implied instance
> argument explicit. They can be called as either functions or methods,
> and Python can neither guess nor assume that a simple function might 
> eventually become a class's method.
> The main reason for the explicit self argument, though, is to make the 
> meanings of names more obvious: names not referenced through 
> self are simple variables mapped to scopes, while names referenced
> through self with attribute notation are obviously instance attributes.
> ***********************************************************************

Exactly.

> 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, maybe.  The difference is that in the original code the class has the 
attribute and the instance merely inherits it, while in the code above only 
the instance has the attribute.

IOW, in the code above the attribute (value) is not implicitly shared with 
other instances of that class.  And ISTM that with the original code it is 
not possible to modify the attribute value except by accessing it directly 
or through a method that is passed the reference to the *class* (because a 
simple assignment in a method merely defines a local variable; there appears 
to be no closure over class attributes).

Compare

,----
| >>> class C (object):
| ...     foo = 42
| ...     def bar (self):
| ...         print(self.foo)
| ...         self.foo = 23
| ... 
| >>> C.foo
| 42
| >>> o = C()
| >>> o.foo
| 42
| >>> C.foo
| 42
| >>> o.bar()
| 42
| >>> o.foo
| 23
| >>> C.foo
| 42
`----

vs.

,----
| >>> class C2 (object):
| ...     def __init__ (self):
| ...         self.foo = 42
| ... 
| >>> C2().foo
| 42
| >>> C2.foo
| Traceback (most recent call last):
|   File "<stdin>", line 1, in <module>
| AttributeError: type object 'C2' has no attribute 'foo'
`----

> On the other hand, when I checked further:
> 
>>>>dir(x.method)
> [........, '__self__',.......]
> 
> but
>>>>dir(rec.method)
> [.... list of method and  '__self__'  wasn't there.....]

,----
| >>> print(dir.__doc__)
| dir([object]) -> list of strings
| 
| If called without an argument, return the names in the current scope.
| Else, return an alphabetized list of names comprising (some of) the 
| attributes of the given object, and of attributes reachable from it.
| If the object supplies a method named __dir__, it will be used; otherwise
| the default dir() logic is used and returns:
|   for a module object: the module's attributes.
|   for a class object:  its attributes, and recursively the attributes
|     of its bases.
|   for any other object: its attributes, its class's attributes, and
    ^^^^^^^^^^^^^^^^^^^^
|     recursively the attributes of its class's base classes.
`----
 
> I got a "bit" confused.

There is no good reason that “__self__” should be an attribute of a *class* 
method or a *class*, so it most certainly is not.  On the other hand, it 
makes a lot of sense that a method of an instance has a way to refer to its 
owner.

> 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?

Because classes and instances are not only different objects, but also 
(instances) of different (classes/)types.  It is the way Python OOP (in 
fact, its entire type system) works:

| >>> class C (object): pass
| >>> type(C)
| <class 'type'>
| >>> type(C())
| <class '__main__.C'>

> So  I need to write down an "obj" argument manually.

If you intend the function to be called as the method of an instance, you 
would be well-advised to name the parameter “self”, as recommended.  (Which 
is probably derived from Smalltalk-80 and Self, some of the first OOPLs.)

> Why '__self__' exists only in instance "x"?

If I am not mistaken, you have not yet ascertained that the attribute 
'__self__' exists in the instance at all, only that it exists as an 
attribute of the *method* of an instance.  In fact, I find:

| >>> '__self__' in dir(C())
| False

> (maybe because "rec", initially was created as an empty class?)

Unlikely.  But you can simply test that.
 
> How does a function "uppername()" looks like, when I apply it to "rec"
> class, so it becomes  a class's method?
> 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")?

def uppername (self):
    return self._name.upper()

and the like (BTDT).  (It is recommended to start identifiers of 
implementation-specific symbols, that should not be accessed from outside 
the class, with “_” – PyDev then recognizes them as “protected”.  Therefore, 
“self._name” instead.)

(I prefer the space before the parameter list in declarations/definitions in 
order to tell them apart easily from argument lists in calls/instantiations.  
YMMV.)

> Thanks a  lot in advance,

You’re welcome.

-- 
PointedEars

[toc] | [prev] | [next] | [standalone]


#82536

FromTerry Reedy <tjreedy@udel.edu>
Date2014-12-14 19:11 -0500
Message-ID<mailman.16964.1418602282.18130.python-list@python.org>
In reply to#82531
On 12/14/2014 6:15 PM, Thomas 'PointedEars' Lahn wrote:
> Ivan Evstegneev wrote:
>
>> I have stuck a bit with this example(took this one from the book).
>>
>> Here are a description steps of what I've done till now:
>>
>>
>> Step 1 - creating an empty namespace:
>>
>>>>> class rec: pass
>
> IMHO that is not actually creating a namespace; it is just
> declaring/defining an empty class.

I pythonland, a namespace is a many to one mapping between names and 
objects.  They are usually but not necessarily implemented with dicts. 
Some might restrict the term to a mapping with a .attribute interface 
for getting and setting.  Others consider any string-key dict to be a 
namespace. The types module has a class SimpleNamespace.  It has been 
proposed to move it to builtins with the name 'namespace'.

> BTW, the recommended Python 3.x way is
>
> class Rec (object):
>      pass

I hope you meant Python *2*.x, where '(object)' *is* needed to make a 
newstyle class.  In 3.x, '(object)' is optional and normally omitted 
except in code meant to run unchanged in 2 and 3.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#82537

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2014-12-15 01:32 +0100
Message-ID<3517223.7xnpL0NDtR@PointedEars.de>
In reply to#82536
Terry Reedy wrote:

> On 12/14/2014 6:15 PM, Thomas 'PointedEars' Lahn wrote:
>> Ivan Evstegneev wrote:
>>> I have stuck a bit with this example(took this one from the book).
>>>
>>> Here are a description steps of what I've done till now:
>>>
>>> Step 1 - creating an empty namespace:
>>>
>>>>>> class rec: pass
>>
>> IMHO that is not actually creating a namespace; it is just
>> declaring/defining an empty class.
> 
> I pythonland, a namespace is a many to one mapping between names and
> objects.  They are usually but not necessarily implemented with dicts.
> […]
> 
>> BTW, the recommended Python 3.x way is
>>
>> class Rec (object):
>>      pass
> 
> I hope you meant Python *2*.x,

I did not.

> where '(object)' *is* needed to make a newstyle class.  In 3.x, '(object)' 
> is optional and normally omitted except in code meant to run unchanged in 
> 2 and 3.

Your statements are corroborated by the Language Reference:

<https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces>

<https://docs.python.org/2.7/reference/datamodel.html#new-style-and-classic-classes>

Thanks.

-- 
PointedEars

[toc] | [prev] | [next] | [standalone]


#82540

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-12-15 13:01 +1100
Message-ID<548e40de$0$12997$c3e8da3$5496439d@news.astraweb.com>
In reply to#82531
Thomas 'PointedEars' Lahn wrote:

> Ivan Evstegneev wrote:
> 
>> I have stuck a bit with this example(took this one from the book).
>> 
>> Here are a description steps of what I've done till now:
>>  
>> 
>> Step 1 - creating an empty namespace:
>> 
>>>>>class rec: pass
> 
> IMHO that is not actually creating a namespace; it is just
> declaring/defining an empty class.

And classes are namespaces. As are instances.

One clue is the fact that we use exactly the same syntax for accessing names
in a namespace regardless of whether the namespace is a package, a module,
a class or an instance:

import collections.abc  # a package namespace
math.sin  # a module namespace
OrderedDict.fromkeys  # a class namespace
mystring.upper  # an instance namespace

I call it a "clue" rather than definitive proof because the syntax is not
quite the same for all namespaces. Local and global variables also exist in
namespaces, but you don't use dotted notation for them.

Another clue is that most of these are implemented by using a __dict__ to
store the name:value mapping. Again, that's not universal: instances can
optionally use __slots__ instead of __dict__ and packages use the file
system.

Apart from packages, one can use getattr(), setattr() and delattr() on all
of these objects (modules, classes and instances) to manipulate their
attributes.

Wikipedia says:

"In general, a namespace is a container for a set of identifiers (also known
as symbols, names)."

https://en.wikipedia.org/wiki/Namespace

and that applies to packages, modules, classes, and instances.

Last but not least, another clue: in some languages, such as Java, what
Python calls "attributes" are known as *variables*. So per-instance members
are called "instance variables", per-class members are sometimes
called "class variables" (although not in Java, where I believe they are
known as static variables for technical reasons). Personally, I don't like
that terminology, but I do recognise that it does reflect a certain
connection between names in local/global/instance/class namespaces.


> BTW, the recommended Python 3.x way is
> 
> class Rec (object):
>     pass


I think you mean Python 2 rather than 3. In Python 2, we have legacy "old
style" or "classic" classes, and "new style" classes which inherit from
object. In Python 3, classic classes are gone, and inheriting from object
is optional.


> (whereas “pass” is a placeholder statement, a bit like the yada-yada
> operator of Python) and you should start class identifiers uppercase
> (therefore, “Rec” instead) in order to avoid name collisions with built-in
> class identifiers (“str”, “int” etc.) and make it easier to tell apart
> instantiations from function/method calls.

Agreed!

It is good practice to name classes with initial capital letter, and
instances in all lowercase.


> If you call that method as the method of a class (object), you need to
> pass an argument for the first parameter because you have made it
> positional, not
> optional (it has no default value).  If you pass (a reference to) the
> class as first argument of that method, the class is the object whose
> attribute is
> accessed.  Classes are objects (this, too, was probably derived from
> Java). (In fact, AFAIK almost everything is an object in Python; there are
> no primitive data types at all.)

You are correct that "everything is an object" in Python, but wrong that
this is derived from Java. As I understand it, Java classes are not values:
you cannot assign a class to a variable, or create classes on the fly, or
delete them, or stick them in lists, etc. 

Well, I say that you can't do it, but you actually can, using reflection and
other tricks. But the important thing is that you need to use special
techniques to work around the fact that classes aren't values and therefore
not implemented as objects in Java. What is natural in Python is unnatural
in Java.

http://stackoverflow.com/questions/2320404/creating-classes-dynamically-with-java


[...]
> If you intend the function to be called as the method of an instance, you
> would be well-advised to name the parameter “self”, as recommended. 
> (Which is probably derived from Smalltalk-80 and Self, some of the first
> OOPLs.)

Good advice.


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#82565

From"Ivan Evstegneev" <webmailgroups@gmail.com>
Date2014-12-15 21:13 +0200
Message-ID<mailman.16986.1418670889.18130.python-list@python.org>
In reply to#82540
Again Thanks for your help.

I saw that there was a debate about  "namespace" nature.


That is what a book says about it(Learning Python 5 Ed. By Mark Lutz):

*********************************************
"Classes and Instances

Although they are technically two separate object types in the Python model, the classes
and instances we put in these trees are almost identical—each type’s main purpose is
to serve as another kind of namespace—a package of variables, and a place where we
can attach attributes. If classes and instances therefore sound like modules, they should;
however, the objects in class trees also have automatically searched links to other
namespace objects, and classes correspond to statements, not entire files."

"Customization via inheritance
....More generally, classes can build up namespace hierarchies, which
define names to be used by objects created from classes in the hierarchy. This
supports multiple customizable behaviors more directly than other tools."

"...classes live in modules and are namespaces as well, but they add an extra component to attribute
lookup called inheritance search."


"In fact, classes have just three primary distinctions. At a base level, they are mostly just
namespaces, much like the modules we studied in Part V. Unlike modules, though,
classes also have support for generating multiple objects, for namespace inheritance,
and for operator overloading."
****************************************************************************

I'm not pretending to be a "smartass" here, but as I can understand from the context:

Classes are namespaces, but they also have an additional capabilities.


BR,

Ivan






> -----Original Message-----
> From: Python-list [mailto:python-list-
> bounces+webmailgroups=gmail.com@python.org] On Behalf Of Steven
> D'Aprano
> Sent: Monday, December 15, 2014 04:01
> To: python-list@python.org
> Subject: Re: Classes - converting external function to class's method.
> 
> Thomas 'PointedEars' Lahn wrote:
> 
> > Ivan Evstegneev wrote:
> >
> >> I have stuck a bit with this example(took this one from the book).
> >>
> >> Here are a description steps of what I've done till now:
> >>
> >>
> >> Step 1 - creating an empty namespace:
> >>
> >>>>>class rec: pass
> >
> > IMHO that is not actually creating a namespace; it is just
> > declaring/defining an empty class.
> 
> And classes are namespaces. As are instances.
> 
> One clue is the fact that we use exactly the same syntax for accessing names in a
> namespace regardless of whether the namespace is a package, a module, a class
> or an instance:
> 
> import collections.abc  # a package namespace math.sin  # a module namespace
> OrderedDict.fromkeys  # a class namespace mystring.upper  # an instance
> namespace
> 
> I call it a "clue" rather than definitive proof because the syntax is not quite the
> same for all namespaces. Local and global variables also exist in namespaces, but
> you don't use dotted notation for them.
> 
> Another clue is that most of these are implemented by using a __dict__ to store
> the name:value mapping. Again, that's not universal: instances can optionally
> use __slots__ instead of __dict__ and packages use the file system.
> 
> Apart from packages, one can use getattr(), setattr() and delattr() on all of these
> objects (modules, classes and instances) to manipulate their attributes.
> 
> Wikipedia says:
> 
> "In general, a namespace is a container for a set of identifiers (also known as
> symbols, names)."
> 
> https://en.wikipedia.org/wiki/Namespace
> 
> and that applies to packages, modules, classes, and instances.
> 
> Last but not least, another clue: in some languages, such as Java, what Python
> calls "attributes" are known as *variables*. So per-instance members are called
> "instance variables", per-class members are sometimes called "class variables"
> (although not in Java, where I believe they are known as static variables for
> technical reasons). Personally, I don't like that terminology, but I do recognise
> that it does reflect a certain connection between names in
> local/global/instance/class namespaces.
> 
> 
> > BTW, the recommended Python 3.x way is
> >
> > class Rec (object):
> >     pass
> 
> 
> I think you mean Python 2 rather than 3. In Python 2, we have legacy "old style"
> or "classic" classes, and "new style" classes which inherit from object. In Python
> 3, classic classes are gone, and inheriting from object is optional.
> 
> 
> > (whereas “pass” is a placeholder statement, a bit like the yada-yada
> > operator of Python) and you should start class identifiers uppercase
> > (therefore, “Rec” instead) in order to avoid name collisions with
> > built-in class identifiers (“str”, “int” etc.) and make it easier to
> > tell apart instantiations from function/method calls.
> 
> Agreed!
> 
> It is good practice to name classes with initial capital letter, and instances in all
> lowercase.
> 
> 
> > If you call that method as the method of a class (object), you need to
> > pass an argument for the first parameter because you have made it
> > positional, not optional (it has no default value).  If you pass (a
> > reference to) the class as first argument of that method, the class is
> > the object whose attribute is accessed.  Classes are objects (this,
> > too, was probably derived from Java). (In fact, AFAIK almost
> > everything is an object in Python; there are no primitive data types
> > at all.)
> 
> You are correct that "everything is an object" in Python, but wrong that this is
> derived from Java. As I understand it, Java classes are not values:
> you cannot assign a class to a variable, or create classes on the fly, or delete
> them, or stick them in lists, etc.
> 
> Well, I say that you can't do it, but you actually can, using reflection and other
> tricks. But the important thing is that you need to use special techniques to work
> around the fact that classes aren't values and therefore not implemented as
> objects in Java. What is natural in Python is unnatural in Java.
> 
> http://stackoverflow.com/questions/2320404/creating-classes-dynamically-
> with-java
> 
> 
> [...]
> > If you intend the function to be called as the method of an instance,
> > you would be well-advised to name the parameter “self”, as recommended.
> > (Which is probably derived from Smalltalk-80 and Self, some of the
> > first
> > OOPLs.)
> 
> Good advice.
> 
> 
> --
> Steven
> 
> --
> https://mail.python.org/mailman/listinfo/python-list

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web