简体   繁体   中英

python when I use the '__slots__'

Recent I study Python,but I have a question about __slots__ . In my opinion, it is for limiting parameters in Class, but also limiting the method in Class?

For example:

from types import MethodType

Class Student(object):
  __slots__=('name','age')

When I run the code:

def set_age(self,age):
  self.age=age
stu=Student()
stu.set_age=MethodType(set_age,stu,Student)
print stu.age

An error has occurred:
stu.set_age=MethodType(set_age,stu,Student)
AttributeError: 'Student' object has no attribute 'set_age'

I want to know, why not use set_age for this class?

Using __slots__ means you don't get a __dict__ with each class instance, and so each instance is more lightweight. The downside is that you cannot modify the methods and cannot add attributes. And you cannot do what you attempted to do, which is to add methods (which would be adding attributes).

Also, the pythonic approach is not to instantiate a MethodType, but to simply create the function in the class namespace. If you're attempting to add or modify the function on the fly, as in monkey-patching, then you simply assign the function to the class, as in:

Student.set_age = set_age

Assigning it to the instance, of course, you can't do if it uses __slots__ .

Here's the __slots__ docs: https://docs.python.org/2/reference/datamodel.html#slots

In new style classes, methods are not instance attributes. Instead, they're class attributes that follow the descriptor protocol by defining a __get__ method. The method call obj.some_method(arg) is equivalent to obj.__class__.method.__get__(obj)(arg) , which is in turn, equivalent to obj.__class__.method(obj, arg) . The __get__ implementation does the instance binding (sticking obj in as the first argument to method when it is called).

In your example code, you're instead trying to put a hand-bound method as an instance variable of the already-existing instance. This doesn't work because your __slots__ declaration prevents you from adding new instance attributes. However, if you wrote to the class instead, you'd have no problem:

class Foo(object):
    __slots__ = () # no instance variables!

def some_method(self, arg):
    print(arg)

Foo.some_method = some_method     # this works!

f = Foo()
f.some_method()                   # so does this

This code would also work if you created the instance before adding the method to its class.

Your attribute indeed doesn't have an attribute set_age since you didn't create a slot for it. What did you expect?

Also, it should be __slots__ not __slots (I imagine this is right in your actual code, otherwise you wouldn't be getting the error you're getting).

Why aren't you just using:

class Student(object):
    __slots__ = ('name','age')

    def set_age(self,age):
        self.age = age

where set_age is a method of the Student class rather than adding the function as a method to an instance of the Student class.

Instead of __slots__ , I'm using the following method. It allow the use of only a predefined set of parameters:

class A(object):
   def __init__(self):
      self.__dict__['a']=''
      self.__dict__['b']=''

   def __getattr__(self,name):
      d=getattr(self,'__dict__')
      if d.keys().__contains__(name):
         return d.__dict__[attr]
      else:
         raise AttributeError

   def __setattr__(self,name,value):
      d=getattr(self,'__dict__')
      if d.keys().__contains__(name):
         d[name] = value
      else:
         raise AttributeError

The use of getattr(..) is to avoid recursion.

There are some merits usin __slots__ vs __dict__ in term of memory and perhaps speed but this is easy to implement and read.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM