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

问题描述 投票:0回答:6

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

是否有聪明的程序员可以抽出一点时间来启发我有关“只读”错误的信息?

python exception descriptor readonly-attribute
6个回答
49
投票

当您使用

__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,)
1,
而不是
(1)


11
投票

你完全误用了

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

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

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

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


7
投票

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

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

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

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 )

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


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

这里的

m
是类属性,而不是实例属性。您需要在
__init__
中自行将其与您的实例连接。


0
投票

这个问题早已得到解答,但我想我应该再添加一条注释,以防有人像我一样在搜索中遇到这个问题。自 2016 年提出此问题以来,Python 的错误报告已经不断发展,现在将失败并提供更多帮助:

ValueError: 'm' in __slots__ conflicts with class variable
© www.soinside.com 2019 - 2024. All rights reserved.