473,218 Members | 1,675 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,218 software developers and data experts.

Make staticmethod objects callable?

Hi everyone,
I was wondering if it would make sense to make staticmethod objects
callable, so that the following code would work:

class A:
@staticmethod
def foo(): pass
bar = foo()

I understand staticmethod objects don't need to implement __call__ for
their other use cases, but would it still make sense to implement
__call__ for that specific use case? Would it be error-prone in any way?

Thx and regards,
Nicolas
Feb 28 '06 #1
10 6950
Nicolas Fleury wrote:
I was wondering if it would make sense to make staticmethod objects
callable, so that the following code would work:

class A:
@staticmethod
def foo(): pass
bar = foo()


Do you have a real-world use case? I pretty much never use
staticmethods (preferring instead to use module-level functions) so I'm
having a hard time coming up with some code where this would be really
useful. I'm also a little wary of breaking the parallel between
classmethod and staticmethod which are currently *just* descriptors
(without any other special functionality).

Maybe instead of making just staticmethods callable, both staticmethods
and classmethods could gain an 'im_func' attribute like bound and
unbound methods have?

STeVe
Feb 28 '06 #2
Em Ter, 2006-02-28 √*s 15:17 -0500, Nicolas Fleury escreveu:
class A:
@staticmethod
def foo(): pass
bar = foo()


# Why not:

def foo(): pass

class A:
bar = foo()
foo = staticmethod(foo)

--
"Quem excele em empregar a força militar subjulga os exércitos dos
outros povos sem travar batalha, toma cidades fortificadas dos outros
povos sem as atacar e destrói os estados dos outros povos sem lutas
prolongadas. Deve lutar sob o Céu com o propósito primordial da
'preservação'. Desse modo suas armas não se embotarão, e os ganhos
poderão ser preservados. Essa é a estratégia para planejar ofensivas."

-- Sun Tzu, em "A arte da guerra"

Feb 28 '06 #3
Felipe Almeida Lessa wrote:
Em Ter, 2006-02-28 √*s 15:17 -0500, Nicolas Fleury escreveu:
class A:
@staticmethod
def foo(): pass
bar = foo()

# Why not:

def foo(): pass

class A:
bar = foo()
foo = staticmethod(foo)


Well, you could even do:

class A:
def foo(): pass
bar = foo()
staticmethod(foo)

But it's a bit sad to have a special syntax for decorators then. It's a
usability problem, nothing to do with functionality. There's obvious
workarounds, but IMHO any user saying "it should just work" is at least
partly right.

Regards,
Nicolas
Feb 28 '06 #4
Steven Bethard wrote:
Nicolas Fleury wrote:
I was wondering if it would make sense to make staticmethod objects
callable, so that the following code would work:

class A:
@staticmethod
def foo(): pass
bar = foo()
Do you have a real-world use case? I pretty much never use
staticmethods (preferring instead to use module-level functions) so I'm
having a hard time coming up with some code where this would be really
useful. I'm also a little wary of breaking the parallel between
classmethod and staticmethod which are currently *just* descriptors
(without any other special functionality).


Well, IMHO, if staticmethod is worth being standard, than calling these
static methods inside the class definition is worth being supported. To
be honest I don't use static methods like you, but users come see me
asking "Why?" and I find their code logically structured so I conclude
there's a usability problem here.
Maybe instead of making just staticmethods callable, both staticmethods
and classmethods could gain an 'im_func' attribute like bound and
unbound methods have?


I don't like it either (__get__ can be called anyway). My problem is
the expectation of the user. I wonder if it should just work. Adding a
few lines of code in staticmethod is worth it if it avoids all these
questions over and over again, no?

Regards,
Nicolas
Feb 28 '06 #5
You have a text-database, each record has some "header info" and some
data (text-blob). e.g.

--------------------
<HEADER>
name = "Tom"
phone = "312-996-XXXX"
</HEADER>
I last met tom in 1998. He was still single then.
blah
blah
<HEADER>
name = "John"
birthday = "1976-Mar-12"
</HEADER>
I need to ask him his email when I see him next.
------------------

I use this format for a file to keep track of tit bits of information.
Lets say the file has several hundred records. I know want to say
generate a birthday list of people and their birthdays. Ofcourse along
with that I also need the "text-blob" (because I dont want to send a
birthday card to a person I dont like). In order to do this I execute a
script

../filter --input=database.txt --condn='similar(name,"tom")'.

The way it is implemented is simple. Have a class which has dict as its
base class. For each record the text between <hEADER> and </HEADER> is
executed with the class instance as "locals()". Now that I have a list
of class instances, I just exec the condition and those instances where
it evaluates True comprise the output text file.

To make the user, not have to know too much python, one would like to
define "functions" which can be used. For eg. similar would have the
following definition

