1

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?

ephemient
  • 198,619
  • 38
  • 280
  • 391
chao zhou
  • 73
  • 1
  • 2
  • 10
  • This appears to possibly have been answered already: http://stackoverflow.com/questions/472000/ – ThorSummoner Jan 21 '15 at 00:34
  • As @ThorSummoner's link says, `__slots__` is mainly used to save space when you're creating a whole bunch of items whose attributes are constrained. You *shouldn't* use it to limit the attributes that a user can set. – jme Jan 21 '15 at 02:21
  • Plus one for an interesting question. – Russia Must Remove Putin Jan 21 '15 at 02:52
  • Chao, welcome to StackOverflow! If I answered your question, you can accept it by clicking the checkmark next to it and it will add plus 2 to your rep. Good luck as you learn Python! – Russia Must Remove Putin Jan 21 '15 at 05:47

5 Answers5

2

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

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
1

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.

Blckknght
  • 100,903
  • 11
  • 120
  • 169
0

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

kindall
  • 178,883
  • 35
  • 278
  • 309
0

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.

Dan D.
  • 73,243
  • 15
  • 104
  • 123
  • While this is a good point, it's not really an answer. Perhaps you can change the text around the code to make it into one? Otherwise, it should probably be a comment (alas, without the code). – Blckknght Jan 21 '15 at 04:47
-1

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.

fcm
  • 1,247
  • 15
  • 28