Как был выбран синтаксис для статических методов в Python?

Я работаю с Python некоторое время, и я нахожу синтаксис для объявления методов как статических странным.

Обычный метод будет объявлен:

def mymethod(self, params)
   ...
   return

Статический метод объявлен:

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

Если вы не добавите строку статического метода, компилятор пожалуется на отсутствие себя.

Это очень сложный способ сделать что-то очень простое, что в других языках просто использовать ключевое слово и грамматику объявления для. Кто-нибудь может рассказать мне об эволюции этого синтаксиса? Это просто потому, что классы были добавлены в существующий язык?

Так как я могу переместить строку статического метода в класс позже, это также говорит о том, что синтаксический анализатор очень усердно работает над бухгалтерией.

Обратите внимание, что я знаю о синтаксисе декоратора, который был добавлен позже, мне интересно узнать, как появился оригинальный синтаксис с точки зрения языкового дизайна. Единственное, о чем я могу думать, - это то, что приложение staticmethod вызывает операцию, которая преобразует объект функции в статический метод.

8 ответов

Решение

Статические методы были добавлены в Python задолго до того, как появились классы (классы были добавлены очень рано, возможно, даже до 1.0; статические методы не появлялись до какого-то времени около 2.0). Они были реализованы как модификация обычных методов - вы создаете объект статического метода из функции, чтобы получить статический метод, тогда как компилятор генерирует методы экземпляра по умолчанию.

Как и во многих других вещах в Python, статические методы вводились, а затем совершенствовались по мере того, как люди использовали их и хотели лучшего синтаксиса. Начальный раунд был способом введения семантики без добавления нового синтаксиса в язык (а Python довольно устойчив к изменениям синтаксиса). Я не Гвидо, поэтому я не совсем уверен, что происходило в его голове, и это несколько умозрительно, но Python имеет тенденцию двигаться медленно, развиваться постепенно и совершенствовать вещи по мере того, как они получают больше опыта с ними (в частности, им не нравится добавлять что-либо до тех пор, пока они не выяснят, как это сделать правильно, возможно, именно поэтому с самого начала не было специального синтаксиса для статических методов).

Как указывалось в mjv, теперь есть более простой путь, через некоторый синтаксис "сахар", добавленный в 2.2 или 2.3 под названием "декораторы":

@staticmethod
def mystaticmethod(params)
    ...
    return

@staticmethod синтаксис сахар для сдачи mystaticmethod = staticmethod(mystaticmethod) после определения метода.

voyager и adurdin хорошо между ними объясняют, что произошло: с введением классов и дескрипторов нового стиля в Python 2.2 появились новые и глубокие семантические возможности - и наиболее очевидные полезные примеры (статические методы, методы классов, свойства) поддерживаются встроенными типами дескрипторов без какого-либо нового синтаксиса (синтаксис @foo для декораторов была добавлена ​​пара выпусков позже, как только новые дескрипторы убедительно доказали свою реальную полезность). Я не совсем квалифицирован, чтобы направлять Гвидо (где Тим Питерс, когда он вам нужен!), Но в то время я уже был коммиттером Python и участвовал в этих разработках, и я могу подтвердить, что это действительно так.

Наблюдение Вояджера об этом, напоминающее ему о С, прямо на цели: я давно утверждал, что Python захватывает больше "Духа С", чем любой из языков, имитирующих синтаксис С (фигурные скобки, скобки после if/while)., так далее). "Дух C" фактически описан в (ненормативной) части обоснования стандарта ISO C и включает пять принципов (ни один из которых не требует скобок!-), из которых я утверждаю, что Python соответствует 4.5 (есть несколько видео на сеть моих презентаций на "Python для программистов", где я освещаю это, если вам интересно).

В частности, Дух C "предоставляет только один способ выполнить операцию" совпадает с Zen of Python "Должен быть один - и предпочтительно только один - очевидный способ сделать это" - и C и Python, я считаю являются единственными двумя широко распространенными языками, которые явно принимают такой идеал дизайна, как единообразие и отсутствие избыточности (это идеал, и его нельзя достичь разумно на 100% - например, если a и b являются целыми числами, a+b и b+ Если бы ЛУЧШЕ было два одинаково очевидных способа получить свою сумму!-) - но это цель, к которой нужно стремиться!-).

Статические методы в Python восходит к введению так называемых "классов нового стиля" в Python 2.2. До этого методы в классах были просто обычными функциями, хранящимися как атрибуты в классе:

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..."