@staticmethod
def similar(regexp,str):
return re.match("(?i)^.*%s.*$" % regexp, str) != None

This way the "locals()" dictionary in the exec'ed environment has
access to the function similar (if similar was callable). At the same
time, I can enclose all these functions in their own name space (as
static methods of a class).

Right now, I declare all these "helper" functions in a different
module, and "attach" the "helper" functions as keys into the
dictionary. If only staticmethods were callable. For some reason (I
dont recall why) the idea of converting the staticmethod into a
callable still did not work, e.g.

class Callable:
def __init__(self,method):
self.__call__ = method

class Record(dict):

@staticmethod
def similar(regexp,string):
....

self['similar'] = Callable(similar)

The above did not work. The error message was still related to a
staticmethod not being a callable.

- Murali

Mar 1 '06 #6
Nicolas Fleury wrote:
Hi everyone,
I was wondering if it would make sense to make staticmethod objects
callable, so that the following code would work:
This is one of the more unintuitive areas of Python,
with side effects and different behaviour depending on
whether code is called inside or outside a class:
class Parrot: .... def speak():
.... return "dead parrot"
.... speak = staticmethod(speak)
.... def playdead():
.... return "still dead"
.... type(Parrot.speak) <type 'function'> type(Parrot.playdead) <type 'instancemethod'>

So, based on this evidence, staticmethod() converts an
instance method into an ordinary function. Parrot.speak
certainly behaves like an ordinary function.
callable(Parrot.speak) True Parrot.speak() 'dead parrot'
But now try to do the same outside of a class:
f = staticmethod(Parrot.playdead)
type(f) <type 'staticmethod'>

f is not a function?
Parrot.playdead = staticmethod(Parrot.playdead)
type(Parrot.playdead) <type 'instancemethod'>

So, based on this evidence, staticmethod() inside a
class definition converts instance methods to
functions. Outside a class definition, staticmethod()
does one of two things: it either converts an instance
method to a static method, or if the output is assigned
to a class attribute, it leaves it as an instance method.

Hmmm.
class A:
@staticmethod
def foo(): pass
bar = foo()


Here is a work around:
class A: .... def foo(): return "foo foo foo"
.... foo = staticmethod(foo)
.... def __init__(self):
.... if not hasattr(self.__class__, "bar"):
.... self.__class__.bar = self.foo()
.... dir(A) ['__doc__', '__init__', '__module__', 'foo'] a = A()
dir(A) ['__doc__', '__init__', '__module__', 'bar', 'foo'] a.foo() 'foo foo foo' a.bar 'foo foo foo'
Here is a more interesting example:
class B: .... def foo():
.... return lambda x: x+1
.... foo = staticmethod(foo)
.... def __init__(self):
.... if not hasattr(self.__class__, "bar"):
.... self.__class__.bar = \
.... staticmethod(self.foo())
.... dir(B) ['__doc__', '__init__', '__module__', 'foo'] b = B()
dir(B) ['__doc__', '__init__', '__module__', 'bar', 'foo'] b.foo() <function <lambda> at 0xb7f70c6c> b.bar <function <lambda> at 0xb7f70c34> b.bar(3)

4
Hope this helps.

--
Steven.

Mar 1 '06 #7
Steven D'Aprano wrote:
So, based on this evidence, staticmethod() inside a class definition
converts instance methods to functions. Outside a class definition,
staticmethod() does one of two things: it either converts an instance
method to a static method, or if the output is assigned to a class
attribute, it leaves it as an instance method.


This is exactly why I'm concerned about augmenting staticmethod's
behavior. When people run into this, it should be the opportunity to
explain to them how descriptors work. Descriptors are hugely important
in the new object system, and even if we hide them by giving
staticmethod a __call__, we'll still run into problems when people try
to do:

class C(object):
@classmethod
def foo(cls):
print cls
bar = foo(None)

Then, not only do we have to explain how descriptors work, but we also
have to explain why staticmethod has a __call__, and classmethod doesn't.

(For anyone else out there reading who doesn't already know this, Steven
D'Aprano's comments are easily explained by noting that the __get__
method of staticmethod objects returns functions, and classes always
call the __get__ methods of descriptors when those descriptors are class
attributes:
class C(object): .... @staticmethod
.... def foo():
.... pass
.... print foo
....
<staticmethod object at 0x00E73950> print C.foo <function foo at 0x00E80330> @staticmethod .... def foo():
.... pass
.... print foo <staticmethod object at 0x00E73990> print foo.__get__(C, None)

<function foo at 0x00E80130>

Yes, you have to explain descriptors, but at the point that you start
trying to do funny things with staticmethods and classmethods, I think
you need to start learning about them anyway.)

All that said, you should probably just submit a patch and see what
happens. I'll make a brief comment on it along the above lines, but
since I'm not a committer, it's not really worth your time to try to
convince me. ;)

