이 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.counterfoo.불행히도 여전히 접두사 를 사용해야합니다 .
(크레딧 : @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 itEDIT2 : 함수가 여러 위치에서 호출 될 때 위의 접근 방식 만 권장합니다. 대신 함수가 한 곳에서만 호출되면 다음을 사용하는 것이 좋습니다 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__()메소드를 정의하여 임의 클래스의 인스턴스를 호출 할 수 있습니다 .
