2014-10-29 4 views
5

В C++ мы имеем статическое ключевое слово, которое в петлях является чем-то вроде этого:Статическая переменная в Python?

for(int x=0; x<10; x++) 
    { 
     for(int y=0; y<10; y++) 
     { 
     static int number_of_times = 0; 
     number_of_times++; 
     } 
    } 

статических здесь делает number_of_times инициализируется один раз. Как я могу сделать то же самое в python 3.x?

EDIT: Поскольку большинство людей запутались, я хотел бы указать, что код, который я дал, является просто примером статического использования в C++. Моя реальная проблема заключается в том, что я хочу инициализировать только одну переменную времени в функции, поскольку я не хочу, чтобы она была глобальной (blah!) Или параметром по умолчанию.

+0

Объявить эту переменную вне из для петель. –

+5

Это не единственное, что объявляет локальную переменную 'static'. Скажите, пожалуйста, что вы хотите сделать с переменной в Python и какую проблему вы пытаетесь решить (прочитайте о проблеме XY) (http://meta.stackexchange.com/questions/66377/what-is- -х-проблема)). –

+0

Обратите внимание, что Python имеет гораздо меньше областей, чем C++, поэтому для таких конструкций меньше необходимости. 'number_of_times' в Python-версии этого кода не будет ограничиваться внутренним циклом for. – chepner

ответ

8

Предполагая, что вы хотите «переменная, которая инициализируется только один раз при первом вызове функции», нет такой вещи, в синтаксисе Python. Но есть способы получить аналогичный результат:

1 - Используйте глобальный. Обратите внимание, что в Python, «глобальный» на самом деле означает «глобальный для модуля», а не «глобальный процессу»:

_number_of_times = 0 

def yourfunc(x, y): 
    global _number_of_times 
    for i in range(x): 
     for j in range(y): 
      _number_of_times += 1 

2 - Оберните ваш код в классе и использовать атрибут класса (то есть: атрибут который разделяется всеми экземплярами).:

class Foo(object): 
    _number_of_times = 0 

    @classmethod 
    def yourfunc(cls, x, y): 
     for i in range(x): 
      for j in range(y): 
       cls._number_of_times += 1 

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

3 - Оберните ваш код в классе, использовать атрибут экземпляра и обеспечить ярлык для метода :

class Foo(object): 
    def __init__(self): 
     self._number_of_times = 0 

    def yourfunc(self, x, y): 
     for i in range(x): 
      for j in range(y): 
       self._number_of_times += 1 

yourfunc = Foo().yourfunc 

4 - Написать вызываемый класс и обеспечить ярлык:

class Foo(object): 
    def __init__(self): 
     self._number_of_times = 0 

    def __call__(self, x, y): 
     for i in range(x): 
      for j in range(y): 
       self._number_of_times += 1 


yourfunc = Foo() 

4 бис - использовать атрибут класса и метакласса

class Callable(type): 
    def __call__(self, *args, **kw): 
     return self._call(*args, **kw) 

class yourfunc(object): 
    __metaclass__ = Callable 

    _numer_of_times = 0 

    @classmethod 
    def _call(cls, x, y): 
     for i in range(x): 
      for j in range(y):     
       cls._number_of_time += 1 

5 - Сделать «творческий» использование аргументов функции по умолчанию быть инстанцирован только один раз при импорте модуля:

def yourfunc(x, y, _hack=[0]): 
    for i in range(x): 
     for j in range(y): 
      _hack[0] += 1 

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

EDIT: с учетом разъяснений op, то есть «Предположим, что у вас есть рекурсивная функция с параметром по умолчанию, но если кто-то действительно пытается дать еще один аргумент вашей функции, это может быть катастрофическим», похоже, что OP действительно хочет это что-то вроде:

# private recursive function using a default param the caller shouldn't set 
def _walk(tree, callback, level=0): 
    callback(tree, level) 
    for child in tree.children: 
     _walk(child, callback, level+1): 

# public wrapper without the default param 
def walk(tree, callback): 
    _walk(tree, callback) 

Который, кстати, доказать, что мы на самом деле была еще одна проблема XY ...

+0

Я не понимаю, почему элемент «4 бис» помечен таким образом. Почему бы не назвать его 5 и назвать текущий 5 номер 6? –

+0

@StevenRumbalski Потому что это редактирование, и я не хотел смешивать уже существующие номера;) –

2

Вы можете создать закрытие с nonlocal, чтобы сделать их доступными для редактирования (python 3 .x только). Ниже приведен пример рекурсивной функции для вычисления длины списка.

def recursive_len(l): 
    res = 0 
    def inner(l2): 
     nonlocal res 
     if l2: 
      res += 1 
      inner(l2[1:]) 
    inner(l) 
    return res 

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

def fn(self): 
    self.number_of_times += 1 
fn.func_defaults = (fn,) 
fn.number_of_times = 0 

fn() 
fn() 
fn() 
print (fn.number_of_times) 
+0

Не будет работать внутри функции. –

+1

«Атрибут самой функции» * очень * хрупкий, поскольку он зависит от глобальной привязки между именем ('fn') и объектом функции, чтобы оставаться стабильным. –

+0

Почему бы просто не назначить атрибут функции непосредственно после определения функции? 'fn.number_of_times = 0'. –

1

Вы также можете использовать глобальное ключевое слово:

def main(args): 
    for i in xrange(10): 
     print i 
     global tmp 
     tmp = i 

Но будьте осторожны ... Я в большинстве случаев это добавит больше проблем, чем решает.

5

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

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

0

Другая функция на основе способа сделать это в питоне:

def f(arg, static_var=[0]): 
    static_var[0] += arg 

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

>>> def f(arg, static_var=[0]): 
...   static_var[0] += arg 
...   print(static_var[0]) 
... 
>>> f(1) 
1 
>>> f(2) 
3 
>>> f(3) 
6 
+0

Я на самом деле пытаюсь сделать прямо противоположное этому: Я хочу удалить этот параметр по умолчанию, инициализировать static_var = [] (например) ONCE, а затем изменить его, но мне нравится на C++, это можно сделать с помощью статического ключевого слова, но, по-видимому, это функция не реализована в python – kuskmen

Смежные вопросы