python当我使用' __ slots __'

时间:2015-01-20 23:27:03

标签: python

最近我研究Python,但我对__slots__有疑问。在我看来,它是限制Class中的参数,但也限制了Class?

中的方法

例如:

from types import MethodType

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

当我运行代码时:

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'

我想知道,为什么不在这个类中使用set_age?

5 个答案:

答案 0 :(得分:2)

使用__slots__表示您没有为每个类实例获取__dict__,因此每个实例都更轻量级。缺点是您无法修改方法,也无法添加属性。你不能做你想做的事情,即添加方法(这将添加属性)。

此外,pythonic方法不是实例化MethodType,而是简单地在类命名空间中创建函数。如果您正在尝试动态添加或修改该功能,如猴子修补,那么您只需将该功能分配给该类,如:

Student.set_age = set_age

将其分配给实例,当然,如果它使用__slots__则无法执行。

以下是__slots__文档: https://docs.python.org/2/reference/datamodel.html#slots

答案 1 :(得分:1)

在新样式类中,方法不是实例属性。相反,它们是通过定义__get__方法跟随descriptor protocol的类属性。方法调用obj.some_method(arg)相当于obj.__class__.method.__get__(obj)(arg),而obj.__class__.method(obj, arg)相当于__get__obj实现执行实例绑定(在调用method时将__slots__作为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 的第一个参数。)

在您的示例代码中,您尝试将手动绑定方法作为已存在实例的实例变量。这不起作用,因为您的{{1}}声明阻止您添加新的实例属性。但是,如果你写了这个课程,你就没有问题了:

{{1}}

如果在将方法添加到类之前创建了实例,则此代码也可以使用。

答案 2 :(得分:0)

您的属性确实没有属性set_age,因为您没有为其创建插槽。你有什么期望?

此外,它应该是__slots__而不是__slots(我想这在你的实际代码中是正确的,否则你不会得到你得到的错误。)

答案 3 :(得分:0)

为什么你不使用:

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

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

其中set_ageStudent类的方法,而不是将函数作为方法添加到Student类的实例。

答案 4 :(得分:0)

我使用以下方法代替__slots__。它只允许使用一组预定义的参数:

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

使用getattr(..)是为了避免递归。

在内存和速度方面,__slots__ vs __dict__有一些优点,但这很容易实现和阅读。