@quantsol

Как правильно использовать глобальные переменные и какие аналогиченые методы global есть в Питоне?

Начал изучать Питон и сам для себя выдумываю всякие легкие задачки, чтобы двигаться дальше. В один прекрасный день при написании текстовой игрушки мне понадобилось сохранить значение переменной, которое было объявлено внутри функции. Загуглив, нашел инфу про global и применил ее в своей игрушке. Спустя какое-то время прочитал, что глобальные переменные – зло, и есть куда более элегантные способы решения моей проблемы. Внизу кусок кода игры, в котором используются 'global'.

Вкратце описание того, что меня интересует:
Начинаем в стартовой точке – идем на дорогу – мужик дает нам топор – снова идем к этому мужику на дорогу – убиваем его топором (тут у нас объявляется глобальная переменная) – снова выходим на дорогу и обнаруживаем, что на дороге нам больше делать нечего. Если бы не глобальная переменная, то мужик все равно оставался бы на дороге, хотя должен быть мертв.

# -*- coding: utf-8 -*-

from sys import exit

items = []
dead_man = False
print "Вы – охотник за привидениями и Ваша цель попасть в заброшенный дом."
print "Сейчас Вы стоите перед этим самым домом."
print "Слева от Вас находится сарай, по центру – дом, справа – дорога."
print "Куда Вы пойдете?"

def start():
    
    while True:
        choice = raw_input()
        
        if "ключ" in items and ("дом" in choice or "цен" in choice):
            print "Ура! Вы зашли в дом!"
            print "Поздравляю, вы прошли игру!"
            print "Продолжение следует..."
            exit()
        elif "ключ" not in items and ("дом" in choice or "цен" in choice):
            print "Вы подошли к дому, но у вас нет ключа, чтобы открыть его."
            print "Кстати, дом можно обойти. Хотите посмотреть, что есть сзади?"
            behind()
        elif "нап" in choice or "дор" in choice:
            print "Вы решили выйти на дорогу. Куда пойдете в левую сторону или в правую?"
            road()
        elif "нал" in choice or "сар" in choice:
            print "Вы решили дойти до сарая. Сарай закрыт на висячий замок."
            print "Хотите попробовать открыть сарай?"
            barn()
        else:
            print "Не понимаю вас."
            
def road():
    while True:
        choice = raw_input()
        
        if dead_man == True and ("нал" in choice or "лев" in choice):
            print "Вампир убит, тут делать больше нечего."    
        elif "нал" in choice or "лев" in choice:
            print "Вы пошли налево и встретили человека."
            print "Что вы хотите с ним сделать?"
            print "1. Поговорить с ним. Вдруг он расскажет что-нибудь полезное?"
            print "2. Убить его. От него исходит слабое свечение, кажется, он нечитсь."
            choice = raw_input()
            
            if "топор" not in items and choice == "2":
                print "Попытаться убить человека голыми руками – плохое решение."
                print "Мужчина с нечеловеческой скоростью переместился за вашу спину и сломал Вам шею."
                print "Game Over"
                exit()
            elif "топор" in items and choice == "2":
                print "Мужчина оказался высшим вампиром. Наверняка он хотел заманить Вас в дом и съесть Вас."
                print "Ваши инстинкты не подвели вас, повезло, что вы его зарубили."
                print "Больше ничего тут вы не обнаружили и решили вернуться к дому."
                global dead_man
                dead_man = True
                start()
            elif choice == "1":
                print "Мужчина оказался поклонником охотников за привидениями."
                print "Он рассказал вам, что семья в доме была жестоко убита, но владелец дома успел закопать ключ."
                print "Не зная, как больше вам помочь, он дал вам серебрянный топор. Осталось найти чем можно копать и сама место, где нужно копать."
                print "Вы снова вернулись к заброшенному дому."
                items.extend(["топор"])
                start()
            else:
                print "Вы вводите что-то не то. Научитесь печатать!"
        
        elif "карта" in items and "лопата" in items  and ("нап" in choice or "пра" in choice):
            print "Вы нашли место, где закопан клад, и начали рыть землю лопатой."
            print "Ваши старания увенчались успехом! Вы нашли ключ от дома! Осталось лишь открыть дверь!"
            print "Вы вновь пришли к дому."
            items.extend(["ключ"])  
            start()     
            
        elif "карта" in items and ("нап" in choice or "пра" in choice):
            print "Вы нашли место, где зарыт клад. К сожалению, у Вас нечем копать. Хотите попробовать копать руками?"
            choice = raw_input(">:")
            if choice == "да":
                print "Вы попробовали вырыть яму руками, но обнаружили, что земля оказалась ядовитой!"
                print "Яд быстро распространился по телу и вы умерли."
                exit()
            elif choice == "нет":
                print "Действительно, зачем копать землю руками?" 
                print "Вы решили вернуться к дому и поискать лопату."
                start()
            else:
                print "Вы вводите что-то не то. Научитесь печатать!"
                
        elif "карта" not in items and ("нап" in choice or "пра" in choice):
            print "Дорога окончилась тупиком. Осмотрев местность, вы ничего не нашли и вернулись к дому."
            start()
        else:
            print "Научитесь печатать!"

