d l*_*d l 3 python variables class count
在python中,有没有办法防止在定义对象后添加新的类变量?
例如:
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"
Run Code Online (Sandbox Code Playgroud)
或者,有没有办法计算对象中的变量数?
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"
Run Code Online (Sandbox Code Playgroud)
我想到这样做的唯一方法是使用字典或列表:
class foo:
def __int__(self):
self.dict = {'foo':1, 'bar':2}
self.len = 2
def chk():
return self.len == len(self.list)
Run Code Online (Sandbox Code Playgroud)
然而,这样做对于python来说感觉相当麻烦.(obj.dict [ '富']).如果可能的话,我更喜欢obj.foo.
我希望这样,以便在我意味着更改现有变量时,我从不会意外地声明变量.
f = foo()
f.somename = 3
...
f.simename = 4 #this is a typo
if f.somename == 3:
solve_everything()
Run Code Online (Sandbox Code Playgroud)
提前致谢.
我建议使用__setattr__
以避免奇怪的__slots__
.
在搞乱时总是要小心__setattr__
,因为它负责设置所有实例属性,包括你设置的那些属性__init__
.因此,它必须有一些方法知道何时允许设置属性,以及何时拒绝它.在这个解决方案中,我指定了一个特殊属性来控制是否允许新属性:
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)
Run Code Online (Sandbox Code Playgroud)
测试:
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
Run Code Online (Sandbox Code Playgroud)
结果:
It works! 1 42 28
另请参阅gnibblers的答案,它将这个概念整齐地包装在类装饰器中,因此它不会使类定义混乱,并且可以在不重复代码的情况下在多个类中重用.
编辑:
一年后回到这个答案,我意识到一个上下文管理器可能会更好地解决这个问题.这是gnibbler的类装饰器的修改版本:
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
Run Code Online (Sandbox Code Playgroud)
以下是如何使用它:
@restrict_attributes
class A(object):
def __init__(self):
with self.declare_attributes():
self.a = 1
self.b = 2
self.c = 3
Run Code Online (Sandbox Code Playgroud)
因此,只要您想设置新属性,只需使用with
上面的语句即可.它也可以从实例外部完成:
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
Run Code Online (Sandbox Code Playgroud)