[python] 함수 내에서 정적 변수와 동등한 파이썬은 무엇입니까?

이 C / C ++ 코드와 같은 관용적 인 파이썬은 무엇입니까?

void foo()
{
    static int counter = 0;
    counter++;
    printf("counter is %d\n", counter);
}

특히 클래스 수준이 아닌 함수 수준에서 정적 멤버를 어떻게 구현합니까? 그리고 함수를 클래스에 배치하면 아무것도 변경됩니까?



답변

약간 역전되었지만 작동해야합니다.

def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter
foo.counter = 0

카운터 초기화 코드를 하단 대신 상단에 표시하려면 데코레이터를 만들 수 있습니다.

def static_vars(**kwargs):
    def decorate(func):
        for k in kwargs:
            setattr(func, k, kwargs[k])
        return func
    return decorate

그런 다음 다음과 같은 코드를 사용하십시오.

@static_vars(counter=0)
def foo():
    foo.counter += 1
    print "Counter is %d" % foo.counter

foo.불행히도 여전히 접두사 를 사용해야합니다 .

(크레딧 : @ony )


답변

함수에 속성을 추가하고 정적 변수로 사용할 수 있습니다.

def myfunc():
  myfunc.counter += 1
  print myfunc.counter

# attribute must be initialized
myfunc.counter = 0

또는 함수 외부에서 변수를 설정하지 않으려 hasattr()AttributeError경우 예외 를 피하기 위해 사용할 수 있습니다 .

def myfunc():
  if not hasattr(myfunc, "counter"):
     myfunc.counter = 0  # it doesn't exist yet, so initialize it
  myfunc.counter += 1

어쨌든 정적 변수는 다소 드물며 클래스 내 에서이 변수에 대한 더 좋은 곳을 찾아야합니다.


답변

또한 다음을 고려할 수 있습니다.

def foo():
    try:
        foo.counter += 1
    except AttributeError:
        foo.counter = 1

추리:

  • 많은 pythonic ( “허용을 요구하지 않습니다”)
  • if분기 대신 예외를 사용하십시오 ( StopIteration 예외를 생각하십시오 )

답변

다른 답변은 당신이 이것을 해야하는 방법을 보여주었습니다. 하지 말아야 할 방법은 다음과 같습니다.

>>> def foo(counter=[0]):
...   counter[0] += 1
...   print("Counter is %i." % counter[0]);
...
>>> foo()
Counter is 1.
>>> foo()
Counter is 2.
>>> 

기본값은 함수가 실행될 때마다가 아니라 함수가 처음 평가 될 때만 초기화되므로 목록 또는 기타 변경 가능한 객체를 사용하여 정적 값을 저장할 수 있습니다.


답변

많은 사람들이 이미 ‘hasattr’테스트를 제안했지만 더 간단한 답변이 있습니다.

def func():
    func.counter = getattr(func, 'counter', 0) + 1

시도 / 제외, 테스트 hasattr 없음, 기본값으로 getattr.


답변

다음은 외부 초기화 호출이 필요하지 않은 완전히 캡슐화 된 버전입니다.

def fn():
    fn.counter=vars(fn).setdefault('counter',-1)
    fn.counter+=1
    print (fn.counter)

파이썬에서 함수는 객체이며 특별한 속성을 통해 멤버 변수를 추가하거나 원숭이 패치 할 수 있습니다 __dict__. 내장 vars()은 특수 속성 을 반환합니다 __dict__.

편집 : 참고, 대안 try:except AttributeError답변 과 달리이 접근법을 사용하면 변수는 초기화 후에 항상 코드 논리를 준비합니다. try:except AttributeError다음에 대한 대안은 덜 건조하고 어색한 흐름 이라고 생각합니다 .

def Fibonacci(n):
   if n<2: return n
   Fibonacci.memo=vars(Fibonacci).setdefault('memo',{}) # use static variable to hold a results cache
   return Fibonacci.memo.setdefault(n,Fibonacci(n-1)+Fibonacci(n-2)) # lookup result in cache, if not available then calculate and store it

EDIT2 : 함수가 여러 위치에서 호출 될 때 위의 접근 방식 만 권장합니다. 대신 함수가 한 곳에서만 호출되면 다음을 사용하는 것이 좋습니다 nonlocal.

def TheOnlyPlaceStaticFunctionIsCalled():
    memo={}
    def Fibonacci(n):
       nonlocal memo  # required in Python3. Python2 can see memo
       if n<2: return n
       return memo.setdefault(n,Fibonacci(n-1)+Fibonacci(n-2))
    ...
    print (Fibonacci(200))
    ...


답변

파이썬에는 정적 변수가 없지만 호출 가능한 클래스 객체를 정의한 다음 함수로 사용하여 위조 할 수 있습니다. 이 답변도 참조하십시오 .

class Foo(object):
  # Class variable, shared by all instances of this class
  counter = 0

  def __call__(self):
    Foo.counter += 1
    print Foo.counter

# Create an object instance of class "Foo," called "foo"
foo = Foo()

# Make calls to the "__call__" method, via the object's name itself
foo() #prints 1
foo() #prints 2
foo() #prints 3

참고 __call__자신의 이름으로 클래스 (객체) 호출의 인스턴스를 만든다. 그래서 foo()위의 호출은 클래스의 __call__메소드를 호출하는 이유 입니다. 설명서에서 :

클래스에서 __call__()메소드를 정의하여 임의 클래스의 인스턴스를 호출 할 수 있습니다 .