start()


Еще раз повторюсь: как можно сохранить значение переменной, заданной в функции, не используя global?
  • Вопрос задан
  • 2403 просмотра
Решения вопроса 1
angru
@angru
Глобальные переменные действительно - зло, Можно решить классами, но если до классов еще не дошли, то можно обьявить в функции start словарь:

world = {
  'player': {
    'items': [],
    'is_dead': False,
  },
  # other game info
}


и передавать его в каждую игровую функцию:

behind(world)
road(world)
...


еще несколько советов:

1. не стоит в каждой функции обьявлять бесконечный цикл, пусть лучше он будет на самом верхнем уровне в функции start, тоже самое и про пользовательский ввод(raw_input) - лучше чтобы он был только одном месте.
2. не надо в road/behind/barn/... вызывать функцию start - это неявная рекурсия да еще и вместе с бесконечными циклами, пусть лучше они выполняют конкретное действие, изменяют игровое состояние(world) и все, остальное забота функции start.
3. Если добавляете один элемент в список, то лучше делать items.append("топор"), а не items.extend(["топор"])
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@lega
У вас dead_man используется только в ф-ии road, значит вам нужна не глобальная а статическая переменная, поэтому можно сделать такой трюк:
def road(*, static={'dead_man': 0}):
    print(static['dead_man'])
    static['dead_man'] += 1

road()
road()
road()
road()

Результат:
0
1
2
3

Или так:
def road():
    print(road.dead_man)
    road.dead_man += 1

road.dead_man = 0

road()
road()
road()
road()


Примеры для Python 3, переходите на 3-юю ветку, нечего со старьем возится.

ЗЫ: а вообще это не глобальные переменные, а в пределах модуля, глобальной она будет если её поместить в __builtins__, вот это будет "зло", а в пределах модуля переменные можно использовать (с головой).
Ответ написан
Комментировать
sim3x
@sim3x
0. Тебе не нужны переменные - тебе нужен обьект или даже состояние обьекта

1. Попробуй функциональний стиль
https://www.youtube.com/watch?v=DblOFqPE1Pk

2. Попробуй ООП

Вкратце, чтоб не появлялись глобальние переменние их нужно тянуть через весь код
Ответ написан
Комментировать
@iegor
Вам видимо нужен аналог статических переменных в Python.
Можно реализовать так:
try:
    if road.dead == True:
        pass #вместо пасс пишем то, что происходит, если мужик мертв
except AttributeError:
    road.dead = True #если жив, то убиваем

Хотя реализация с глобальной переменной мне больше нравится
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы