我需要一个像这样工作的课程:
>>> a=Foo()
>>> b=Foo()
>>> c=Foo()
>>> c.i
3
这是我的尝试:
class Foo(object):
i = 0
def __init__(self):
Foo.i += 1
它可以按要求运行,但我想知道是否有更多的pythonic方法可以做到。
答案 0 :(得分:13)
不。那很不错。
来自Python的禅宗:“简单比复杂更好。”
这很好,并且清楚你正在做什么,不要复杂化。也许可以将它命名为counter
或其他东西,但除此之外,你可以像pythonic那样去做。
答案 1 :(得分:5)
滥用装饰器和元类。
def counting(cls):
class MetaClass(getattr(cls, '__class__', type)):
__counter = 0
def __new__(meta, name, bases, attrs):
old_init = attrs.get('__init__')
def __init__(*args, **kwargs):
MetaClass.__counter += 1
if old_init: return old_init(*args, **kwargs)
@classmethod
def get_counter(cls):
return MetaClass.__counter
new_attrs = dict(attrs)
new_attrs.update({'__init__': __init__, 'get_counter': get_counter})
return super(MetaClass, meta).__new__(meta, name, bases, new_attrs)
return MetaClass(cls.__name__, cls.__bases__, cls.__dict__)
@counting
class Foo(object):
pass
class Bar(Foo):
pass
print Foo.get_counter() # ==> 0
print Foo().get_counter() # ==> 1
print Bar.get_counter() # ==> 1
print Bar().get_counter() # ==> 2
print Foo.get_counter() # ==> 2
print Foo().get_counter() # ==> 3
你可以通过频繁使用双重下划线名称来告诉它是Pythonic。 (开玩笑,开玩笑......)
答案 2 :(得分:4)
如果您想担心线程安全(以便可以从实例化Foo
s的多个线程修改类变量),上面的答案是正确的。我问了一个关于线程安全的问题here。总之,你必须做这样的事情:
from __future__ import with_statement # for python 2.5
import threading
class Foo(object):
lock = threading.Lock()
instance_count = 0
def __init__(self):
with Foo.lock:
Foo.instance_count += 1
现在可以从多个线程实例化Foo
。
答案 3 :(得分:0)
我们可以使用装饰器吗?例如,..
class ClassCallCount:
def __init__(self,dec_f):
self._dec_f = dec_f
self._count = 0
def __call__(self, *args, **kwargs):
self._count +=1
return self._dec_f(*args, **kwargs)
def PrintCalled(self):
return (self._count)
@ClassCallCount
def somefunc(someval):
print ('Value : {0}'.format(someval))
somefunc('val.1')
somefunc('val.2')
somefunc('val.3')
somefunc('val.4')
## Get the # of times the class was called
print ('of times class was called : {0}'.format(somefunc._count))