How was the syntax chosen for static methods in Python?

I've been working with Python for a while and I find the syntax for declaring methods as static to be peculiar.

A regular method would be declared:

def mymethod(self, params)
   ...
   return

A static method is declared:

def mystaticethod(params)
   ...
   return
mystaticmethod = staticmethod(mystaticmethod)

If you don't add the static method line, the compiler complains about self missing.

This is a very complex way of doing something very simple that in other languages simply use a keyword and a declaration grammar to. Can anyone tell me about the evolution of this syntax? Is this merely because classes were added into the existing language?

Since I can move the staticmethod line to later in the class, it also suggests that the parser is working extra hard on bookkeeping.

Note that I'm aware of the decorator syntax that was added later, I'm interested to know how the original syntax came about from a language design perspective. The only think I can think of is that the staticmethod application invokes an operation that transforms the function object into a static method.


Static methods were added to Python long after classes were (classes were added very early on, possibly even before 1.0; static methods didn't show up until sometime about 2.0). They were implemented as a modification of normal methods — you create a static method object from a function to get a static method, whereas the compiler generates instance methods by default.

As with many things in Python, static methods got introduced and then refined as people used them and wanted better syntax. The initial round was a way of introducing the semantics without adding new syntax to the language (and Python is quite resistant to syntax changes). I'm not Guido, so I'm not exactly sure what was going on in his head and this is somewhat speculative, but Python tends to move slowly, develop incrementally, and refine things as they gain more experience with them (in particular, they don't like adding something until they've figured out the right way to do it. This could have been why there wasn't special syntax for static methods from the beginning).

As mjv indicated, though, there is an easier way now, through some syntax sugar added in 2.2 or 2.3 called "decorators":

@staticmethod
def mystaticmethod(params)
    ...
    return

The @staticmethod syntax is sugar for putting mystaticmethod = staticmethod(mystaticmethod) after the method definition.


voyager and adurdin do a good job, between them, of explaining what happened: with the introduction of new-style classes and descriptors in Python 2.2, new and deep semantic possibilities arose -- and the most obviously useful examples (static methods, class methods, properties) were supported by built-in descriptor types without any new syntax (the syntax @foo for decorators was added a couple releases later, once the new descriptors had amply proven their real-world usefulness). I'm not really qualified to channel Guido (where's Tim Peters when you need him!-), but I was already a Python committer at the time and participated in these developments, and I can confirm that's indeed what happened.

voyager's observation on this reminding him of C is right on-target: I've long claimed that Python captures more of the "Spirit of C" than any of the languages who have mimicked the syntax of C (braces, parentheses after if/while, etc). "The spirit of C" is actually described in the (non-normative) Rationale part of the ISO C Standard, and comprises five principles (none of which requires braces!-) of which I claim Python matches 4.5 (there are several videos on the web of presentations of mine on "Python for Programmers" where I cover this if you're curious).

In particular, the Spirit of C's "provide only one way to do an operation" matches the Zen of Python's "There should be one-- and preferably only one --obvious way to do it" -- and C and Python, I believe, are the only two widespread languages to explicitly adopt such a design ideal of uniformity and non-redundancy (it's an ideal, and can't be sensibly reached 100% -- eg if a and b are integers, a+b and b+a had BETTER be two identically-obvious ways to get their sum!-) -- but it's a goal to aim for!-).


Static methods in python date back to the introduction of the so-called “new-style classes” in Python 2.2. Previous to this, methods on classes were just ordinary functions, stored as attributes on the class:

class OldStyleClass:
    def method(self):
        print "'self' is just the first argument of this function"

instance = OldStyleClass()
OldStyleClass.method(instance) # Just an ordinary function call
print repr(OldStyleClass.method) # "unbound method..."

Method calls on instances were specially handled to automatically bind the instance to the first argument of the function:

instance.method() # 'instance' is automatically passed in as the first parameter
print repr(instance.method) # "bound method..."

In Python 2.2, much of the class system was rethought and reengineered as “new-style classes”—classes that inherit from object . One of the features of new-style classes was “descriptors”, essentially an object in a class that is responsible for describing, getting, and setting the class's attributes. A descriptor has a __get__ method, that gets passed the class and the instance, and should return the requested attribute of the class or instance.

Descriptors made it possible to use a single API to implement complex behaviour for class attributes, like properties, class methods, and static methods. For example, the staticmethod descriptor could be implemented like this:

class staticmethod(object):
    """Create a static method from a function."""

    def __init__(self, func):
        self.func = func

    def __get__(self, instance, cls=None):
        return self.func

Compare this with a hypothetical pure-python descriptor for an ordinary method, which is used by default for all plain functions in the classes attributes (this is not exactly what happens with method lookup from an instance, but it does handle the automatic 'self' argument):

class method(object):
    """Create a method from a function--it will get the instance
    passed in as its first argument."""

    def __init__(self, func):
        self.func = func

    def __get__(self, instance, cls=None):
        # Create a wrapper function that passes the instance as first argument
        # to the original function
        def boundmethod(*args, **kwargs):
            return self.func(self, *args, **kwargs)
        return boundmethod

So when you write method = staticmethod(method) , you are actually creating a new descriptor whose job it is to return the original function unchanged, and storing this descriptor in the class's "method" attribute.

If that seems like a lot of work to go to just to get the original function back—you're right, it is. But since normal method calls are the default case, static methods and class methods need to be implemented separately, and descriptors give a way of enabling these and other complex behaviours with one simple API.

As others have already pointed out, the decorator syntax introduced in Python 2.4 gives a more convenient way of declaring static methods, but it is just a syntactic convenience, and doesn't change anything of how static methods work.

See http://www.python.org/doc/2.2.3/whatsnew/sect-rellinks.html and http://users.rcn.com/python/download/Descriptor.htm for more details on the new-style classes and descriptors.

链接地址: http://www.djcxy.com/p/54176.html

上一篇: Python:装饰的静态方法接收非

下一篇: 在Python中为静态方法选择的语法如何?