class Foo(object):# Class variable, shared by all instances of this classcounter = 0
def __call__(self):Foo.counter += 1print Foo.counter
# Create an object instance of class "Foo," called "foo"foo = Foo()
# Make calls to the "__call__" method, via the object's name itselffoo() #prints 1foo() #prints 2foo() #prints 3
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()` inname `name` of calling function and return it.
:param name: name to use to store static objectin 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.aTraceback (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 functioncalling_fn_scope = stack()[2][0]# get calling functioncalling_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)
def Fibonacci(n):if n<2: return nFibonacci.memo=vars(Fibonacci).setdefault('memo',{}) # use static variable to hold a results cachereturn Fibonacci.memo.setdefault(n,Fibonacci(n-1)+Fibonacci(n-2)) # lookup result in cache, if not available then calculate and store it
既然你给出了一个写C++的例子,我将首先解释C++中的“函数对象”是什么。“函数对象”只是任何重载operator()的类。类的实例将表现得像函数。例如,你可以写int x = square(5);,即使square是一个对象(重载operator()),而不是技术上不是“函数”。你可以给函数对象任何可以给类对象的特征。
# C++ function objectclass 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定义:
class Foo_class:def __init__(self): # __init__ is similair to a C++ class constructorself.counter = 0# self.counter is like a static member# variable of a function named "foo"def __call__(self): # overload operator()self.counter += 1print("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 1counter is 2counter is 3counter is 4counter is 5
如果您希望您的函数接受输入参数,您也可以将这些参数添加到__call__:
# FILE: foo.py - - - - - - - - - - - - - - - - - - - - - - - - -
class Foo_class:def __init__(self):self.counter = 0def __call__(self, x, y, z): # overload operator()self.counter += 1print("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 1x, y, z, are 7, 8, 9counter is 2x, y, z, are 7, 8, 9counter is 3x, y, z, are 7, 8, 9counter is 4x, y, z, are 7, 8, 9counter is 5x, y, z, are 7, 8, 9
def Static():### get the func object by which Static() is called.from inspect import currentframe, getframeinfocaller = currentframe().f_backfunc_name = getframeinfo(caller)[2]# print(func_name)caller = caller.f_backfunc = 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.staticVarselse:# add an attribute to funcfunc.staticVars = StaticVars()return func.staticVars
如何使用:
def myfunc(arg):if Static().has('test1'):Static().test += 1else:Static().test = 1print(Static().test)
# declare() only takes effect in the first time for each static variable.Static().declare('test2', 1)print(Static().test2)Static().test2 += 1