Вызовы методов для экземпляров были специально обработаны, чтобы автоматически связать экземпляр с первым аргументом функции:

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

В Python 2.2 большая часть системы классов была переосмыслена и переработана как "классы нового стиля" - классы, которые наследуются от object, Одной из особенностей классов нового стиля были "дескрипторы", по сути, объект в классе, который отвечает за описание, получение и установку атрибутов класса. Дескриптор имеет __get__ метод, который получает класс и экземпляр и должен возвращать запрошенный атрибут класса или экземпляра.

Дескрипторы позволили использовать один API для реализации сложного поведения атрибутов класса, таких как свойства, методы класса и статические методы. Например, staticmethod дескриптор может быть реализован так:

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

Сравните это с гипотетическим дескриптором чистого Python для обычного метода, который используется по умолчанию для всех простых функций в атрибутах классов (это не совсем то, что происходит с поиском метода из экземпляра, но он обрабатывает автоматическое 'self') аргумент):

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

Поэтому, когда вы пишете method = staticmethod(method)вы фактически создаете новый дескриптор, задачей которого является возвращение исходной функции без изменений, и сохраняете этот дескриптор в атрибуте класса "method".

Если это кажется большой работой, чтобы просто вернуть исходную функцию - вы правы, это так. Но так как обычные вызовы методов являются случаем по умолчанию, статические методы и методы класса должны быть реализованы отдельно, а дескрипторы дают возможность включить эти и другие сложные поведения с помощью одного простого API.

Как уже отмечали другие, синтаксис декоратора, представленный в Python 2.4, предоставляет более удобный способ объявления статических методов, но это всего лишь синтаксическое удобство и ничего не меняет принцип работы статических методов.

См. http://www.python.org/doc/2.2.3/whatsnew/sect-rellinks.html и http://users.rcn.com/python/download/Descriptor.htm для получения дополнительной информации о новом стиле классы и дескрипторы.

Гвидо всегда был осторожен с добавлением новых конструкций в язык. Когда были предложены статические методы, было показано, что вы уже можете это сделать (есть staticmethod() начиная с версии 2.2), у вас просто не было синтаксического сахара для этого.

Если вы прочитаете PEP, вы сможете увидеть все обсуждения, которые идут на добавление чего-либо. Мне, например, нравится такой подход. Это напоминает мне о C в этом нет ненужных ключевых слов.

Когда новый синтаксис для декораторов был добавлен в Python 2.4, вы можете использовать существующие декораторы с более чистым синтаксисом.

Во всяком случае, они не так уж отличаются, если вы должны поддерживать старую систему.

#>2.4
class MyClass(object):
    @staticmethod
    def mystaticmethod(params)
        pass
        return

#<2.4
class MyClass(object):

    def mystaticmethod(params)
        '''Static Method'''
        pass
        return
    staticmethod(mystaticmethod)

Я бы порекомендовал вам добавить комментарий или строку документации к статическому методу screaming, который является статическим методом.

Статическая ситуация с методами в Python является довольно прямым следствием проектных решений первоклассного всего, и все является исполняемым оператором. Как уже говорили другие, staticmethod стал доступен только с новой семантикой, разрешенной протоколом дескриптора Python 2.2, и синтаксически улучшен декораторами функций в Python 2.4. Есть простая причина, по которой статическим методам уделяется так мало внимания - они никак не расширяют возможности языка и лишь немного улучшают синтаксис. Семантически они эквивалентны простым старым функциям. Вот почему они были реализованы только тогда, когда возможности языка выросли достаточно, чтобы сделать их реализуемыми с точки зрения других языковых возможностей.

Начиная с Python 2.4, можно также использовать декоратор, как в:

   @staticmethod
   def mystaticethod(params)
      ...
      return

Но я не имею никакого представления о происхождении этой функции, как это первоначально реализовано, в языке. Но опять же, я не голландец:-) Посмотрите на ответ Майкла Е. в этом посте относительно позднего появления статических методов в эволюции Python.

Кстати, при всей их простоте, как

 @MyDeco
 SomeObject

   просто "синтаксический сахар" для

  MyDeco(SomeObject)

декораторы могут быть использованы для многих других интересных вещей!

Гвидо пишет блог "История Python". Я думаю, что есть способ связаться с ним с просьбой расширить эту конкретную тему.

Возможно, дизайн изначально не думал, что статический метод необходим, когда можно использовать функцию. Поскольку в python не было скрытия данных, нет необходимости использовать статические методы вместо использования классов в качестве пространств имен.

Другие вопросы по тегам