LINUX.ORG.RU

Как работает global в python?

 , ,


0

1

Доброго времени суток! Объясните мне пожалуйста как работает global внутри функции python-а? Что он в действительности делает. Вот у меня есть такая задача: внутри модуля есть переменная, и мне нужно из функции внутри класса менять эту переменную, которая одна на весь модуль будет, — могу ли я в этом случае использовать global module_var, — на какую область видимости распространяется global, до ближайшей найденной переменной или всё-таки на реальную глобальную область? Благодарю!

use nonlocal, Luke

А так global будет среди глобальных искать, см. доки

true_admin ★★★★★ ()

Ты хоть книжку почитай.

Бизли Д. Python. Подробный справочник. – Пер. с англ. – СПб.: Символ-Плюс, 2010. – 864 с., ил. ISBN 978-5-93286-157-8

Когда внутри функции создаются новые переменные, они имеют локальную область видимости. То есть такие переменные определены только в пределах тела функции, и они уничтожаются, когда функция возвращает управление вызывающей программе. Чтобы иметь возможность изменять глобальные переменные внутри функции, эти переменные следует определить в теле функции с помощью инструкции global

count = 0
...
def foo():
    global count
    count += 1  # Изменяет значение глобальной переменной count

kernelpanic ★★★★★ ()
Ответ на: комментарий от true_admin

Методом научного тыка проверил — global ищет ближайшую по слою области видимости переменную и работает именно с ней, в глобальную область ничего не попадает. Так что global — это не global в обычном понимании. И по-моему его вполне можно использовать, если понимаешь что делаешь.

unclechu ()
Ответ на: комментарий от kernelpanic

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

unclechu ()

Оффтоп: что-то тут одни котики собрались…

unclechu ()

m.py


v = 'data'


import m

class A:

    def set_v(self, new_data):
        m.v = new_data

AGUtilities ★★★ ()
Последнее исправление: AGUtilities (всего исправлений: 2)
Ответ на: комментарий от unclechu

Методом научного тыка проверил — global ищет ближайшую по слою области видимости переменную и работает именно с ней

Проверочную программу - в студию.

tailgunner ★★★★★ ()
Ответ на: комментарий от true_admin

nonlocal уже есть во втором питоне?

anonymous ()
Ответ на: комментарий от AGUtilities

Выносить парочку переменных в отдельный модуль — по-моему диковато.

unclechu ()
Ответ на: комментарий от unclechu

Таки код в студию, как тебе уже шизофрения подсказала.

anonymous ()
Ответ на: комментарий от unclechu

Выносить парочку переменных в отдельный модуль — по-моему диковато.

я почему-то подумал, что ты имеешь в виду что класс находится в отдельном модуле. во всяком случае так сделано в ряде пакеджей, взять на пример logging или cherrypy...

если в одном модуле, тогда да - global

AGUtilities ★★★ ()
Ответ на: комментарий от tailgunner

main.py

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

test_var = 'some value'

def test_1():
    global test_var
    test_var = 'test 1'
    
def test_2():
    test_var = 'test 2'

def test_3():
    global test_real_global
    test_real_global = 'real!'

print test_var # some value

test_1()
print test_var # test 1

test_2()
print test_var # test 1

test_3()
import module # see module comments

module.py

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

print test_var # NameError: name 'test_var' is not defined
print test_real_global # NameError: name 'test_real_global' is not defined

unclechu ()
Ответ на: комментарий от unclechu

Как минимум тут понятно, что global действует только в рамках модуля, ну это уже особенность python, который не даёт «прострелить себе колено» ради светлых идеалов.

unclechu ()
Ответ на: комментарий от unclechu

Охлол, кто-то конфет на ночь объелся.

anonymous ()
Ответ на: комментарий от unclechu

Тебе похоже нужен пхп и его include statement.

anonymous ()
Ответ на: комментарий от unclechu

Вот ещё парочка примеров. global, если ничего не встречает на своём пути, добирается до области видимости модуля, но не дальше.

def main():
    test_var
    
    def subfunc():
        global test_var
        test_var = 'check'
        
    subfunc()
    
main()

