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 선됨으로 선언됩니다.nonlocaldo_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 |