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

发布于 2024-07-19 01:58:35 字数 512 浏览 12 评论 0原文

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

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

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:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

我一向站在原地 2024-07-26 01:58:35

当您使用 __slots__ 声明实例变量时,Python 会创建一个 描述符对象< /a> 作为同名的类变量。 在您的情况下,此描述符将被您在以下行中定义的类变量 m 覆盖:

  m = None # my attribute

以下是您需要执行的操作:不要定义名为 m 的类变量code>,并在__init__方法中初始化实例变量m

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

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

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

When you declare instance variables using __slots__, Python creates a descriptor object as 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:

  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.

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).

何时共饮酒 2024-07-26 01:58:35

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

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

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

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

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.

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).

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.

书间行客 2024-07-26 01:58:35

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

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

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

__slots__ works with instance variables, whereas what you have there is a class variable. This is how you should be doing it:

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

a = MyClass()
a.m = "?"       # No error
清秋悲枫 2024-07-26 01:58:35

考虑一下这一点。

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 )

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

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.

纵情客 2024-07-26 01:58:35
class MyClass( object ) :
    m = None # my attribute

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

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__.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文