print test_var # NameError: global name 'test_var' is not defined
def main():
    
    def subfunc():
        global test_var
        test_var = 'check'
        
    subfunc()
    
main()

print test_var # 'check'
unclechu ()
Ответ на: комментарий от unclechu

python - это не bash. python - это как java.

в python неймспейсы делятся на несколько этапов. модуль, класс, функция, скрипт, eval - каждый из них имеет отдельный неймспейс

AGUtilities ★★★ ()
Ответ на: комментарий от anonymous

Я Вас не понял, или Ваш юмор не понял. Мне нужно было то поведение global, которое я сейчас прояснил для себя, просто я хотел выяснить, не делаю ли я чего-то пакостного, когда использую такое рискованное слово global.

unclechu ()

В общем вопрос решён! И то, что и предполагалось — подтвердилось, global в python — это никакая не глобальная переменная на самом-то деле. Благодарю за помощь!

unclechu ()
Ответ на: комментарий от AGUtilities

Вопрос: почему? Желательно с маленьким реальным примером из жизни, чтобы в лоб било.

unclechu ()
Ответ на: комментарий от unclechu

не делаю ли я чего-то пакостного, когда использую такое рискованное слово global.

Как такового глобального scope'а в питоне не существует. Так что оно не такое уж и рискованное, хоть и не является хорошей практикой.
global не объявляет новую «глобальную» переменную, он лишь указывает, что переменную нужно искать в другом месте.
Глобальные переменные в питоне таки есть, но их все равно нужно импортировать, если они находятся в других модулях.

anonymous ()
Ответ на: комментарий от anonymous

global не объявляет новую «глобальную» переменную

Вот кстати если глянуть на мои последние примерчики — объявляет.

unclechu ()
Ответ на: комментарий от unclechu

Но не в том смысле, о котором ты говорил изначально.

anonymous ()
Ответ на: комментарий от unclechu

потому что, как ты сам уже заметил, python так сделан, чтобы не выстрелить себе в ногу.

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

если тебе нужно чтобы одна и та же переменная была доступна (для записи) из разных мест программы, то лучше использовать реферальные типы, на пример list или dict

пример:


a = dict()

class A:

    def __init__(self, d):
        self.d = d

    def set_d(self, key, val):
        self.d[key] = val

class B:

    def __init__(self, d):
        self.d = d

    def get_d(self, key):
        print(repr(self.d[key]))

b = A(a)
c = B(a)

b.set_d('name', 'some')
c.get_d('name')

AGUtilities ★★★ ()
Последнее исправление: AGUtilities (всего исправлений: 1)
Ответ на: комментарий от anonymous

nonlocal уже есть во втором питоне?

кто-то ещё пользуется вторым питоном?

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

кто-то ещё пользуется вторым питоном?

4.3 Провокация flame (-7)

anonymous ()
Ответ на: комментарий от AGUtilities

Ок, только в моём случае создание экземпляров класса происходит в другом модуле, как в таком случае тогда быть? Например так?:

import module

b = module.A(module.a)
c = module.B(module.a)

b.set_d('name', 'some')
c.get_d('name')

unclechu ()
Ответ на: комментарий от unclechu

примером из жизни

может послужить любая крупная поделка на php, когда тебе нужно найти место, где эта переменная объявляется. так в питоне поиск global переменной сразу сократится до одного файла.

AGUtilities ★★★ ()
Ответ на: комментарий от AGUtilities

Мне просто кажется лишним выносить из избы в API модуля подобные внутримодулевые конфиги.

unclechu ()
Ответ на: комментарий от unclechu

Мне просто кажется лишним выносить из избы в API модуля подобные внутримодулевые конфиги.

если ты считаешь нежелательным доступ к объектам модуля из других модулей, то можешь ставить подчёркивание в начале имени объекта. это будет обозначать, что такой объект является спецификой реализации, и все кто его будут использовать из других модулей - ссзб.

AGUtilities ★★★ ()
Последнее исправление: AGUtilities (всего исправлений: 1)
Ответ на: комментарий от AGUtilities

Но при этом ты ему посоветовал, передавать такой объект в конструкторы классов.

anonymous ()
Ответ на: комментарий от anonymous

