python、__slots__ 和“属性是只读的”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/820671/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
python, __slots__, and "attribute is read-only"
提问by grigoryvp
I want to create an object in python that has a few attributes and I want to protect myself from accidentally using the wrong attribute name. The code is as follows:
我想在 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
But after running this simple code, I get a very strange error:
但是在运行这个简单的代码之后,我得到了一个非常奇怪的错误:
Traceback (most recent call last):
File "test.py", line 8, in <module>
a.m = "?"
AttributeError: 'test' object attribute 'm' is read-only
Is there any wise programmer who can spare a bit of their time and enlighten me about "read-only" errors?
有没有聪明的程序员可以抽出一点时间来启发我有关“只读”错误的信息?
回答by Ayman Hourieh
When you declare instance variables using __slots__
, Python creates a descriptor objectas a class variable with the same name. In your case, this descriptor is overwritten by the class variable m
that you are defining at the following line:
当您使用 声明实例变量时__slots__
,Python 会创建一个描述符对象作为同名的类变量。在您的情况下,此描述符被m
您在以下行定义的类变量覆盖:
m = None # my attribute
Here is what you need to do: Do not define a class variable called m
, and initialize the instance variable m
in the __init__
method.
这里是你需要做的:不要定义一个名为 的类变量m
,并m
在__init__
方法中初始化实例变量。
class MyClass(object):
__slots__ = ("m",)
def __init__(self):
self.m = None
a = MyClass()
a.m = "?"
As a side note, tuples with single elements need a comma after the element. Both work in your code because __slots__
accepts a single string or an iterable/sequence of strings. In general, to define a tuple containing the element 1
, use (1,)
or 1,
and not (1)
.
作为旁注,具有单个元素的元组在元素后需要一个逗号。两者都在您的代码中工作,因为__slots__
接受单个字符串或可迭代/字符串序列。通常,要定义包含元素的元组1
,请使用(1,)
or1,
和 not (1)
。
回答by nikow
You are completely misusing __slots__
. It prevents the creation of __dict__
for the instances. This only makes sense if you run into memory problems with many small objects, because getting rid of __dict__
can reduce the footprint. This is a hardcore optimization that is not needed in 99.9% of all cases.
你完全在滥用__slots__
. 它可以防止__dict__
为实例创建。这仅在您遇到许多小对象的内存问题时才有意义,因为摆脱__dict__
可以减少占用空间。这是 99.9% 的情况下不需要的核心优化。
If you need the kind of safety you described then Python really is the wrong language. Better use something strict like Java (instead of trying to write Java in Python).
如果您需要您描述的那种安全性,那么 Python 确实是错误的语言。最好使用像 Java 这样严格的东西(而不是尝试用 Python 编写 Java)。
If you couldn't figure out yourself why the class attributes caused these problems in your code then maybe you should think twice about introducing language hacks like this. It would probably be wiser to become more familiar with the language first.
如果您无法弄清楚为什么类属性会在您的代码中导致这些问题,那么也许您应该在引入这样的语言技巧时三思而后行。首先更熟悉该语言可能会更明智。
Just for completeness, here is the documentation link for slots.
回答by RichieHindle
__slots__
works with instance variables, whereas what you have there is a class variable. This is how you should be doing it:
__slots__
使用实例变量,而您拥有的是一个类变量。这就是你应该这样做的方式:
class MyClass( object ) :
__slots__ = ( "m", )
def __init__(self):
self.m = None
a = MyClass()
a.m = "?" # No error
回答by S.Lott
Consider this.
考虑一下。
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 )
A better approach is to use unit tests for this kind of checking. This is a fair amount of run-time overhead.
更好的方法是使用单元测试进行这种检查。这是相当数量的运行时开销。
回答by pinseng
class MyClass( object ) :
m = None # my attribute
The m
here is the class attributes, rather than the instance attribute. You need to connect it with your instance by self in __init__
.
在m
这里是类属性,而不是实例属性。您需要通过 self in 将其与您的实例连接__init__
。