A variety of techniques and methods of writing a class in Python

Brief introduction

For the preparation of a variety of techniques and methods in the Python class (Construction and initialization, overloaded operators, the class description, the access control attributes, the custom sequence, reflection, callable, context management, constructed descriptor object, Pickling). You can use it as a tutorial, Advanced, or the use of reference; I hope it can become a user-friendly guide for Python methods.

Content Directory

介绍
构建和初始化
使操作符在自定义类内工作
神奇方法——比较
神奇方法——数字
描述你的类
属性访问控制
制作自定义序列
反射
可调用对象
上下文管理
构建描述符对象
Pickling 你的对象

总结
附录:如何调用神奇方法

1 Introduction

This guide is a few months most valuable Blog contributor essence. Its subject is a magical method in Python to tell you.

What is the magic way to do that? They are all oriented in Python, it is some special method allows the definition of their class definitions add "magic" function. They always use double underscore (such as __ init__ or __ lt__), but their documentation is not well express it. All these magical methods appear in the official documentation of Python, but the content is relatively decentralized organizational structure also appears loose. There you will find a difficult example (though they are very good design, are described in detail in the language reference, and then will be accompanied by boring grammar descriptions, etc.).

So, I think that in order to solve a flaw in the Python documentation, and I intend to use more plain English, example-driven document to illustrate Python's magic methods. Then I began to spend a couple of weeks to write the blog, and now I have completed them, and together they set into a guide.

I hope you like it. Treat it as a tutorial, Advanced, or the use of reference; I hope it can become a user-friendly guide for Python methods.

2. Construction and initialization

