글로벌 스코프가 아닌 외부(포함) 범위에 있는 파이썬에서 변수를 수정할 수 있습니까?
이 예를 고려해 보십시오.
def A():
b = 1
def B():
# I can access 'b' from here.
print(b)
# But can i modify 'b' here?
B()
A()
에 있는 B 수, 변b전역이 아닌 엔클로저(포함) 범위에 있습니다. 수정할 수 요?b에서.B나는 이해합니다.UnboundLocalError, 가직시면하도접다사, 고용니합그리제.global이후로 문제를 해결하지 않습니다.b전역이 아닙니다.
Python은 거의 모든 현대 언어와 마찬가지로 동적 범위가 아닌 어휘적 범위를 구현합니다.여기서 기술은 발신자가 범위에 포함되지 않기 때문에 발신자가 포함된 함수가 아닌 한 발신자의 변수에 액세스할 수 없습니다.이 문제에 대한 자세한 내용은 호출자로부터 변수에 액세스하는 방법(예: 동적 범위 지정 구현)을 참조하십시오.
Python 3에서는 다음 키워드를 사용합니다.
그
nonlocal문은 나열된 식별자가 전역을 제외한 가장 가까운 범위에서 이전에 바인딩된 변수를 참조하도록 합니다.바인딩의 기본 동작은 먼저 로컬 네임스페이스를 검색하기 때문에 중요합니다.명령문을 사용하면 캡슐화된 코드가 전역(모듈) 범위 외의 로컬 범위 밖에서 변수를 다시 바인딩할 수 있습니다.
def foo():
a = 1
def bar():
nonlocal a
a = 2
bar()
print(a) # Output: 2
Python 2에서 변수를 재할당하는 대신 변수 개체(예: 목록 또는 dict)를 사용하여 값을 변경합니다.
def foo():
a = []
def bar():
a.append(1)
bar()
bar()
print a
foo()
출력:
[1, 1]
빈 클래스를 사용하여 임시 범위를 유지할 수 있습니다.변형 가능한 것 같지만 조금 더 예뻐요.
def outer_fn():
class FnScope:
b = 5
c = 6
def inner_fn():
FnScope.b += 1
FnScope.c += FnScope.b
inner_fn()
inner_fn()
inner_fn()
그러면 다음과 같은 대화형 출력이 생성됩니다.
>>> outer_fn()
8 27
>>> fs = FnScope()
NameError: name 'FnScope' is not defined
저는 파이썬에 대해 조금 생소하지만, 이것에 대해 조금 읽었습니다.저는 여러분이 얻을 수 있는 최선의 방법은 외부 변수를 목록으로 묶는 자바 해결책과 유사하다고 생각합니다.
def A():
b = [1]
def B():
b[0] = 2
B()
print(b[0])
# The output is '2'
편집: 이것은 아마도 파이썬 3 이전에 사실이었을 것입니다.처럼 .nonlocal당신의 대답입니다.
아니요, 적어도 이런 식으로는 할 수 없습니다.
왜냐하면 "set 작업"은 현재 범위에 새 이름을 생성하며, 이 범위는 외부 이름을 포함하기 때문입니다.
다음을 제공하는 함수의 속성이 있는지 모르겠습니다.__dict__Python 3에서 이 외부 공간이 전역 공간이 아닐 때 함수의 외부 공간 == 모듈(함수가 중첩 함수인 경우).
하지만 Python 2에는 그런 속성이 없는 것으로 알고 있습니다.
따라서 원하는 작업을 수행할 수 있는 유일한 가능성은 다음과 같습니다.
다른 사람들이 말한 것처럼, 변형 가능한 물체를 사용하는 것.
2)
def A() :
b = 1
print 'b before B() ==', b
def B() :
b = 10
print 'b ==', b
return b
b = B()
print 'b after B() ==', b
A()
결과
b before B() == 1
b == 10
b after B() == 10
.
노타
세드릭 줄리앙의 해결책에는 다음과 같은 단점이 있습니다.
def A() :
global b # N1
b = 1
print ' b in function B before executing C() :', b
def B() :
global b # N2
print ' b in function B before assigning b = 2 :', b
b = 2
print ' b in function B after assigning b = 2 :', b
B()
print ' b in function A , after execution of B()', b
b = 450
print 'global b , before execution of A() :', b
A()
print 'global b , after execution of A() :', b
결과
global b , before execution of A() : 450
b in function B before executing B() : 1
b in function B before assigning b = 2 : 1
b in function B after assigning b = 2 : 2
b in function A , after execution of B() 2
global b , after execution of A() : 2
실행 후 글로벌 bA()이 되지 않을 수 . 그래서 정되었그속않삭수을있다습니수지이렇고게▁has다있니▁be습수수▁it▁may▁wh않.
글로벌 네임스페이스에 식별자가 b인 개체가 있는 경우에만 해당됩니다.
자동으로 작동하는 짧은 답변
저는 이 특정 문제를 해결하기 위해 파이썬 라이브러리를 만들었습니다.언라이즌 하에 출시되니 원하는 대로 사용하세요.설할수있다와 함께 할 수 .pip install seapie또는 여기 홈 페이지를 확인하십시오. https://github.com/hirsimaki-markus/SEAPIE
user@pc:home$ pip install seapie
from seapie import Seapie as seapie
def A():
b = 1
def B():
seapie(1, "b=2")
print(b)
B()
A()
산출물
2
인수의 의미는 다음과 같습니다.
- 첫 번째 인수는 실행 범위입니다.0은 로컬을 의미합니다.
B()1은 상위 항목을 의미합니다.A()합니다.<module>합니다. - 두 번째 인수는 지정된 범위에서 실행할 문자열 또는 코드 개체입니다.
- 프로그램 내부의 대화형 셸에 대한 인수 없이 호출할 수도 있습니다.
긴 대답
이것은 더 복잡합니다.Seapie는 CPython api를 사용하여 콜 스택의 프레임을 편집하여 작동합니다.Cython은 사실상의 표준이기 때문에 대부분의 사람들은 그것에 대해 걱정할 필요가 없습니다.
만약 당신이 이것을 읽고 있다면 아마도 당신이 가장 관심을 가질만한 마법 단어는 다음과 같습니다.
frame = sys._getframe(1) # 1 stands for previous frame
parent_locals = frame.f_locals # true dictionary of parent locals
parent_globals = frame.f_globals # true dictionary of parent globals
exec(codeblock, parent_globals, parent_locals)
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),ctypes.c_int(1))
# the magic value 1 stands for ability to introduce new variables. 0 for update-only
후자의 경우 업데이트가 로컬 범위로 전달됩니다.그러나 로컬 범위는 글로벌 범위와 다르게 최적화되므로 새 개체가 초기화되지 않은 경우 개체를 직접 호출하려고 하면 몇 가지 문제가 발생합니다.나는 이 문제들을 피하기 위한 몇 가지 방법을 github 페이지에서 복사할 것입니다.
- 사전에 객체를 할당, 가져오기 및 정의
- 미리 개체에 자리 표시자 할당
- 기호 테이블을 업데이트하기 위해 메인 프로그램에서 개체를 자체적으로 재할당: x = locals("x")
- 최적화를 방지하려면 직접 호출하는 대신 기본 프로그램에서 exec()을 사용합니다.x do: exec("x")을 호출하는 대신
만약 당신이 그것을 느끼고 있다면 사용.exec()실제 로컬 사전(로컬에서 반환한 사전이 아님)을 업데이트하여 동작을 에뮬레이트할 수 없습니다.https://faster-cpython.readthedocs.io/mutable.html 에서 예제를 복사하겠습니다.
import sys
import ctypes
def hack():
# Get the frame object of the caller
frame = sys._getframe(1)
frame.f_locals['x'] = "hack!"
# Force an update of locals array from locals dict
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame),
ctypes.c_int(0))
def func():
x = 1
hack()
print(x)
func()
출력:
hack!
저는 당신이 이것을 하고 싶어하지 않아야 한다고 생각합니다.주변 환경에서 상황을 변경할 수 있는 기능은 위험합니다. 해당 컨텍스트는 기능에 대한 지식 없이 작성될 수 있기 때문입니다.
B와 C를 클래스의 비공개 메서드로 만들거나(가장 좋은 방법은) 목록과 같은 변수 유형을 사용하여 C:
def A():
x = [0]
def B(var):
var[0] = 1
B(x)
print x
A()
이것을 훨씬 나중에 더 안전하지만 무거운 해결책으로 보는 사람들에게.변수를 매개 변수로 전달할 필요가 없습니다.
def outer():
a = [1]
def inner(a=a):
a[0] += 1
inner()
return a[0]
가능하지만 글로벌 문을 사용해야 합니다(글로벌 변수를 사용할 때 항상 좋은 솔루션은 아니지만 효과가 있음).
def A():
global b
b = 1
def B():
global b
print( b )
b = 2
B()
A()
언급URL : https://stackoverflow.com/questions/8447947/is-it-possible-to-modify-a-variable-in-python-that-is-in-an-outer-enclosing-b
'programing' 카테고리의 다른 글
| Android TextView에서 글꼴 스타일을 굵고 기울임꼴 및 밑줄로 설정하는 방법은 무엇입니까? (0) | 2023.06.04 |
|---|---|
| Python을 사용한 웹 스크래핑 (0) | 2023.06.04 |
| Attach로 연 SQLite 데이터베이스 파일의 테이블을 나열하려면 어떻게 해야 합니까? (0) | 2023.06.04 |
| class << 루비의 자기 관용어 (0) | 2023.06.04 |
| Android 에뮬레이터 디스플레이를 회전하려면 어떻게 해야 합니까? (0) | 2023.06.04 |