Python 중첩 함수 변수 범위 지정
저는 그 주제에 대한 다른 질문들을 거의 다 읽었지만, 제 코드는 여전히 작동하지 않습니다.
파이썬 가변 범위에 대해 뭔가 누락된 것 같습니다.
내 코드는 다음과 같습니다.
PRICE_RANGES = {
64:(25, 0.35),
32:(13, 0.40),
16:(7, 0.45),
8:(4, 0.5)
}
def get_order_total(quantity):
global PRICE_RANGES
_total = 0
_i = PRICE_RANGES.iterkeys()
def recurse(_i):
try:
key = _i.next()
if quantity % key != quantity:
_total += PRICE_RANGES[key][0]
return recurse(_i)
except StopIteration:
return (key, quantity % key)
res = recurse(_i)
그리고 나는.
"글로벌 이름 '_total'이(가) 정의되지 않았습니다."
가 나는문제있것압니다을다는가▁the다▁on▁the에 있다는 것을 알고 있습니다._total
왜 그런지 이해할 수가 없어요해선 안된다recurse()
상위 기능의 변수에 액세스할 수 있습니까?
누가 파이썬 가변 범위에 대해 제가 빠진 것을 설명해주실 수 있나요?
Python 3에서는 문을 사용하여 로컬이 아닌 전역이 아닌 범위에 액세스할 수 있습니다.
그nonlocal
문을 사용하면 변수 정의가 이전에 생성된 변수와 가장 가까운 범위에 바인딩됩니다.다음은 몇 가지 예입니다.
def sum_list_items(_list):
total = 0
def do_the_sum(_list):
for i in _list:
total += i
do_the_sum(_list)
return total
sum_list_items([1, 2, 3])
는 다음합니다.UnboundLocalError: local variable 'total' referenced before assignment
용사를 합니다.nonlocal
코드를 작동시킬 수 있습니다.
def sum_list_items(_list):
total = 0
def do_the_sum(_list):
# Define the total variable as non-local, causing it to bind
# to the nearest non-global variable also called total.
nonlocal total
for i in _list:
total += i
do_the_sum(_list)
return total
sum_list_items([1, 2, 3])
하지만 "가장 가까운"은 무엇을 의미할까요?다음은 또 다른 예입니다.
def sum_list_items(_list):
total = 0
def do_the_sum(_list):
# The nonlocal total binds to this variable.
total = 0
def do_core_computations(_list):
# Define the total variable as non-local, causing it to bind
# to the nearest non-global variable also called total.
nonlocal total
for i in _list:
total += i
do_core_computations(_list)
do_the_sum(_list)
return total
sum_list_items([1, 2, 3])
예에서, 위의예에서,,total
는 부에정 변바니다됩인딩수 .do_the_sum
수고정에서 정의된 .sum_list_items
함수, 그래서 코드가 반환됩니다.0
할 수 . if 다 과 같 수 있 수 니 습 다 할 행 을 음 중 첩 이 중 은 ▁such ▁note 니 다 습 있 ▁nesting ▁if ▁double 다 수 : ▁as ▁that ▁this ▁ittotal
선됨으로 선언됩니다.nonlocal
do_the_sum
위의 예는 예상대로 작동할 것입니다.
def sum_list_items(_list):
# The nonlocal total binds to this variable.
total = 0
def do_the_sum(_list):
def do_core_computations(_list):
# Define the total variable as non-local, causing it to bind
# to the nearest non-global variable also called total.
nonlocal total
for i in _list:
total += i
do_core_computations(_list)
do_the_sum(_list)
return total
sum_list_items([1, 2, 3])
위의 예에서 비로컬 할당은 위치를 찾기 전에 두 개의 레벨을 통과합니다.total
에 sum_list_items
.
여기 데이비드의 대답의 핵심을 이루는 삽화가 있습니다.
def outer():
a = 0
b = 1
def inner():
print a
print b
#b = 4
inner()
outer()
명서와함께라는 .b = 4
out,이는 " 트코아웃출다, 코는니합력드이멘다▁outputs니▁commented출"를 출력합니다.0 1
당신이 예상했던 바로 그것.
하지만 만약 당신이 그 대사를 언급하지 않는다면, 그 대사에.print b
당신은 오류를 이해합니다.
UnboundLocalError: local variable 'b' referenced before assignment
가 존재한다는 것은 불가사의해 보입니다.b = 4
든 어떻든만수있것을들게▁somehow것▁might▁make있을수어.b
그 앞의 행에서 사라집니다.그러나 David가 인용한 텍스트는 그 이유를 설명합니다: 정적 분석 중에, 통역사는 b가 다음에 할당된 것을 결정합니다.inner
따서 그은 변지수다니입의 국소 입니다.inner
▁the다▁attempts▁the▁print▁to를 인쇄하려고 합니다.b
할당되기 전에 내부 범위에서.
코드를 실행하면 다음 오류가 발생합니다.
UnboundLocalError: local variable '_total' referenced before assignment
이 문제는 다음 행으로 인해 발생합니다.
_total += PRICE_RANGES[key][0]
범위 및 네임스페이스에 대한 설명서에는 다음과 같이 나와 있습니다.
Python의 특별한 특징은 그렇지 않은 경우
global
문이 적용됩니다. 이름에 대한 할당은 항상 가장 안쪽 범위에 들어갑니다.할당은 데이터를 복사하지 않고 이름만 개체에 바인딩합니다.
그래서 그 선이 효과적으로 말하고 있기 때문에:
_total = _total + PRICE_RANGES[key][0]
그것은 창조합니다._total
로의 recurse()
부터.부터_total
그러면 새 항목이고 할당되지 않은 항목입니다. 추가에 사용할 수 없습니다.
특수 개체나 맵 또는 배열을 선언하는 대신 함수 속성을 사용할 수도 있습니다.이를 통해 변수의 범위를 명확하게 지정할 수 있습니다.
def sumsquares(x,y):
def addsquare(n):
sumsquares.total += n*n
sumsquares.total = 0
addsquare(x)
addsquare(y)
return sumsquares.total
물론 이 속성은 함수 호출이 아니라 함수(정의)에 속합니다.따라서 스레드화와 재귀를 염두에 두어야 합니다.
이것은 Redman 솔루션의 변형이지만 변수를 캡슐화하기 위해 배열 대신 적절한 네임스페이스를 사용합니다.
def foo():
class local:
counter = 0
def bar():
print(local.counter)
local.counter += 1
bar()
bar()
bar()
foo()
foo()
클래스 개체를 이런 식으로 사용하는 것이 Python 커뮤니티에서 추악한 해킹으로 간주되는지 아니면 적절한 코딩 기술로 간주되는지는 잘 모르겠지만, python 2.x와 3.x에서 잘 작동합니다(2.7.3과 3.2.3으로 테스트됨).또한 이 솔루션의 런타임 효율성에 대해서도 잘 모르겠습니다.
철학적 관점에서는 "이름 공간에 문제가 있는 경우 고유한 이름 공간을 지정하십시오!"라고 대답할 수 있습니다.
할 수 쉽게 수행할 수 있고, 할 수 , 다양한 수 있습니다(할 여지 없이▁just▁than▁around▁providing▁(dou▁be'▁more▁not▁therell▁in수btless있,▁it며▁own▁its▁various▁the▁variables수할으▁between▁class자행▁top-쉽als더게체▁but▁functions▁easier▁to▁and▁shovel▁problem▁you▁to▁reduceslevelky,▁globulate 성가신 글로벌 요소를 제거하고 다양한 최상위 기능 간에 변수를 삽입할 필요성을 줄일 수 있습니다(의심할 여지 없이 그 이상의 기능이 있을 것입니다).get_order_total
).
근본적인 변화에 초점을 맞추기 위해 작전 코드를 보존하는 것,
class Order(object):
PRICE_RANGES = {
64:(25, 0.35),
32:(13, 0.40),
16:(7, 0.45),
8:(4, 0.5)
}
def __init__(self):
self._total = None
def get_order_total(self, quantity):
self._total = 0
_i = self.PRICE_RANGES.iterkeys()
def recurse(_i):
try:
key = _i.next()
if quantity % key != quantity:
self._total += self.PRICE_RANGES[key][0]
return recurse(_i)
except StopIteration:
return (key, quantity % key)
res = recurse(_i)
#order = Order()
#order.get_order_total(100)
PS로서, 다른 답변의 목록 아이디어에 변형된 하나의 해킹이지만, 아마도 더 명확할 것입니다.
def outer():
order = {'total': 0}
def inner():
order['total'] += 42
inner()
return order['total']
print outer()
@redman의 목록 기반 접근 방식을 사용했지만 가독성 측면에서는 최적이 아닙니다.
여기 수정된 @Hans의 접근법이 있습니다. 단, 저는 외부가 아닌 내부 함수의 속성을 사용합니다.이는 재귀 및 멀티스레딩과 더 호환되어야 합니다.
def outer(recurse=2):
if 0 == recurse:
return
def inner():
inner.attribute += 1
inner.attribute = 0
inner()
inner()
outer(recurse-1)
inner()
print "inner.attribute =", inner.attribute
outer()
outer()
인쇄할 내용:
inner.attribute = 3
inner.attribute = 3
inner.attribute = 3
inner.attribute = 3
내가 만약에s/inner.attribute/outer.attribute/g
다음을 확인:
outer.attribute = 3
outer.attribute = 4
outer.attribute = 3
outer.attribute = 4
그래서 실제로, 그것들을 내부 기능의 속성으로 만드는 것이 더 나은 것처럼 보입니다.
또한 가독성 측면에서도 합리적인 것 같습니다. 왜냐하면 변수는 개념적으로 내부 함수와 관련이 있고, 이 표기법은 변수가 내부 함수와 외부 함수의 범위 사이에서 공유된다는 것을 독자에게 상기시키기 때문입니다.은 성에약단점은의간대한가라는 입니다.inner.attribute
다음 이후에만 구문적으로 설정할 수 있습니다.def inner(): ...
.
내 길은...
def outer():
class Cont(object):
var1 = None
@classmethod
def inner(cls, arg):
cls.var1 = arg
Cont.var1 = "Before"
print Cont.var1
Cont.inner("After")
print Cont.var1
outer()
>>> def get_order_total(quantity):
global PRICE_RANGES
total = 0
_i = PRICE_RANGES.iterkeys()
def recurse(_i):
print locals()
print globals()
try:
key = _i.next()
if quantity % key != quantity:
total += PRICE_RANGES[key][0]
return recurse(_i)
except StopIteration:
return (key, quantity % key)
print 'main function', locals(), globals()
res = recurse(_i)
>>> get_order_total(20)
main function {'total': 0, 'recurse': <function recurse at 0xb76baed4>, '_i': <dictionary-keyiterator object at 0xb6473e64>, 'quantity': 20} {'__builtins__': <module '__builtin__' (built-in)>, 'PRICE_RANGES': {64: (25, 0.34999999999999998), 32: (13, 0.40000000000000002), 16: (7, 0.45000000000000001), 8: (4, 0.5)}, '__package__': None, 's': <function s at 0xb646adf4>, 'get_order_total': <function get_order_total at 0xb646ae64>, '__name__': '__main__', '__doc__': None}
{'recurse': <function recurse at 0xb76baed4>, '_i': <dictionary-keyiterator object at 0xb6473e64>, 'quantity': 20}
{'__builtins__': <module '__builtin__' (built-in)>, 'PRICE_RANGES': {64: (25, 0.34999999999999998), 32: (13, 0.40000000000000002), 16: (7, 0.45000000000000001), 8: (4, 0.5)}, '__package__': None, 's': <function s at 0xb646adf4>, 'get_order_total': <function get_order_total at 0xb646ae64>, '__name__': '__main__', '__doc__': None}
{'recurse': <function recurse at 0xb76baed4>, '_i': <dictionary-keyiterator object at 0xb6473e64>, 'quantity': 20}
{'__builtins__': <module '__builtin__' (built-in)>, 'PRICE_RANGES': {64: (25, 0.34999999999999998), 32: (13, 0.40000000000000002), 16: (7, 0.45000000000000001), 8: (4, 0.5)}, '__package__': None, 's': <function s at 0xb646adf4>, 'get_order_total': <function get_order_total at 0xb646ae64>, '__name__': '__main__', '__doc__': None}
{'recurse': <function recurse at 0xb76baed4>, '_i': <dictionary-keyiterator object at 0xb6473e64>, 'quantity': 20}
{'__builtins__': <module '__builtin__' (built-in)>, 'PRICE_RANGES': {64: (25, 0.34999999999999998), 32: (13, 0.40000000000000002), 16: (7, 0.45000000000000001), 8: (4, 0.5)}, '__package__': None, 's': <function s at 0xb646adf4>, 'get_order_total': <function get_order_total at 0xb646ae64>, '__name__': '__main__', '__doc__': None}
Traceback (most recent call last):
File "<pyshell#32>", line 1, in <module>
get_order_total(20)
File "<pyshell#31>", line 18, in get_order_total
res = recurse(_i)
File "<pyshell#31>", line 13, in recurse
return recurse(_i)
File "<pyshell#31>", line 13, in recurse
return recurse(_i)
File "<pyshell#31>", line 12, in recurse
total += PRICE_RANGES[key][0]
UnboundLocalError: local variable 'total' referenced before assignment
>>>
보시는 바와 같이, 토탈은 주 함수의 로컬 범위에 있지만, 반복의 로컬 범위에 있지는 않지만 글로벌 범위에도 없습니다. 왜냐하면 get_order_total의 로컬 범위에만 정의되어 있기 때문입니다.
언급URL : https://stackoverflow.com/questions/5218895/python-nested-functions-variable-scoping
'programing' 카테고리의 다른 글
WPF MouseLeftButtonDown 이벤트 핸들러의 Ctrl 키 누름 조건 (0) | 2023.07.08 |
---|---|
VBA: Excel에서 필터링된 행을 삭제하는 방법은 무엇입니까? (0) | 2023.07.08 |
새 리포지토리에서 오리진 마스터 푸시 오류 (0) | 2023.07.08 |
사이트 '글로벌이 정의되지 않았습니다' (0) | 2023.07.08 |
Angular2 - TypeError: this.http.get(...).toPromise가 함수가 아닙니다. (0) | 2023.07.08 |