I believe we are all familiar with the magic of the most basic methods __ init__. It can make you a custom initialization behavior of an object. And when I call = SomeClass the X-(), the init is not the first to be called. There are actually called new method, in fact, is that it creates an instance of it to pass any parameter initialization process to achieve the purpose of creation. At the end of the life cycle of the object, call del . Let these three magical methods closer look at it:

  • __ new__(cls,[...)

Instantiated object a __ new__ first method is called. Any other parameter passed to the __ init__ in the class. __new__ rarely used, it does have certain object, especially when a subclass inherits an immutable type (a tuple or a string) time. I do not intend to continue to thoroughly pursue new details, because it will not have much use, because in Python Docs already covered by a detailed description of the giant.

  • __ init__(self,[...)

Initialization class. It will get the initial call to build anything pass over (that is, for example, when we call x = SomeClass (10, 'foo'), __ init__ will pass over 10 and the 'foo' as a parameter in .__ init__ Python class definitions almost universally used)

  • __ del__(self)

If __ new__ and init is a configuration object, then del is the destructor. It does not achieve the declared del x (this code will not be interpreted as the X-. Del ()) behavior. Instead, it is defined as the behavior when an object is garbage. This can be quite useful for objects may require additional cleanup, such as sockets or file object. But be careful, and when the exit is interpreted, if the object is still alive state del there is no guarantee it will be executed, so this del not regulate alternative as good coding. (Like when you are finished always want to close a connection. But in fact, del vigilant when almost never executed, because it is in an unsafe condition is called a use!)

The contents of these together, it would be a __ __ del__ init__ and practical use cases:

from os.path import join
class FileObject:
'''对文件对象的包装,确保文件在关闭时得到删除'''

def __init__(self, filepath='~', filename='sample.txt'):
# 按filepath,读写模式打开名为filename的文件
self.file=open(join(filepath,filename), 'r+')

def __del__(self):
self.file.close()
del self.file

3. The operator makes work in the custom class

One of the advantages of using Python magical approach is that it provides a simple way to make objects behave like built-in types. This means you can avoid using ugly, counter-intuitive and non-standard methods to perform basic operations. In some languages, usually do:

if instance.equals(other_instance):
# do something

You should really do in Python, but it will increase the user's confusion and unnecessary lengthy. Different libraries may have the same operation using different names, which makes the user more things done than usual. Rely on the power of magic methods, you can define a method (such as __ eq__), then instead of with our true intentions:

if instance == other_instance:
# do something

Now you see is part of the magic power of the method. The vast majority have allowed us to define the meaning of the operator itself, when used in the definition of the class of our own as if they were built-in types.

3.1 Method magic - Compare

Python is a set of methods designed to magic visual comparison between objects is achieved by the operator, rather awkward method invocation. They also provide a comparison of coverage Python default behavior (by reference). The following is a list of these methods and practices:

__ cmp__(self, other)

__ cmp__ is the most basic method magical one. In fact, it acts to implement all comparison operators (<, ==,! =, Etc.), but it may not follow the way you want to work (for example, one instance is equal to another depending on the criterion of comparison, and one example is greater than the other it also depends on other criteria). If self <other, that cmp should return a negative integer; if self == other, then return 0; if self> other, returns a positive integer. It is usually best defined, without requiring you to first define good on the whole they are, but when you need to make all comparisons with similar criteria when, cmp would be a good way to help you save and improve the repeatability clear degree.

__ eq__(self, other)

定义了相等操作符,==的行为。

__ ne__(self, other)

定义了不相等操作符,!= 的行为。

__ lt__(self, other)

定义了小于操作符,< 的行为。

__ gt__(self, other)

定义了大于操作符,> 的行为。

__ le__(self, other)

定义了小于等于操作符,<=的行为。

__ ge__(self, other)

定义了大于等于操作符,>= 的行为。

As an example, consider the word be the class definition. We might want to be able to press the internal default behavior for string comparison, that is lexicographically (by letter) to compare the words, hope can be based on some other criteria, such as length or number of syllables. In this example, we sorted by word length, to achieve given below:

class Word(str):
'''单词类,比较定义是基于单词长度的'''

def __new__(cls, word):
# 注意,我们使用了__new__,这是因为str是一个不可变类型,
# 所以我们必须更早地初始化它(在创建时)
if ' ' in word:
print "单词内含有空格,截断到第一部分"
word = word[:word.index(' ')] # 在出现第一个空格之前全是字符了现在
return str.__new__(cls, word)

def __gt__(self, other):
return len(self) > len(other)
def __lt__(self, other):
return len(self) < len(other)
def __ge__(self, other):
return len(self) >= len(other)
def __le__(self, other):
return len(self) <= len(other)

Now, we can create two words (by Word ( 'foo') and Word ( 'bar')) and compared based on their length. Note that we do not define __ eq__ and __ ne__. This is because it may lead to some strange behavior (especially when compared to Word ( 'foo') == Word ( 'bar') will get the results of True). More likely it is lost in the mind based on equal word length, so we followed the implementation of relatively equal str itself.

Now might be a good time to remind you, you do not have to reload each associated with a more magical way to get a variety of comparison. The standard library has been kind enough to provide us with a decorated (decorator) class template functools, the definition of all the comparative method. You can just reload __ eq__ and one of the other methods (such as gt__ __, lt , etc.). This feature is only Python2.7 (after?) Applies, but when you have the opportunity, should try it, it would save a lot of time and trouble for you. You can in your own overloaded methods to use plus @total_ordering.

3.2 magic method - Digital

As you can create your own class instance by way of comparison operator overloading, you can also reload digital operator. Fasten your seat belts, friends, and a lot of it. The paper is organized in need, I'll method magic number is divided into 5: unary operator, the conventional arithmetic operators, arithmetic operators reflected incremental assignment, the type of conversion.

Unary operator

Only a few functions and unary operation, such as a negative number, the absolute value of the like

__ pos__(self)

实现一元正数的行为(如:+some_object)

__ neg__(self)

实现负数的行为(如: -some_object)

__ abs__(self)

实现内建 abs() 函数的行为

__ invert__(self)

实现用~操作符进行的取反行为。你可以参考 Wiki:bitwise operations 来解释这个运算符究竟会干什么
常规算术操作符

现在我们涵盖了基本的二元运算符:+,-,* 等等。其中大部分都是不言自明的。

__ add__(self, other)

实现加法

__ sub__(self, other)

实现减法

__ mul__(self, other)

实现乘法

__ floordiv__(self, other)

实现地板除法,使用 // 操作符

__ div__(self, other)

实现传统除法,使用 / 操作符

__ truediv__(self, other)

实现真正除法。注意,只有当你 from __ future__ import division 时才会有效

__ mod__(self, other)

实现求模,使用 % 操作符

__ divmod__(self, other)

实现内建函数 divmod() 的行为

__ pow__(self, other)

实现乘方,使用 ** 操作符

__ lshift__(self, other)

实现左按位位移,使用 << 操作符

__ rshift__(self, other)

实现右按位位移,使用 >> 操作符

__ and__(self, other)

实现按位与,使用 & 操作符

__ or__(self, other)

实现按位或,使用 | 操作符

__ xor__(self, other)

实现按位异或,使用 ^ 操作符

Reflection arithmetic operators

You know how I'll explain reflection arithmetic operators? Some of you might think it is very, very frightening, is the concept abroad. But it is actually very simple, below give an example:

some_object + other

This is the "normal" addition. It is the equivalent thing while reflecting, in addition to changing the location of the operand changes:

other + some_object

Accordingly, all such methods will magic do the same thing is equivalent to the conventional arithmetic operators, in addition to changing the positional relationship of the number of operations, such as a first operand and a second itself. In addition there is no other mode of operation. In most cases, the results reflected arithmetic operation is equivalent to the conventional arithmetic operation, so you can do just overloaded finished __ radd__ is called in the Add . Altogether happy:

__radd__(self, other)

实现反射加法

__rsub__(self, other)

实现反射减法

__rmul__(self, other)

实现反射乘法

__rfloordiv__(self, other)

实现反射地板除,用 // 操作符

__rdiv__(self, other)

实现传统除法,用 / 操作符

__rturediv__(self, other)

实现真实除法,注意,只有当你 from __future__ import division 时才会有效

__rmod__(self, other)

实现反射求模,用 % 操作符

__rdivmod__(self, other)

实现内置函数 divmod() 的长除行为,当调用 divmod(other,self) 时被调用

__rpow__(self, other)

实现反射乘方,用 ** 操作符

__rlshift__(self, other)

实现反射的左按位位移,使用 << 操作符

__rrshift__(self, other)

实现反射的右按位位移,使用 >> 操作符

__rand__(self, other)

实现反射的按位与,使用 & 操作符

__ror__(self, other)

实现反射的按位或,使用 | 操作符

__rxor__(self, other)

实现反射的按位异或,使用 ^ 操作符

Augmented assignment

Python also has a variety of magical methods allow users to customize the behavior of the incremental assignment. You may already be familiar with augmented assignment, which combines "conventional" operators and assignment. If you still do not understand what I'm saying, here's an example:

x = 5
x += 1 # 等价 x = x + 1

These methods will not have a return value, because the assignment in Python does not have any return value. Instead, they just change the state of the class. List is as follows:

__iadd__(self, other)

实现加法和赋值

__isub__(self, other)

实现减法和赋值

__imul__(self, other)

实现乘法和赋值

__ifloordiv__(self, other)

实现地板除和赋值,用 //= 操作符

__idiv__(self, other)

实现传统除法和赋值,用 /= 操作符

__iturediv__(self, other)

实现真实除法和赋值,注意,只有当你 from __future__ import division 时才会有效

__imod__(self, other)

实现求模和赋值,用 %= 操作符

__ipow__(self, other)

实现乘方和赋值,用 **= 操作符

__ilshift__(self, other)

实现左按位位移和赋值,使用 <<= 操作符

__irshift__(self, other)

实现右按位位移和赋值,使用 >>= 操作符

__iand__(self, other)

实现按位与和赋值,使用 &= 操作符

__ior__(self, other)

实现按位或和赋值,使用 |= 操作符

__ixor__(self, other)

实现按位异或和赋值,使用 ^= 操作符

Magical type conversion method

Python is also a set of magic methods are designed to implement the behavior of the built-in type conversion function, such as a float ()

__int__(self)

实现到 int 的类型转换

__long__(self)

实现到 long 的类型转换

__float__(self)

实现到 float 的类型转换

__complex__(self)

实现到复数的类型转换

__oct__(self)

实现到 8 进制的类型转换

__hex__(self)

实现到 16 进制的类型转换

__index__(self)

实现一个当对象被切片到 int 的类型转换。如果你自定义了一个数值类型,考虑到它可能被切片,所以你应该重载__index__

__trunc__(self)

当 math.trunc(self) 被调用时调用。__trunc__ 应当返回一个整型的截断,(通常是 long)

__coerce__(self, other)

该方法用来实现混合模式的算术。如果类型转换不可能那 __coerce__ 应当返回 None。 否则,它应当返回一对包含 self 和 other(2 元组),且调整到具有相同的类型

4. Describe your class

With a character string which illustrate a class is often useful. Provides a number of methods in Python allows you to customize the built-in function returns the description of your class act in your own class.

__str__(self)

当你定义的类中一个实例调用了 str(),用于给它定义行为

__repr__(self)

当你定义的类中一个实例调用了 repr(),用于给它定义行为。 str() 和 repr() 主要的区别在于它的阅读对象。 repr() 产生的输出主要为计算机可读(在很多情况下,这甚至可能是一些有效的 Python 代码),而 str() 则是为了让人类可读。

__unicode__(self)

当你定义的类中一个实例调用了 unicode(),用于给它定义行为。 unicode() 像是 str(),只不过它返回一个 unicode 字符串。 警惕!如果用户用你的类中的一个实例调用了 str(),而你仅定义了 __unicode__(),那它是不会工作的。 以防万一,你应当总是定义好 __str__(),哪怕用户不会使用 unicode

__hash__(self)

当你定义的类中一个实例调用了 hash(),用于给它定义行为。 它必须返回一个整型,而且它的结果是用于来在字典中作为快速键比对。

__nonzero__(self)

当你定义的类中一个实例调用了 bool(),用于给它定义行为。 返回 True 或 False,取决于你是否考虑一个实例是 True 或 False 的。

We have finished the job quite nicely magical method boring part (no example), so far we have discussed some of the basic methods of magic, it's time for us to move to senior topic.

The access control attribute

There are many other languages ​​to Python from the camp to the people complaining about the lack of real Python class of package (for example, there is no way to customize private property, it has been given public getter and setter). This is not the truth yo: Python implements much of the package by magical way, rather than through explicit method or field modifiers.

Take a look:

__ getattr__(self, name)

You can define its behavior when a user is trying to access class properties (whether present or not yet established) does not exist. This capture and redirect common spelling errors, use property given warning is useful (as long as you want, you still optional calculation, return the property) or throw an exception AttributeError. This method applies only to access a property that does not exist, so this is not a real package solution.

__ setattr__(self, name, value)

Unlike getattr__ __, setattr is a packaging solution. It allows behavior when you assign to a property, whether this property exists. This means you can change any attribute values of custom rules. However, you need to care about is that you have to be careful to use setattr , will be given as an example later in the list.

__ delattr__

This is equivalent to __ setattr__, but as a class attribute instead set delete them. It requires the same precautions as setattr , prevent infinite recursion (when delattr call del self.name cause infinite recursion).

__ getattribute__(self, name)

__ getattribute__ well suited to its companions __ setattr__ and __ delattr__. But I do not recommend you use it. getattribute can only be used in the new class (the latest version of Python, all classes are the new class, in slightly older versions you can create a new class by inheriting object class. It allows you to set the rules, in any regardless of when a class attribute value at that time whether or not accessible.) it would be wrong because his companion in guilt plagued by some infinite recursion problem (when you can call the base class getattribute to prevent method). When getattribute be achieved but only if this method is called getattribute is explicitly call or throw a AttributeError exception, while also avoiding the main getattr dependent. This method can be used (after all, it's your own choice), but I do not recommend it because it has a small use case (though relatively rare, but we need to get a special behavior rather than the value assigned) and it really It is very difficult to achieve 0bug.

You can easily lead to a problem when you customize any class attribute access methods. Reference this example:

def __setattr__(self, name, value):
self.name = value
# 当每次给一个类属性赋值时,会调用__setattr__(),这就形成了递归
# 因为它真正的含义是 self.__setattr__('name', value)
# 所以这方法不停地调用它自己,变成了一个无法退出的递归最终引发crash

def __setattr__(self, name, value):
self.__dict__[name] = value # 给字典中的name赋值
# 在此自定义行为

Again, Python's magic methods to show us their incredible ability, tremendous power while also accompanied by great responsibility. It is important to let you know the proper use of magic methods, so you do not damage other code.

So, what we have learned about the custom attribute access class? Do not use the fact that it is too strong and counterintuitive. This is also the reason why it exists: Python seek the possibility to do bad things, but they will disfigured. Freedom is paramount, so you can do anything you want. The following is a practical example of the special properties of the access method (note that we use super as not all classes have __ dict__ class attributes):

class AccessCounter:
'''一个类包含一个值和实现了一个访问计数器。
当值每次发生变化时,计数器+1'''

def __init__(self, val):
super(AccessCounter, self).__setattr__('counter',0)
super(AccessCounter, self).__setattr__('value', val)

def __setattr__(self, name, value):
if name == 'value':
super(AccessCounter, self).__setattr__('counter', self.counter + 1)
# Make this unconditional.
# 如果你想阻止其他属性被创建,抛出AttributeError(name)异常
super(AccessCounter, self).__setattr__(name, value)

def __delattr__(self, name)
if name == 'value':
super(AccessCounter, self).__setattr__('counter', self.counter + 1)
super(AccessCounter, self).__delattr__(name)

6. Make a custom sequence

Quite a number of ways you can make your class act like built-in sequence (dictionaries, tuples, lists, strings, etc.). These are by far the most magical way I like, because they are irrational control gives you a sense magically make your entire global function Array class instance beautiful way to work. Before we begin to explain this content, let's take a quick sort out the demand.
demand

Now we are talking about how to create your own sequence. What is the talk of the protocol. protocol in some places very similar interface. Interface in other languages, is a group of a given method, and you have to define them. However, in Python protocol is totally informal, and does not require an explicit statement to achieve. Furthermore, they are more like guidelines.

Why do we now want to talk about protocol? Since in Python to implement a custom type of container that will involve the use of some of the protocol.

First, there is a protocol for defining immutable containers: In order to make an immutable container, you only need to define __ len__ and __ getitem __ (more on that later). Protocol requires that all non-variable container varactor increase setitem and delItem . Then, if you want your object is iterative, you have to define an iterator will return the iterator iter method. And this iteration iterator must comply with a protocol, which is required to have a callback method iterator iter (return itself) and next.
Magic hidden behind container

I can not wait? The following is the magic of the container used:

__ len__(self)

返回容器的长度。部分 protocol 同时支持可变和不可变容器

__ getitem__(self, key)

定义当某一个 item 被访问时的行为,使用 self[key] 表示法。 这个同样也是部分可变和不可变容器 protocol。 这也可抛出适当的异常: TypeError 当 key 的类型错误,或没有值对应 Key 时。

__ setitem__(self, key, value)

定义当某一个 item 被赋值时候的行为,使用 self[key]=value 表示法。 这也是部分可变和不可变容器 protocol。 再一次重申,你应当在适当之处抛出 KeyError 和 TypeError 异常。

__delitem__(self, key)

定义当某一个 item 被删除(例如 del self[key])时的行为。 这仅是部分可变容器的 protocol。在一个无效key 被使用后,你必须抛出一个合适的异常。

__ iter__(self)

应该给容器返回一个迭代器。 迭代器会返回若干内容,大多使用内建函数 iter() 表示。 当一个容器使用形如 for x in container: 的循环。 迭代器本身就是其对象,同时也要定义好一个 __iter__ 方法来返回自身。

__ reversed__(self)

当定义调用内建函数 reversed() 时的行为。应该返回一个反向版本的列表。

__ contains__(self, item)

__ contains__ 为成员关系,用 in 和 not in 测试时定义行为。 那你会问这个为何不是一个序列的 protocol 的一部分? 这是因为当 __contains__ 未定义,Python 就会遍历序列,如果遇到正在寻找的 item 就会返回True。

__ concat__(self, other)

最后,你可通过 __concat__ 定义你的序列和另外一个序列的连接。 应该从 self 和 other 返回一个新构建的序列。 当调用 2 个序列时 __concat__ 涉及操作符 +

one example

In our example, let's look at some of the features of the building on the basis of a list to achieve. It may make you think of other language you use (such as Haskell).

class FunctionalList:
'''类覆盖了一个list的某些额外的功能性魔法,像head,
tail,init,last,drop,and take'''
def __init__(self, values=None):
if values is None:
self.values = []
else:
self.values = values

def __len__(self):
return len(self.values)

def __getitem__(self, key):
# 如果key是非法的类型和值,那么list valuse会抛出异常
return self.values[key]

def __setitem__(self, key, value):
self.values[key] = value

def __delitem__(self, key):
del self.values[key]

def __iter__(self):
return iter(self.values)

def __reversed__(self):
return reversed(self.values)

def append(self, value):
self.values.append(value)
def head(self):
# 获得第一个元素
return self.values[0]
def tail(self):
# 获得在第一个元素后的其他所有元素
return self.values[1:]
def init(self):
# 获得除最后一个元素的序列
return self.values[:-1]
def last(last):
# 获得最后一个元素
return self.values[-1]
def drop(self, n):
# 获得除前n个元素的序列
return self.values[n:]
def take(self, n):
# 获得前n个元素
return self.values[:n]

Through this (lightweight) useful example you know how to implement your own sequence. Of course, there are many more useful applications, but many of them have been standard library implementation, like Counter, OrderedDict, NamedTuple

7. reflection

You may also be controlled by defining how magical reflection method using a built-in function behavior isinstance () and issubclass () of. These magic methods are:

__instancecheck__(self, instance)

检查一个实例是否是你定义类中的一个实例(比如,isinstance(instance, class))

__subclasscheck__(self, subclass)

检查一个类是否是你定义类的子类(比如,issubclass(subclass, class))

It may be small for a use case scenario for the magic method, but it really is true. I do not want to spend too much time reflecting the above methods, because they are not so important. But they reflect in Python object-oriented programming about something important, and generally in Python: always looking for an easy way to do something, even if it is not much used. These methods seem magical looks less and less useful, but when you need to use them when you will be grateful for their presence (and you read this guide!).

8. callables

As you may already know, in Python functions are first-class objects. This means they can be passed to functions and methods, just like any type of object. This is a powerful feature incredible.

This is a special magic in Python method, which allows instances of your class like a function. So you can "call" them, using them as parameters passed to the function, and so on. This is another powerful and convenient features make Python programming becomes more lovely.

__ call__(self, [args...])

Allow class instance like a function is called. Essentially, this means that x () is equivalent to x .__ call __ (). Note, call the required number of parameters is variable, which means you can define the parameters according to your preferences define any number of function call

__ call__ can be extremely useful for instance for those who frequently change the state of. Examples of the "call" is a follow the intuition and elegant way to change the object's state. The following is an example of a class represents a physical position on a plane:

class Entity:
'''描述实体的类,被调用的时候更新实体的位置'''

def __init__(self, size, x, y):
self.x, self.y = x, y
self.size = size

def __call__(self, x, y):
'''改变实体的位置'''
self.x, self.y = x, y

#省略...

9. Context Management

Introduced a new keyword (with) in the Python2.5 in such a new method to obtain code reuse. Context management concept in Python already is not new (before it is implemented as part of the library too), but only until PEP343 achieved important status as a first class language structure is accepted. You may already have seen with the statement:

with open('foo.txt') as bar:
# 对bar执行某些动作

Context management allows the object to be disposed and cleaning operation performed with the operation has been packaged with the statement. Behavioral context of the operation depends on two magic Method:

__ enter__(self)

Context management should start doing what the definition of a block in the block when it is created with the with statement. Note, the Enter the name of the return must be bound with a statement of goals, or behind as value.

__ exit__(self, exception_type, exception_value, traceback)

After the defined block execution (or termination) context management should do. It can be used to handle exceptions, clean up, or some action in the matter after the block is always processed immediately. If the block execution is successful, excepteion_type, exception_value, and traceback will be set to None. Otherwise, you can choose to handle the exception, or make your own to deal with. If you want to deal with, to ensure that after the completion of all __ exit__ returns True. If you do not want to handle exceptions management context, it would be better to let it happen.

__ enter__ and __ exit__ is useful for those who have a well-defined and special classes have common behavior settings, clean up the act. You can also use these methods to create a package of other objects general context management. See the examples below:

class Closer:
'''用with声明一个上下文管理用一个close方法自动关闭一个对象'''

def __init__(self, obj):
self.obj = obj

def __enter__(self):
return self.obj # 绑定目标

def __exit__(self, exception_type, exception_val, trace):
try:
self.obj.close()
except AttributeError: #obj不具备close
print 'Not closable.'
return True # 成功处理异常

The following is a demonstration of (a closable socket) Closer One example of a practical application, the use of an FTP connection:

>>> from magicmethods import Closer
>>> from ftplib import :;;
>>> with Closer(FTP('ftp.somsite.com')) as conn:
... conn.dir()
...
# 省略的输出
>>> conn.dir()
# 一个很长的AttributeError消息, 不能关闭使用的一个连接
>>> with Closer(int(5)) as i:
... i += 1
...
Not closeable.
>>> i
6

We saw how beautifully packaged deal with correct or incorrect use cases yet? That is the power of magic and context management methods.

10. Construction descriptor object

Descriptor may be changed to other objects, may be accessible to any one class of getting, setting, deleting. Descriptor does not mean isolation; rather, they are meant to control their owner class. When building or object-oriented database that interdependent class has attributes, descriptors are useful. Even more useful if the descriptor is calculated at several distinct elements or attributes described.

As a descriptor, a class must implement at least get__ __, SET , and __delete__ one. Let's quickly look at these magical methods it:

__ get__(self, instance, owner)

Define its behavior when the value of the descriptor is retrieved. instance is an instance of the object owner, owner of all classes.

__ set__(self, instance, value)

Define its behavior when the value of the descriptor is changed. instance is an instance of the object owner, value is the value set descriptor

__ delete__(self, instance)

Define its behavior when the value of the descriptor is deleted. instance is an instance of the object owner.

Now, there is a useful descriptor application example: unit conversion policy

class Meter(object):
'''米描述符'''

def __init__(self, value=0.0):
self.value = float(value)
def __get__(self, instance, owner):
return self.value
def __set__(self, instance, value):
self.value = float(value)

class Foot(object):
'''英尺描述符'''

def __get__(self, instance, owner):
return instance.meter * 3.2808
def __set__(self, instance, value):
instance.meter = float(value) / 3.2808

class Distance(object):
'''表示距离的类,控制2个描述符:feet和meters'''
meter = Meter()
foot = Foot()

11.Pickling your object

If you take the time and other Pythonistas deal, then you have probably at least heard of the word Pickling. Pickling process is a sequence of data structures Python. If you need to store an object, and then retrieve it later (usually for caching) then it is extraordinarily useful. At the same time, it also generates a major source of anxiety and confusion.

Pickling is so important that it not only has its own specific modules (pickle), also has its own protocol and magical methods accompany it. But first a brief text to explain under what type of pickle that already exists (if you've got it feel free to skip this section)
Pickling: quick immersion in salt water

Let's jump into the pickling. Saying you have a dictionary you want to save and retrieve it later. You can put it writes the contents of a file to go, need to be very careful to make sure you write the correct syntax, and then use the exec () or enter the processing of documents retrieved written content. But it is unstable: if you save your important data in plain text, it may be altered in several ways, cause your program to crash or run malicious code on your computer and errors. So, we are ready to pickle it:

import pickle

data = {'foo': [1,2,3],
'bar': ('Hello','world!'),
'baz': True}
jar = open('data.pk1', 'wb')
pickle.dump(data, jar) # 把pickled数据写入jar文件
jar.close()

Well now, a few hours have passed. We want to collect data, but we need to do is just unpickle it:

import pickle

pk1_file = open('data.pk1','rb') #连接pickled数据
data = pickle.load(pk1_file) #把数据load到一个变量中去
print data
pk1_file.close()

What happened? As you expected, we get the data.

Now, I want to give you some advice: pickling is not perfect. Pickle files easily due to accidental or willful acts were damaged. Pickling may use than plain text files safer, but it is still likely to be used to run malicious code. Because there are incompatibilities Python version, so do not expect publish Pickled objects do not expect people to be able to open them. However, it is still a powerful tool for caching and other common sequence of tasks.

Pickling the object of your custom

Pickling be used not only in the built-in type, may also be used to comply with any pickle protocol class. pickle protocol has four optional methods for how to customize the Python object to run (this extension with the C bit different, but that is not within the scope of our discussion):

__ getinitargs__(self)

如果你想当你的类 unpickled 时调用 __ init__,那你可以定义__ getinitargs__,该方法应该返回一个元组的参数,然后你可以把他传递给 __ init__。注意,该方法仅适用于旧式类。

__ getnewargs__(self)

对于新式类,你可以影响有哪些参数会被传递到 __new__ 进行 unpickling。 该方法同样应该返回一个元组参数,然后能传递给 __new__

__getstate__(self)

代替对象的 __dict__ 属性被保存。 当对象 pickled,你可返回一个自定义的状态被保存。 当对象 unpickled 时,这个状态将会被 __setstate__ 使用。

__setstate__(self, state)

对象 unpickled 时,如果 __setstate__ 定义对象状态会传递来代替直接用对象的 __dict__ 属性。 这正好跟__getstate__ 手牵手:当二者都被定义了,你可以描述对象的 pickled 状态,任何你想要的。

one example:

Our example is Slate class, it will remember its former value and the value has been written. However, when this special slate will be cleared every pickle: The current value will not be saved.

import time

class Slate:
'''存储一个字符串和一个变更log,当Pickle时会忘记它的值'''

def __init__(self, value):
self.value = value
self.last_change = time.asctime()
self.history = {}

def change(self, new_value):
# 改变值,提交最后的值到历史记录
self.history[self.last_change] = self.value
self.value = new_value
self.last_change = time.asctime()

def print_changes(self):
print 'Changelog for Slate object:'
for k, v in self.history.items():
print '%st %s' % (k, v)

def __getstate__(self):
# 故意不返回self.value 或 self.last_change.
# 当unpickle,我们希望有一块空白的"slate"
return self.history

def __setstate__(self, state):
# 让 self.history = state 和 last_change 和 value被定义
self.history = state
self.value, self.last_change = None, None

12. summary

The objective of this guide is to anyone to read it, regardless of whether readers have Python or object-oriented programming experience. If you are ready to learn Python, then you've got to write feature-rich, elegant, easy to use class of valuable knowledge. If you are an intermediate Python programmer, you may have picked up some new concepts and strategies and some good ways to reduce the amount of code you write and your users. If you are a Pythonista expert, you may have reviewed some of you may have been forgotten your knowledge, or with you and learn some new tricks. No matter what your level of experience, I hope this magical journey Python method reached a truly magical effect. (I can not control myself at last not a pun)

Appendix: If you call the magic method

Some magic Python method maps directly to a built-in function; in this case, invoke their methods are quite obvious. However, in other cases, those who call the method is not so obvious. This appendix is committed to uncover non-obvious syntax magic can guide method is called.
Magical method calls Method Description

`__new__(cls [,...])` `instance = MyClass(arg1, arg2)` `__new__` 在创建实例的时候被调用
`__init__(self [,...])` `instance = MyClass(arg1, arg2)` `__init__` 在创建实例的时候被调用
`__cmp__(self, other)` `self == other`, `self > other`, 等 在比较的时候调用
`__pos__(self)` `+self` 一元加运算符
`__neg__(self)` `-self` 一元减运算符
`__invert__(self)` `~self` 取反运算符
`__index__(self)` `x[self]` 对象被作为索引使用的时候
`__nonzero__(self)` `bool(self)` 对象的布尔值
`__getattr__(self, name)` `self.name # name不存在` 访问一个不存在的属性时
`__setattr__(self, name, val)` `self.name = val` 对一个属性赋值时
`__delattr__(self, name)` `del self.name` 删除一个属性时
`__getattribute(self, name)` `self.name` 访问任何属性时
`__getitem__(self, key)` `self[key]` 使用索引访问元素时
`__setitem__(self, key, val)` `self[key] = val` 对某个索引值赋值时
`__delitem__(self, key)` `del self[key]` 删除某个索引值时
`__iter__(self)` `for x in self` 迭代时
`__contains__(self, value)` `value in self`, `value not in self` 使用 `in` 操作测试关系时
`__concat__(self, value)` `self + other` 连接两个对象时
`__call__(self [,...])` `self(args)` “调用”对象时
`__enter__(self)` `with self as x:` `with` 语句上下文管理
`__exit__(self, exc, val, trace)` `with self as x:` `with` 语句上下文管理
`__getstate__(self)` `pickle.dump(pkl_file, self)` 序列化
`__setstate__(self)` `data = pickle.load(pkl_file)` 序列化

I hope this form can help you clear away your questions about grammar involves magical methods.

Guess you like

Origin www.cnblogs.com/djdjdj123/p/11845090.html