1. Enumeration - enumerate can have parameters
We did this before:
i = 0for item in iterable: print i, item i += 1
Now let's do this:
for i, item in enumerate(iterable): print i, item
The enumerate function also receives the second parameter. As follows:
>>> list(enumerate('abc')) [(0, 'a'), (1, 'b'), (2, 'c')] >>> list(enumerate('abc', 1)) [(1, 'a'), (2, 'b'), (3, 'c')]
If you are still confused in the world of programming, you can join our Python Learning button qun: 784758214 to see how our predecessors learned. Exchange of experience. From basic Python script to web development, crawler, django, data mining, zero-base to actual project data are sorted out. To every Python buddy! Share some learning methods and small details that need attention. Click to join us. python learner gathering place
2. Dictionary/Set Resolution
You may know how to do list parsing, but you may not know dictionary / set parsing. They are easy to use and efficient. Like the following example:
my_dict = {i: i * i for i in xrange(100)} my_set = {i * 15 for i in xrange(100)} # There is only a difference of ':' in both # The difference between the two is that there is a colon in the derivation of dictionaries.
3. Forced floating-point division
from __future__ import division result = 1/2# print(result)# 0.5
4. Evaluating Python expressions
We all know the Eval function, but do we know the literal_eval function? Maybe many people don't know. This operation can be used:
import ast my_list = ast.literal_eval(expr)
To replace the following operation:
expr = "[1, 2, 3]"my_list = eval(expr)
I believe this is the first time that most people see it, but in fact it has been in Python for a long time.
5. String/Sequence Inverse
You can use the following method to quickly reverse the sequence of numbers:
>>> a = [1,2,3,4]>>> a[::-1] [4, 3, 2, 1]# This creates a new reversed list. # If you want to reverse a list in place you can do:a.reverse()
This general approach also applies to the reverse order of strings:
>>> foo = "yasoob">>> foo[::-1]'boosay'
6. Ternary operations
Triple operation is a fast operation of if-else statement, also known as conditional operation. Here are a few examples for your reference, which can make your code more compact and beautiful.
[on_true] if [expression] else [on_false] x, y = 50, 25small = x if x < y else y
7. How to copy an object in Python
The copy module in the standard library provides two ways to implement the copy. One is copy, which returns objects with the same content as the parameters.
import copynew_list = copy.copy(existing_list)
Sometimes, you want the attributes in the object to be copied, so you can use the deepcopy method:
import copynew_list_of_dicts = copy.deepcopy(existing_list_of_dicts)copy(x)Shallow copy operation on arbitrary Python objects.deepcopy(x, memo=None, _nil=[]) Deep copy operation on arbitrary Python objects.
8. How to judge object equality in Python
The first is the == and equal methods of strings in C #. "= =": For built-in value types, === determines whether two memory values are equal. For user-defined value types (Struct), === needs to be overloaded, otherwise it cannot be used. For reference types, the default is that the same reference returns true, but the system overloads many reference types == (such as string mentioned below), so the comparison of reference types in c# is not recommended to use ==. "equals": For value types, memory equality returns true. For reference types, pointing to the same reference is equivalent. But String is a special reference type. In C # language, the equals() method of string is overloaded so that string objects can be used as value types. In python== The object in python contains three elements: id, type, value ID to identify the only object, type to identify the type of object, value to set the value of the object. Is judges whether it is an object or not, and uses ID to judge it. == It is to determine whether the value of object a is the value of object b and call its _eq_ method by default.
9. Naming Skills
Read the code today and find a good way to name functions:
def request(_argv):
That is, all parameters are preceded by underscores, so that you can see at a glance in the body of the function that those are local variables, those are passed in as parameters, similar to the global variable preceded by g.
10. Developer Tools Collection
-
pydoc: Modules can generate well-formed documents for any importable module based on docstrings in the source code.
-
doctest module: This module can extract test cases from source code or individual file examples.
-
Unit test module: This module is a fully functional automated testing framework, which provides support for test fixtures, predefined test suites and test discovery.
-
Trac: The module monitors how Python executes the program and generates a report showing how many times each line of the program executes. This information can be used to find program execution paths that are not covered by automated test suites, or to study program call graphs to discover dependencies between modules. Writing and executing tests can find problems in most programs, and Python makes debug easier because in most cases Python can print unprocessed errors to the console, which we call traceback. If the program is not running in the text console, traceback can also output error messages to log files or message dialogs. When standard traceback does not provide enough information, you can use the cgitb module to view the details of stacks and source code contexts at all levels, such as local variables. Cgitb module can also output these tracking information in HTML form to report errors in web applications.
-
pdb: This module can show the execution path of the program when the error occurs, and dynamically adjust the object and code for debugging.
-
profile, timeit: Developers can use profiles and timit modules to test the speed of the program, find out where the program is really slow, and then tune this part of the code independently.
-
Compoileall: The Python program is executed by an interpreter whose input is a byte-code compiled version of the original program. This bytecode compiled version can be generated dynamically when the program is executed or when the program is packaged. The compileall module can handle packaging, which exposes packaging-related interfaces that can be used by installers and packaging tools to generate files containing module bytecodes. At the same time, in the development environment, the compileall module can also be used to verify whether the source file contains syntax errors.
-
YAPF: Google's open source Python code formatting tool.
-
IPDB: The iPDB is an excellent tool, and I've used it to find many fantastic bug s. pip install ipdb install the tool, then import IPDB in your code; ipdb. set_trace(), then you will get a good interactive prompt when your program runs. It executes one line of the program at a time and checks variables.
-
Pycallgraph: In some cases, I use pycallgraph to track performance issues. It can create graphs of the time and number of function calls.
- objgraph: objgraph is very useful for finding memory leaks.
11. Accelerated Finding of Python Code Microoptimization
collections.OrderedDict Class: def __setitem__(self, key, value, dict_setitem=dict.__setitem__): if key not in self: root = self.__root last = root[0] last[1] = root[0] = self.__map[key] = [last, root, key] return dict_setitem(self, key, value)
Notice the last parameter: dict_setitem=dict.setitem. If you think about it carefully, it makes sense. To associate values with keys, you only need to pass three parameters to setitem: the key to be set, the value associated with the key, and the setitem class method of the built-in Dict class. Wait a minute. Okay, maybe the last parameter doesn't make sense. The last parameter actually binds a function to a function in a local scope. Specifically, dict.setitem is assigned to the default value of the parameter. Here is another example:
def not_list_or_dict(value): return not (isinstance(value, dict) or isinstance(value, list)) def not_list_or_dict(value, _isinstance=isinstance, _dict=dict, _list=list): return not (_isinstance(value, _dict) or _isinstance(value, _list))
Here we do the same thing by binding objects that would otherwise be in built-in namespaces to local scopes. Therefore, python will use LOCAL_FAST instead of LOAD_GLOBAL (global lookup). So how fast is that? Let's do a simple test:
$ python -m timeit -s 'def not_list_or_dict(value): return not (isinstance(value, dict) or isinstance(value, list))' 'not_list_or_dict(50)'1000000 loops, best of 3: 0.48 usec per loop$ python -m timeit -s 'def not_list_or_dict(value, _isinstance=isinstance, _dict=dict, _list=list): return not (_isinstance(value, _dict) or _isinstance(value, _list))' 'not_list_or_dict(50)'1000000 loops, best of 3: 0.423 usec per loop
In other words, about 11.9% increase [2]. More than 5% of what I promised at the beginning of this article!
12. Package Management
One of the best places in the Python world is the large number of third-party packages. Similarly, it's easy to manage these packages. By convention, packages required for a project are listed in the requirements.txt file. Each package takes up one line and usually contains a version number.
pelican==3.3Markdown pelican-extended-sitemap==1.0.0
13. Traps and principles of default values of Python function parameters
Python 2.7.9 (default, Dec 19 2014, 06:05:48) [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin Type "help", "copyright", "credits" or "license" for more information.>>> def generate_new_list_with(my_list=[], element=None): ... my_list.append(element) ... return my_list ...>>> list_1 = generate_new_list_with(element=1)>>> list_1 [1]>>> list_2 = generate_new_list_with(element=2)>>> list_2 [1, 2]>>>
It can be seen that the result of code running is not the same as we expected. list_2 does not get a new list and fill in 2 on the second call of the function, but append s a 2 on the basis of the result of the first call. Why does it happen that in other programming languages it's just like designing bug s? It can be seen that if the default value of the parameter is determined at the compile stage of the function compilation. When all subsequent function calls are made, the so-called default value of the parameter is nothing more than a pointer to the object that already exists in the compile phase if the parameter is not assigned. If the specified incoming parameter is not displayed when the function is called, it is worthwhile. In all cases, this parameter exists as an alias for the object created at compile time. If the default value of a parameter is an Imuttable value, then if the parameter is modified in the function body, the parameter will redirect to another new immutable value. If the default value of the parameter is a Muttable, as in the initial example in this article, then the situation is worse. The modification of this parameter in all functions is actually a modification of the object that has been determined in the compile stage.
14. Single underscore ()
1. In an interpreter: In this case, "" represents the result of the last statement executed in an interactive interpreter session. This usage is first adopted by standard CPython interpreters, and then by other types of interpreters.
>>> _ Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name '_' is not defined >>> 42>>> _ 42>>> 'alright!' if _ else ':(''alright!'>>> _ 'alright!'
2. As a name: This is slightly related to the above point. At this time "" is used as a temporary name. This way, when someone else reads your code, they will know that you have assigned a specific name, but that name will not be used again later. For example, in the following example, you may not be interested in the actual value in the loop count, so you can use ".
n = 42for _ in range(n): do_something()
3. Internationalization: You may have seen that "" will be used as a function. In this case, it is usually used to translate and find function names between internationalized and localized strings, which seems to originate from and follow the corresponding C convention. For example, in the "Conversion" section of the Django document, you will see the following code:
from django.utils.translation import ugettext as _ from django.http import HttpResponse def my_view(request): output = _("Welcome to my site.") return HttpResponse(output)
It can be found that the usage methods in Scenario 2 and Scenario 3 may conflict with each other, so we need to avoid using "" as a temporary name in the code block of the internationalization search conversion function.
15. Single underscore before the name (e.g. _shahriar)
The programmer uses a single underscore before the name to specify that the name property is "private". This is somewhat similar to the convention that in order for others (or yourself) to use the code, they will know that the name starting with "" is for internal use only. As described in the Python document:
Names prefixed with underscore (such as pam) should be considered as non-public parts of the API (whether functions, methods, or data members). At this point, they should be seen as implementation details without external notification when they are modified.
As mentioned above, this is really similar to a convention, because it does make sense for interpreters if you write code: from <module/package name> import
Names that begin with are not imported unless all in a module or package
Lists explicitly contain them. For more information, see Importing in Python
16. Double underscores before the name (e.g. _shahriar)
The use of double underscore before a name (specifically a method name) is not a convention, but has a specific meaning for an interpreter. This usage in Python is intended to avoid name conflicts with subclass definitions. The Python document states that any identifier in the form of spam (at least two leading underscores and at most one subsequent underscore) will be as expected, "_internal_use" has not changed, while "method_name" has been changed to "_classname_ method_name". At this point, if you create a subclass B of A, you will not be able to easily override the method "_method_name" in A. This form of spam is replaced by the original text, where the class name is the current class name with the leading underscore removed. For example, the following example:
>>> class A(object): ... def _internal_use(self): ... pass... def __method_name(self): ... pass... >>> dir(A()) ['_A__method_name', ..., '_internal_use']
As expected, "_internal_use" has not changed, while "method_name" has been changed to "_ClassName method_name". At this point, if you create a subclass B of A, you will not be able to easily override the method "_method_name" in A.
17. Double underscores before and after the name (e.g. init)
This usage represents a special method name in Python. In fact, it's just a convention, and for Python systems, it will ensure that it doesn't conflict with user-defined names. Usually, you will override these methods and implement the functions you need in them so that Python can call them. For example, when defining a class, you often override the "init" method.
Although you can also write your own special method names, don't do so.
17. Hidden feature 1, function unpack
def foo(x, y): print x, y alist = [1, 2] adict = {'x': 1, 'y': 2} foo(*alist) # 1, 2foo(**adict) # 1, 2
18. Hidden feature 2, chain comparison operator
>>> x = 3>>> 1 < x < 5True>>> 4 > x >=3True
19. Hidden feature 3, default parameter of function
>>> def foo(x=[]): ... x.append(1) ... print x ...>>> foo() [1]>>> foo() [1, 1]
A safer approach is to:
>>> def foo(x=None):... if x is None:... x = []... x.append(1)... print x ...>>> foo() [1]>>> foo() [1] >>>
20. Hidden feature 4. get method of dictionary
21. Hidden feature 5, formatting with keywords
>>> print "Hello %(name)s !" % {'name': 'James'} Hello James !>>> print "I am years %(age)i years old" % {'age': 18} I am years 18 years old
Update some formatting:
>>> print "Hello {name} !".format(name="James") Hello James !
22. Hiding feature 6, step size parameters of slicing operation
Step-1 can be used to reverse the list: >> a = 1, 2, 3, 4, 5]> a [::2] [1, 3, 5]>>> a[::-1] [5, 4, 3, 2, 1]>>>
23. Hidden Characteristic 7, Nested List Derivation
[(i, j) for i in range(3) for j in range(i)] [(1, 0), (2, 0), (2, 1)]
List derivation constructs permutation: it can be implemented with itertools.permutations.
In[47]: a = 'abcd'In[48]: [i+j+k for i in a for j in a.replace(i,'') for k in a.replace(i,'').replace(j,'')]Out[48]: ['abc', 'abd', 'acb', 'acd', 'adb', 'adc', 'bac', 'bad', 'bca', 'bcd', 'bda', 'bdc', 'cab', 'cad', 'cba', 'cbd', 'cda', 'cdb', 'dab', 'dac', 'dba', 'dbc', 'dca', 'dcb']
24. Hiding feature 8, print redirection output to file
Note the open mode: "w+" instead of "w", of course "a" is possible.
>>> print >> open("somefile", "w+"), "Hello World"
25. Hidden feature 9, tuple unpack in Python 3
>>> a, b, *rest = range(10) >>> a0>>> b1>>> rest [2, 3, 4, 5, 6, 7, 8, 9] >>> >>> first, second, *rest, last = range(10) >>> first0>>> second1>>> last9>>> rest [2, 3, 4, 5, 6, 7, 8]
26. Hidden property 10, third parameter of pow
In fact, the third parameter is to find the module: pow (x, y, z) = (x ** y)% Z. Note that the built-in POW and math.pow are not a function, the latter accepts only two parameters.
>>> pow(4, 2, 2)0>>> pow(4, 2, 3)1
27. Hidden feature 11, enumerate has a second parameter
enumerate is very good. It can give us a pair of index and sequence values, but it also has a second parameter, which is used to specify the starting value of the index.
>>> lst = ["a", "b", "c"]>>> list(enumerate(lst, 1)) [(1, 'a'), (2, 'b'), (3, 'c')]
28. Hidden feature 12, explicitly declaring a collection
You can declare a collection like this after Python 2.7. >>> {1,2,3} set([1, 2, 3])
29. Hiding feature 13, using slices to delete a segment of a sequence
>>> a = [1, 2, 3, 4, 5, 6, 7]>>> a[1:4] = []>>> a [1, 5, 6, 7]
Of course, it is also possible to use del a[1:4] to remove even items (even index):
>>> a = [0, 1, 2, 3, 4, 5, 6, 7] >>> del a[::2] >>> a[1, 3, 5, 7]
30. Hidden feature 14, isinstance can accept a tuple
This is really little known. We can use isinstance(x, (float, int)) to determine whether x is a number, that is, the relation of yes or in that tuple, and return True as long as one of the instances.
>>> isinstance(1, (float, int))True>>> isinstance(1.3, (float, int))True>>> isinstance("1.3", (float, int))False
31. Make critical code dependent on external packages
Although Python makes many programming tasks easier, it may not always provide the best performance for urgent tasks. You can use external packages written in C, C++ or machine language for urgent tasks to improve application performance. These packages are not cross-platform, which means you need to find the right packages based on the platform you are using. In short, this scheme abandons the portability of some applications in exchange for program performance that can only be achieved by direct programming on a specific host. Here are some packages that you should consider adding to your "performance arsenal":
Cython PyInlne PyPy Pyrex
These packages improve performance in different ways. For example, Pyrex can extend what Python can do, such as using C's data type to make memory tasks more efficient or direct. PyInIne lets you use C code directly in Python applications. The inline code in the program is compiled separately, but it makes use of the efficiency provided by C language, at the same time, all the code is in the same place.
32. Use key s when sorting
There are many old Python sort codes that take your time when you create a custom sort, but they do speed up the sort process at runtime. The best way to sort elements is to use key s and the default sort() sort method whenever possible. For example, consider the following code:
import operator somelist = [(1, 5, 8), (6, 2, 4), (9, 7, 5)] somelist.sort(key=operator.itemgetter(0)) somelist #Output = [(1, 5, 8), (6, 2, 4), (9, 7, 5)] somelist.sort(key=operator.itemgetter(1)) somelist #Output = [(6, 2, 4), (1, 5, 8), (9, 7, 5)] somelist.sort(key=operator.itemgetter(2)) somelist
In each instance, the arrays are sorted according to the index you choose as part of the key parameter. Similar to sorting by numbers, this method is also applicable to sorting by strings.
33. Optimizing the cycle
Each programming language emphasizes the need to optimize loops. When using Python, you can rely on a lot of techniques to make the cycle run faster. However, one way developers often miss is to avoid using point operations in a loop. For example, consider the following code:
lowerlist = ['this', 'is', 'lowercase'] upper = str.upperupperlist = [] append = upperlist.appendfor word in lowerlist: append(upper(word)) print(upperlist) #Output = ['THIS', 'IS', 'LOWERCASE']
Every time you call the method str.upper, Python calculates the value of the method. However, if you replace the calculated value with a variable, the value becomes known and Python can perform the task faster. The key to optimizing the loop is to reduce the workload of Python executing inside the loop, because the native interpreter of Python really slows down execution in that case.
(Note: There are many ways to optimize the cycle. This is just one of them. For example, many programmers would say that list inference is the best way to speed up execution in a loop. The key here is that optimizing loops is one of the better ways for programs to achieve higher execution speeds.)
34. Try a variety of coding methods
If you create an application with the same encoding method every time you create it, it will almost certainly lead to some situations where your application runs more slowly than it can. As part of the analysis process, you can try some experiments. For example, if you manage some elements in a dictionary, you can use a safe method to determine whether the element exists and updates, or you can add elements directly, and then handle the absence of the element as an exception. Consider the first coding example:
n = 16myDict = {}for i in range(0, n): char = 'abcd'[i%4] if char not in myDict: myDict[char] = 0 myDict[char] += 1 print(myDict)
This code usually runs faster at the beginning of myDict when it is empty. However, when mydict is usually filled with data (or at least most of it) another method works better.
n = 16myDict = {}for i in range(0, n): char = 'abcd'[i%4] try: myDict[char] += 1 except KeyError: myDict[char] = 1 print(myDict)
Both cases have the same output: {d': 4, `c': 4, `b': 4, `a': 4}. The only difference is how this output is obtained. Getting out of the box and creating new coding techniques can help you get faster results with your application.
35. Use list derivation
A list derivation consists of the following parts:
An input sequence
A variable representing the members of an input sequence
An optional assertion expression
An output expression that converts a member of an input sequence that satisfies an assertion expression into an output list member
num = [1, 4, -5, 10, -7, 2, 3, -1] filtered_and_squared = []for number in num: if number > 0: filtered_and_squared.append(number ** 2) print filtered_and_squared# [1, 16, 100, 4, 9]
If filter, lambda and map functions are used, the code can be greatly simplified:
num = [1, 4, -5, 10, -7, 2, 3, -1] filtered_and_squared = map(lambda x: x ** 2, filter(lambda x: x > 0, num))print filtered_and_squared # [1, 16, 100, 4, 9] ## A simpler way of writing num = [1, 4, -5, 10, -7, 2, 3, -1] filtered_and_squared = [ x**2 for x in num if x > 0]print filtered_and_squared # [1, 16, 100, 4, 9]
[Image upload failed... (image-372582-1565252337522)]
comprehension.jpg
List deduction may also have some negative effects, that is, the entire list must be loaded in memory at one time, which is not a problem for the examples above, or even after enlarging several times. But it always reaches the limit, and memory is always used up.
To solve the above problems, Generator can solve them well. Generator expressions do not load the entire list into memory at once, but instead generate a Generator object, so only one list element is loaded at a time.
Generator expressions have almost the same grammatical structure as list derivatives. The difference is that generator expressions are surrounded by parentheses, not square brackets:
num = [1, 4, -5, 10, -7, 2, 3, -1] filtered_and_squared = ( x**2 for x in num if x > 0 ) print filtered_and_squared# <generator object <genexpr> at 0x00583E18>for item in filtered_and_squared: print item# 1, 16, 100 4,9
This is slightly more efficient than list derivation. Let's revamp the code once again.
num = [1, 4, -5, 10, -7, 2, 3, -1]def square_generator(optional_parameter): return (x ** 2 for x in num if x > optional_parameter)print square_generator(0)# <generator object <genexpr> at 0x004E6418># Option Ifor k in square_generator(0): print k# 1, 16, 100, 4, 9# Option IIg = list(square_generator(0))print g# [1, 16, 100, 4, 9]
Generator expressions should be used frequently in code, except for special reasons. But unless you're faced with a very large list, you won't see a significant difference. Let's look at an example of traversing directories through a two-order list derivation:
import os def tree(top): for path, names, fnames in os.walk(top): for fname in fnames: yield os.path.join(path, fname)for name in tree('C:\Users\XXX\Downloads\Test'): print name
36. Decorators
Decorators provide us with an effective way to add functionality to existing functions or classes. Does it sound like Aspect-Oriented Programming in Java? Both are simple, and the decorator has more powerful functions. For example, suppose you want to do some special operations at the entry and exit points of a function (such as security, tracing, locking, etc.) to use the decorator.
Decorator is a special function that wraps another function: the main function is called, and its return value will be passed to the decorator. Next, the decorator will return an alternative function that wraps the main function. The rest of the program will see the wrapper function.
import timefrom functools import wrapsdef timethis(func): ''' Decorator that reports the execution time. ''' @wraps(func) def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(func.__name__, end-start) return result return wrapper@timethisdef countdown(n): while n > 0: n -= 1countdown(100000)# ('countdown', 0.006999969482421875)
37. Context Lib
The contextlib module contains tools related to context managers and with declarations. Usually if you want to write a context manager, you need to define a class that contains the enter method and exit method, for example:
import timeclass demo: def __init__(self, label): self.label = label def __enter__(self): self.start = time.time() def __exit__(self, exc_ty, exc_val, exc_tb): end = time.time() print('{}: {}'.format(self.label, end - self.start))
Here is a complete example:
import timeclass demo: def __init__(self, label): self.label = label def __enter__(self): self.start = time.time() def __exit__(self, exc_ty, exc_val, exc_tb): end = time.time() print('{}: {}'.format(self.label, end - self.start)) with demo('counting'): n = 10000000 while n > 0: n -= 1# counting: 1.36000013351
The context manager is activated by the with declaration, which involves two methods. The enter method, when the execution stream enters the with code block, executes the enter method. And it will return an object that can be used in context.
When the execution stream leaves the with code block, the exit method is called, which cleans up the used resources.
Use the @contextmanager decorator to rewrite the above example:
from contextlib import contextmanagerimport time@contextmanagerdef demo(label): start = time.time() try: yield finally: end = time.time() print('{}: {}'.format(label, end - start))with demo('counting'): n = 10000000 while n > 0: n -= 1# counting: 1.32399988174
Looking at the example above, all the code before yield in the function is similar to the content of the enter method in the context manager. And all the code after yield is like the content of exit method. If an exception occurs during execution, it is triggered in the yield statement.
38. Descriptors
The descriptor determines how object attributes are accessed. The function of the descriptor is to customize what happens when you want to refer to an attribute.
The way to build a descriptor is to define at least one of the three methods. It should be noted that the instance below is an object instance that contains the accessed attributes, while the owner is a class that is rhetorically described by the descriptor.
get(self, instance, owner) - This method is called when an attribute is acquired by (value = obj.attr), and the return value of this method is assigned to the code part requesting the attribute value. set(self, instance, value) - This method is called when you want to set the value of the property (obj.attr ='value'), and it does not return any value. delete(self, instance) - This method is called when an attribute is deleted from an object (del obj.attr). Translator's Note: For instance and owner's understanding, consider the following code:
class Celsius(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 Temperature(object): celsius = Celsius() temp=Temperature() temp.celsius #calls Celsius.__get__
39. Zipping and unzipping lists and iterables
>>> a = [1, 2, 3]>>> b = ['a', 'b', 'c']>>> z = zip(a, b)>>> z [(1, 'a'), (2, 'b'), (3, 'c')]>>> zip(*z) [(1, 2, 3), ('a', 'b', 'c')]
40. Grouping adjacent list items using zip
>>> a = [1, 2, 3, 4, 5, 6]>>> # Using iterators>>> group_adjacent = lambda a, k: zip(*([iter(a)] * k))>>> group_adjacent(a, 3) [(1, 2, 3), (4, 5, 6)]>>> group_adjacent(a, 2) [(1, 2), (3, 4), (5, 6)]>>> group_adjacent(a, 1) [(1,), (2,), (3,), (4,), (5,), (6,)]>>> # Using slices>>> from itertools import islice>>> group_adjacent = lambda a, k: zip(*(islice(a, i, None, k) for i in range(k)))>>> group_adjacent(a, 3) [(1, 2, 3), (4, 5, 6)]>>> group_adjacent(a, 2) [(1, 2), (3, 4), (5, 6)]>>> group_adjacent(a, 1) [(1,), (2,), (3,), (4,), (5,), (6,)]
41. Sliding windows (n-grams) using zip and iterators
>>> from itertools import islice>>> def n_grams(a, n):... z = (islice(a, i, None) for i in range(n))... return zip(*z) ...>>> a = [1, 2, 3, 4, 5, 6]>>> n_grams(a, 3) [(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]>>> n_grams(a, 2) [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]>>> n_grams(a, 4) [(1, 2, 3, 4), (2, 3, 4, 5), (3, 4, 5, 6)]
42. Inverting a dictionary using zip
>>> m = {'a': 1, 'b': 2, 'c': 3, 'd': 4}>>> m.items() [('a', 1), ('c', 3), ('b', 2), ('d', 4)]>>> zip(m.values(), m.keys()) [(1, 'a'), (3, 'c'), (2, 'b'), (4, 'd')]>>> mi = dict(zip(m.values(), m.keys()))>>> mi {1: 'a', 2: 'b', 3: 'c', 4: 'd'}
43. Flattening lists
>>> a = [[1, 2], [3, 4], [5, 6]]>>> list(itertools.chain.from_iterable(a)) [1, 2, 3, 4, 5, 6] >>> sum(a, []) [1, 2, 3, 4, 5, 6] >>> [x for l in a for x in l] [1, 2, 3, 4, 5, 6] >>> a = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] >>> [x for l1 in a for l2 in l1 for x in l2] [1, 2, 3, 4, 5, 6, 7, 8] >>> a = [1, 2, [3, 4], [[5, 6], [7, 8]]] >>> flatten = lambda x: [y for l in x for y in flatten(l)] if type(x) is list else [x] >>> flatten(a) [1, 2, 3, 4, 5, 6, 7, 8]
44. Dictionary comprehensions
>>> m = {x: x ** 2 for x in range(5)}>>> m {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}>>> m = {x: 'A' + str(x) for x in range(10)}>>> m {0: 'A0', 1: 'A1', 2: 'A2', 3: 'A3', 4: 'A4', 5: 'A5', 6: 'A6', 7: 'A7', 8: 'A8', 9: 'A9'}
45. Often make mistakes, abuse expression as default value of function parameter
Python allows developers to specify a default value for function parameters. Although this is a feature of the language, it can easily lead to confusion when parameters are variable. For example, the following function definition:
>>> def foo(bar=[]): # bar is optional and defaults to [] if not specified... bar.append("baz") # but this line could be problematic, as we'll see...... return bar
In the above code, once the foo() function is called repeatedly (without specifying a bar parameter), it will always return'bar', because there is no specified parameter, then foo() will be given [] every time it is called. Let's take a look at the results of this:
>>> foo() ["baz"]>>> foo() ["baz", "baz"]>>> foo() ["baz", "baz", "baz"]
Solution:
>>> def foo(bar=None):... if bar is None: # or if not bar:... bar = []... bar.append("baz")... return bar ...>>> foo() ["baz"]>>> foo() ["baz"]>>> foo() ["baz"]
46. Misunderstanding the scope of Python rules
The scope resolution of Python is based on LEGB rules, namely Local, Enclosing, Global and Built-in. In fact, there are some mysteries in this analytical method. Look at the following example:
>>> x = 10>>> def foo(): ... x += 1... print x ...>>> foo() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in fooUnboundLocalError: local variable 'x' referenced before assignment
Many people will be surprised that when they add a parameter statement to the body of the function they are working on, they will report an Unbound Local Error error in the code they worked on earlier (click here for a more detailed description). It's easy for developers to make this mistake when using lists. Here's an example:
>>> lst = [1, 2, 3]>>> def foo1(): ... lst.append(5) # This works ok......>>> foo1()>>> lst [1, 2, 3, 5]>>> lst = [1, 2, 3]>>> def foo2(): ... lst += [5] # ... but this bombs!...>>> foo2() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in fooUnboundLocalError: local variable 'lst' referenced before assignment
Why did foo2 fail and foo1 work properly? The answer is the same as the previous example, but there are some subtleties. Foo1 is not assigned to lst, but foo2 is assigned to lst. lst += [5] is actually lst = lst + [5], trying to assign LST (therefore, assume that Python is in a local scope). However, we are looking for a value assigned to LST based on the lst itself, which has not yet been determined.
47. Modify traversal list
>>> odd = lambda x : bool(x % 2) >>> numbers = [n for n in range(10)] >>> for i in range(len(numbers)): ... if odd(numbers[i]): ... del numbers[i] # BAD: Deleting item from a list while iterating over it ... Traceback (most recent call last): File "<stdin>", line 2, in <module> IndexError: list index out of range
When traversing, deleting the list is a very low-level error. No one with a little experience will commit it it. Modify the above code and execute it correctly:
>>> odd = lambda x : bool(x % 2)>>> numbers = [n for n in range(10)]>>> numbers[:] = [n for n in numbers if not odd(n)] # ahh, the beauty of it all>>> numbers [0, 2, 4, 6, 8]
48. Rational Use of copy and Depcopy
For objects with data structures such as dict and list, direct assignment is done by reference. In some cases, the whole object needs to be copied. In this case, copy and deepcopy in the copy package can be used. The difference between the two functions is that the latter is recursively copied. The efficiency is also different: (The following program runs in ipython)
The - n after timeit denotes the number of runs, and the last two lines correspond to the output of two timeit lines, the same below. So the latter slows down by an order of magnitude.
import copya = range(100000) %timeit -n 10 copy.copy(a) # Run 10 times copy.copy(a)% timeit-n 10 copy.deepcopy(a) 10 loops, best of 3:1.55 ms per loop 10 loops, best of 3:151 ms per loop
49. Rational Use of Generators and Yields
%timeit -n 100 a = (i for i in range(100000)) %timeit -n 100 b = [i for i in range(100000)]100 loops, best of 3: 1.54 ms per loop100 loops, best of 3: 4.56 ms per loop
Using () you get a generator object, and the required memory space is independent of the size of the list, so it's more efficient. In specific applications, such as set(i for i in range(100000)) will be faster than set([i for i in range(100000)]).
But for cases where circular traversal is required:
%timeit -n 10 for x in (i for i in range(100000)): pass %timeit -n 10 for x in [i for i in range(100000)]: pass10 loops, best of 3: 6.51 ms per loop10 loops, best of 3: 5.54 ms per loop
The latter is more efficient, but if there is break in the loop, the benefits of using generator are obvious. yield is also used to create generator:
50. Cascade comparison x < y < Z
x, y, z = 1,2,3%timeit -n 1000000 if x < y < z:pass %timeit -n 1000000 if x < y and y < z:pass1000000 loops, best of 3: 101 ns per loop1000000 loops, best of 3: 121 ns per loop
X < y < Z is slightly more efficient and readable.
51. while 1 is faster than while True
def while_1(): n = 100000 while 1: n -= 1 if n <= 0: breakdef while_true(): n = 100000 while True: n -= 1 if n <= 0: break m, n = 1000000, 1000000 %timeit -n 100 while_1() %timeit -n 100 while_true()100 loops, best of 3: 3.69 ms per loop100 loops, best of 3: 5.61 ms per loop
while 1 is much faster than while true because in Python 2. x, True is a global variable, not a keyword.
52. Use ** instead of pow
%timeit -n 10000 c = pow(2,20) %timeit -n 10000 c = 2**2010000 loops, best of 3: 284 ns per loop10000 loops, best of 3: 16.9 ns per loop
53. Use c Profile, cStringIO and cPickle to implement the same package with c (corresponding to profile, StringIO, pickle, respectively).
import cPickleimport pickle a = range(10000) %timeit -n 100 x = cPickle.dumps(a) %timeit -n 100 x = pickle.dumps(a)100 loops, best of 3: 1.58 ms per loop100 loops, best of 3: 17 ms per loop
Packet implemented by c, faster than 10 times!
54. Use the best deserialization method
The following comparisons show that json is nearly three times faster than cPickle and more than 20 times faster than eval.
import jsonimport cPickle a = range(10000)s1 = str(a)s2 = cPickle.dumps(a)s3 = json.dumps(a)%timeit -n 100 x = eval(s1) %timeit -n 100 x = cPickle.loads(s2) %timeit -n 100 x = json.loads(s3)100 loops, best of 3: 16.8 ms per loop100 loops, best of 3: 2.02 ms per loop100 loops, best of 3: 798 μs per loop
55. How to master python
This question is rather difficult to answer. I have sorted out some opinions according to my own views. Don't ask me what criteria I put together. I can only say that the points I put together are good in my opinion. Secondly, I will go and see how far I am from being "proficient" in python.
-
Familiar with grammar and sound data structure
-
Familiar with the performance characteristics of basic implementations is to know what operations will be slow.
-
Use profiles and profile-based performance analysis tools
-
Tools for runtime compilation and static compilation are used. pypy, numba, cython, ctypes, original C/C++ extension
-
Be familiar with the development libraries in your field. For example, I don't need too many libraries in scientific computing. numpy has generated a lot of libraries.
-
Understand the basic compilation process, basic operating system knowledge (as long as you learn C, C++)
-
To be proficient in python, you have to write pythonic code first.
-
Reading Niu B's open source code will encounter many higher-order uses of python in the process
-
Understanding Decorators, Generators, Descriptors, Metaclasses
-
Master list comprehension,
- Multipurpose built-in functions: map, reduce, filter, iter, range, divmod, round, chr, enumerate, all, any, slice, zip+
56. python monkey patch correlation
There is a wonderful monkey patch in python, which is called monkey patch in Chinese. It refers to the implementation of replacing some loaded modules dynamically at runtime. The first time to understand this concept is when using gevent, you need to change the implementation of the socket, os and other related modules of Python to asynchronous form, but at the same time do not change the source code of python.