함수 내부의 정적 변수와 동등한 Python은 무엇입니까?
이 C/C++ 코드의 관용 Python은 무엇입니까?
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
이유:
- 많은 피조어("허가가 아니라 용서를 구함")
if
branch (StopIteration 예외로 간주)
많은 사람들이 이미 'hasattr' 테스트를 제안했지만, 더 간단한 답이 있습니다.
def func():
func.counter = getattr(func, 'counter', 0) + 1
시도/예외, 테스트 hasatr은 없습니다.기본값으로 getatr만 사용합니다.
다른 답변에서는 이 방법을 시연하고 있습니다.다음 방법이 있습니다.
>>> def foo(counter=[0]):
... counter[0] += 1
... print("Counter is %i." % counter[0]);
...
>>> foo()
Counter is 1.
>>> foo()
Counter is 2.
>>>
기본값은 함수를 실행할 때마다가 아니라 함수를 처음 평가할 때만 초기화되므로 목록 또는 기타 가변 개체를 사용하여 정적 값을 저장할 수 있습니다.
Python에는 정적 변수가 없지만 호출 가능한 클래스 객체를 정의한 후 함수로 사용하여 가짜로 만들 수 있습니다.이 답변도 참조해 주세요.
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__()
수업의 방법을 가르쳐 주세요.
외부 초기화 콜이 필요 없는 완전 캡슐화 버전을 다음에 나타냅니다.
def fn():
fn.counter=vars(fn).setdefault('counter',-1)
fn.counter+=1
print (fn.counter)
이며, 는 특별한 속성 을 통해 멤버 수 __dict__
. ★★★★★★★★★★★★★★★★」vars()
는, 특수 어트리뷰트 「CHANGE」를 합니다.__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))
...
제너레이터 함수를 사용하여 반복기를 생성합니다.
def foo_gen():
n = 0
while True:
n+=1
yield n
그럼 이렇게 쓰세요.
foo = foo_gen().next
for i in range(0,10):
print foo()
상한을 원하는 경우:
def foo_gen(limit=100000):
n = 0
while n < limit:
n+=1
yield n
위의 예시와 같이 반복기가 종료된 경우 다음과 같이 직접 루프 오버할 수도 있습니다.
for i in foo_gen(20):
print i
물론 이러한 간단한 경우에는 xrange를 사용하는 것이 좋습니다.
여기 수익률 명세서에 대한 문서가 있습니다.
다른 솔루션에서는 일반적으로 초기화를 처리하기 위해 복잡한 로직을 사용하여 카운터 속성을 함수에 부가합니다.새 코드에는 적합하지 않습니다.
에서는 Python 3 、 Python 3 、 Python 3 、 Python 3 、 Python 3 、 Python 3 、 Python 3 、 Python 3 、 Python 3 の a a a a a a a a a a a a a a a anonlocal
★★★★★★★★
counter = 0
def foo():
nonlocal counter
counter += 1
print(f'counter is {counter}')
의 사양에 대해서는, 「PE 3104」를 참조해 주세요.nonlocal
★★★★★★ 。
비공개로 은 """로 ._counter
★★★★★★ 。
함수의 Atribute를 static 변수로 사용하면 다음과 같은 잠재적인 단점이 있습니다.
- 변수에 액세스할 때마다 함수의 전체 이름을 입력해야 합니다.
- 외부 코드는 변수에 쉽게 액세스하여 값을 조작할 수 있습니다.
두 번째 이슈의 관용적인 python은 아마도 변수 이름을 선두에 언더스코어로 붙여서 접근하지 않도록 하면서 접근하지 않도록 하는 것일 것입니다.
클로저 사용
폐쇄를 입니다. 폐쇄는 어휘적 폐쇄를 하여 사용할 수 있습니다.nonlocal
def make_counter():
i = 0
def counter():
nonlocal i
i = i + 1
return i
return counter
counter = make_counter()
슬프게도 나는 이 용액을 데코레이터에 담는 방법을 모른다.
내부 상태 매개 변수 사용
다른 옵션은 문서화되지 않은 매개 변수가 가변 값 컨테이너로 사용될 수 있습니다.
def counter(*, _i=[0]):
_i[0] += 1
return _i[0]
이는 기본 인수가 함수가 호출되었을 때가 아니라 함수가 정의되었을 때 평가되기 때문입니다.
청소부는 목록 대신 용기 유형을 가질 수 있습니다.
def counter(*, _i = Mutable(0)):
_i.value += 1
return _i.value
목적을 명확하게 전달할 수 있는 빌트인 타입은 알 수 없습니다.
조금 더 읽기 쉽지만 좀 더 상세하게(Jen of Python: 명시적인 것이 암묵적인 것보다 낫다):
>>> def func(_static={'counter': 0}):
... _static['counter'] += 1
... print _static['counter']
...
>>> func()
1
>>> func()
2
>>>
이 기능의 상세한 것에 대하여는, 여기를 참조해 주세요.
_counter = 0def foo(): 글로벌_카운터_counter + = 1'counter is', _counter를 인쇄합니다.
Python은 개인 변수를 나타내기 위해 일반적으로 밑줄을 사용합니다.C에서 함수 내부에 정적 변수를 선언하는 유일한 이유는 함수 외부에 정적 변수를 숨기기 위한 것인데, 이것은 실제로 관용적인 Python이 아닙니다.
def staticvariables(**variables):
def decorate(function):
for variable in variables:
setattr(function, variable, variables[variable])
return function
return decorate
@staticvariables(counter=0, bar=1)
def foo():
print(foo.counter)
print(foo.bar)
위의 vincent 코드와 마찬가지로 이것은 함수 데코레이터로 사용되며 정적 변수에는 함수 이름을 접두사로 사용하여 액세스해야 합니다.이 코드의 장점은(누구나 그것을 이해할 수 있을 만큼 똑똑하지만) 여러 개의 정적 변수를 가지고 보다 일반적인 방법으로 초기화할 수 있다는 것입니다.
몇 가지 방법을 시도해 본 결과 @warvariuc의 답변이 개선되었습니다.
import types
def func(_static=types.SimpleNamespace(counter=0)):
_static.counter += 1
print(_static.counter)
관용적인 방법은 속성을 가질 수 있는 클래스를 사용하는 것입니다.인스턴스를 분리하지 않으려면 싱글톤을 사용합니다.
Python에 변수를 위장하거나 주입할 수 있는 방법은 여러 가지가 있지만(아직까지 언급되지 않은 것은 가변 기본 인수를 갖는 것입니다), 이것은 피토닉식 관용적인 방법이 아닙니다.그냥 수업을 이용하세요.
사용 패턴에 맞는 경우 생성기를 사용할 수도 있습니다.
Python 메서드 내의 정적 변수
class Count:
def foo(self):
try:
self.foo.__func__.counter += 1
except AttributeError:
self.foo.__func__.counter = 1
print self.foo.__func__.counter
m = Count()
m.foo() # 1
m.foo() # 2
m.foo() # 3
펑키한 콜시그니처를 사용해도 괜찮으시다면 https://stackoverflow.com/a/279598/916373,과 같은 콜 가능 오브젝트 상에서 또 다른 트위스트(권장하지 않음!)는 다음과 같습니다.
class foo(object):
counter = 0;
@staticmethod
def __call__():
foo.counter += 1
print "counter is %i" % foo.counter
>>> foo()()
counter is 1
>>> foo()()
counter is 2
소울레이션 n +=1
def foo():
foo.__dict__.setdefault('count', 0)
foo.count += 1
return foo.count
글로벌 선언은 이 기능을 제공합니다.아래의 예("f"를 사용하려면 python 3.5 이상)에서는 카운터 변수가 함수 외부에 정의되어 있습니다.함수에서 글로벌하게 정의하면 함수 외부의 "글로벌" 버전을 함수가 사용할 수 있도록 해야 합니다.따라서 함수가 실행될 때마다 함수의 외부 값이 수정되어 함수의 외부 값이 유지됩니다.
counter = 0
def foo():
global counter
counter += 1
print("counter is {}".format(counter))
foo() #output: "counter is 1"
foo() #output: "counter is 2"
foo() #output: "counter is 3"
이 질문에 따라 사용하기에 좀 더 좋을 수 있고 방법과 기능 모두 동일하게 보이는 다른 대안을 제시해도 되겠습니까?
@static_var2('seed',0)
def funccounter(statics, add=1):
statics.seed += add
return statics.seed
print funccounter() #1
print funccounter(add=2) #3
print funccounter() #4
class ACircle(object):
@static_var2('seed',0)
def counter(statics, self, add=1):
statics.seed += add
return statics.seed
c = ACircle()
print c.counter() #1
print c.counter(add=2) #3
print c.counter() #4
d = ACircle()
print d.counter() #5
print d.counter(add=2) #7
print d.counter() #8
사용법이 마음에 드는 경우는, 다음과 같이 실장합니다.
class StaticMan(object):
def __init__(self):
self.__dict__['_d'] = {}
def __getattr__(self, name):
return self.__dict__['_d'][name]
def __getitem__(self, name):
return self.__dict__['_d'][name]
def __setattr__(self, name, val):
self.__dict__['_d'][name] = val
def __setitem__(self, name, val):
self.__dict__['_d'][name] = val
def static_var2(name, val):
def decorator(original):
if not hasattr(original, ':staticman'):
def wrapped(*args, **kwargs):
return original(getattr(wrapped, ':staticman'), *args, **kwargs)
setattr(wrapped, ':staticman', StaticMan())
f = wrapped
else:
f = original #already wrapped
getattr(f, ':staticman')[name] = val
return f
return decorator
정적 로컬 변수를 가진 함수를 작성하는 대신 항상 "함수 개체"라고 하는 함수를 생성하여 표준(비정적) 멤버 변수를 지정할 수 있습니다.
++는 C++는 C++는 C++는 C++는 C++는 Function Object로, Object는 단순히 "Function object"가 오버로드된 operator()
. 클래스의 인스턴스는 함수처럼 동작합니다.를 들어, 이렇게 쓰면 됩니다.int x = square(5);
라 square
되어 있습니다).operator()
」는, 엄밀히 말하면 「기능」이 아닙니다.function - object function function function function function function function function function function function function 。
# C++ function object
class Foo_class {
private:
int counter;
public:
Foo_class() {
counter = 0;
}
void operator() () {
counter++;
printf("counter is %d\n", counter);
}
};
Foo_class foo;
Python을 오버로드할 .operator()
, 이 는 대신 '''로 명명됩니다.__call__
:
클래스 정의는 다음과 같습니다.
class Foo_class:
def __init__(self): # __init__ is similair to a C++ class constructor
self.counter = 0
# self.counter is like a static member
# variable of a function named "foo"
def __call__(self): # overload operator()
self.counter += 1
print("counter is %d" % self.counter);
foo = Foo_class() # call the constructor
다음은 사용되는 클래스의 예입니다.
from foo import foo
for i in range(0, 5):
foo() # function call
콘솔에 출력되는 출력은 다음과 같습니다.
counter is 1
counter is 2
counter is 3
counter is 4
counter is 5
에서 입력 인수를 할 수 .__call__
아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아.
# FILE: foo.py - - - - - - - - - - - - - - - - - - - - - - - - -
class Foo_class:
def __init__(self):
self.counter = 0
def __call__(self, x, y, z): # overload operator()
self.counter += 1
print("counter is %d" % self.counter);
print("x, y, z, are %d, %d, %d" % (x, y, z));
foo = Foo_class() # call the constructor
# FILE: main.py - - - - - - - - - - - - - - - - - - - - - - - - - - - -
from foo import foo
for i in range(0, 5):
foo(7, 8, 9) # function call
# Console Output - - - - - - - - - - - - - - - - - - - - - - - - - -
counter is 1
x, y, z, are 7, 8, 9
counter is 2
x, y, z, are 7, 8, 9
counter is 3
x, y, z, are 7, 8, 9
counter is 4
x, y, z, are 7, 8, 9
counter is 5
x, y, z, are 7, 8, 9
장식기 및 마감 사용
다음 데코레이터를 사용하여 정적 함수 변수를 만들 수 있습니다.선언된 함수는 그 자체에서 반환된 함수로 대체됩니다.이는 장식된 함수가 함수를 반환해야 함을 의미합니다.
def static_inner_self(func):
return func()
그런 다음 캡처된 변수와 함께 다른 함수를 반환하는 함수에 데코레이터를 사용합니다.
@static_inner_self
def foo():
counter = 0
def foo():
nonlocal counter
counter += 1
print(f"counter is {counter}")
return foo
nonlocal
않은 Python은 이 명령어를 "이 명령어"로합니다.파이썬counter
변수가 입니다. 할당 Python 때문에 합니다.counter += 1
함수의 할당은 Python으로 하여금 변수가 로컬이라고 생각하게 합니다.
함수의 " "는 .nonlocal
이 위해 사용합니다.이 경우 Python은 가 " " ", "입니다."라고할 수 있습니다. 여기서 Python은 변수가 다음과 같은 것을 추론할 수 있습니다.nonlocal
:
@static_inner_self
def indent_lines():
import re
re_start_line = re.compile(r'^', flags=re.MULTILINE)
def indent_lines(text, indent=2):
return re_start_line.sub(" "*indent, text)
return indent_lines
추신: 같은 제안을 한 삭제된 답변이 있습니다.저자가 왜 삭제했는지 모르겠어요.https://stackoverflow.com/a/23366737/195417
이 답변은 @claudiu의 답변에 기초하고 있습니다.
정적 변수에 액세스하려고 할 때마다 함수 이름을 앞에 붙여야 할 때 코드가 명확하지 않다는 것을 알게 되었습니다.
즉, 기능 코드에 다음과 같이 쓰고 싶습니다.
print(statics.foo)
대신
print(my_function_name.foo)
그래서 저의 해결책은 다음과 같습니다.
- 을 추가하다
statics
함수에 귀속되다 - 함수 범위에서 로컬 변수 추가
statics
에 대한 가명으로서my_function.statics
from bunch import *
def static_vars(**kwargs):
def decorate(func):
statics = Bunch(**kwargs)
setattr(func, "statics", statics)
return func
return decorate
@static_vars(name = "Martin")
def my_function():
statics = my_function.statics
print("Hello, {0}".format(statics.name))
발언
my method는 다음과 같은 클래스를 사용합니다.Bunch
이것은 자바스크립트(Attribute-Style Access)를 지원하는 딕셔너리입니다(2000년경)
설치 방법은 다음과 같습니다.pip install bunch
또한 다음과 같이 손으로 쓸 수도 있습니다.
class Bunch(dict):
def __init__(self, **kw):
dict.__init__(self,kw)
self.__dict__ = self
저는 개인적으로 데코레이터보다 다음과 같은 것을 선호합니다.각자에게.
def staticize(name, factory):
"""Makes a pseudo-static variable in calling function.
If name `name` exists in calling function, return it.
Otherwise, saves return value of `factory()` in
name `name` of calling function and return it.
:param name: name to use to store static object
in calling function
:type name: String
:param factory: used to initialize name `name`
in calling function
:type factory: function
:rtype: `type(factory())`
>>> def steveholt(z):
... a = staticize('a', list)
... a.append(z)
>>> steveholt.a
Traceback (most recent call last):
...
AttributeError: 'function' object has no attribute 'a'
>>> steveholt(1)
>>> steveholt.a
[1]
>>> steveholt('a')
>>> steveholt.a
[1, 'a']
>>> steveholt.a = []
>>> steveholt.a
[]
>>> steveholt('zzz')
>>> steveholt.a
['zzz']
"""
from inspect import stack
# get scope enclosing calling function
calling_fn_scope = stack()[2][0]
# get calling function
calling_fn_name = stack()[1][3]
calling_fn = calling_fn_scope.f_locals[calling_fn_name]
if not hasattr(calling_fn, name):
setattr(calling_fn, name, factory())
return getattr(calling_fn, name)
Daniel의 답변(추가사항):
class Foo(object):
counter = 0
def __call__(self, inc_value=0):
Foo.counter += inc_value
return Foo.counter
foo = Foo()
def use_foo(x,y):
if(x==5):
foo(2)
elif(y==7):
foo(3)
if(foo() == 10):
print("yello")
use_foo(5,1)
use_foo(5,1)
use_foo(1,7)
use_foo(1,7)
use_foo(1,1)
이 부분을 추가하고 싶은 이유는 static var가 어떤 값만큼 증가하는 것뿐만 아니라 실제 예로서 static var가 어떤 값과 동일한지 확인하는 것입니다.
static 변수는 여전히 보호되며 use_foo() 함수의 범위 내에서만 사용됩니다.
이 예에서는 foo() 함수에 대한 콜은 (대응하는 c++ 등가물에 대해) 그대로입니다.
stat_c +=9; // in c++
foo(9) #python equiv
if(stat_c==10){ //do something} // c++
if(foo() == 10): # python equiv
#add code here # python equiv
Output :
yello
yello
클래스 Foo가 싱글톤 클래스로 제한적으로 정의되어 있다면 이상적입니다.이렇게 하면 좀 더 버마틱하게 만들 수 있어요.
정적 변수를 사용하기 위한 간단한 함수를 작성합니다.
def Static():
### get the func object by which Static() is called.
from inspect import currentframe, getframeinfo
caller = currentframe().f_back
func_name = getframeinfo(caller)[2]
# print(func_name)
caller = caller.f_back
func = caller.f_locals.get(
func_name, caller.f_globals.get(
func_name
)
)
class StaticVars:
def has(self, varName):
return hasattr(self, varName)
def declare(self, varName, value):
if not self.has(varName):
setattr(self, varName, value)
if hasattr(func, "staticVars"):
return func.staticVars
else:
# add an attribute to func
func.staticVars = StaticVars()
return func.staticVars
사용방법:
def myfunc(arg):
if Static().has('test1'):
Static().test += 1
else:
Static().test = 1
print(Static().test)
# declare() only takes effect in the first time for each static variable.
Static().declare('test2', 1)
print(Static().test2)
Static().test2 += 1
물론 오래된 질문이지만 업데이트를 해드릴 수 있을 것 같습니다.
performance 인수는 더 이상 사용되지 않는 것 같습니다.같은 테스트 스위트에서 siInt_try 및 isInt_re2에 대해 유사한 결과를 얻을 수 있습니다.물론 결과는 다양하지만, 이것은 Xeon W3550을 사용하는 커널 4.3.01에서 python 3.4를 사용하는 제 컴퓨터 세션입니다.여러 번 해봤는데 결과는 비슷한 것 같아요.글로벌 regex를 function static으로 전환했지만 성능 차이는 무시할 수 있습니다.
isInt_try: 0.3690
isInt_str: 0.3981
isInt_re: 0.5870
isInt_re2: 0.3632
성능 문제가 해결되었으므로 try/catch를 통해 가장 미래적이고 구석구석인 입증 코드를 생성할 수 있을 것으로 생각되므로 기능적으로만 정리할 수 있습니다.
언급URL : https://stackoverflow.com/questions/279561/what-is-the-python-equivalent-of-static-variables-inside-a-function
'programing' 카테고리의 다른 글
Maria에서 암호 재시도 횟수를 설정할 수 없습니다.DB (0) | 2022.09.14 |
---|---|
PHP: 문자열의 공백을 %20으로 변환하시겠습니까? (0) | 2022.09.14 |
apache error.log의 "notice" child pid XXXX 종료 신호 Segmentation fault (11)" (0) | 2022.09.14 |
Composer를 사용하여 특정 버전의 패키지를 설치하는 방법 (0) | 2022.09.14 |
Http를 사용하여 응답 본문을 가져오는 방법URL 연결, 2xx 이외의 코드가 반환될 때? (0) | 2022.09.14 |