Эмпирическое правило относительно того, когда мы должны использовать глобальную переменную в функции - PullRequest
4 голосов
/ 25 мая 2020

Когда я кодирую игры с функциями, я часто не понимаю, какую переменную сделать глобальной.

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

Может ли кто-нибудь сказать мне эмпирическое правило относительно того, когда мы должны глобализировать переменную в функции, , а когда в этом нет необходимости? (функции): import turtle from random import randint as rd from time import sleep delay = 0.1 wn = turtle.Screen() wn.setup(400,400) wn.tracer(0) player = turtle.Turtle('square') player.penup() player.goto(0,-170) rock = turtle.Turtle('circle') rock.shapesize(0.5,0.5) rock.penup() rock.goto(rd(-190,190),200) rocks = [rock] pen = turtle.Turtle(visible=False) pen.penup() pen.goto(0,150) def go_left(): # No globalizing here if player.xcor() >= -170: player.setx(player.xcor()-10) def go_right(): # No globalizing here if player.xcor() <= 170: player.setx(player.xcor()+10) def move_rocks(): # No globalizing here for rock in rocks: rock.sety(rock.ycor()-rd(0,2)) def loop_rocks(): global count # rocks not globalized here for rock in rocks: if rock.ycor() < -200: count += 1 rock.goto(rd(-190,190),200) def add_rocks(): global count # rocks not globalized here if count == len(rocks) and len(rocks) <= 15: rock = turtle.Turtle('circle') rock.shapesize(0.5,0.5) rock.penup() rock.goto(rd(-190,190),200) rocks.append(rock) count = 0 def write_score(): global time,score,high_score # pen not globalized here time += 1 if time == 500: score += 1 time = 0 if score > high_score: high_score = score pen.clear() pen.write(f'Score: {score} High Score: {high_score}',align='center',font=('Arial',10,'bold')) def hit(): # No globalizing here for rock in rocks: if player.distance(rock) < 15: return True def die(): global score,rocks # player not globalized here sleep(1) for rock in rocks: rock.goto(300,300) rocks = rocks[:1] rocks[0].goto(rd(-190,190),200) player.goto(0,-170) score = 0 wn.listen() wn.onkeypress(go_left,'Left') wn.onkeypress(go_right,'Right') score = 0 high_score = 0 count = 0 time = 0 while True: if hit(): die() move_rocks() loop_rocks() add_rocks() write_score() wn.update()

Ответы [ 2 ]

8 голосов
/ 26 мая 2020

Правила стиля не являются языковыми правилами. Т.е. вы не должны использовать eval(), но он есть в языке.

скажите мне эмпирическое правило относительно того, когда мы должны глобализировать переменную в функции, а когда это не обязательно?

Правила, когда, а когда нет, использовать global просты, но даже обучающие материалы в Интернете ошибаются.

  1. global ключевое слово не должно использоваться для создания глобальной переменной.

(Да, это частично правило стиля .) Когда вы определяете верхний уровень переменная вне функции, Python делает ее глобальной. (Вы не используете для этого ключевое слово global.) Когда вы назначаете переменной внутри функции, Python предполагает, что он является локальным по отношению к функции. Вам нужно только ключевое слово global, если вы хотите изменить это более позднее предположение, чтобы можно было переназначить (=) глобальную переменную из функции. Объявление global не требуется для проверки глобальной переменной. Он не требуется для вызова метода глобальной переменной, который может изменить ее внутреннее состояние или содержимое:

Вам нужно только ключевое слово global, если вы хотите переназначить (=) глобальную переменную внутри функции.

Объявление global используется в любой функции, где глобальная переменная переназначен. Он помещается перед первой ссылкой на переменную, доступ или присвоение. Для простоты и стиля глобальные операторы помещаются в начало функции.

Такие утверждения, как «Вы никогда не должны использовать глобальные переменные», является правилом стиля и справедливо для большинства языков программирования - применяйте его. если / когда сможешь. А если вы совершенно не можете этого сделать, не расстраивайтесь, просто:

Прокомментируйте все глобальные переменные, которые вы правильно используете.

Глобальные константы не являются проблемой:

Если глобальные константы действительно постоянны, им никогда не понадобится ключевое слово global.

