이 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__()
메소드를 정의하여 임의 클래스의 인스턴스를 호출 할 수 있습니다 .