STeVe
Mar 1 '06 #8
Steven Bethard wrote:
...
Yes, you have to explain descriptors, but at the point that you start
trying to do funny things with staticmethods and classmethods, I think
you need to start learning about them anyway.)
That's all good points, but IMHO, descriptors are a much more advanced
Python feature than static methods, especially for programmers from
other backgrounds, like Java/C#/C++. We basically have the choice
between hiding something unnecessarily complex or force to understand a
useful feature;)
All that said, you should probably just submit a patch and see what
happens. I'll make a brief comment on it along the above lines, but
since I'm not a committer, it's not really worth your time to try to
convince me. ;)


I might do it, but even if I'm not a commiter, I'll continue trying to
convince myself;)

Nicolas
Mar 1 '06 #9

"Steven D'Aprano" <st***@REMOVEMEcyber.com.au> wrote in message
news:44**************@REMOVEMEcyber.com.au...
class Parrot: ... def speak():
... return "dead parrot"
... speak = staticmethod(speak)
... def playdead():
... return "still dead"
... type(Parrot.speak) <type 'function'> type(Parrot.playdead) <type 'instancemethod'>

So, based on this evidence, staticmethod() converts an
instance method into an ordinary function. Parrot.speak
certainly behaves like an ordinary function.


Actually, staticmethod() prevents an ordinary function from being converted
to (wrapped as) a method upon access via the class.
class C(object): def f(s): pass
type(C.__dict__['f']) <type 'function'> type(C.f)

<type 'instancemethod'>

As to the general topic: my impression is that staticmethod was a rather
optional addon with limited usage and that beginners hardly need to know
about it.

Terry Jan Reedy

Mar 1 '06 #10
On Wed, 01 Mar 2006 08:32:20 -0700, Steven Bethard wrote:
(For anyone else out there reading who doesn't already know this, Steven
D'Aprano's comments are easily explained by noting that the __get__
method of staticmethod objects returns functions, and classes always
call the __get__ methods of descriptors when those descriptors are class
attributes:


....

A usage of the word "easily" that I am unfamiliar with.

*wink*

Why all the indirection to implement something which is, conceptually,
the same as an ordinary function?

--
Steven.

Mar 1 '06 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Michal Vitecek | last post by:
hello everyone, today i've come upon a strange exception, consider the following file test.py: --- beginning of test.py --- class A(object): def method1(parA): print "in A.method1()"
0
by: Robin Becker | last post by:
A colleague wanted to initialize his class __new__ and tried code resembling this #######################1 class Metaclass (type): def __init__(cls, name, bases, *args, **kwargs):...
1
by: Neil Zanella | last post by:
Hello, Coming from C++ and Java, one of the surprising things about Python is that not only class instances (AKA instance objects) but also classes themselves are objects in Python. This...
28
by: The Eternal Squire | last post by:
PEP: 336 Title: Make None Callable Version: $Revision: 1.1 $ Last-Modified: $Date: 2004/11/03 16:58:30 $ Author: Andrew McClelland Status: Draft Type: Standards Track Content-Type: text/plain...
1
by: Olaf Meding | last post by:
What does the below PyChecker warning mean? More importantly, is there a way to suppress it? PyChecker warning: ..\src\phaseid\integration.py:21: self is argument in staticmethod My best...
0
by: Steven Bethard | last post by:
Steven Bethard wrote: > (For anyone else out there reading who doesn't already know this, > Steven D'Aprano's comments are easily explained by noting that the > __get__ method of staticmethod...
28
by: Steven Bethard | last post by:
Ok, I finally have a PEP number. Here's the most updated version of the "make" statement PEP. I'll be posting it shortly to python-dev. Thanks again for the previous discussion and suggestions!...
7
by: Steven Bethard | last post by:
I've updated PEP 359 with a bunch of the recent suggestions. The patch is available at: http://bugs.python.org/1472459 and I've pasted the full text below. I've tried to be more explicit about...
20
by: walterbyrd | last post by:
Reading "Think Like a Computer Scientist" I am not sure I understand the way it describes the way objects work with Python. 1) Can attributes can added just anywhere? I create an object called...
1
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
0
by: VivesProcSPL | last post by:
Obviously, one of the original purposes of SQL is to make data query processing easy. The language uses many English-like terms and syntax in an effort to make it easy to learn, particularly for...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 3 Jan 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). For other local times, please check World Time Buddy In...
0
by: jianzs | last post by:
Introduction Cloud-native applications are conventionally identified as those designed and nurtured on cloud infrastructure. Such applications, rooted in cloud technologies, skillfully benefit from...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: fareedcanada | last post by:
Hello I am trying to split number on their count. suppose i have 121314151617 (12cnt) then number should be split like 12,13,14,15,16,17 and if 11314151617 (11cnt) then should be split like...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.