Почему в Python нет статических переменных? - PullRequest
47 голосов
/ 27 февраля 2009

Есть вопросы, спрашивающие, как имитировать статические переменные в python .

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

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

Edit:

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

Ответы [ 9 ]

76 голосов
/ 27 февраля 2009

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

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

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 - это может показаться глупым, но это нормально для небольших одноразовых скриптов:

def foo():
    global bar
    do_stuff(bar)

foo()
foo()
19 голосов
/ 27 февраля 2009

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

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

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

8 голосов
/ 08 марта 2009

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

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

foo = makefoo()

print(foo())
print(foo())
7 голосов
/ 27 февраля 2009

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

5 голосов
/ 27 февраля 2009

Выбор дизайна.

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

4 голосов
/ 27 февраля 2009

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

0 голосов
/ 27 февраля 2009

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

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

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

0 голосов
/ 27 февраля 2009

Опрометчивая альтернатива:

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

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.

0 голосов
/ 27 февраля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...