Programing

Python 2.x의 nonlocal 키워드

c10106 2022. 3. 28. 21:07
반응형

Python 2.x의 nonlocal 키워드

Python 2.6에서 폐쇄를 구현하려고 하는데 비로컬 변수에 액세스해야 하는데 이 키워드는 Python 2.x에서 사용할 수 없는 것 같아.이러한 버전의 파이썬에서 폐쇄의 비로컬 변수에 어떻게 접근해야 하는가?

내부 함수는 비 국부적 변수를 2.x로 읽을 수 있지만, 재바인딩하지 않는다.이것은 귀찮지만, 너는 그것을 해결할 수 있다.사전을 만들고 그 안에 데이터를 요소로 저장하십시오.내부 함수는 비로컬 변수가 참조하는 객체를 변이하는 것을 금지하지 않는다.

위키백과의 예를 사용하려면:

def outer():
    d = {'y' : 0}
    def inner():
        d['y'] += 1
        return d['y']
    return inner

f = outer()
print(f(), f(), f()) #prints 1 2 3

다음의 해결책은 엘리아스 자마리아(Elias Zamaria)의 대답에서 영감을 받지만, 그 대답과는 반대로 외부 기능의 여러 호출을 정확하게 처리한다."변수"inner.y현재 통화의 지역적 위치outer. 단지 그것은 금지되어 있기 때문에 변수가 아니라 객체 속성(개체가 함수임)이다.inner그 자체다이것은 매우 추하다(속성은 다음에나 생성될 수 있다는 점에 유의한다).inner함수가 정의되어 있지만 효과적인 것 같다.

def outer():
    def inner():
        inner.y += 1
        return inner.y
    inner.y = 0
    return inner

f = outer()
g = outer()
print(f(), f(), g(), f(), g()) #prints (1, 2, 1, 3, 2)

사전이라기 보다는, 지역적이지 않은 수업은 덜 복잡하다.@ChrisB의 예 수정:

def outer():
    class context:
        y = 0
    def inner():
        context.y += 1
        return context.y
    return inner

그러면

f = outer()
assert f() == 1
assert f() == 2
assert f() == 3
assert f() == 4

각각의 외부() 호는 컨텍스트라고 하는 새롭고 뚜렷한 클래스를 만든다(단순한 새로운 인스턴스만이 아니다).그래서 그것은 공유된 맥락에 대한 나다니엘의 주의를 피한다.

g = outer()
assert g() == 1
assert g() == 2

assert f() == 5

여기서 핵심은 '접근'이 의미하는 것이라고 생각한다.예를 들어, 닫힘 범위 밖의 변수를 읽는 데 문제가 없어야 한다.

x = 3
def outer():
    def inner():
        print x
    inner()
outer()

예상대로 작동해야 한다(제3장).단, 예를 들어 x의 값을 재정의하는 것은 작동하지 않는다.

x = 3
def outer():
    def inner():
        x = 5
    inner()
outer()
print x

여전히 3번 인쇄될 것이다.내가 PEP-3104에 대해 이해한 바로는 이것이 비로컬 키워드를 다루기 위한 것이다.PEP에서 언급된 바와 같이, 같은 것을 성취하기 위해 클래스를 사용할 수 있다(일종의 지저분함).

class Namespace(object): pass
ns = Namespace()
ns.x = 3
def outer():
    def inner():
        ns.x = 5
    inner()
outer()
print ns.x

Python 2에서 비로컬 변수를 구현하는 또 다른 방법이 있는데, 여기서의 답변 중 어떤 것이든 어떤 이유로든 바람직하지 않은 경우:

def outer():
    outer.y = 0
    def inner():
        outer.y += 1
        return outer.y
    return inner

f = outer()
print(f(), f(), f()) #prints 1 2 3

변수의 할당명세서에 있는 함수명을 사용하는 것은 중복되지만, 내가 보기에는 변수를 사전에 넣는 것보다 간단하고 깨끗해 보인다.그 가치는 크리스 B의 대답에서처럼 한 통화에서 다른 통화로 기억된다.

알로이스 마달이 다른 대답에 대해 논평에서 한 제안에서 영감을 얻은 것이 있다.

class Nonlocal(object):
    """ Helper to implement nonlocal names in Python 2.x """
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)


def outer():
    nl = Nonlocal(y=0)
    def inner():
        nl.y += 1
        return nl.y
    return inner

f = outer()
print(f(), f(), f()) # -> (1 2 3)

비단뱀의 범위 지정 규칙에는 사마귀가 있다 - 할당은 변수를 즉시 둘러싸는 함수 범위에 로컬로 만든다.라면 이 를 '로마'로 할 수 것이다global키워드

해결책은 두 범위 사이에 공유되는 물체를 도입하는 것인데, 여기에는 변이 가능한 변수가 포함되어 있지만, 그 자체가 할당되지 않은 변수를 통해 참조되는 것이다.

def outer(v):
    def inner(container = [v]):
        container[0] += 1
        return container[0]
    return inner

또 다른 방법은 다음과 같은 종류의 해킹이다.

def outer(v):
    def inner(varname = 'v', scope = locals()):
        scope[varname] += 1
        return scope[varname]
    return inner

매개 변수의 이름을 다음과 같은 방법으로 알아낼 수 있을 것이다.outer, 그런 다음 varname으로 전달하지만 이름에 의존하지 않고outerY 콤비네이터를 사용해야 한다.

다른 방법(너무 장황하긴 하지만):

import ctypes

def outer():
    y = 0
    def inner():
        ctypes.pythonapi.PyCell_Set(id(inner.func_closure[0]), id(y + 1))
        return y
    return inner

x = outer()
x()
>> 1
x()
>> 2
y = outer()
y()
>> 1
x()
>> 3

Martineau의 우아한 솔루션을 실용적이고 다소 덜 우아한 사용 사례로 확대:

class nonlocals(object):
""" Helper to implement nonlocal names in Python 2.x.
Usage example:
def outer():
     nl = nonlocals( n=0, m=1 )
     def inner():
         nl.n += 1
     inner() # will increment nl.n

or...
    sums = nonlocals( { k:v for k,v in locals().iteritems() if k.startswith('tot_') } )
"""
def __init__(self, **kwargs):
    self.__dict__.update(kwargs)

def __init__(self, a_dict):
    self.__dict__.update(a_dict)

전역 변수 사용

def outer():
    global y # import1
    y = 0
    def inner():
        global y # import2 - requires import1
        y += 1
        return y
    return inner

f = outer()
print(f(), f(), f()) #prints 1 2 3

개인적으로, 나는 세계적인 변수들을 좋아하지 않는다.그러나 나의 제안은 https://stackoverflow.com/a/19877437/1083704의 답변에 기초한다.

def report():
        class Rank: 
            def __init__(self):
                report.ranks += 1
        rank = Rank()
report.ranks = 0
report()

사용자가 전역 변수를 선언해야 하는 경우ranks당신이 전화할때마다report 나의 개선으로 인해 사용자로부터 함수 변수를 초기화할 필요가 없어졌다.

참조URL: https://stackoverflow.com/questions/3190706/nonlocal-keyword-in-python-2-x

반응형