Python - использовать статические методы или функции верхнего уровня

Я родом из фона Java, и я новичок в python. У меня есть несколько сценариев, которые разделяют некоторые вспомогательные функции, уникальные для приложения, связанные с чтением и записью файлов. Некоторые функции связаны с чтением, некоторые - с записью. При поиске правильного подхода я увидел следующее: Статические методы в Python?

Он упоминает в своем ответе:

Наконец, используйте staticmethod экономно! Очень мало ситуаций, когда в Python необходимы статические методы, и я видел их много раз, когда отдельная функция "верхнего уровня" была бы более ясной.

Я не очень хорошо понимаю функции верхнего уровня, и я не уверен, что этот простой пример лучше: 1) создать класс для читателя со статическими функциями чтения и то же самое для писателя или 2) для объявить этих помощников глобальными функциями и почему?

EDIT: ДЕЙСТВИТЕЛЬНО хорошая статья об этой теме, я только что нашел http://tomayko.com/writings/the-static-method-thing

Ответ 1

В Java существует идея (IMHO wrong) использовать классы везде, даже просто группировать статические функции, которые не разделяют какое-либо состояние (и, следовательно, такие классы никогда не будут созданы).

Python здесь хочет отличать; если у вас есть функции, которые не имеют какого-либо общего состояния 1 (и, следовательно, в Java обычно будут static функциями) и не тесно связаны с "реальным" классом (= фактически созданный экземпляр), вы просто используете свободные функции внутри модуля.

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

Собственно, вы можете несколько думать о модуле как о классе static, то есть о контейнере функций (= статические методы), переменных модуля (= статические поля) и типах.

Хорошая вещь в Python заключается в том, что наличие функции верхнего уровня не дает проблем глобального загрязнения пространства имен, поскольку в Python функции/объекты/объекты верхнего уровня все еще ограничены модулем. Таким образом, вы можете группировать функции по модулю без ненужного class -tax.


  • на самом деле, они могут иметь какое-то общее состояние в виде переменных уровня модуля (так, синглтоны); опять же, похоже, что существуют аналоговые модули - статические классы.

Ответ 2

Из Zen Python (import this):

Namespaces are one honking great idea -- let do more of those!

Одной из основных причин создания статических методов на языке Java является обеспечение того, чтобы эти методы не перекрывали глобальное пространство имен. (Хотя Java применяет свои собственные соглашения о пространстве имен, полностью запретив "функции уровня пакета"!). В Python все функции верхнего уровня автоматически помещаются в пространство имен модуля, содержащего эти функции, поэтому нет опасности заразить глобальные пространство имен таким образом.

Другими словами, как и многие другие языки, Python может создавать пространства имен несколькими способами. В этом случае мало нужно создавать класс, содержащий только статические методы, когда модуль выполняет одну и ту же задачу назначения имен без беспорядка (или когнитивной нагрузки), связанного с определением класса.

Ответ 3

Если функция связана с классом, то сделайте ее статическим методом. Например:

class DBobject():
    name = StringProperty()

    @staticmethod
    def get_by_name(name):
        return db.select('select * from DBobject where name = "%s"' % name)

python = DBobject.get_by_name('python')

То есть, метод полностью связан с классом DBobject, поэтому он должен быть статическим методом.

Ответ 4

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

>>> class A(object):
...     @staticmethod
...     def static_1():
...             print 'i am static'
...     def a(self):
...             self.static_1()
...
>>> A.static_1()
i am static
>>> a=A()
>>> a.a()
i am static
>>> a.static_1()
i am static
>>> class B(A):
...     pass
...
>>> b=B()
>>> b.static_1()
i am static
>>>