2013-07-07 5 views
4

Я пишу реализацию игры Конвей в жизни. Моя первая попытка состояла лишь в том, чтобы построить доску после каждого обновления, используя imshow matplotlib на плате NxN 1 и 0. Однако это не сработало, так как программа останавливается всякий раз, когда отображается сюжет. Вы должны закрыть график, чтобы получить следующую итерацию цикла.анимация python без globals

Я обнаружил, что в matplotlib был пакет анимации, но он не принимает (или не дает) переменные, поэтому каждый реализованный им вариант (даже matplotlib's documentation) основан на глобальных переменных.

Так вроде двух вопросов здесь:

1) ли это место, где это нормально использовать глобалам? Я всегда читал, что это никогда не хорошая идея, но это просто догма?

2) Как бы вы сделали такую ​​анимацию в python без globals (Даже если это означает, что я считаю, что matplotlib, стандартная библиотека всегда предпочтительна).

ответ

4

Это просто примеры программ. Вы можете использовать object вместо глобальных переменных, например:

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() 

Если вы действительно хотите, чтобы избежать классов, вы можете переписать программу так:

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() 

Обратите внимание, что для не-математического анимации (без меток, графиков, весов и т. д.), вы можете предпочесть pyglet или pygame.

+0

Я предполагал, что самым простым методом были функции imshow или pcolor с игрой данных типа жизни (сетка из двоичных целых чисел). В pygame, подумал я, мне придется рисовать доску самостоятельно. Я только недавно смотрел видео «прекратить использование классов», поэтому в последнее время я был непривлекательным для класса и был подсознательно решен без занятий. Является ли этот класс полезным, потому что это самый удобный способ получить результат из анимации (это в основном моя проблема, попытка обратной связи выходного состояния вернуться к шагу программы: вы можете дать ему вклад, но как вы получаете обновленное состояние?). –

+0

В вашем примере, как называется метод шагов? Я ничего не вижу в [FuncAnimation documentation] (http://matplotlib.org/api/animation_api.html?highlight=funcanimation#matplotlib.animation.FuncAnimation). –

+0

Пожалуйста, не следуйте советам, таким как «Прекратить использование классов», не понимая почему. Хотя вы, безусловно, могли бы использовать бесклассовый подход здесь, это, скорее всего, окажется более беспорядочным, чем это. 'FuncAnimation' ожидает произвольного вызываемого, и этот ответ проходит в функции' plot_step' объекта (здесь: единственного) 'GameOfLife', который сам называет' step'. – phihag

1

Вот пример использования FuncAnimation без пользовательского класса:

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's 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() 

При использовании выхода (в отличии от возврата) в функции, она делает функцию а generator. Функции генератора сохраняют состояние. Каждый раз, когда вы вызываете next на итераторе, возвращенном генератором, поток выполнения берет вверх, где он остановился (из последнего выражения yield). Вот почему генераторы - это способ избежать глобальных привязок - потенциальные глобальные переменные являются лишь локальными переменными внутри функции генератора, и их состояние сохраняется между вызовами до next.


Кстати, предупреждение «никогда не использовать глобалы» недостаточно точно. Мы постоянно используем глобальные переменные. Каждый раз, когда вы импортируете модуль на уровне модуля, объект модуля является глобальным. Каждый раз, когда вы определяете функцию или класс на уровне модуля, она является глобальной. Нет ничего плохого в использовании глобалов (хотя верно, что доступ к глобальным функциям изнутри функции медленнее, чем доступ к локальным функциям функции. Тем не менее, остерегайтесь предварительной оптимизации).

Возможно, вместо этого предупреждение должно гласить: «Не пытайтесь использовать глобальные переменные, которые меняют состояние». Причина, по которой изменение глобальных значений является плохим, состоит в том, что каждая функция, которая изменяет глобальную, становится бессвязной. Эта функция больше не может быть понята и протестирована как изолированная единица кода. Первичные инструменты-программисты используют для решения проблем, чтобы разбить большие проблемы на более мелкие части. Функции и классы помогают разбить проблемы на более мелкие куски. Но когда вы используете mutating globals, вы теряете это преимущество. Ум должен теперь заглянуть весь модуль сразу, чтобы понять код.

+0

Я замечаю, что оба функциональных решения используют [yield] (http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained), поэтому я сейчас читаю об этом, спасибо. –

+0

похоже на дескриптор функции, [@] (http://www.mathworks.com/help/matlab/ref/function_handle.html), в Matlab –

+0

Я не знаю Matlab, но, судя по ссылку, которую вы предоставляете, @ используется для создания «дескрипторов функций», поэтому вы можете передавать функции в качестве аргументов и создавать анонимные функции. В Python функции уже являются «первоклассными объектами» - они могут передаваться как аргументы другим функциям; no @ not требуется. А в Python анонимные функции создаются с использованием 'lambda'. Поэтому я не думаю, что @ аналогичен «урожайности». – unutbu

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