在Python中,计算类中的变量数或阻止添加新的类变量 [英] In Python, count the number of variables in a class or prevent adding new class variables

查看:173
本文介绍了在Python中,计算类中的变量数或阻止添加新的类变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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
28

Also 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