Simultaion статической переменной: классы против генераторов - PullRequest
1 голос
/ 16 октября 2011

Мне было любопытно использовать статические переменные в Python, и я остановился на: Почему в Python нет статических переменных?

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

Однако я был немного смущен, так как используемый здесь пример можно сделать и с классом.:

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

    def __call__(self):                                                         
        self.bar = self.bar * 3 % 5                                             
        return self.bar

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

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

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

Ответы [ 4 ]

3 голосов
/ 16 октября 2011

Генераторы (простые, не попадающие в сопрограммы) имеют одну очень специфическую цель: написание итераторов.С этой целью вы получаете неявный захват локальной переменной и ключевое слово, чтобы приостановить (в отличие от «прекратить» - вы можете возобновить) выполнение и дать вызывающей стороне следующее значение итератора.Преимущества:

  • Логика читается более естественно, так как вам не нужно разбивать ее на несколько вызовов метода - сохраняется все состояние, включая счетчик программы - выможно использовать поток управления через урожайность.Вы можете заменить yield x на results.append(x) и return results в конце и получить функцию, эквивалентную list(the_original_generator(...)).
  • Вам не нужно явно делать значения долгоживущими, помещая их вself - меньше печатать и меньше читать.
  • Вам не нужно объявление класса с двумя объявлениями методов (несколько строк стандартного шаблона, что значительно по стандартам Python).

Вы можете использовать функцию "захвата локальной переменной" для реализации итерируемого, который ведет себя как, за исключением того, что вы можете иметь несколько и вы не вызываете функцию, а используете итератор (next_val = next(vals) вместо next_val = vals()).Уместно ли это, зависит.

2 голосов
/ 16 октября 2011

Правильный класс генератора выглядит следующим образом:

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

    def __iter__(self):
        return self

    def next(self):
        self.bar = self.bar * 3 % 5                                             
        return self.bar

foo = Foo(3)                                                                  
print next(foo)                                                                     
print next(foo)

Эквивалентная функция генератора занимает половину кода:

def Foo(bar):
    while True:
        bar = bar * 3 % 5   
        yield bar                                                          

foo = Foo(3)                                                                  
print next(foo)                                                                     
print next(foo)

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

2 голосов
/ 16 октября 2011

Вы ничего не можете сделать с генератором, который вы не можете сделать с классом.

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

1 голос
/ 16 октября 2011

Для генераторов нет другого способа получить доступ к переменной, кроме как с помощью вызова функции, в то время как в варианте на основе классов вы можете изменить его напрямую.Это может быть как преимуществом, так и недостатком в зависимости от вашего варианта использования.Также код проще.Для более подробного обсуждения см .: http://wiki.python.org/moin/Generators

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