简体   繁体   English

python当我使用'__slots__'

[英]python when I use the '__slots__'

Recent I study Python,but I have a question about __slots__ . 最近我研究Python,但我有一个关于__slots__的问题。 In my opinion, it is for limiting parameters in Class, but also limiting the method in Class? 在我看来,它是用于限制Class中的参数,还限制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? 我想知道,为什么不在这个类中使用set_age?

Using __slots__ means you don't get a __dict__ with each class instance, and so each instance is more lightweight. 使用__slots__意味着你没有得到每个类实例的__dict__ ,因此每个实例都更轻量级。 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. 此外,pythonic方法不是实例化MethodType,而是简单地在类命名空间中创建函数。 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__ . 当然,如果它使用__slots__ ,则无法将其分配给实例。

Here's the __slots__ docs: https://docs.python.org/2/reference/datamodel.html#slots 这是__slots__文档: https__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. 相反,它们是通过定义__get__方法遵循描述符协议的类属性。 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) . 调用obj.some_method(arg)方法等同于obj.__class__.method.__get__(obj)(arg) ,它相当于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). __get__实现执行实例绑定(在调用obj时将obj作为method的第一个参数)。

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. 这不起作用,因为__slots__声明阻止您添加新的实例属性。 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. 您的属性确实没有属性set_age因为您没有为它创建插槽。 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). 此外,它应该是__slots__而不是__slots (我想这在你的实际代码中是正确的,否则你不会得到你得到的错误)。

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. 其中set_ageStudent类的方法,而不是将函数作为方法添加到Student类的实例。

Instead of __slots__ , I'm using the following method. 而不是__slots__ ,我使用以下方法。 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. getattr(..)是为了避免递归。

There are some merits usin __slots__ vs __dict__ in term of memory and perhaps speed but this is easy to implement and read. 在内存和速度方面,__ __slots____dict__有一些优点,但这很容易实现和阅读。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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