изначально вопрос стоял о том, что лучше использовать чем global.

а теперь вопрос о том, как ограничить использование объектов только одним модулем.

AGUtilities ★★★ ()
Ответ на: комментарий от AGUtilities

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

anonymous ()
Ответ на: комментарий от AGUtilities

если суммировать первое и второе, то для работы с нужной глобальной переменной (которая находится в конкретном модуле), можно создать «управляющий/проксирующий» код

AGUtilities ★★★ ()
Ответ на: комментарий от anonymous

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

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

AGUtilities ★★★ ()
Ответ на: комментарий от unclechu

global, если ничего не встречает на своём пути, добирается до области видимости модуля

Что значит «если ничего не встречает»? global указывает, что нужно брать глобальную переменную, даже если где-то в объемлющей области видимости объявлена локальная.

a.py:

test_var = 0
def main():
    test_var = 1
    
    def subfunc():
        global test_var
        print test_var
    subfunc()
    
main()
$ python a.py
0

Если убрать global, будет:

$ python a.py
1

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

tailgunner

Что значит «если ничего не встречает»? global указывает, что нужно брать глобальную переменную, даже если где-то в объемлющей области видимости объявлена локальная.

def main():
    test_var
    
    def subfunc():
        global test_var
        test_var = 'check'
        
    subfunc()
    
main()

print test_var # NameError: global name 'test_var' is not defined
unclechu ()
Ответ на: комментарий от tailgunner

А вот уже эта парочка примеров убедила меня в том, что global — это атата.

test_var = 0
def main():
    test_var = 1
    
    def subfunc():
        global test_var
    subfunc()
    
main()
print test_var # 0
test_var = 0
def main():
    test_var = 1
    
    def subfunc():
        global test_var
        test_var = 2
    subfunc()
    
main()
print test_var # 2
unclechu ()
Ответ на: комментарий от unclechu

Это не глобал атата, это просто у тебя каша в голове.

anonymous ()
Ответ на: комментарий от unclechu
test_var = 0
def main():
    test_var = 1
    
    def subfunc():
        global test_var
        test_var = 2
    subfunc()
    
    print test_var # 1
    
main()
print test_var # 2

Я похоже ошибался, global берёт не ближайшую в области видимости, а самую дальнюю. Это не то, что я хотел, это даже адово, в следующий раз всеми возможными способами избегу связи с global.

unclechu ()
Ответ на: комментарий от unclechu
$ cat a1.py
def main():
    test_var
    
    def subfunc():
        global test_var
        test_var = 'check'
        
    subfunc()
    
main()

print test_var

$ python a1.py 
Traceback (most recent call last):
  File "a1.py", line 10, in <module>
    main()
  File "a1.py", line 2, in main
    test_var
NameError: global name 'test_var' is not defined

До оператора global управление вообще не доходит. Таки что ты хотел сказать? Скажи словами, а не примером кода.

Я похоже ошибался, global берёт не ближайшую в области видимости, а самую дальнюю. Это не то, что я хотел, это даже адово

Не самую дальнюю, а глобальную. Не адово, а задумано так.

tailgunner ★★★★★ ()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Давайте для начала проясним, что по Вашему глобальная переменная в python?

unclechu ()
Ответ на: комментарий от unclechu

Давайте для начала проясним, что по Вашему глобальная переменная в python?

Это вопрос с подвохом? «If a name is bound at the module level, it is a global variable».

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Ох, простите, я сам себя ввёл в заблуждение допустив ошибку в коде, действительно, глобальная область видимости:

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

def main():
    test_var = 'test 1'
    
    def subfunc():
        global test_var
        test_var = 'test 2'
        
    subfunc()
    
    print test_var # 'test 1'
    
main()

print test_var # 'test 2'
Благодарю, что помогли разобраться!

unclechu ()
Ответ на: комментарий от true_admin

кто-то ещё пользуется вторым питоном?

Я например;-) На 3х переходить не планирую.

По сабжу - кто то сказал, что можно получать глобальные переменные из других модулей как modulename.variable в любом месте кода?;-)

AIv ★★★★★ ()
Последнее исправление: AIv (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.