Зачем python ключевое слово global, а C / C ++ - нет? - PullRequest
2 голосов
/ 10 января 2020

Если я хочу изменить глобальную переменную, я мог бы сделать это непосредственно в C ++:

#include <stdio.h>

int x = 1;

int main()
{
    x = 1 + x;
    printf("%d\n", x);
    return 0;
}

Но получил ошибку, используя Python:

x = 1
def foo():
    x += 1

foo()

UnboundLocalError: local variable 'x' referenced before assignment

Мне нужно добавить global x в функцию foo, чтобы сделать это.


Кажется, python сделать это более явным, это "просто чтобы быть явным" причина?

Ответы [ 3 ]

9 голосов
/ 10 января 2020

Принципиальное отличие состоит в том, что C и C ++ имеют объявления переменных. Расположение объявления определяет, будет ли объявлено глобальное.

В Python у вас есть только назначения. Присвоение еще не назначенной переменной создает эту переменную. Присвоение существующей переменной изменяет эту переменную. Следовательно, без global вы не могли бы создать локальную переменную, если бы существовала глобальная переменная с таким именем.

2 голосов
/ 10 января 2020

без ключевого слова global, x не существует в функции. Когда анализатор видит

x += 1

, он предполагает, что x является локальной переменной (потому что она находится в левой части выражения)

Теперь, когда += пытается изменить значение переменной, поскольку x не существует как локальная переменная, происходит сбой.

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

Это терпит неудачу так же, как и с целым числом, потому что парсер не заботится о типах:

x = []
def foo():
    x += [12]

, но это работает, так как x isn не воспринимается синтаксическим анализатором как локальное.

x = []
def foo():
    x.extend([12])

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

class MyTool:
   def __init__(self):
      self.x = 12
   def add_one_to_x(self):
      self.x += 1

m = MyTool()
m.add_one_to_x()

x - это переменная экземпляра, совместно используемая всеми методами вашего одноэлементного объекта. Видеть? теперь нет необходимости в глобальных переменных (ну, кроме m, но 1) в проекте есть только одна глобальная переменная и 2) ее также можно определить в основной функции)

0 голосов
/ 11 января 2020

Я думаю, ответ @MSalters очень хорошо решил мой вопрос. Но я хочу больше поговорить о x = 1 + x в Python и C / C ++.


TL; DR

В обоих C / C ++ и Python, если есть глобальная переменная x и оператор (int) x = 1 + x в функции. Python сообщит об ошибке, как я написал в вопросе, C / C ++ должен быть НЕ УКАЗАН. Фактически, причина, по которой она НЕ УКАЗАНА в C / C ++, такая же, как у Python: используйте локальную переменную x перед присваиванием.


Подробно о том, почему она НЕПРАВИЛЬНА (НЕ УКАЗАНА) в C / C ++ тоже.

#include <stdio.h>

int x = 1;

int main()
{
    int x = 1 + x;  // Here compiler know we take not only first x as a local variable but also the second. It means first and second x point to same memory.
    printf("%d\n", x);  // print 1.
    return 0;
}

, поскольку clang жалуется: [clangtidy] The right operand of '+' is a garbage value [clang-analyzer-core.UndefinedBinaryOperatorResult] [W].

Соответствующий код сборки:

x:
    .long   1
    .section    .rodata
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    addl    $1, -4(%rbp)  // 1 + local x, if use global x it should be: movl    x(%rip), %eax THEN: addl    $1, %eax
    movl    -4(%rbp), %eax  // use result of 1 + local x as print's arg
    movl    %eax, %esi
    leaq    .LC0(%rip), %rdi
    movl    $0, %eax
    call    printf@PLT
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (GNU) 9.2.0"
    .section    .note.GNU-stack,"",@progbits

Это показывает, что мы никогда не используем глобальный x. И почему компилятор не использует глобальный x, возможно, не заслуживает этого, поскольку это неправильный / запутанный стиль написания.


Так что в C / C ++ компилятор знает, что весь код ниже ссылается на новую переменную в этом область видимости, когда компилятор видит variable declaration , вроде int x = 1 + x;. Это глобальная переменная, если нет variable declaration, как x = 1 + x в функции.

Но в python интерпретатор был сбит с толку, когда x += 1 или x = 1 + x были прочитаны, как @MSalters 's ответ сказал python нет variable declaration. Python принятие присваивания ссылается на переменную в текущей области видимости, чтобы сделать ее более точной c, иначе интерпретатор должен отслеживать цепочку вызовов, чтобы найти переменную (или просто найти ее в глобальной области видимости), тогда будет плохо, если вы захотите объявить переменная как x в текущей области видимости.

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