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

Отличный вопрос! Я опубликовал ответ в выпуске ipywidgets: https://github.com/jupyter-widgets/ipywidgets/issues/2296

Итак, вот как можно создать пользовательское представление с использованием представлений ipywidget, используя виджеты из поста. Ключ - это ссылка для привязки атрибутов к значениям виджетов.

import ipywidgets as widgets
from traitlets import link
from IPython.display import display

class FXWidgetView:
    def __init__(self, model):
        self.model = model
        self.domestic_label = widgets.Label("Domestic quantity")
        self.domestic_field = widgets.FloatText()

        self.foreign_label = widgets.Label("Foreign quantity")
        self.foreign_field = widgets.FloatText()

        self.fx_label = widgets.Label("Exchange rate (domestic/foreign)")
        self.fx_field = widgets.FloatText()

        self.lock_label = widgets.Label("If rates change, keep ")
        self.lock_field = widgets.Dropdown(options=["domestic", "foreign"])
        self.lock_label_post = widgets.Label('fixed')

        self.ipyview = widgets.HBox([widgets.VBox([self.domestic_label, self.foreign_label, self.fx_label, self.lock_label]),
                      widgets.VBox([self.domestic_field, self.foreign_field, self.fx_field, widgets.HBox([self.lock_field, self.lock_label_post])])])

        link((model, 'domestic_qty'), (self.domestic_field, 'value'))
        link((model, 'foreign_qty'), (self.foreign_field, 'value'))
        link((model, 'fx_rate'), (self.fx_field, 'value'))
        link((model, 'lock'), (self.lock_field, 'value'))

    def _ipython_display_(self):
        display(self.ipyview)

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

47
задан Community 23 May 2017 в 12:25
поделиться

9 ответов

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

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

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

def foo():
    global bar
    do_stuff(bar)

foo()
foo()
77
ответ дан Ben Blank 26 November 2019 в 19:24
поделиться

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

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

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

19
ответ дан davidavr 26 November 2019 в 19:24
поделиться

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

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

foo = makefoo()

print(foo())
print(foo())
8
ответ дан Josh Lee 26 November 2019 в 19:24
поделиться

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

6
ответ дан Il-Bhima 26 November 2019 в 19:24
поделиться

Это - проектное решение.

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

5
ответ дан Jonas Kölker 26 November 2019 в 19:24
поделиться

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

4
ответ дан Mr Fooz 26 November 2019 в 19:24
поделиться

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

0
ответ дан Jason Baker 26 November 2019 в 19:24
поделиться

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

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

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
ответ дан Richard Levasseur 26 November 2019 в 19:24
поделиться

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

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

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

-1
ответ дан Ber 26 November 2019 в 19:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: