python, __slots__, and “attribute is read-only”

后端 未结 5 1221
無奈伤痛
無奈伤痛 2021-02-02 11:59

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:

<         


        
相关标签:
5条回答
  • 2021-02-02 12:03

    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.

    0 讨论(0)
  • 2021-02-02 12:06

    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.

    0 讨论(0)
  • 2021-02-02 12:07

    __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
    
    0 讨论(0)
  • 2021-02-02 12:10

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

    0 讨论(0)
  • 2021-02-02 12:17
    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__.

    0 讨论(0)
提交回复
热议问题