область видимости переменной Python - PullRequest
2 голосов
/ 27 августа 2009

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

def some_function():
    foo.some_method()
    # some other code

if __name__ == '__main__' :
    foo = Some_Object()

    some_function()

, хотя я не передаю foo в some_function (), но some_function все еще может манипулировать foo (??!). Мне это не совсем нравится, хотя это несколько похоже на закрытие Javascript (?). Я хотел бы знать, возможно ли остановить some_function () от доступа к foo, если foo не передан в качестве аргумента функции? Или это предпочтительный способ в питоне ??! (Я сейчас использую python 2.5 под Ubuntu Hardy)

Ответы [ 3 ]

4 голосов
/ 27 августа 2009

У этого скрипта действительно серьезные проблемы со стилем и организацией - например, если кто-то импортирует его, он должен каким-то образом предугадать тот факт, что ему нужно установить thescript.foo для экземпляра Some_Object перед вызовом some_function. .. ура! -)

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

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

import new
f=new.function(some_function.func_code, {})

теперь вызывающий f() даст исключение NameError: global name 'foo' is not defined. Вы можете установить это обратно в модуль с именем some_function или даже сделать это систематически через декоратор, например ::

def noglobal(f):
    return new.function(f.func_code, {})
...
@noglobal
def some_function(): ...

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

2 голосов
/ 27 августа 2009

Насколько я знаю, единственный способ остановить some_function доступ к foo - это исключить переменную foo из области действия some_function, возможно, такую ​​как:

tmp = foo
del foo
some_function()
foo = tmp

Конечно, это приведет к краху вашего (текущего) кода, поскольку foo больше не существует в области действия some_function.

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

Другой вариант может быть:

with some_object as foo:
    some_function()

Но тогда вам придется хотя бы объявить some_object.__exit__, может быть some_object.__enter__. Конечным результатом является то, что вы контролируете, какой foo находится в области действия some_function.

Более подробное объяснение оператора "with" здесь .

1 голос
/ 27 августа 2009

В Python что-то вроде foo - это не значение, это имя . Когда вы пытаетесь получить к нему доступ, python пытается найти значение, связанное с ним (например, разыменование указателя). Он делает это, сначала просматривая локальную область (функцию), затем продвигаясь наружу, пока не достигнет области модуля (то есть глобальной), и, наконец, встроившись, пока не найдет что-то, совпадающее с именем.

Это делает что-то вроде этой работы:

def foo():
    bar()

def bar():
    pass

Несмотря на то, что bar не существует, когда вы определили foo, функция будет работать, потому что вы позже определили bar в области действия, в которую входит foo.

Точно то же самое происходит в коде, который вы публикуете, просто foo - это вывод Some_Object(), а не определение функции.

Как сказал Алекс, тот факт, что вы можете писать такой код, не означает, что вы должны .

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