[PYTHON] Learn with FizzBuzz Iterator, Generator, Decorator

Introduction

I read the python docs and learned Iterator, Generator, Decorator, etc., so I wrote FizzBuzz with these for practice.

What is Iterator (quote)

http://docs.python.jp/2/tutorial/classes.html#iterator (Begin quote) These access methods are clear, concise, and convenient. The use of iterators is widespread throughout Python and brings unity. Behind the scenes, the for statement calls the container object ʻiter (). This function returns an iterator object with the next ()method defined. Thenext ()method accesses the elements in the container one at a time. When there are no more elements in the container to access,next ()throws aStopIterationexception and terminates the for loop. The following example shows how it actually works. (Omitted) Once you've seen the mechanism behind the iterator protocol, it's easy to add iterator behavior to your class. Define aiter ()method to return an object with anext ()method. If the class itself definesnext (), iter ()can simply returnself`. (End of citation)

If you want to make it easy, you can define a class with __iter__ () method and next () method, and throw an exception of StopIteration when the termination condition is satisfied. Iterator instances seem to be usable as-is in for statements.

code

I wrote a FizzBuzzIterator with similar specifications by referring to the range () function.

def fizzbuzz(n):
  n = int(n)
  if (n%15) == 0: return "FizzBuzz"
  elif (n%5) == 0: return "Buzz"
  elif (n%3) == 0: return "Fizz"
  else: return n

class FizzBuzzIterator:
  def __init__(self,start, stop, step=1):
    self.count = start
    self.stop = stop
    self.step = step

  def __iter__(self):
    return self

  def next(self):
    if (self.step > 0 and self.count >= self.stop) or (self.step < 0 and self.count <= self.stop):
      raise StopIteration
    else:
      result = fizzbuzz(self.count)
      self.count += self.step
      return result

Output FizzBuzz from 1 to 100

fbiter1 =  FizzBuzzIterator(1,101)
for fzbz in fbiter1: print fzbz

Output FizzBuzz only for odd numbers from 1 to 99

fbiter2 =  FizzBuzzIterator(1,101,2)
for fzbz in fbiter2: print fzbz

Output FizzBuzz in reverse order from 100 to 1

fbiter3 =  FizzBuzzIterator(100,0,-1)
for fzbz in fbiter3: print fzbz

What is Generator (quote)

http://docs.python.jp/2/tutorial/classes.html#generator (Begin quote) Generators are a concise and powerful tool for creating iterators. Generators are written like regular functions, but use yield statements to return any data. Each time next () is called, the generator resumes previously interrupted processing (the generator remembers all data values and which statement was last executed). If you look at the example below, you can see that the generator is very easy to create. (End of citation)

code

Iterator seemed to work very hard, but should the generator just be a for document? It made me wonder.

def fizzbuzz(n):
  n = int(n)
  if (n%15) == 0: return "FizzBuzz"
  elif (n%5) == 0: return "Buzz"
  elif (n%3) == 0: return "Fizz"
  else: return n

def fizzbuzz_generator(start,finish,diff=1):
   for n in range(start,finish,diff):
     yield fizzbuzz(n)

for fzbz in fizzbuzz_generator(1,100):
  print fzbz

What is Decorator (quote)

http://docs.python.jp/2/glossary.html#term-decorator (Begin quote) (Decorator) A function that returns a function. It is usually used to convert a function with the grammar @wrapper. Common uses for decorators are classmethod () and staticmethod ().

The decorator grammar is syntactic sugar. The following two function definitions are semantically identical.

def f(...):
    ...
f = staticmethod(f)

@staticmethod
def f(...):
    ...

(End of citation)

code

I didn't understand so I wrote it.

def fizzbuzz(n):
  n = int(n)
  if (n%15) == 0: return "FizzBuzz"
  elif (n%5) == 0: return "Buzz"
  elif (n%3) == 0: return "Fizz"
  else: return n

def fizzbuzz_decorator(func):
  def wrapper(*args, **kwargs):
    func(fizzbuzz(*args))
  return wrapper

@fizzbuzz_decorator
def f(n):
  print n

f(1)
f(2)
f(3)
f(4)
f(5)

In the above, it seems that f is rewritten by the decorator expression @fizzbuzz_decorator, and f is rewritten tofizzbuzz_decorator (f), that is, the following wrapper () function.

def wrapper(*args, **kwargs):
  f(fizzbuzz(args[0]))

So, since the argument of f is processed by the fizzbuzz () function and then passed to the original f, it seems that the fizzbuzz string will be output.

Execution result

1
2
Fizz
3
Buzz

Nesting Decorator expressions (quotes)

It seems that decorator expressions can also be nested. http://docs.python.jp/2/reference/compound_stmts.html#function (Begin quote) Function definitions can be wrapped in one or more decorator expressions. When you define a function, the decorator expression is evaluated in the scope that contains the function definition. The result must be a callable object that takes a function object as its only argument. Instead of a function object, the returned value is bound to the function name. Multiple decorators are nested and applied. (End of citation)

def fizzbuzz(n):
  n = int(n)
  if (n%15) == 0: return "FizzBuzz"
  elif (n%5) == 0: return "Buzz"
  elif (n%3) == 0: return "Fizz"
  else: return n

def fizzbuzz_decorator(func):
  def wrapper(*args, **kwargs):
    func(fizzbuzz(*args))
  return wrapper

def fizzbuzz_decorator2(func):
  def wrapper(*args, **kwargs):
    for n in range(1,args[0]):
      func(n)
  return wrapper

@fizzbuzz_decorator2
@fizzbuzz_decorator
def f(n):
  print n

f(101)

This is a pattern equivalent to the following.

f = fizzbuzz_decorator2(fizzbuzz_decorator(f))

Execution result

1
2
Fizz
3
Buzz
(Omitted)
98
Fizz
Buzz

It seems that you can pass arguments to the decorator, so I will add it as soon as I investigate.

Recommended Posts

Learn with FizzBuzz Iterator, Generator, Decorator
Calculate Fibonacci sequence with generator and iterator
FizzBuzz with Python3
Learn Python with ChemTHEATER
Learn Zundokokiyoshi with LSTM
The first algorithm to learn with Python: FizzBuzz problem
Learn Pandas with Cheminformatics
Learn with chemoinformatics scikit-learn
Learn with Cheminformatics Matplotlib
Learn with Cheminformatics NumPy
DCGAN with TF Learn
Decorate with a decorator
Learn Pendulum-v0 with DDPG
Fizzbuzz with exception handling
Learn librosa with a tutorial 1
Learn elliptical orbits with Chainer
Learn new data with PaintsChainer
Easily cProfile with a decorator