23

我想在 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

有没有聪明的程序员可以抽出一点时间来告诉我“只读”错误?

4

5 回答 5

46

当您使用 声明实例变量时__slots__,Python 会创建一个描述符对象作为具有相同名称的类变量。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,)or1,和 not (1)

于 2009-05-04T16:07:51.587 回答
12

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

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

如果您自己无法弄清楚为什么类属性会在您的代码中导致这些问题,那么也许您应该三思而后行地引入这样的语言技巧。首先更熟悉该语言可能会更明智。

为了完整起见,这里是slot 的文档链接

于 2009-05-04T20:05:24.620 回答
7

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

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

a = MyClass()
a.m = "?"       # No error
于 2009-05-04T16:02:54.873 回答
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 )

更好的方法是使用单元测试进行这种检查。这是相当多的运行时开销。

于 2009-05-04T17:06:55.173 回答
0
class MyClass( object ) :
    m = None # my attribute

这里m是类属性,而不是实例属性。您需要通过 self in 将它与您的实例连接起来__init__

于 2014-10-20T15:51:31.073 回答