@juanpa.arrivillaga Пример go_left() использования дополнительных значений в качестве параметров вместо глобальных переменных не позволяет примите во внимание, что go_left() - это обратный вызов и что функции назначения событий черепахи не предоставляют дополнительных параметров. (Они должны, но они этого не делают.) Мы можем обойти это, используя выражение lambda (или функцию partial из functools ), но при таком использовании lambda не особенно отличный стиль, ИМХО. не сказано, что это означает создание подкласса Turtle или обертывание экземпляра черепахи другим классом.

Моя личная проблема с изменяемыми глобальными c глобальными переменными в том, что они проблематичны в многопоточном мире.

1 голос
/ 26 мая 2020

Хотя это не ответ, я просто хотел указать еще на одну вещь, на которую следует обратить внимание при затенении имен из внешних областей видимости / глобальных переменных. cdlane записывает в свой ответ , что

Вам не нужно объявление global для проверки глобальной переменной.

Я думаю, что это идет еще дальше, потому что вы не можете использовать ключевое слово global таким образом, поскольку это объявление. Как уже говорилось в cdlane, он используется для объявления переменных в локальной области видимости (например, функции или класса) глобальной области видимости, чтобы вы могли назначать новые значения этим переменным из локальной области. Вы даже можете использовать ключевое слово gobal для объявления глобальных переменных new из локальной области видимости, хотя опять же, как указал cdlane, это не очень хорошая идея. Вот код, выделяющий это поведение:

a = c = 1  # define global variables 'a' and 'b' and assign both the
# value 1.


class Local:
    def __init__(self):
        print(a)  # if you only want to examine the global variable 'a',
        # you don't need any keywords
        self.declare_variables()

    def declare_variables(self):
        global a, b  # declare 'a' and 'b' as global variables, such that any
        # assignment statements in this scope refer to the global variables
        a = 2  # reassign a new value to the already existing global
        # variable 'a'.
        b = 3  # assign a value to the previously undeclared global variable
        # 'b'. you should avoid this.
        c = 4  # this does not affect the global variable 'c', since the
        # variable 'c' in this scope is assumed to be local by default.


local = Local()
print(a, b, c)  # the vaules of the gobal variables 'a' and 'b' have changed,
# while 'c' remains unaffected.

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

  • Если вы объявляете переменную, скрывающую имя глобальной переменной перед , вы пытаетесь получить доступ к этой глобальной переменной, все ссылки на это имя переменной после этого объявления будут ссылаться на локальную переменную. переменная. Я думаю, что это может быть худший случай, поскольку это может go не обнаруживаться и не вызывать никаких ошибок, но возвращает неправильные результаты.
  • Если вы попытаетесь объявить новую локальную переменную или использовать ключевое слово global с тем же именем переменной после вы уже ссылались на это имя переменной в той же области, это приведет к в UnboundLocalError или SyntaxError соответственно.
def reference_global_before_local_declaration():
    print(a)  # first reference the global variable 'a'. this statement would
    # work on its own if 'a' wouldn't be redeclared to be a local variable 
    # later on.
    a = 5  # redeclare 'a' to be a local variable and assign it the value 5.


reference_global_before_local_declaration()


def reference_global_before_global_declaration():
    print(a)  # first reference the global variable 'a'. this statement would
    # work on its own if 'a' wouldn't be declared to be a global variable
    # again later on.
    global a  # declare 'a' to be a global variable again.


reference_global_before_global_declaration()


def reference_global_after_local_declaration():
    a = 'text'  # redeclare 'a' to be a local variable of type string and
    # assign it the value 'text'.
    b = a + 1  # here, 'a' was supposed to reference the global variable 
    # 'a', but is now referencing the local variable 'a' instead, due to 'a'
    # being declared in the same scope and shadowing the name of the gobal 
    # variable 'a'.


reference_global_after_local_declaration()

Единственный известный мне способ избежать этого - использовать функцию globals(), хотя это действительно сводит на нет все цели и я бы не рекомендовал это. Однако я бы порекомендовал прочитать PEP 3104 - Доступ к именам во внешних областях , в котором обсуждаются проблемы такого рода и предлагается решение, которое в конечном итоге так и не было реализовано.

def reference_global_before_local_declaration():
    print(globals()['a'])
    a = 5


reference_global_before_local_declaration()


def reference_global_before_global_declaration():
    print(globals()['a'])
    global a


reference_global_before_global_declaration()


def reference_global_after_local_declaration():
    a = 'text'
    b = globals()['a'] + 1


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