Re: [Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-08 Thread boB Stepp
On Tue, Aug 8, 2017 at 2:39 AM, Alan Gauld via Tutor  wrote:
> On 08/08/17 02:22, boB Stepp wrote:

[snip lots of good stuff]

I am coming to the conclusion I need to code a substantial,
challenging project using OOP techniques, instead of just the toy
programs I have been playing around with so far.  When I do so, I
think I will start to see where all these different Python tools are
useful when I perceive I have a practical problem which reminds me of
one of these tools.

Thanks, Alan!


-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-08 Thread Cameron Simpson

On 08Aug2017 08:39, Alan Gauld  wrote:

(1) There are very, very few good uses for static methods in Python. If
you think you need a static method, you probably could just use a
regular module-level function.


Amen to that, I try to avoid staticmethods... and so far
have never found a valid use for one. I treat them as a
piece of legacy from earlier versions, prior to classmethods.


I use them a bit for things that _could_ be module level functions, but using a 
static method lets me (a) associate if with a class and (b) one gets access to 
the method when one imports the class. So one can write code like this:


 from my_module import SomeDataFormat

 with open(datafile) as f:
   header_info = SomeDataFormat.parse_header(f)

and the module's SomeDataFormat class might have:

 class Foo:

   @staticmethod
   def parse_header(f):
 # decode the header structure and return info about it

That could easily be a standalone module function, but if the header record is 
a specific to the class then one can expose the parser function as a static 
method: it comes in with the class when it is imported, and it is clear that 
the parser is for what the class manages. It lets you avoid 
cumber_long_function_names because the "SomeDataFormat." contributes to the 
description.


I've also used them for factories, but think a class method is better. Thus:

 class Foo:

   def __init__(self, x, y, z):
 self.x = x
 self.y = y
 self.z = z

   @staticmethod
   def from_point(p):
 return Foo(p.x, p.y, p.z)

so that one can make a Foo directly:

 f = Foo(1,2,3)

or from some hypothetical "point" object:

 f = Foo.from_point(p)

But arguably this would be better as a class method anyway:

 @classmethod
 def from_point(klass, p):
   return klass(p.x, p.y, p.z)

because it lets you subclass Foo:

 class Bah(Foo):

and call Bah.from_point(p) for free, and it will make a Bah instead of a Foo 
because it gets the class as "klass".


Cheers,
Cameron Simpson  (formerly c...@zip.com.au)
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-08 Thread Peter Otten
Alan Gauld via Tutor wrote:

> classes are objects too...

Also, classes are instances. Given

>>> class Foo:
... pass
... 
>>> foo = Foo()
>>> type(foo)

>>> type(Foo)


what is the type of the type of the type ... of foo?
The answer is a circular definition that you cannot spell in Python itself:

>>> type(type)


The type of type is... type. Put the other way round: like ordinary classes 
type is an instance of type.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-08 Thread Alan Gauld via Tutor
On 08/08/17 02:22, boB Stepp wrote:

> "@staticmethod" then there are two ways of calling the method, using
> objects or using the class.  Is there some reason not to use the
> "ClassName.a_static_method()" syntax?  Are there intended uses for
> doing this?

classes are objects too...

You could have a list of objects, some of which are classes
and some instances.

Its nice to use polymorphism and just call the staticmethod (or
classmethod) and let the interpreter do the hard work without
having to test types - a nasty non-OO style of programming that
should be avoided if possible

> Class methods look to be something I will find difficult to find a use for.

Once you start using objects a lot they come in very useful.
I don't think I've built any significant OO system without
using at least a few class methods. Remember that class methods
conceptually act on the class as a whole - ie on all instances
both current and future. So any time you have a large group
of objects and you want to set some kind of state for all
of them you can use classmethods to set class state. Instance
methods can refer to the class state and modify their behaviour
accordingly. (Some OO gurus argue that you should only set
class state via a class method, although you can do it via an
instance too - but what if you need to set it when no
instances exist. In Python direct access allows that
from outside the class, but in other OO systems you need
a class method.)

Class methods are also the best place to put alternate
constructors - eg loading from a database given an
instance ID or by parsing a string representation.

Class methods can also be used to manage caches of instances,
do global searches of instances (eg from a database) etc.

>> (1) There are very, very few good uses for static methods in Python. If
>> you think you need a static method, you probably could just use a
>> regular module-level function.

Amen to that, I try to avoid staticmethods... and so far
have never found a valid use for one. I treat them as a
piece of legacy from earlier versions, prior to classmethods.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-08 Thread Cameron Simpson

On 07Aug2017 20:22, boB Stepp  wrote:

On Mon, Aug 7, 2017 at 8:36 AM, Steven D'Aprano  wrote:

[...]

It is hard to see the distinction between an ordinary method and a
static method from this example. What you are seeing is, by accident,
the equivalent of just writing:

def my_method():
print('This is my_method in MyClass!')

outside of the class and calling the bare function. Notice that despite
the name, my_method is not *actually* usable as a method. It has no
"self" parameter.


I thought that was the whole essence of static methods -- no self parameter.


The point of a static method is that it doesn't have an instance or class 
context (a method's first argument).


A method gets called like this:

 obj.method(blah)

where obj is an instance of the class and blah is some arguments.

A method can be defined, essentially, 3 ways:

 def method(self, blah):

 @classmethod
 def method(klass, blah):

 @staticmethod
 def method(blah):

They all can be _called_ the same way. The decorator controls what context they 
receive. An ordinary method gets the instance ("obj", above) as its first 
argument as context. A class method receives the instance's class as its first 
argument as context. A static method gets no context, and no presupplied 
parameter.


What Steven is getting at is that if you define a method like this:

 def my_method():

is is supposed to be an ordinary method. However, orderinary methods are handed 
the instance ("obj") as the first parameter, and you have specified no 
parameter. This will blow up when you call it:


 class K(object):
   def m():
 pass

 o=K()
 o.m()
 Traceback (most recent call last):
   File "", line 1, in 
 TypeError: m() takes 0 positional arguments but 1 was given

This is because m() is an ordinary method, and therefore it gets called with 
"o" as the first parameter. But it doesn't expect that, hence the TypeError.


Now, you _can_ call m() via the class:

 K.m()

but the point of classmethods and staticmethods is that you can call them on 
instances, and the caller doesn't need to know what style of method they are.  
The caller just goes:


 K.m(blah)

and doesn't care.

Cheers,
Cameron Simpson  (formerly c...@zip.com.au)
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-07 Thread boB Stepp
I feel like I have gazed into a crystal clear pool, apparently
shallow, with many interesting objects (Pun intended!) on the pool
floor.  Interested in these beautiful things, I jump in to grab one
for close-up study only to find that the pool is much, ... , much
deeper (> 1 boB-height) than it appeared.  And alas!  I don't know how
to swim!

On Mon, Aug 7, 2017 at 8:36 AM, Steven D'Aprano  wrote:
> On Sun, Aug 06, 2017 at 06:35:10PM -0500, boB Stepp wrote:
>
>> py3: class MyClass:
>> ... def my_method():
>> ... print('This is my_method in MyClass!')
>> ...
>> py3: class MyOtherClass:
>> ... @staticmethod
>> ... def my_other_method():
>> ... print('This is my_other_method in MyOtherClass!')
>> ...
>> py3: MyClass.my_method()
>> This is my_method in MyClass!
>> py3: MyOtherClass.my_other_method()
>> This is my_other_method in MyOtherClass!
>
> A small comment: since the methods have different names, there's no
> reason why they couldn't both be in the same class.

As I did not know exactly where I was going with these exploratory
examples, I thought I would keep things separated in case something
surprising developed.  Then I could easily compare the two.

> It is hard to see the distinction between an ordinary method and a
> static method from this example. What you are seeing is, by accident,
> the equivalent of just writing:
>
> def my_method():
> print('This is my_method in MyClass!')
>
> outside of the class and calling the bare function. Notice that despite
> the name, my_method is not *actually* usable as a method. It has no
> "self" parameter.

I thought that was the whole essence of static methods -- no self parameter.

>
>> I see no difference in result, whether I use the @staticmethod decorator or 
>> not.
>
> Indeed you would not, because you are calling MyClass.my_method,
> directly from the class object. If you created an instance first, and
> then called the methods, you would see a big difference!

Alan pointed out I might want to investigate this.  I did and got what
you show below.

> obj = MyClass()
> obj.my_method()  # fails with TypeError, as there is no "self" parameter
>
> while the staticmethod would succeed.
>
> So what's going on here?
>
> When you call MyClass.my_method, Python looks up my_method on the class
> object, equivalent to:
>
> thing = getattr(MyClass, 'my_method')
>
> before calling thing(), which then prints the message.
>
> This is where is gets complex... Python performs some special magic when
> you look up attributes, according to "the descriptor protocol". Don't
> worry about how it works -- think of it as black magic for now. But the
> bottom line is, if the look up returns something like a string or an int
> or a list, no descriptor magic happens, but if it returns a function
> (something you created with "def"), something not far removed from this
> happens:
>
> # (instance) method descriptor
> if thing is a function:
> if the source was a class # like "MyClass.method":
> # This was different in Python 2.
> return thing, unchanged
> else:  # source was an instance, "MyClass().method"
> wrap thing in a method object that receives "self"
> return the method object
>
> Why does it bother? Because that way Python can automatically fill in
> the instance as "self".

[snip]

>
> Despite the name, your example "my_method" isn't a method and doesn't
> require "self". If you try to pass one in, you get a TypeError because
> the function doesn't take any arguments at all. But normally methods
> need to know what instance they are working on, in other words, they
> need to know "self".

Question(s):  While something like "my_method" can't be called from an
object instance, it can be called on the class.  Are there use cases
where this behavior is actually desired?  If wrapped with
"@staticmethod" then there are two ways of calling the method, using
objects or using the class.  Is there some reason not to use the
"ClassName.a_static_method()" syntax?  Are there intended uses for
doing this?

> So when you call MyClass.my_method, calling from the class, Python just
> gives you the raw function object, unchanged. Normally that means you
> would need to provide "self" yourself. This is called an "unbound
> method", it's unbound because it doesn't know what instance to work on.

[snip]

> Unbound methods have their uses. In Python 2, they were actual custom
> method objects, but in Python 3 it was decided that this was pointless
> and instead the bare function is returned instead. But conceptually, the
> base function is an unbound method.
>
> So normal methods convert a function to a method which automatically
> provides "self", but only if called from the instance (self). Otherwise
> they return the function, which needs you to manually provide self.
>
> In your example, by accident (I assume?) ...

No, on purpose.  I was just playing 

Re: [Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-07 Thread Steven D'Aprano
On Sun, Aug 06, 2017 at 06:35:10PM -0500, boB Stepp wrote:

> py3: class MyClass:
> ... def my_method():
> ... print('This is my_method in MyClass!')
> ...
> py3: class MyOtherClass:
> ... @staticmethod
> ... def my_other_method():
> ... print('This is my_other_method in MyOtherClass!')
> ...
> py3: MyClass.my_method()
> This is my_method in MyClass!
> py3: MyOtherClass.my_other_method()
> This is my_other_method in MyOtherClass!

A small comment: since the methods have different names, there's no 
reason why they couldn't both be in the same class. 

It is hard to see the distinction between an ordinary method and a 
static method from this example. What you are seeing is, by accident, 
the equivalent of just writing:

def my_method():
print('This is my_method in MyClass!')

outside of the class and calling the bare function. Notice that despite 
the name, my_method is not *actually* usable as a method. It has no 
"self" parameter.


> I see no difference in result, whether I use the @staticmethod decorator or 
> not.

Indeed you would not, because you are calling MyClass.my_method, 
directly from the class object. If you created an instance first, and 
then called the methods, you would see a big difference!

obj = MyClass()
obj.my_method()  # fails with TypeError, as there is no "self" parameter

while the staticmethod would succeed.

So what's going on here?

When you call MyClass.my_method, Python looks up my_method on the class 
object, equivalent to:

thing = getattr(MyClass, 'my_method')

before calling thing(), which then prints the message.

This is where is gets complex... Python performs some special magic when 
you look up attributes, according to "the descriptor protocol". Don't 
worry about how it works -- think of it as black magic for now. But the 
bottom line is, if the look up returns something like a string or an int 
or a list, no descriptor magic happens, but if it returns a function 
(something you created with "def"), something not far removed from this 
happens:

# (instance) method descriptor
if thing is a function:
if the source was a class # like "MyClass.method":
# This was different in Python 2.
return thing, unchanged
else:  # source was an instance, "MyClass().method"
wrap thing in a method object that receives "self"
return the method object

Why does it bother? Because that way Python can automatically fill in 
the instance as "self".

Example: today we write:

s = "Hello world!"
t = s.upper()

But without this method magic, or something similar, we would have to 
write:

s = "Hello world!"
t = str.upper(s)  # need to manually provide "self"

or even:

s = "Hello world!"
t = s.upper(s)

in order for the upper() method to receive the instance s as the "self" 
parameter.

Despite the name, your example "my_method" isn't a method and doesn't 
require "self". If you try to pass one in, you get a TypeError because 
the function doesn't take any arguments at all. But normally methods 
need to know what instance they are working on, in other words, they 
need to know "self".

So when you call MyClass.my_method, calling from the class, Python just 
gives you the raw function object, unchanged. Normally that means you 
would need to provide "self" yourself. This is called an "unbound 
method", it's unbound because it doesn't know what instance to work on.

Example:

str.upper

is the equivalent of an unbound method. It is incomplete, because it 
doesn't know what string to uppercase. You have to provide one for it to 
work on:

str.upper("spam")

But if you call directly from an instance, Python knows what string to 
use as "self", and you don't need to do any more:

"spam".upper()


Unbound methods have their uses. In Python 2, they were actual custom 
method objects, but in Python 3 it was decided that this was pointless 
and instead the bare function is returned instead. But conceptually, the 
base function is an unbound method.

So normal methods convert a function to a method which automatically 
provides "self", but only if called from the instance (self). Otherwise 
they return the function, which needs you to manually provide self.

In your example, by accident (I assume?) you forgot to include "self", 
so the fact that no self was provided didn't stop the function from 
working.

Now, how about class methods? Class methods are just like ordinary 
(instance) methods, except instead of "self", they receive the class 
object as first parameter. There aren't many good examples of class 
methods, and so they aren't common. But here's one:

dict.fromkeys

Most dict methods (update, pop, popitem, clear, etc.) need to know which 
specific dict to work on. But fromkeys is different: it does not care 
what instance you use. Both of these will work exactly the same:

{}.fromkeys(['one', 'two', 'three'])
{100: 'A', 200: 

Re: [Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-06 Thread eryk sun
On Sun, Aug 6, 2017 at 11:35 PM, boB Stepp  wrote:
>
> I see no difference in result, whether I use the @staticmethod decorator or 
> not.

While a staticmethod and a function are both descriptors [1], a
staticmethod is basically a no-op descriptor. Its __get__ method
always returns its unbound callable (i.e. its __func__ attribute)
instead of returning a computed property or bound method.

Examples

>>> descr = vars(MyOtherClass)['my_other_method']
>>> descr


>>> descr.__func__


When accessed as an attribute of a class (i.e. the instance argument
passed to __get__ is None), a staticmethod returns just its __func__.

>>> descr.__get__(None, MyOtherClass)


That's effectively no different from a Python 3 function. But they
diverge when accessed as an attribute of an instance. In this case the
__get__ method of a staticmethod also simply returns its __func__,

>>> descr.__get__(MyOtherClass(), MyOtherClass)


whereas the __get__ method of a function returns a method that's bound
to the instance.

>>> func = vars(MyClass)['my_method']
>>> func


>>> func.__get__(MyClass(), MyClass)
>

[1]: https://docs.python.org/3/reference/datamodel.html#implementing-descriptors
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-06 Thread Alan Gauld via Tutor
On 07/08/17 00:35, boB Stepp wrote:

> =
> Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64
> bit (AMD64)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
> py3: class MyClass:
> ... def my_method():
> ... print('This is my_method in MyClass!')
> ...
> py3: class MyOtherClass:
> ... @staticmethod
> ... def my_other_method():
> ... print('This is my_other_method in MyOtherClass!')
> ...
> py3: MyClass.my_method()
> This is my_method in MyClass!
> py3: MyOtherClass.my_other_method()
> This is my_other_method in MyOtherClass!

You should also try calling them from an instance of the class.
That should also illustrate a difference between classmethod and
staticmethod when you get round to that.

> the entry "staticmethod(function)" the author states, "... Use the
> @staticmethod functiion decorator in version 2.4 and later ... In
> Python 3.X only, this built-in is not required for simple functions in
> classes called only through class objects (and never through instance
> objects)."  

Notice the bit in parens...
It doesn't say you cannot call staticmethods from instances,
it says that you don;t need the decorator unless you are
doing that. Very different.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Difference(s) betweenPython 3 static methods with and without @staticmethod?

2017-08-06 Thread boB Stepp
I am looking more deeply into the subject of decorators for a bit (So
I can thoroughly digest Steve's information in the thread "basic
decorator question".) and have been first looking at static and class
methods.  As a start, I have tried the following:

=
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64
bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
py3: class MyClass:
... def my_method():
... print('This is my_method in MyClass!')
...
py3: class MyOtherClass:
... @staticmethod
... def my_other_method():
... print('This is my_other_method in MyOtherClass!')
...
py3: MyClass.my_method()
This is my_method in MyClass!
py3: MyOtherClass.my_other_method()
This is my_other_method in MyOtherClass!
=

I see no difference in result, whether I use the @staticmethod decorator or not.

In "Python Pocket Reference, 5th ed." by Mark Lutz, on page 151 under
the entry "staticmethod(function)" the author states, "... Use the
@staticmethod functiion decorator in version 2.4 and later ... In
Python 3.X only, this built-in is not required for simple functions in
classes called only through class objects (and never through instance
objects)."  So what I am understanding is that I only need use the
@staticmethod decorator if I am using Python versions 2.4 through 2.7
(new-style classes).  Is my understanding correct?

TIA!

-- 
boB
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor