Почему у Python нет статических переменных?

Существует вопрос о том, как моделировать статические переменные в python.

Кроме того, в Интернете можно найти множество различных решений для создания статических переменных. (Хотя я еще не видел того, что мне нравится.)

Почему Python не поддерживает статические переменные в методах? Является ли это неприличным или имеет какое-то отношение к синтаксису Python?

Edit:

Я спросил конкретно о том, почему дизайнерское решение, и я не представил какой-либо пример кода, потому что я хотел избежать объяснений для моделирования статических переменных.

Ответ 1

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

Если вы хотите привязать информацию о состоянии к функции, вам нужен класс. Тривиально простой класс, возможно, но класс тем не менее:

def foo(bar):
    static my_bar # doesn't work

    if not my_bar:
        my_bar = bar

    do_stuff(my_bar)

foo(bar)
foo()

# -- becomes ->

class Foo(object):
    def __init__(self, bar):
        self.bar = bar

    def __call__(self):
        do_stuff(self.bar)

foo = Foo(bar)
foo()
foo()

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

def foo(bar):
    static my_bar # doesn't work

    if not my_bar:
        my_bar = bar

    my_bar = my_bar * 3 % 5

    return my_bar

foo(bar)
foo()

# -- becomes ->

def foogen(bar):
    my_bar = bar

    while True:
        my_bar = my_bar * 3 % 5
        yield my_bar

foo = foogen(bar)
foo.next()
foo.next()

Конечно, статические переменные полезны для быстрых и грязных сценариев, где вы не хотите справляться с проблемами больших структур для небольших задач. Но там вам не нужно ничего больше, чем global - это может показаться, но kludgy, но это нормально для небольших одноразовых скриптов:

def foo():
    global bar
    do_stuff(bar)

foo()
foo()

Ответ 2

Одной из альтернатив класса является атрибут функции:

def foo(arg):
    if not hasattr(foo, 'cache'):
        foo.cache = get_data_dict()
    return foo.cache[arg]

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

Ответ 3

В Python 3 я бы использовал закрытие:

def makefoo():
    x = 0
    def foo():
        nonlocal x
        x += 1
        return x
    return foo

foo = makefoo()

print(foo())
print(foo())

Ответ 4

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

Ответ 5

Это выбор дизайна.

Я предполагаю, что Гвидо считает, что вы не нуждаетесь в них очень часто, и они вам действительно не нужны: вы всегда можете просто использовать глобальную переменную и сказать всем, чтобы их жирные лапы не соответствовали вашей переменной; -)

Ответ 6

Для кеширования или memoization, декораторы могут использоваться как элегантное и общее решение.

Ответ 7

Ответ почти такой же, как почему никто не использует статические методы (хотя они и существуют). У вас есть пространство имен на уровне модулей, которое в любом случае будет иметь ту же цель, что и класс.

Ответ 8

Непродуманная альтернатива:

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

def func(initial=0, my_static=[])
  if not my_static:
    my_static.append(initial)

   my_static[0] += 1
  return my_static[0]

print func(0), func(0), func(0)

Это действительно уродливое и легко разрушенное, но работает. Использование global будет чище, чем это, imo.

Ответ 9

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

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

Это показывает, что на SO всегда окупается, чтобы указать одну проблему, а не запрашивать конкретное решение низкого уровня (например, для недостающей языковой функции). Таким образом, вместо бесконечных дебатов о симуляции "статического" (устаревшая черта с древнего языка, на мой взгляд) кто-то мог бы дать хороший ответ на вашу проблему раньше.