python,__slots__和“属性是只读的”

时间:2009-05-04 15:50:36

标签: python exception descriptor readonly-attribute

我想在python中创建一个具有一些属性的对象,我想保护自己不会意外地使用错误的属性名称。代码如下:

class MyClass( object ) :
    m = None # my attribute
    __slots__ = ( "m" ) # ensure that object has no _m etc

a = MyClass() # create one
a.m = "?"  # here is a PROBLEM

但是在运行这个简单的代码后,我得到一个非常奇怪的错误:

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    a.m = "?"
AttributeError: 'test' object attribute 'm' is read-only

有没有明智的程序员可以节省一些时间并让我了解“只读”错误?

5 个答案:

答案 0 :(得分:42)

使用__slots__声明实例变量时,Python会创建一个descriptor object作为具有相同名称的类变量。在您的情况下,此描述符将被您在以下行定义的类变量m覆盖:

  m = None # my attribute

以下是您需要做的事情:不要定义名为m的类变量,并在m方法中初始化实例变量__init__

class MyClass(object):
  __slots__ = ("m",)
  def __init__(self):
    self.m = None

a = MyClass()
a.m = "?"

作为旁注,具有单个元素的元组在元素后面需要逗号。两者都在您的代码中工作,因为__slots__接受单个字符串或可迭代/字符串序列。通常,要定义包含元素1的元组,请使用(1,)1,而不是(1)

答案 1 :(得分:14)

您完全滥用__slots__。它阻止为实例创建__dict__。这只有在遇到许多小对象的内存问题时才有意义,因为摆脱__dict__可以减少占用空间。这是一项核心优化,在99.9%的情况下都不需要。

如果您需要您所描述的那种安全性,那么Python确实是错误的语言。更好地使用像Java这样严格的东西(而不是尝试用Python编写Java)。

如果你无法弄清楚为什么类属性会在你的代码中引起这些问题,那么你可能应该三思而行,就像这样引入语言黑客。首先要更熟悉这门语言可能会更明智。

为了完整起见,这里是documentation link for slots

答案 2 :(得分:7)

__slots__适用于实例变量,而你拥有的是一个类变量。这就是你应该这样做的方式:

class MyClass( object ) :
  __slots__ = ( "m", )
  def __init__(self):
    self.m = None

a = MyClass()
a.m = "?"       # No error

答案 3 :(得分:6)

考虑一下。

class SuperSafe( object ):
    allowed= ( "this", "that" )
    def __init__( self ):
        self.this= None
        self.that= None
    def __setattr__( self, attr, value ):
        if attr not in self.allowed:
            raise Exception( "No such attribute: %s" % (attr,) )
        super( SuperSafe, self ).__setattr__( attr, value )

更好的方法是使用单元测试进行此类检查。这是一个相当大的运行时开销。

答案 4 :(得分:0)

class MyClass( object ) :
    m = None # my attribute

m这里是类属性,而不是实例属性。您需要在__init__中通过self将其与您的实例相关联。