Как был выбран синтаксис для статических методов в 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 не было скрытия данных, нет необходимости использовать статические методы вместо использования классов в качестве пространств имен.