在Python中,计算类中的变量数或阻止添加新的类变量 [英] In Python, count the number of variables in a class or prevent adding new class variables
问题描述
在python中,有没有办法防止在定义对象后添加新的类变量?
例如:
class foo:
def __init __(self):
self.a = 1
self.b = 2
self.c = 3
bar = foo()
:
bar.d = 4
except Exception,e:
print我想让它总是打印
或者,有没有办法计算对象中变量的数量?
class foo:
def __init __(self):
self.a = 1
self.b = 2
self.c = 3
def count :
...
bar = foo()
如果bar.count()== 3:
print我想让它总是打印
我想到的唯一方法是使用字典或列表:
class foo:
def __int __(self):
self.dict = {'foo':1,'bar':2}
self.len = 2
def chk():
return self.len == len(self.list)
但是,这样做对于python来说很麻烦。 (obj.dict ['foo'])。如果可能的话,我更喜欢只是obj.foo。
我想要这样,所以当我要更改一个变量时,我不会不小心声明一个变量。 p>
f = foo()
f.somename = 3
...
f.simename = 4 #this is a typo
if f.somename == 3:
solve_everything()
感谢高级。
我建议使用 __ setattr __
,以避免
__ slots __
的怪异。
你总是要小心, code> __ setattr __ ,因为它需要设置所有实例属性,包括在 __ init __
。因此,它必须具有某种方式知道何时允许属性的设置,以及何时拒绝它。在这个解决方案中,我指定了一个特殊的属性来控制是否允许新的属性:
def __init __(self):
self.a = 1
self.b = 2
self.c = 3
self.freeze = True
def __setattr __(self,attr,value):
如果getattr(self,freeze,False)和不hasattr(self,attr):
raise AttributeError属性!)
super(A,self).__ setattr __(attr,value)
测试:
a = A()
try:
ad = 89
:
printIt works!
else:
print它不工作。
ac = 42
print aa
print ac
a.freeze = False
ad = 28
a.freeze = True
打印广告
结果:
它的工作!
1
42
28
另请参阅 gnibblers answer ,它将这个概念整齐地放在类装饰器中,因此它不会混淆类定义,并且可以在不重复代码的情况下重用在多个类中。
编辑:
这个回答一年后,我意识到一个上下文管理器可能解决这个问题更好。以下是gnibbler类装饰器的修改版本:
来自contextlib import contextmanager
@contextmanager
def declare_attributes(self):
self._allow_declarations = True
try:
yield
finally:
self._allow_declarations = False
def restrict_attributes(cls):
cls.declare_attributes = declare_attributes
def _setattr(self,attr,value):
disallow_declarations = not getattr(self,_allow_declarations,False)
如果disallow_declarations和attr!=_allow_declarations:
如果没有hasattr(self,attr):
raise AttributeError(你不应该设置属性!)
super(cls,self)。 __setattr __(attr,value)
cls .__ setattr__ = _setattr
return cls
$ b b
这里是如何使用它:
@restrict_attributes
class A(object):
def __init __(self):
with self.declare_attributes():
self.a = 1
self.b = 2
self.c = 3
所以每当你想设置新的属性,语句如上。也可以在实例外部执行:
a = A()
try:
ad = 89
except AttributeError:
printIt works!
else:
print它不工作。
ac = 42
print aa
print ac
with a.declare_attributes():
ad = 28
print ad
In python, is there a way to prevent adding new class variables after defining the object?
For example:
class foo: def __init__(self): self.a = 1 self.b = 2 self.c = 3 bar = foo() try: bar.d = 4 except Exception, e: print "I want this to always print"
Alternatively, is there a way to count the number of variables in an object?
class foo: def __init__(self): self.a = 1 self.b = 2 self.c = 3 def count(self): ... bar = foo() if bar.count() == 3: print "I want this to always print"
The only way I thought of doing this was using a dictionary or list:
class foo: def __int__(self): self.dict = {'foo':1, 'bar':2} self.len = 2 def chk(): return self.len == len(self.list)
However, doing this feels rather cumbersome for python. (obj.dict['foo']). I'd prefer just obj.foo if possible.
I want to have this so that I never accidentally declare a variable when I mean to change an existing one.
f = foo() f.somename = 3 ... f.simename = 4 #this is a typo if f.somename == 3: solve_everything()
Thanks in advanced.
解决方案I suggest using
__setattr__
to avoid the oddities of__slots__
.You always have to be careful when messing with
__setattr__
, since it takes care of setting all instance attributes, including those you set in__init__
. Therefore it has to have some way of knowing when to allow the setting of an attribute, and when to deny it. In this solution I've designated a special attribute that controls whether new attributes are allowed or not:class A(object): def __init__(self): self.a = 1 self.b = 2 self.c = 3 self.freeze = True def __setattr__(self, attr, value): if getattr(self, "freeze", False) and not hasattr(self, attr): raise AttributeError("You shall not set attributes!") super(A, self).__setattr__(attr, value)
Testing:
a = A() try: a.d = 89 except AttributeError: print "It works!" else: print "It doesn't work." a.c = 42 print a.a print a.c a.freeze = False a.d = 28 a.freeze = True print a.d
Result:
It works! 1 42 28Also see gnibblers answer that wraps this concept neatly up in a class decorator, so it doesn't clutter up the class definition and can be reused in several classes without duplicating code.
EDIT:
Coming back to this answer a year later, I realize a context manager might solve this problem even better. Here's a modified version of gnibbler's class decorator:
from contextlib import contextmanager @contextmanager def declare_attributes(self): self._allow_declarations = True try: yield finally: self._allow_declarations = False def restrict_attributes(cls): cls.declare_attributes = declare_attributes def _setattr(self, attr, value): disallow_declarations = not getattr(self, "_allow_declarations", False) if disallow_declarations and attr != "_allow_declarations": if not hasattr(self, attr): raise AttributeError("You shall not set attributes!") super(cls, self).__setattr__(attr, value) cls.__setattr__ = _setattr return cls
And here's how to use it:
@restrict_attributes class A(object): def __init__(self): with self.declare_attributes(): self.a = 1 self.b = 2 self.c = 3
So whenever you want to set new attributes, just use the
with
statement as above. It can also be done from outside the instance:a = A() try: a.d = 89 except AttributeError: print "It works!" else: print "It doesn't work." a.c = 42 print a.a print a.c with a.declare_attributes(): a.d = 28 print a.d
这篇关于在Python中,计算类中的变量数或阻止添加新的类变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!