Python animation without globals

I am writing an implementation of the game Conway Game of Life. My first attempt was only to build a board after each update using matplotlib imshow on NxN 1 and 0. However, this did not work, because the program stopped whenever the plot was displayed. You must close the graph to get the next iteration of the loop.

I found out that there was an animation package in matplotlib, but it does not accept (or does not give) variables, so every one I realized from them (even the matplotlib documentation ) uses global variables.

So there are two questions here:

1) Is this a place to use global variables? I always read that this is not a good idea, but is it just dogma?

2) how would you do such an animation in python without globals (Even if it means that I want to use matplotlib, a standard library is always preferred).

+4
source share
2 answers

These are just examples of programs. You can use an object instead of global variables, for example:

class GameOfLife(object): def __init__(self, initial): self.state = initial def step(self): # TODO: Game of Life implementation goes here # Either assign a new value to self.state, or modify it def plot_step(self): self.step() # TODO: Plot here # TODO: Initialize matplotlib here initial = [(0,0), (0,1), (0,2)] game = GameOfLife(initial) ani = animation.FuncAnimation(fig, game.plot_step) plt.show() 

If you really want to avoid classes, you can also rewrite the program as follows:

 def step(state): newstate = state[:] # TODO Game of Life implementation goes here return newstate def plot(state): # TODO: Plot here def play_game(state): while True: yield state state = step(state) initial = [(0,0), (0,1), (0,2)] game = play_game(initial) ani = animation.FuncAnimation(fig, lambda: next(game)) plt.show() 

Please note that for non-mathematical animations (without labels, graphs, scales, etc.) you may prefer pyglet or pygame .

+4
source

Here is an example of using FuncAnimation without a custom class:

 import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation def animate(data, im): im.set_data(data) def step(): while True: # replace this with Conway Game of Life logic data = np.random.randn(10, 10) yield data fig, ax = plt.subplots() im = ax.imshow(np.random.randn(10, 10), interpolation='nearest') ani = animation.FuncAnimation( fig, animate, step, interval=10, repeat=True, fargs=(im, )) plt.show() 

When you use yield (as opposed to returning) in a function, it makes the function a generator . Generator functions save state. Each time you call next on the iterator returned by the generator, the thread of execution is selected where it was stopped (from the last yield expression). That's why generators are a way to avoid global bindings - potential global variables are only local variables inside the generator function, and their state is preserved between next calls.


By the way, the warning "never use global variables" is not accurate enough. We constantly use global variables. Each time you import a module at the module level, the module object is global. Each time you define a function or class at the module level, it is global. There is nothing wrong with using globals (although it’s true that accessing global functions inside a function is slower than accessing local functions. However, beware of prior optimization).

Perhaps a warning should be read instead: "Do not try to use global variables that change state." The reason why changing global values ​​is bad is because every function that changes the global becomes incoherent. This function can no longer be understood and tested as an isolated unit of code. Primary programming tools are used to solve problems in order to break down big problems into smaller parts. Functions and classes help break down problems into smaller pieces. But when you use mutating globals, you lose this advantage. The mind should now look at the entire module at once to understand the code.

+1
source

Source: https://habr.com/ru/post/1490126/


All Articles