Advanced Python [] 5-4 __slots__ / __call__

1 Introduction

Under normal circumstances, when we define a class, creates an instance of a class, we can bind any properties and methods to the examples, this is the flexibility of dynamic languages.
First define the class:

class Student(object):
    pass

Then, try to bind a property to an instance:

>>> s = Student()
>>> s.name = 'Michael' # 动态给实例绑定一个属性
>>> print(s.name)
Michael

You can also try to bind a method to an instance:

>>> def set_age(self, age): # 定义一个函数作为实例方法
...     self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25

However, a method to bind an example, another example is inoperative:

>>> s2 = Student() # 创建新的实例
>>> s2.set_age(25) # 尝试调用方法
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'set_age'

In order to give all instances are bound method, the method can be bound to the class:

>>> def set_score(self, score):
...     self.score = score
...
>>> Student.set_score = set_score

After binding to class method, all instances can be called:

>>> s.set_score(100)
>>> s.score
100
>>> s2.set_score(99)
>>> s2.score
99

Under normal circumstances, the above method may set_score defined directly in the class, but dynamic binding allows us to add a dynamic to the class during program running function, which is difficult to achieve in a static language.

2, __slots__

However, if we want to attribute limiting examples of how to do?
For example, adding only the name and age of the Student instance attributes.

To achieve the purpose of limitation, Python allows the definition of class time, the definition of a particular __slots__variable to limit the class instance attributes can be added:

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

Then, we try:

>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

Since the 'score' __slots__ not been put in, so the property can not bind score, trying to bind score will get AttributeError error.

Use __slots__ to be noted that, __ slots__ attributes defined only for the current instance of the class function, subclasses inherit is ineffective:

>>> class GraduateStudent(Student):
...     pass
...
>>> g = GraduateStudent()
>>> g.score = 9999

Unless define subclasses __slots__, this sub-class instance attribute is defined to allow itself plus __slots__ __slots__ parent class.

__slots__ is selected to limit the current class has attributes that can, if not add any dynamic properties using __slots__ can save memory.

task

Assuming that defines the Person class by name and gender __slots__, please continue to add score defined by __slots__ in a derived class Student in the Student class can implement name, gender, and score 3 attributes.

CODE

Student class __slots__ need only contain the score attribute to the Person class does not contain.

class Person(object):

    __slots__ = ('name', 'gender')

    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

class Student(Person):

    __slots__ = ('score',)

    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

s = Student('Bob', 'male', 59)
s.name = 'Tim'
s.score = 99
print s.score

Here Insert Picture Description

3, using __call__

In Python, an object is in fact a function of:

>>> f = abs
>>> f.__name__
'abs'
>>> f(-123)
123

Since f can be called so, f is called callable object.

All functions are callable objects.

A class instance can also become a callable object only needs to implement a particular method __call__().

We become a Person class callable:


class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

    def __call__(self, friend):
        print 'My name is %s...' % self.name
        print 'My friend is %s...' % friend
        

You can now direct calls to the Person instance:

>>> p = Person('Bob', 'male')
>>> p('Tim')
My name is Bob...
My friend is Tim...

Look p ( 'Tim') you can not determine p is an instance of a class or a function, therefore, in Python, is the difference between the object, the object function and the function is not significant.

task

Improved look at that number Fibonacci deed previously defined columns:

class Fib(object):
    ???

Please add a __call__ way to make calls more simply:

>>> f = Fib()
>>> print f(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

CODE

class Fib(object):
    def __call__(self, num):
        a, b, L = 0, 1, []
        for n in range(num):
            L.append(a)
            a, b = b, a + b
        return L

f = Fib()
print f(10)

Here Insert Picture Description

Published 26 original articles · won praise 0 · Views 625

Guess you like

Origin blog.csdn.net/yipyuenkay/article/details/104555555