python小技巧(转)

http://blog.jobbole.com/63320/html

A、30 Python Language Features and Tricks You May Not Know About

Posted on Mar 05, 2014 , last modified on May 19, 2014 Permanent linkpython

1   Introduction

Since I started learning Python, I decided to maintain an often visited list of "tricks". Any time I saw a piece of code (in an example, on Stack Overflow, in open source software, etc.) that made me think "Cool! I didn't know you could do that!" I experimented with it until I understood it and then added it to the list. This post is part of that list, after some cleaning up. If you are an experienced Python programmer, chances are you already know most of these, though you might still find a few that you didn't know about. If you are a C, C++ or Java programmer who is learning Python, or just brand new to programming, then you might find quite a few of them surprisingly useful, like I did.linux

Each trick or language feature is demonstrated only through examples, with no explanation. While I tried my best to make the examples clear, some of them might still appear cryptic depending on your familiarity level. So if something still doesn't make sense after looking at the examples, the title should be clear enough to allow you to use Google for more information on it.c++

The list is very roughly ordered by difficulty, with the easier and more commonly known language features and tricks appearing first.git

table of contents is given at the end.程序员

Update - April 9th, 2014
As you can see the article has been growing with currently 38 items in it, mostly thanks to comments from readers. As such the number 30 in the title is no longer accurate. However, I chose to leave it as is since that's the original title the article was shared as, making it more recognizable and easier to find.
Update - March 14th, 2014
Roy Keyes made a great suggestion of turning this article into a GitHub repository to allow readers to make improvements or additions through pull requests. The repository is now at  https://github.com/sahands/python-by-example. Feel free to fork, add improvements or additions and submit pull requests. I will update this page periodically with the new additions.
Update - March 8th, 2014

This article generated a lot of good discussion on Reddit (http://redd.it/1zv3q3), Hacker News (https://news.ycombinator.com/item?id=7365410), and in the comments below, with many readers suggesting great alternatives and improvements. I have updated the list below to include many of the improvements suggested, and added a few new items based on suggestions that made me have one of those "Cool! I didn't know you could do that!" moments. In particular, I did not know about itertools.chain.from_iterable, and dictionary comprehensions.github

There was also a very interesting discussion about the possibility of some of the techniques below leading to harder to debug code. My say on it is that as far as I can see, none of the items below are inherently harder to debug. But I can definitely see how they can be taken too far, resulting in hard to debug, maintain and understand code. Use your best judgment and if it feels like how short and smart your code is is outweighing how readable and maintainable it is, then break it down and simplify it. For example, I think list comprehensions can be very readable and rather easy to debug and maintain. But a list comprehension inside another list comprehension that is then passed to map and then toitertools.chain? Probably not the best idea!web

1.1   Unpacking

>>> a, b, c = 1, 2, 3 >>> a, b, c (1, 2, 3) >>> a, b, c = [1, 2, 3] >>> a, b, c (1, 2, 3) >>> a, b, c = (2 * i + 1 for i in range(3)) >>> a, b, c (1, 3, 5) >>> a, (b, c), d = [1, (2, 3), 4] >>> a 1 >>> b 2 >>> c 3 >>> d 4 

1.2   Unpacking for swapping variables

>>> a, b = 1, 2 >>> a, b = b, a >>> a, b (2, 1) 

1.3   Extended unpacking (Python 3 only)

>>> a, *b, c = [1, 2, 3, 4, 5] >>> a 1 >>> b [2, 3, 4] >>> c 5 

1.4   Negative indexing

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> a[-1] 10 >>> a[-3] 8 

1.5   List slices (a[start:end])

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> a[2:8] [2, 3, 4, 5, 6, 7] 

1.6   List slices with negative indexing

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> a[-4:-2] [7, 8] 

1.7   List slices with step (a[start:end:step])

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> a[::2] [0, 2, 4, 6, 8, 10] >>> a[::3] [0, 3, 6, 9] >>> a[2:8:2] [2, 4, 6] 

1.8   List slices with negative step

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> a[::-1] [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>> a[::-2] [10, 8, 6, 4, 2, 0] 

1.9   List slice assignment

>>> a = [1, 2, 3, 4, 5] >>> a[2:3] = [0, 0] >>> a [1, 2, 0, 0, 4, 5] >>> a[1:1] = [8, 9] >>> a [1, 8, 9, 2, 0, 0, 4, 5] >>> a[1:-1] = [] >>> a [1, 5] 

1.10   Naming slices (slice(start, end, step))

>>> a = [0, 1, 2, 3, 4, 5] >>> LASTTHREE = slice(-3, None) >>> LASTTHREE slice(-3, None, None) >>> a[LASTTHREE] [3, 4, 5] 

1.11   Iterating over list index and value pairs (enumerate)

>>> a = ['Hello', 'world', '!'] >>> for i, x in enumerate(a): ... print '{}: {}'.format(i, x) ... 0: Hello 1: world 2: ! 

1.12   Iterating over dictionary key and value pairs (dict.iteritems)

>>> m = {'a': 1, 'b': 2, 'c': 3, 'd': 4} >>> for k, v in m.iteritems(): ... print '{}: {}'.format(k, v) ... a: 1 c: 3 b: 2 d: 4 

Note: use dict.items in Python 3.算法

1.13   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')] 

1.14   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,)] 

1.15   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)] 

1.16   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'} 

1.17   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] 

Note: according to Python's documentation on sumitertools.chain.from_iterable is the preferred method for this.sql

1.18   Generator expressions

>>> g = (x ** 2 for x in xrange(10)) >>> next(g) 0 >>> next(g) 1 >>> next(g) 4 >>> next(g) 9 >>> sum(x ** 3 for x in xrange(10)) 2025 >>> sum(x ** 3 for x in xrange(10) if x % 3 == 1) 408 

1.19   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'} 

1.20   Inverting a dictionary using a dictionary comprehension

>>> m = {'a': 1, 'b': 2, 'c': 3, 'd': 4} >>> m {'d': 4, 'a': 1, 'b': 2, 'c': 3} >>> {v: k for k, v in m.items()} {1: 'a', 2: 'b', 3: 'c', 4: 'd'} 

1.21   Named tuples (collections.namedtuple)

>>> Point = collections.namedtuple('Point', ['x', 'y']) >>> p = Point(x=1.0, y=2.0) >>> p Point(x=1.0, y=2.0) >>> p.x 1.0 >>> p.y 2.0 

1.22   Inheriting from named tuples:

>>> class Point(collections.namedtuple('PointBase', ['x', 'y'])): ... __slots__ = () ... def __add__(self, other): ... return Point(x=self.x + other.x, y=self.y + other.y) ... >>> p = Point(x=1.0, y=2.0) >>> q = Point(x=2.0, y=3.0) >>> p + q Point(x=3.0, y=5.0) 

1.23   Sets and set operations

>>> A = {1, 2, 3, 3} >>> A set([1, 2, 3]) >>> B = {3, 4, 5, 6, 7} >>> B set([3, 4, 5, 6, 7]) >>> A | B set([1, 2, 3, 4, 5, 6, 7]) >>> A & B set([3]) >>> A - B set([1, 2]) >>> B - A set([4, 5, 6, 7]) >>> A ^ B set([1, 2, 4, 5, 6, 7]) >>> (A ^ B) == ((A - B) | (B - A)) True 

1.24   Multisets and multiset operations (collections.Counter)

>>> A = collections.Counter([1, 2, 2]) >>> B = collections.Counter([2, 2, 3]) >>> A Counter({2: 2, 1: 1}) >>> B Counter({2: 2, 3: 1}) >>> A | B Counter({2: 2, 1: 1, 3: 1}) >>> A & B Counter({2: 2}) >>> A + B Counter({2: 4, 1: 1, 3: 1}) >>> A - B Counter({1: 1}) >>> B - A Counter({3: 1}) 

1.25   Most common elements in an iterable (collections.Counter)

>>> A = collections.Counter([1, 1, 2, 2, 3, 3, 3, 3, 4, 5, 6, 7]) >>> A Counter({3: 4, 1: 2, 2: 2, 4: 1, 5: 1, 6: 1, 7: 1}) >>> A.most_common(1) [(3, 4)] >>> A.most_common(3) [(3, 4), (1, 2), (2, 2)] 

1.26   Double-ended queue (collections.deque)

>>> Q = collections.deque() >>> Q.append(1) >>> Q.appendleft(2) >>> Q.extend([3, 4]) >>> Q.extendleft([5, 6]) >>> Q deque([6, 5, 2, 1, 3, 4]) >>> Q.pop() 4 >>> Q.popleft() 6 >>> Q deque([5, 2, 1, 3]) >>> Q.rotate(3) >>> Q deque([2, 1, 3, 5]) >>> Q.rotate(-3) >>> Q deque([5, 2, 1, 3]) 

1.27   Double-ended queue with maximum length (collections.deque)

>>> last_three = collections.deque(maxlen=3) >>> for i in xrange(10): ... last_three.append(i) ... print ', '.join(str(x) for x in last_three) ... 0 0, 1 0, 1, 2 1, 2, 3 2, 3, 4 3, 4, 5 4, 5, 6 5, 6, 7 6, 7, 8 7, 8, 9 

1.28   Ordered dictionaries (collections.OrderedDict)

>>> m = dict((str(x), x) for x in range(10)) >>> print ', '.join(m.keys()) 1, 0, 3, 2, 5, 4, 7, 6, 9, 8 >>> m = collections.OrderedDict((str(x), x) for x in range(10)) >>> print ', '.join(m.keys()) 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 >>> m = collections.OrderedDict((str(x), x) for x in range(10, 0, -1)) >>> print ', '.join(m.keys()) 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 

1.29   Default dictionaries (collections.defaultdict)

>>> m = dict() >>> m['a'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'a' >>> >>> m = collections.defaultdict(int) >>> m['a'] 0 >>> m['b'] 0 >>> m = collections.defaultdict(str) >>> m['a'] '' >>> m['b'] += 'a' >>> m['b'] 'a' >>> m = collections.defaultdict(lambda: '[default value]') >>> m['a'] '[default value]' >>> m['b'] '[default value]' 

1.30   Using default dictionaries to represent simple trees

>>> import json >>> tree = lambda: collections.defaultdict(tree) >>> root = tree() >>> root['menu']['id'] = 'file' >>> root['menu']['value'] = 'File' >>> root['menu']['menuitems']['new']['value'] = 'New' >>> root['menu']['menuitems']['new']['onclick'] = 'new();' >>> root['menu']['menuitems']['open']['value'] = 'Open' >>> root['menu']['menuitems']['open']['onclick'] = 'open();' >>> root['menu']['menuitems']['close']['value'] = 'Close' >>> root['menu']['menuitems']['close']['onclick'] = 'close();' >>> print json.dumps(root, sort_keys=True, indent=4, separators=(',', ': ')) {  "menu": {  "id": "file",  "menuitems": {  "close": {  "onclick": "close();",  "value": "Close"  },  "new": {  "onclick": "new();",  "value": "New"  },  "open": {  "onclick": "open();",  "value": "Open"  }  },  "value": "File"  } } 

(See https://gist.github.com/hrldcpr/2012250 for more on this.)

1.31   Mapping objects to unique counting numbers (collections.defaultdict)

>>> import itertools, collections >>> value_to_numeric_map = collections.defaultdict(itertools.count().next) >>> value_to_numeric_map['a'] 0 >>> value_to_numeric_map['b'] 1 >>> value_to_numeric_map['c'] 2 >>> value_to_numeric_map['a'] 0 >>> value_to_numeric_map['b'] 1 

1.32   Largest and smallest elements (heapq.nlargest andheapq.nsmallest)

>>> a = [random.randint(0, 100) for __ in xrange(100)] >>> heapq.nsmallest(5, a) [3, 3, 5, 6, 8] >>> heapq.nlargest(5, a) [100, 100, 99, 98, 98] 

1.33   Cartesian products (itertools.product)

>>> for p in itertools.product([1, 2, 3], [4, 5]): (1, 4) (1, 5) (2, 4) (2, 5) (3, 4) (3, 5) >>> for p in itertools.product([0, 1], repeat=4): ... print ''.join(str(x) for x in p) ... 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 

1.34   Combinations and combinations with replacement (itertools.combinations anditertools.combinations_with_replacement)

>>> for c in itertools.combinations([1, 2, 3, 4, 5], 3): ... print ''.join(str(x) for x in c) ... 123 124 125 134 135 145 234 235 245 345 >>> for c in itertools.combinations_with_replacement([1, 2, 3], 2): ... print ''.join(str(x) for x in c) ... 11 12 13 22 23 33 

1.35   Permutations (itertools.permutations)

>>> for p in itertools.permutations([1, 2, 3, 4]): ... print ''.join(str(x) for x in p) ... 1234 1243 1324 1342 1423 1432 2134 2143 2314 2341 2413 2431 3124 3142 3214 3241 3412 3421 4123 4132 4213 4231 4312 4321 

1.36   Chaining iterables (itertools.chain)

>>> a = [1, 2, 3, 4] >>> for p in itertools.chain(itertools.combinations(a, 2), itertools.combinations(a, 3)): ... print p ... (1, 2) (1, 3) (1, 4) (2, 3) (2, 4) (3, 4) (1, 2, 3) (1, 2, 4) (1, 3, 4) (2, 3, 4) >>> for subset in itertools.chain.from_iterable(itertools.combinations(a, n) for n in range(len(a) + 1)) ... print subset ... () (1,) (2,) (3,) (4,) (1, 2) (1, 3) (1, 4) (2, 3) (2, 4) (3, 4) (1, 2, 3) (1, 2, 4) (1, 3, 4) (2, 3, 4) (1, 2, 3, 4) 

1.37   Grouping rows by a given key (itertools.groupby)

>>> from operator import itemgetter >>> import itertools >>> with open('contactlenses.csv', 'r') as infile: ... data = [line.strip().split(',') for line in infile] ... >>> data = data[1:] >>> def print_data(rows): ... print '\n'.join('\t'.join('{: <16}'.format(s) for s in row) for row in rows) ... >>> print_data(data) young myope no reduced none young myope no normal soft young myope yes reduced none young myope yes normal hard young hypermetrope no reduced none young hypermetrope no normal soft young hypermetrope yes reduced none young hypermetrope yes normal hard pre-presbyopic myope no reduced none pre-presbyopic myope no normal soft pre-presbyopic myope yes reduced none pre-presbyopic myope yes normal hard pre-presbyopic hypermetrope no reduced none pre-presbyopic hypermetrope no normal soft pre-presbyopic hypermetrope yes reduced none pre-presbyopic hypermetrope yes normal none presbyopic myope no reduced none presbyopic myope no normal none presbyopic myope yes reduced none presbyopic myope yes normal hard presbyopic hypermetrope no reduced none presbyopic hypermetrope no normal soft presbyopic hypermetrope yes reduced none presbyopic hypermetrope yes normal none >>> data.sort(key=itemgetter(-1)) >>> for value, group in itertools.groupby(data, lambda r: r[-1]): ... print '-----------' ... print 'Group: ' + value ... print_data(group) ... ----------- Group: hard young myope yes normal hard young hypermetrope yes normal hard pre-presbyopic myope yes normal hard presbyopic myope yes normal hard ----------- Group: none young myope no reduced none young myope yes reduced none young hypermetrope no reduced none young hypermetrope yes reduced none pre-presbyopic myope no reduced none pre-presbyopic myope yes reduced none pre-presbyopic hypermetrope no reduced none pre-presbyopic hypermetrope yes reduced none pre-presbyopic hypermetrope yes normal none presbyopic myope no reduced none presbyopic myope no normal none presbyopic myope yes reduced none presbyopic hypermetrope no reduced none presbyopic hypermetrope yes reduced none presbyopic hypermetrope yes normal none ----------- Group: soft young myope no normal soft young hypermetrope no normal soft pre-presbyopic myope no normal soft pre-presbyopic hypermetrope no normal soft presbyopic hypermetrope no normal soft 

1.38   Start a static HTTP server in any directory

[10:26] $ python -m SimpleHTTPServer 5000 Serving HTTP on 0.0.0.0 port 5000 ... 

1.39   Learn the Zen of Python

>>> import this The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those! 

1.40   Use C-Style Braces Instead of Indentation to Denote Scopes

>>> from __future__ import braces 

2   Table of contents

List of language features and tricks in this article:

B、http://ozkatz.github.io/improving-your-python-productivity.html

I've been programming in python for a few years now, and I'm still often amazed by how clear and DRY well written Python code can be. There are many small tips and tricks I've learned over time, mostly by reading the code of popular open source projects, such as DjangoFlaskRequests and others.

Here are a few things I've picked up that are sometimes overlooked, but can really help with everyday work.

1. Dictionary and Set comprehensions

Most Python developers know and use list comprehensions. For those of you unfamiliar with the concept, a list comprehension is a shorter, more concise way of creating lists.

>>> some_list = [1, 2, 3, 4, 5] >>> another_list = [ x + 1 for x in some_list ] >>> another_list [2, 3, 4, 5, 6] 

Since python 3.1 (and also back-ported to Python 2.7), we can now use the same idiom to create sets and dictionaries:

>>> # Set Comprehensions >>> some_list = [1, 2, 3, 4, 5, 2, 5, 1, 4, 8] >>> even_set = { x for x in some_list if x % 2 == 0 } >>> even_set set([8, 2, 4]) >>> # Dict Comprehensions >>> d = { x: x % 2 == 0 for x in range(1, 11) } >>> d {1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False, 10: True} 

In the first example we create a set of unique items from some_list, but only ones that are even numbers. The Dictionary example shows the creation of a dictionary, where the keys are integers from 1 to 10 (inclusive), and the values are booleans, indicating whether or not the key is an even number.

Another feature worth mentioning here is the availability of set literals. We can create a set simply by doing:

>>> my_set = {1, 2, 1, 2, 3, 4} >>> my_set set([1, 2, 3, 4]) 

Instead of using the set() built-in function.

2. Using a Counter object for, well, counting.

This is a pretty obvious one, but it's often forgotten. Counting stuff is a pretty common task for most developers, and while it isn't a very challenging thing to do (In most cases) - there are ways to make it even easier.

Python's collections library includes a subclass of the built-in dict, created specifically for this task:

>>> from collections import Counter >>> c = Counter('hello world') >>> c Counter({'l': 3, 'o': 2, ' ': 1, 'e': 1, 'd': 1, 'h': 1, 'r': 1, 'w': 1}) >>> c.most_common(2) [('l', 3), ('o', 2)] 

3. Pretty printing JSON

JSON is a great serialization format, heavily used today by APIs and web-services. While it's somewhat human-readable, when working with the built-in json module, It's very hard to make sense of larger data structures with the naked eye, as they appear as one long, continuous line.

To make things a bit easier we can use the indent argument to "pretty print" our JSON data. this is especially useful when working interactively from the REPL or for logging:

>>> import json >>> print(json.dumps(data)) # No indention {"status": "OK", "count": 2, "results": [{"age": 27, "name": "Oz", "lactose_intolerant": true}, {"age": 29, "name": "Joe", "lactose_intolerant": false}]} >>> print(json.dumps(data, indent=2)) # With indention { "status": "OK", "count": 2, "results": [ { "age": 27, "name": "Oz", "lactose_intolerant": true }, { "age": 29, "name": "Joe", "lactose_intolerant": false } ] } 

Also, be sure to checkout the built-in pprint module for pretty-printing anything else.

4. Create a one-off, quick and dirty web service

Sometimes we need a very basic and quick way of doing some sort of RPC between services or machines. All we want is a simple way to call a method of program A by program B, possibly on another machine - for internal use.

While I wouldn't advocate this technique for creating anything other than internal one-off hacks, we can use a protocol called XML-RPC (with its corresponding Python libraries) for this sort of work.

Here is an example of a quick and dirty file-reading server, using theSimpleXMLRPCServer module:

from SimpleXMLRPCServer import SimpleXMLRPCServer def file_reader(file_name): with open(file_name, 'r') as f: return f.read() server = SimpleXMLRPCServer(('localhost', 8000)) server.register_introspection_functions() server.register_function(file_reader) server.serve_forever() 

With the corresponding client:

import xmlrpclib proxy = xmlrpclib.ServerProxy('http://localhost:8000/') proxy.file_reader('/tmp/secret.txt') 

And we now have some sort of a remote file reader with no external dependencies and only a little code (And, of course, no security of any kind, so try this only at home).

5. Python's awesome open source community has you covered

Well, I've only covered things available in Python's standard library, which, if you have Python installed, is already included with your distribution. for most other tasks, there are a ton of community maintained 3rd party libraries at your disposal.

Here is my checklist for choosing a great reliable open source library:

A Great open source library must...
  • Contain a clear license that suites your particular case.
  • Be Actively developed and maintained (Or, your willingness to step in and maintain it).
  • Be installable using pip for easy, repeatable deployment.
  • have a test suite with at least decent coverage.

If you do find a good library that fits your needs, don't be shy - most open source projects welcome contributions and assistance, even if you are not a Python veteran. Helping hands (and heads) are almost always welcome.


As always, I'd be happy to learn from your experience and of course discuss the tips I presented! Hit me up in the comments here below, or on Twitter at ozkatz100.

 C、http://blog.jobbole.com/61171/

本文由 伯乐在线 - 熊崽Kevin 翻译。未经许可,禁止转载!
英文出处:pypix。欢迎加入翻译组

译注:本文的英文题目是《Advanced Design Patterns in Python》,可直译为《Python中的高级设计模式》。不过本人在通读彻底文以后发现文章的内容与咱们一般理解的设计模式有很大出入,原文后的评论中也有其余读者提出了这一点。所以,根据文章内容我将题目译为“Python高级编程技巧”,若有不一样意见请留言指出,很是感谢。

正文:

本文展现一些高级的Python设计结构和它们的使用方法。在平常工做中,你能够根据须要选择合适的数据结构,例如对快速查找性的要求、对数据一致性的要求或是对索引的要求等,同时也能够将各类数据结构合适地结合在一块儿,从而生成具备逻辑性并易于理解的数据模型。Python的数据结构从句法上来看很是直观,而且提供了大量的可选操做。这篇指南尝试将大部分经常使用的数据结构知识放到一块儿,而且提供对其最佳用法的探讨。

推导式(Comprehensions)

若是你已经使用了很长时间的Python,那么你至少应该据说过列表推导(list comprehensions)。这是一种将for循环、if表达式以及赋值语句放到单一语句中的一种方法。换句话说,你可以经过一个表达式对一个列表作映射或过滤操做。

一个列表推导式包含如下几个部分:

  • 一个输入序列
  • 一个表示输入序列成员的变量
  • 一个可选的断言表达式
  • 一个将输入序列中知足断言表达式的成员变换成输出列表成员的输出表达式

举个例子,咱们须要从一个输入列表中将全部大于0的整数平方生成一个新的序列,你也许会这么写:

很简单是吧?可是这就会有4行代码,两层嵌套外加一个彻底没必要要的append操做。而若是使用filter、lambda和map函数,则可以将代码大大简化:

嗯,这么一来代码就会在水平方向上展开。那么是否可以继续简化代码呢?列表推导可以给咱们答案:

list1

  • 迭代器(iterator)遍历输入序列num的每一个成员x
  • 断言式判断每一个成员是否大于零
  • 若是成员大于零,则被交给输出表达式,平方以后成为输出列表的成员。

列表推导式被封装在一个列表中,因此很明显它可以当即生成一个新列表。这里只有一个type函数调用而没有隐式调用lambda函数,列表推导式正是使用了一个常规的迭代器、一个表达式和一个if表达式来控制可选的参数。

另外一方面,列表推导也可能会有一些负面效应,那就是整个列表必须一次性加载于内存之中,这对上面举的例子而言不是问题,甚至扩大若干倍以后也都不是问题。可是总会达到极限,内存总会被用完。

针对上面的问题,生成器(Generator)可以很好的解决。生成器表达式不会一次将整个列表加载到内存之中,而是生成一个生成器对象(Generator objector),因此一次只加载一个列表元素。

生成器表达式同列表推导式有着几乎相同的语法结构,区别在于生成器表达式是被圆括号包围,而不是方括号:

这比列表推导效率稍微提升一些,让咱们再一次改造一下代码:

除非特殊的缘由,应该常常在代码中使用生成器表达式。但除非是面对很是大的列表,不然是不会看出明显区别的。

下例使用zip()函数一次处理两个或多个列表中的元素:

再来看一个经过两阶列表推导式遍历目录的例子:

 

装饰器(Decorators)

装饰器为咱们提供了一个增长已有函数或类的功能的有效方法。听起来是否是很像Java中的面向切面编程(Aspect-Oriented Programming)概念?二者都很简单,而且装饰器有着更为强大的功能。举个例子,假定你但愿在一个函数的入口和退出点作一些特别的操做(好比一些安全、追踪以及锁定等操做)就可使用装饰器。

装饰器是一个包装了另外一个函数的特殊函数:主函数被调用,而且其返回值将会被传给装饰器,接下来装饰器将返回一个包装了主函数的替代函数,程序的其余部分看到的将是这个包装函数。

语法糖@标识了装饰器。

好了,让咱们回到刚才的例子。咱们将用装饰器作一些更典型的操做:

当你写下以下代码时:

意味着你分开执行了如下步骤:

装饰器函数中的代码建立了一个新的函数(正如此例中的wrapper函数),它用 *args 和 **kwargs 接收任意的输入参数,而且在此函数内调用原函数而且返回其结果。你能够根据本身的须要放置任何额外的代码(例如本例中的计时操做),新建立的包装函数将做为结果返回并取代原函数。

当编译器查看以上代码时,function()函数将会被编译,而且函数返回对象将会被传给装饰器代码,装饰器将会在作完相关操做以后用一个新的函数对象代替原函数。

装饰器代码是什么样的?大部分的例子都是将装饰器定义为函数,而我发觉将装饰器定义成类更容易理解其功能,而且这样更能发挥装饰器机制的威力。

对装饰器的类实现惟一要求是它必须能如函数通常使用,也就是说它必须是可调用的。因此,若是想这么作这个类必须实现__call__方法。

这样的装饰器应该用来作些什么?它能够作任何事,但一般它用在当你想在一些特殊的地方使用原函数时,但这不是必须的,例如:

译者注:
1. 语法糖@decorator至关于function=decorator(function),在此调用decorator的__init__打印“inside decorator.__init__()”
2. 随后执行f()打印“inside function()”
3. 随后执行“print(“Finished decorating function()”)”
4. 最后在调用function函数时,因为使用装饰器包装,所以执行decorator的__call__打印 “inside decorator.__call__()”。

一个更实际的例子:

 

上下文管理库(ContextLib)

contextlib模块包含了与上下文管理器和with声明相关的工具。一般若是你想写一个上下文管理器,则你须要定义一个类包含__enter__方法以及__exit__方法,例如:

完整的例子在此:

上下文管理器被with声明所激活,这个API涉及到两个方法。
1. __enter__方法,当执行流进入with代码块时,__enter__方法将执行。而且它将返回一个可供上下文使用的对象。
2. 当执行流离开with代码块时,__exit__方法被调用,它将清理被使用的资源。

利用@contextmanager装饰器改写上面那个例子:

看上面这个例子,函数中yield以前的全部代码都相似于上下文管理器中__enter__方法的内容。而yield以后的全部代码都如__exit__方法的内容。若是执行过程当中发生了异常,则会在yield语句触发。

描述器(Descriptors)

描述器决定了对象属性是如何被访问的。描述器的做用是定制当你想引用一个属性时所发生的操做。

构建描述器的方法是至少定义如下三个方法中的一个。须要注意,下文中的instance是包含被访问属性的对象实例,而owner则是被描述器修辞的类。

  • __get__(self, instance, owner) – 这个方法是当属性被经过(value = obj.attr)的方式获取时调用,这个方法的返回值将被赋给请求此属性值的代码部分。
  • __set__(self, instance, value) – 这个方法是当但愿设置属性的值(obj.attr = ‘value’)时被调用,该方法不会返回任何值。
  • __delete__(self, instance) – 当从一个对象中删除一个属性时(del obj.attr),调用此方法。

译者注:对于instance和owner的理解,考虑如下代码:

上例中,instance指的是temp,而owner则是Temperature。

LazyLoading Properties例子:

描述器很好的总结了Python中的绑定方法(bound method)这个概念,绑定方法是经典类(classic classes)的实现核心。在经典类中,当在一个对象实例的字典中没有找到某个属性时,会继续到类的字典中查找,而后再到基类的字典中,就这么一直递归的查找下去。若是在类字典中找到这个属性,解释器会检查找到的对象是否是一个Python函数对象。若是是,则返回的并非这个对象自己,而是返回一个柯里化(currying function)的包装器对象。当调用这个包装器时,它会首先在参数列表以前插入实例,而后再调用原函数。

译者注:
1. 柯里化 – http://zh.wikipedia.org/wiki/%E6%9F%AF%E9%87%8C%E5%8C%96
2. function,method,bound method及unbound method的区别。首先,函数(function)是由def或lambda建立的。当一个函数在class语句块中定义或是由type来建立时,它会转成一个非绑定方法(unbound method),而当经过类实例(instance)来访问此方法的时候,它将转成绑定方法(bound method),绑定方法会自动将实例做为第一个参数传入方法。综上所述,方法是出如今类中的函数,绑定方法是一个绑定了具体实例的方法,反之则是非绑定方法。

综上,描述器被赋值给类,而这些特殊的方法就在属性被访问的时候根据具体的访问类型自动地调用。

元类(MetaClasses)

元类提供了一个改变Python类行为的有效方式。

元类的定义是“一个类的类”。任何实例是它本身的类都是元类。

在上例中,咱们定义了一个类demo,而且生成了一个该类的对象obj。首先,能够看到obj的__class__是demo。有意思的来了,那么demo的class又是什么呢?能够看到demo的__class__是type。

因此说type是python类的类,换句话说,上例中的obj是一个demo的对象,而demo自己又是type的一个对象。

因此说type就是一个元类,并且是python中最多见的元类,由于它使python中全部类的默认元类。

由于元类是类的类,因此它被用来建立类(正如类是被用来建立对象的同样)。可是,难道咱们不是经过一个标准的类定义来建立类的么?的确是这样,可是python内部的运做机制以下:

    • 当看见一个类定义,python会收集全部属性到一个字典中。
    • 当类定义结束,python将决定类的元类,咱们就称它为Meta吧。
    • 最后,python执行Meta(name, bases, dct),其中:

a. Meta是元类,因此这个调用是实例化它。
b. name是新建类的类名。
c. bases是新建类的基类元组
d. dct将属性名映射到对象,列出全部的类属性。

那么如何肯定一个类(A)的元类呢?简单来讲,若是一个类(A)自身或其基类(Base_A)之一有__metaclass__属性存在,则这个类(A/Base_A)就是类(A)的元类。不然type就将是类(A)的元类。

模式(Patterns)

“请求宽恕比请求许可更容易(EFAP)”

这个Python设计原则是这么说的“请求宽恕比请求许可更容易(EFAP)”。不提倡深思熟虑的设计思路,这个原则是说应该尽可能去尝试,若是遇到错误,则给予妥善的处理。Python有着强大的异常处理机制能够支持这种尝试,这些机制帮助程序员开发出更为稳定,容错性更高的程序。

单例

单例是指只能同时存在一个的实例对象。Python提供了不少方法来实现单例。

Null对象

Null对象可以用来代替None类型以免对None的测试。

观察者

观察者模式容许多个对象访问同一份数据。

构造函数

构造函数的参数常常被赋值给实例的变量。这种模式可以用一行代码替代多个手动赋值语句。

总结

谢谢阅读,若有疑问,请留言讨论。

D、http://www.cnblogs.com/vamei/archive/2012/11/06/2755503.html

Python补充02 Python小技巧

 

做者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

 

在这里列举一些我使用Python时积累的小技巧。这些技巧是我在使用Python过程当中常用的。以前很零碎的记在笔记本中,如今整理出来,和你们分享,也做为Python快速教程的一个补充。

 

import模块

在Python常用import声明,以使用其余模块(也就是其它.py文件)中定义的对象。

1) 使用__name__

当咱们编写Python库模块的时候,咱们每每运行一些测试语句。当这个程序做为库被import的时候,咱们并不须要运行这些测试语句。一种解决方法是在import以前,将模块中的测试语句注释掉。Python有一种更优美的解决方法,就是使用__name__。

下面是一个简单的库程序TestLib.py。当直接运行TestLib.py时,__name__为"__main__"。若是被import的话,__name__为"TestLib"。

复制代码
def lib_func(a):
    return a + 10
def lib_func_another(b):
    return b + 20
if __name__ == '__main__': test = 101 print(lib_func(test))
复制代码

 咱们在user.py中import上面的TestLib。

import TestLib
print(TestLib.lib_func(120))

 你能够尝试不在TestLib.py中使用if __name__=='__main__', 并对比运行结果。

 

2) 更多import使用方式

import TestLib as test         # 引用TestLib模块,并将它更名为t

好比:

import TestLib as t
print(t.lib_func(120))

from TestLib import lib_func   # 只引用TestLib中的lib_func对象,并跳过TestLib引用字段

这样的好处是减少所引用模块的内存占用。

好比:

from TestLib import lib_func
print(lib_func(120))

from TestLib import *          # 引用全部TestLib中的对象,并跳过TestLib引用字段

好比:

from TestLib import *
print(lib_func(120))

 

查询

1) 查询函数的参数

当咱们想要知道某个函数会接收哪些参数的时候,可使用下面方法查询。

import inspect
print(inspect.getargspec(func))

 

2) 查询对象的属性

除了使用dir()来查询对象的属性以外,咱们可使用下面内置(built-in)函数来确认一个对象是否具备某个属性:

hasattr(obj, attr_name)   # attr_name是一个字符串

例如:

a = [1,2,3]
print(hasattr(a,'append'))

 

2) 查询对象所属的类和类名称

a = [1, 2, 3]
print a.__class__
print a.__class__.__name__

 

3) 查询父类

咱们能够用__base__属性来查询某个类的父类:

cls.__base__

例如:

print(list.__base__)

 

使用中文(以及其它非ASCII编码)

在Python程序的第一行加入#coding=utf8,例如:

#coding=utf8
print("你好吗?")

也能用如下方式:

#-*- coding: UTF-8 -*-
print("你好吗?")

 

表示2进制,8进制和16进制数字

在2.6以上版本,以以下方式表示

print(0b1110)     # 二进制,以0b开头
print(0o10)       # 八进制,以0o开头
print(0x2A)       # 十六进制,以0x开头

若是是更早版本,能够用以下方式:

print(int("1110", 2))
print(int("10", 8))
print(int("2A", 16))

 

注释

一行内的注释能够以#开始

多行的注释能够以'''开始,以'''结束,好比

复制代码
'''
This is demo
'''

def func():
    # print something
    print("Hello world!")  # use print() function

# main
func()
复制代码

注释应该和所在的程序块对齐。

 

搜索路径

当咱们import的时候,Python会在搜索路径中查找模块(module)。好比上面import TestLib,就要求TestLib.py在搜索路径中。

咱们能够经过下面方法来查看搜索路径:

import sys
print(sys.path)

咱们能够在Python运行的时候增长或者删除sys.path中的元素。另外一方面,咱们能够经过在shell中增长PYTHONPATH环境变量,来为Python增长搜索路径。

下面咱们增长/home/vamei/mylib到搜索路径中:

$export PYTHONPATH=$PYTHONPATH:/home/vamei/mylib

你能够将正面的这行命令加入到~/.bashrc中。这样,咱们就长期的改变了搜索路径。

 

脚本与命令行结合

可使用下面方法运行一个Python脚本,在脚本运行结束后,直接进入Python命令行。这样作的好处是脚本的对象不会被清空,能够经过命令行直接调用。

$python -i script.py

 

安装非标准包

Python的标准库随着Python一块儿安装。当咱们须要非标准包时,就要先安装。

1) 使用Linux repository (Linux环境)

这是安装Python附加包的一个好的起点。你能够在Linux repository中查找可能存在的Python包 (好比在Ubuntu Software Center中搜索matplot)。

2) 使用pip。pip是Python自带的包管理程序,它链接Python repository,并查找其中可能存在的包。

好比使用以下方法来安装、卸载或者升级web.py:

$pip install web.py

$pip uninstall web.py

$pip install --upgrade web.py

若是你的Python安装在一个非标准的路径(使用$which python来确认python可执行文件的路径)中,好比/home/vamei/util/python/bin中,你可使用下面方法设置pip的安装包的路径:

$pip install --install-option="--prefix=/home/vamei/util/" web.py

3) 从源码编译

若是上面方法都无法找到你想要的库,你可能须要从源码开始编译。Google每每是最好的起点。

 

之后若是有新的收获,会补充到这篇博文中。

E、http://python.jobbole.com/32748/

本文由 伯乐在线 - 刘志军 翻译。未经许可,禁止转载!
英文出处:Max Burstein。欢迎加入翻译组

如下是我近些年收集的一些Python实用技巧和工具,但愿能对你有所帮助。

交换变量

if 语句在行内

链接

下面的最后一种方式在绑定两个不一样类型的对象时显得很cool。

数字技巧

注意浮点数的除法

数值比较

这是我见过诸多语言中不多有的如此棒的简便法

同时迭代两个列表

带索引的列表迭代

列表推导式

已知一个列表,咱们能够刷选出偶数列表方法:

转变成以下:

是否是很牛呢,哈哈。

字典推导

和列表推导相似,字典能够作一样的工做:

初始化列表的值

列表转换为字符串

从字典中获取元素

我认可try/except代码并不雅致,不过这里有一种简单方法,尝试在字典中查找key,若是没有找到对应的alue将用第二个参数设为其变量值。

 

 

获取列表的子集

有时,你只须要列表中的部分元素,这里是一些获取列表子集的方法。

60个字符解决FizzBuzz

前段时间Jeff Atwood 推广了一个简单的编程练习叫FizzBuzz,问题引用以下:

写一个程序,打印数字1到100,3的倍数打印“Fizz”来替换这个数,5的倍数打印“Buzz”,对于既是3的倍数又是5的倍数的数字打印“FizzBuzz”。

这里就是一个简短的,有意思的方法解决这个问题:

集合

除了python内置的数据类型外,在collection模块一样还包括一些特别的用例,在有些场合Counter很是实用。若是你参加过在这一年的Facebook HackerCup,你甚至也能找到他的实用之处。

 迭代工具

和collections库同样,还有一个库叫itertools,对某些问题真能高效地解决。其中一个用例是查找全部组合,他能告诉你在一个组中元素的全部不能的组合方式

False == True

比起实用技术来讲这是一个颇有趣的事,在python中,True和False是全局变量,所以:

若是你还有任何很酷的奇技淫巧,能够在下面留言,感谢阅读

F、http://www.cnblogs.com/JohnABC/p/4673649.html

0.推荐的扩展

  requests urilib的替代品

  BeautifulSoup4 解析HTML代码

  rq 任务队列

  selenium 自动化测试工具,模拟浏览器

1.sys.modules, 根据已加载的模块建立对象, 其中 page 为类名

if hasattr(sys.modules[__name__], page):
    setattr(self, page, getattr(sys.modules[__name__], page)(self))

2.hasattr, setattr, locals(), globals() 动态建立变量

3.绑定、未绑定

  未绑定的类方法: 没有self

    经过类来引用方法返回一个未绑定方法对象, 要调用它, 你必须显示地提供一个实例做为第一个参数

  绑定的实例方法: 有self

    经过实例访问方法返回一个绑定的方法对象, Python自动地给方法绑定一个实例, 因此咱们调用它时不用再传一个实例参数

复制代码
class Test:
    def func(self,message):
        print message
 
object1 = Test()
x = object1.func
x('绑定方法对象,实例是隐含的')
 
t=Test.func
t(object1,'未绑定的方法对象,须要传递一个实例') 
#t('未绑定的方法对象,须要传递一个实例') #错误的调用
复制代码

  object1 = Test()生成一个实例, object1.func返回一个绑定的方法, 把实例object1和方法func绑定, 而Test.func是用类去引用方法, 咱们获得一个未绑定的方法对象, 要调用它就得传一个实例参数, 如t(object1,'未绑定的方法对象,须要传递一个实例')

复制代码
class A(object):  
    def f(self):  
        print "f"

def ff(): 
    print "ff"  

a = A()  
a.f()  
xf = a.f  #xf为绑定的方法, 故不用传入第一个值
xf()  
a.f = ff
a.f()
复制代码

4.MRO(method resolution order, 多继承时判断调的属性的类)

  MRO要先肯定一个线性序列, 而后查找路径由由序列中类的顺序决定, 因此MRO的算法就是生成一个线性序列

  Python前后有三种不一样的MRO: 经典方式、Python2.2 新式算法、Python2.3 新式算法(C3), Python 3中只保留了最后一种, 即C3算法

  经典方式: 很是简单, 深度优先, 按定义从左到右

  新式算法: 仍是经典方式, 但出现重复的, 只保留最后一个

  C3算法: 最先被提出是用于Lisp的, 应用在Python中是为了解决原来基于深度优先搜索算法不知足本地优先级, 和单调性的问题:

    本地优先级: 指声明时父类的顺序, 好比C(A, B), 若是访问C类对象属性时, 应该根据声明顺序, 优先查找A类, 而后再查找B类

    单调性: 若是在C的解析顺序中, A排在B的前面, 那么在C的全部子类里, 也必须知足这个顺序

    class B(A) 这时B的mro序列为[B,A]

    class B(A1,A2,A3 ...) 这时B的mro序列 mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) ..., [A1,A2,A3])

    merge操做就是C3算法的核心, 遍历执行merge操做的序列, 若是一个序列的第一个元素, 是其余序列中的第一个元素, 或不在其余序列出现, 则从全部执行merge操做序列中删除这个元素, 合并到当前的mro中, merge操做后的序列, 继续执行merge操做, 直到merge操做的序列为空, 若是merge操做的序列没法为空, 则说明不合法

class a:pass
class b(a):pass
class c(a):pass
class d(b, c):pass

  好比此菱形继承结构

    按经典方式, d类MRO为dbaca, 缺点是若是c类重写了a类中得方法, c类的方法将不会被调用到(即本地优先顺序问题)

    按新式算法, d类MRO为dbca, 缺点是单调性, 好比d继承b、c, 且b在c的前面, 若是f继承d, 那么f的MRO中也应该和d的同样b在c的前面, 单调性即继承时要保持顺序, 如今e继承c、b, 且c在b的前面, f继承d, e时, bc的顺序就无法决定了, 不管怎样排都违反了单调性

复制代码
class A(O):pass
class B(O):pass
class C(O):pass
class E(A,B):pass
class F(B,C):pass
class G(E,F):pass
复制代码

    按C3算法, A、B、C都继承至一个基类, 因此mro序列依次为[A,O]、[B,O]、[C,O]
      mro(E) = [E] + merge(mro(A), mro(B), [A,B])
               = [E] + merge([A,O], [B,O], [A,B])
      此时须要执行merge操做的序列为[A,O]、[B,O]、[A,B]
      A是序列[A,O]中的第一个元素, 在序列[B,O]中不出现, 在序列[A,B]中也是第一个元素, 因此从执行merge操做的序列([A,O]、[B,O]、[A,B])中删除A, 合并到当前mro, [E]中
        mro(E) = [E,A] + merge([O], [B,O], [B])
      再执行merge操做, O是序列[O]中的第一个元素, 但O在序列[B,O]中出现而且不是其中第一个元素, 继续查看[B,O]的第一个元素B, B知足条件, 因此从执行merge操做的序列中删除B, 合并到[E, A]中
        mro(E) = [E,A,B] + merge([O], [O])
                 = [E,A,B,O]

  实现C3算法的代码:

复制代码
#-*- encoding:GBK -*-#  
def mro_C3(*cls):  
        if len(cls)==1:  
            if not cls[0].__bases__:  
                return  cls  
            else:  
                return cls+ mro_C3(*cls[0].__bases__)  
        else:  
            seqs = [list(mro_C3(C)) for C in cls ] +[list(cls)]  
            res = []  
            while True:  
              non_empty = list(filter(None, seqs))  
              if not non_empty:  
                  return tuple(res)  
              for seq in non_empty:  
                  candidate = seq[0]  
                  not_head = [s for s in non_empty if candidate in s[1:]]  
                  if not_head:  
                      candidate = None  
                  else:  
                      break  
              if not candidate:  
                  raise TypeError("inconsistent hierarchy, no C3 MRO is possible")  
              res.append(candidate)  
              for seq in non_empty:  
                  if seq[0] == candidate:  
                      del seq[0]  
复制代码

  查看一个类的MRO列表, 可使用 classname.__mro__

5.super 避免屡次调用基类

复制代码
# -*- coding:utf-8 -*-  
class D(object):  
    def foo(self):  
        print "class D"  

class B(D):  
    pass  
  
class C(D):  
    def foo(self):  
        print "class C"  
  
class A(B, C):  
    pass  

f = A()  
f.foo()
#A的实例对象f在调用foo函数的时候, 根据广度优先搜索原则, 调用的是C类里面的foo函数, 上面的代码输出class C; 若是定义D类的时候直接class D, 而不是class D(object), 那么上述代码就该输出class D了
复制代码

  1). super并非一个函数, 是一个类名, 形如super(B, self)事实上调用了super类的初始化函数产生了一个super对象;

  2). super类的初始化函数并无作什么特殊的操做, 只是简单记录了类类型和具体实例;

  3). super(B, self).func的调用并非用于调用当前类的父类的func函数;

  4). Python的多继承类是经过mro的方式来保证各个父类的函数被逐一调用, 并且保证每一个父类函数只调用一次(若是每一个类都使用super);

  5). 混用super类和非绑定的函数是一个危险行为, 这可能致使应该调用的父类函数没有调用或者一个父类函数被调用屡次

  6).super并非像咱们想象中同样直接找到当前类的父类, 而是沿着mro顺藤摸瓜

  参考:http://blog.csdn.net/johnsonguo/article/details/585193

6.模块即模块对象

7.利用 __new__ 实现单例

复制代码
class Singleton(object):
    def __new__(cls, *args, **kwargs):
        # 关键在于这,每一次实例化的时候,咱们都只会返回这同一个instance对象
        if not hasattr(cls, "instance"):
            cls.instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls.instance
复制代码

8.__new__ 执行顺序

复制代码
class A(object):
    def __new__(cls):
        Object = super(A, cls).__new__(cls)
        print "in New"
        return Object #若是把此行注释掉, 则不会执行 __init__ 方法
    def __init__(self):
        print "in init"


class B(A):
    def __init__(self):
        print "in B's init"

B()
复制代码

9.判断一个变量是否存在

  1).

'var' in locals().keys()

  2).

try:
     print var
except NameError:
     print 'var not defined'

  3).

'var' in dir()

10.根据类名建立实例, 主要是得到类的 class 对象

  1).类名cls为class类型, 直接 cls() 便可

  2).类名cls为str类型

m = __import__(clsstr所在模块名)
cls = getattr(m, clsstr)
cls()

  若是myclass并不在mymodule的自动导出列表中(__all__), 则必须显式地导入, __import__('mymodule', globals(), locals(), ['myclass'])

11.获取当前模块名

  locals()/globals().get("__name__")

12.import, reload, __import__

  del sys.modules[modulename] 便可实现 unimport

  import 调用的 __import__, 好比 import sys => sys = __import__("sys")

  reload 对已经加载的模块进行从新加载, 通常用于原模块有变化等特殊状况, reload前该模块必须已经import过, 但原来已经使用的实例仍是会使用旧的模块, 新生产的实例会使用新的模块

复制代码
import sys   #引用sys模块进来,并非进行sys的第一次加载  
reload(sys)  #从新加载sys  
sys.setdefaultencoding('utf8')  ##调用setdefaultencoding函数  
#若是去掉reload(sys), 会执行失败, 由于这里的import语句其实并非sys的第一次导入语句, 也就是说这里其实多是第2、三次进行sys模块的import, 这里只是一个对sys的引用, 只能reload才能进行从新加载; 那么为何要从新加载, 而直接引用过来则不能调用该函数呢?由于setdefaultencoding函数在被系统调用后被删除了, 因此经过import引用进来时其实已经没有了, 因此必须reload一次sys模块, 这样setdefaultencoding才会为可用, 才能在代码里修改解释器当前的字符编码
复制代码

  __import__, 返回模块实例

__import__(module_name[, globals[, locals[, fromlist]]]) #可选参数默认为globals(),locals(),[]
__import__('os')    
__import__('os',globals(),locals(),['path','pip'])  #等价于from os import path, pip

13.迭代器

  基本原理:

    实现了__iter__方法的对象是可迭代的, 实现了next()方法的对象是迭代器(迭代器就是一个有next()方法的对象), 因此iter(实现了__iter__方法的对象)会调用此对象的__iter__方法, 返回一个实现了next()方法的迭代器对象, 不断调用此迭代器对象的next()方法, 实现遍历, 直到遇到StopIteration异常, 使用迭代器一个显而易见的好处就是每次只从对象中读取一条数据, 不会形成内存的过大开销

  序列、字典、文件中当使用for x in y的结构时, 其实质就是迭代器, 迭代器是和实际对象绑定在一块儿的, 因此在使用迭代器时或者上述3者时不能修改可变对象的值, 这会产生错误

  迭代器不要求你事先准备好整个迭代过程当中全部的元素, 迭代器仅仅在迭代至某个元素时才计算该元素, 而在这以前或以后, 元素能够不存在或者被销毁, 这个特色使得它特别适合用于遍历一些巨大的或是无限的集合, 好比几个G的文件, 或是斐波那契数列等等, 这个特色被称为延迟计算或惰性求值(Lazy evaluation)

  建立迭代器的方法: iter(object)和iter(func, sentinel)两种, 一种使用的是序列, 另外一种使用类来建立, 迭代器更大的功劳是提供了一个统一的访问集合的接口, 只要是实现了__iter__()方法的对象, 就可使用迭代器进行访问, 返回一个对象, 这个对象拥有一个next()方法, 这个方法能在恰当的时候抛出StopIteration异常便可

for i in seq:  
    do_something_to(i)

  实际为:

复制代码
fetch = iter(seq)  
while True:  
    try:  
        i = fetch.next()  
    except StopIteration:  
        break  
    do_something_to(i)
复制代码

  字典中, iterkeys(), itervalues(), iteritems() 比 keys(), values(), items() 更省内存

  open("test.txt").readlines() 返回的是列表, open("test.txt") 返回的是迭代器

14.生成器

  若是一个函数返回的列表很是大, 仅仅建立这个列表就会用完系统全部内存, 由于在咱们的观念中函数只有一次返回结果的机会, 于是必须一次返回全部的结果, 此类问题能够用生成器解决

  生成器是特定的函数, 容许你返回一个值, 而后“暂停”代码的执行, 稍后恢复, 生成器使用了“延迟计算”, 因此在内存上面更加有效, 生成器函数不能有返回值, 由于 yield 的值就是返回值, 生成器就是一类特殊的迭代器

  1).调用生成器函数将返回一个生成器

>>> generator = get_0_1_2()
>>> generator
<generator object get_0_1_2 at 0x00B1C7D8>

  2).第一次调用生成器的next方法时, 生成器才开始执行生成器函数(而不是构建生成器时), 直到遇到yield时暂停执行(挂起), 而且yield的参数将做为这次next方法的返回值

>>> generator.next()
0

  3).以后每次调用生成器的next方法, 生成器将从上次暂停执行的位置恢复执行生成器函数, 直到再次遇到yield时暂停, 而且一样的, yield的参数将做为next方法的返回值

>>> generator.next()
1
>>> generator.next()
2

  4).若是当调用next方法时生成器函数结束(遇到空的return语句或是到达函数体末尾), 则此次next方法的调用将抛出StopIteration异常(即for循环的终止条件)

>>> generator.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

  5).生成器函数在每次暂停执行时, 函数体内的全部变量都将被封存(freeze)在生成器中, 并将在恢复执行时还原, 而且相似于闭包, 即便是同一个生成器函数返回的生成器, 封存的变量也是互相独立的, 咱们的小例子中并无用到变量, 因此这里另外定义一个生成器来展现这个特色

复制代码
>>> def fibonacci():
...   a = b = 1
...   yield a
...   yield b
...   while True:
...     a, b = b, a+b
...     yield b
...
>>> for num in fibonacci():
...   if num > 100: break
...   print num,
...
1 1 2 3 5 8 13 21 34 55 89
复制代码

  看到while True可别太吃惊, 由于生成器能够挂起, 因此是延迟计算的, 无限循环并无关系, 这个例子中咱们定义了一个生成器用于获取斐波那契数列

  若是生成器函数调用了return, 或者执行到函数的末尾, 会出现一个StopIteration异常

  有一篇好文章:点击进入

15.列表解析器

  也能够直接生成 dict

{x: 1 for x in ["name", "sex"]} #返回 {"name": 1, "sex" 1}

  列表解析一次生成一个列表, 所占内存较大

(x+1 for x in lst) #生成器表达式,返回迭代器。外部的括号可在用于参数时省略。 
[x+1 for x in lst] #列表解析,返回list

  因为返回迭代器时, 并非在一开始就计算全部的元素, 这样能获得更多的灵活性而且能够避开不少没必要要的计算, 因此除非你明确但愿返回列表, 不然应该始终使用生成器表达式

  能够在Python Shell中试一下一下两个语句的执行时间

(for x in range(1000000))    #返回生成器
[for x in range(1000000)]    #返回整个列表

  或者提供多条for子句进行嵌套循环, 嵌套次序就是for子句的顺序:

((x, y) for x in range(3) for y in range(x))

  一样外部也可使用 if

(x for x in (y.doSomething() for y in lst) if x>0)

16.在Python里, 函数的默认值实在函数定义的时候实例化的, 而不是在调用的时候, 若是在调用函数的时候重写了默认值, 那么这个存储的值就不会被使用, 当你不重写默认值的时候, 那么Python就会让默认值引用存储的值(这个例子里的numbers)

def abc(numbers = []):
    numbers.append(9)
    print numbers

  abc(): [9] #第一次执行

  abc(): [9, 9] #第二次执行

  abc([1, 2]): [1, 2, 9] #第三次执行

  abc(): [9, 9, 9] #第四次执行

def print_now(now = time.time()):
    print now    #若是不加参数, 则每次都会返回相同的时间

  默认参数最好指向不变对象!

17.当def这个声明执行的时候, Python会静态地从函数的局部做用域里获取信息, 当来到 xxx = yyy 这行的时候(不是执行到这行代码, 而是当Python解释器读到这行代码的时候), 它会把xxx这个变量加入到函数的局部变量列表里

18.__builtin__模块, 在Python启动后、且没有执行程序员所写的任何代码前, Python会首先加载该内建模块到内存, 另外, 该内建模块中的功能能够直接使用, 不用在其前添加内建模块前缀, 导入仅仅是让__builitin__标识符在该做用域内可见

19.from __future__ import xxx, 必须是模块或程序的第一个语句, 此外,'__ future__' 模块中存在的特性最终将成为Python语言标准的一部分, 到那时, 将再也不须要使用 '__future__' 模块

20.序列解包

a, b, c = 1, 2, 3 #赋值
a, b = b, a #转换a, b的值
a = 1, #声明元组

21.最好了解下二进制文件和文本文件的区别以及编码问题, ASCII(固定一个字节)->Unicode(固定两个字节)->UTF-8(变长), 在计算机内存中, 统一使用Unicode编码, 当须要保存到硬盘或者须要传输的时候, 就转换为UTF-8编码, 用记事本编辑的时候, 从文件读取的UTF-8字符被转换为Unicode字符到内存里, 编辑完成后, 保存的时候再把Unicode转换为UTF-8保存到文件, len()函数计算的是str(Unicode编码)的字符数, 若是换成bytes(UTF-8等编码), len()函数就计算字节数:

参考自:廖雪峰Python

22.dict的key必须是不可变对象

23.Python函数参数顺序

  定义: (arg, kwarg = <value>, *args, **kwargs)

  调用:

    第一, 按顺序把"arg"这种形式的实参给对应的形参
    第二, 把"arg=<value>"这种形式的实参赋值给形式kwarg
    第三, 把多出来的"arg"这种形式的实参组成一个tuple给带一个星号的形参args
    第四, 把多出来的"key=value"这种形式的实参转为一个dictionary给带两个星号的形参kwargs

def test(x, y = 5, *a, **b):
    print x, y, a, b
  test(1) ===> 1 5 () {}
  test(1,2) ===> 1 2 () {}
  test(1,2,3)  ===> 1 2 (3,) {}
  test(1,2,3,4) ===> 1 2 (3,4)
  test(x=1)   ===> 1 5 () {}
  test(x=1,y=1)  ===> 1 1 () {}
  test(x=1,y=1,a=1)   ===> 1 1 () {'a':1}
  test(x=1,y=1,a=1,b=1)   ===> 1 1 () {'a':1,'b':1}
  test(1,y=1) ===> 1 1 () {}
  test(1,2,y=1) ===> 出错, 说y给赋了多个值
  test(1, y = 2, 3, a = 4) ===> 出错, non-keyword arg after keyword arg
  test(1,2,3,4,a=1) ===> 1 2 (3,4) {'a':1}

24.限制 **kwargs 参数个数

#只接收city和job做为关键字参数
def person(name, age, *, city, job):
    print(name, age, city, job)

25.functools 模块

  wraps: 用来装饰返回func的函数, 以同步func与被装饰的函数的属性, 好比__name__等 @functools.wraps(func)

  partial: 变化函数的参数建立偏函数, 固定住原函数的部分参数, 好比 int2 = functools.partial(x, base = 2), 此时 int2 是一个把二进制字符串转为十进制数字的函数, int2('10010')

26.一个.py文件称为一个模块, 为了不模块名冲突, Python按目录来组织模块的方法, 称为包(Package), 包内必须有__init__.py, 由于__init__.py自己就是一个模块, 它的模块名就是包名(目录名)

27.第三方库都会在 Python 官方的 pypi.python.org 网站注册, 要安装一个第三方库, 必须先知道该库的名称, 能够在官网或者 pypi 上搜索

28.各类包管理工具区别:

  distribute是setuptools的取代, pip是easy_install的取代

  distribute被建立是由于setuptools包再也不维护了

29.Python的实例属性必须在__init__(self) 方法中定义, 直接跟在类名后边定义的属性都默认是类属性(相似于c++的static变量), 类的属性一改, 只要没有覆盖此属性的对象的此属性都会改

  main.py

复制代码
#-*- coding: utf-8 -*-

class Model():
    model_path = "online_model"
    model_dict = {}

    def __init__(self, path = None):
        self.reload(path)

    def reload(self, path = None):
        if not path:
            return

        self.model_dict.clear()
        fp = file(path, "r")
        for line in fp:
            cols = line.split()
            self.model_dict[cols[0]] = cols[1]

        self.model_path = path

def main():
    m1 = Model()
    m2 = Model()

    m1.reload("aa_model")
    m2.reload("bb_model")

    print m1.model_path
    print m2.model_path

    print m1.model_dict
    print m2.model_dict

    return 0

if __name__ == "__main__":
    main()
复制代码

  aa_model

1 a
2 b

  bb_model

x 1
y 2
z 3

  结果如图:

  aa_model, bb_model: 因为reload方法中self.model_path = path, 实例重写了类的model_path属性(第一次赋值视为变量的定义), 故输出本实例的model_path

  {‘y': 2, 'x': '1', 'z': '3'}, {‘y': 2, 'x': '1', 'z': '3'}: 因为self.model_dict.clear(), 第一次使用此变量非赋值而是直接使用(相似PHP), 相似函数中表示使用已有的值, 根据MRO, 搜索到Model.model_dict, 故两次会覆盖同一个变量

30.类的特殊属性

  C.__name__: 类的名字

  C.__doc__: 类的文档描述

  C.__bases__: 类的基类组成的元组

  C.__dict__: 类的属性

  C.__module__: 类所在模块

  C.__class__: 类的类名

  __getattribute__: 无论属性是否存在都会调用

  __getattr__: 若是属性不存在则调用, 若是__getattribute__被定义会先被调用, 而后调用此方法, 也能够返回函数

复制代码
class A(object):
    def __getattr__(self, attr):
        if attr == "age":
            return lambda : 25

a = A()
a.age()
复制代码

 

  __setattr__

  __delattr__

  __slots__: 限制实例能够添加到属性

  hasattr(), getattr(), setattr(), delattr()

31.实例的特殊属性

  i.__class__: 实例的类名

  i.__dict__: 实例的属性, __dict__分层存储属性, 每一层的__dict__只存储该层新增的属性, 子类不须要重复存储父类中的属性

32.property()能够即时生成属性

33.类中私有属性__xx, 实现为Python自动为__xx改变变量名

34.当咱们定义一个class的时候, 咱们实际上就定义了一种数据类型, 咱们定义的数据类型和Python自带的数据类型, 好比str、list、dict没什么两样, type(instance), 返回instance对应的Class类型, 好比

复制代码
class A(object):
    pass

a = A()
b = type(a)() #此时b为A的实例

print type(A) #<type 'type'>
print type(a) #<class '__main__.A'>
print isinstance(b, A) #True
复制代码

  type()函数能够查看一个类型或变量的类型, A是一个class(类对象), 它的类型就是type, 而h是一个实例, 它的类型就是class A

  class的定义是运行时动态建立的, 而建立class的方法就是使用type()函数, type()函数既能够返回一个对象的类型, 又能够建立出新的类型, 好比, 咱们能够经过type()函数建立出A类, 而无需经过class A(object)...的定义, 

复制代码
def fn(self, name = "John"):
    self.name = name

A = type('A', (object,), dict(hello=fn))
a = A()
print type(A) #<type 'type'>
print type(a) #<class '__main__.A'>
复制代码

  type() 建立类对象的参数以下: 

    class的名称

    继承的父类集合, 注意Python支持多重继承, 若是只有一个父类, 别忘了tuple的单元素写法

    class的方法名称与函数绑定, 这里咱们把函数fn绑定到方法名hello上

  经过type()函数建立的类和直接写class是彻底同样的, 由于Python解释器遇到class定义时, 仅仅是扫描一下class定义的语法, 而后调用type()函数建立出class

  除了使用type()动态建立类对象, 还可使用元类, 即 metaclass, 流程为先定义metaclass, 就能够建立类, 最后建立实例

复制代码
# metaclass是建立类,因此必须从`type`类型派生:
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class MyList(list):
    __metaclass__ = ListMetaclass # 指示使用ListMetaclass来定制类, 表示建立MyList时要经过ListMetaclass.__new__()来建立, 在此, 咱们能够修改类的定义, 好比, 加上新的方法, 而后, 返回修改后的定义
复制代码

  __new__()方法接收到的参数依次是:当前准备建立的类的对象, 类的名字, 类继承的父类集合, 类的方法集合

35.types模块, 能够查看全部的type, type(abs) == types.BuiltinFunctionType

36.把方法变成属性 @property

复制代码
class Student(object):

    #@property 会建立一个另一个装饰器 @score.setter, 负责把一个方法编程属性赋值
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

s = Student()
s.score = 60
s.score = 101    #ValueError: Score must between 0 ~ 100!
复制代码

37.Linux下用Python实现多进程(此处不是讲线程), Unix/Linux操做系统提供了一个fork()系统调用, 它返回两次, 由于操做系统自动把当前进程(称为父进程)复制了一份(称为子进程), 而后, 分别在父进程和子进程内返回, 子进程永远返回0, 而父进程返回子进程的ID, 这样作的理由是, 一个父进程能够fork出不少子进程, 因此, 父进程要记下每一个子进程的ID, 而子进程只须要调用getppid()就能够拿到父进程的ID; Windows系统不支持fork()函数; 有了fork调用, 一个进程在接到新任务时就能够复制出一个子进程来处理新任务, 常见的Apache服务器就是由父进程监听端口, 每当有新的http请求时, 就fork出子进程来处理新的http请求

复制代码
import os

print('Process (%s) start...' % os.getpid())
# Only works on Unix/Linux/Mac:
pid = os.fork()
if pid == 0:
    print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
else:
    print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
复制代码

38.multiprocessing模块是跨平台的多进程模块

  建立一个进程运行某个函数

复制代码
from multiprocessing import Process
import os

# 子进程要执行的代码
def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('Child process will start.')
    p.start()
    p.join()
    print('Child process end.')
复制代码

  结果为:

Parent process 67416.
Child process will start.
Run child process test (70388)...
Child process end.

  join()方法能够等待子进程结束后再继续往下运行, 一般用于进程间的同步

39.占位

40.timestamp与时区毫无关系, timestamp一旦肯定, 其UTC时间就肯定了, 转换到任意时区的时间也是彻底肯定的, 全球各地的计算机在任意时刻的timestamp都是彻底相同的, datetime是有时区的, 会在timestamp与本地时间之间作转换

复制代码
>>> from datetime import datetime
>>> t = 1429417200.0
>>> print(datetime.fromtimestamp(t)) # 本地时间
2015-04-19 12:20:00
>>> print(datetime.utcfromtimestamp(t)) # UTC时间
2015-04-19 04:20:00
复制代码

41.struct模块, 了解c语言的人, 必定会知道struct结构体在c语言中的做用, 它定义了一种结构, 里面包含不一样类型的数据(int, char, bool等等), 方便对某一结构对象进行处理, 而在网络通讯当中, 大多传递的数据是以二进制流(binary data)存在的, 当传递字符串时, 没必要担忧太多的问题, 而当传递诸如int、char之类的基本数据的时候, 就须要有一种机制将某些特定的结构体类型打包成二进制流的字符串而后再网络传输, 而接收端也应该能够经过某种机制进行解包还原出原始的结构体数据, python中的struct模块就提供了这样的机制, 该模块的主要做用就是对python基本类型值与用python字符串格式表示的C struct类型间的转化.

复制代码
>>>import struct
>>>ss = struct.pack("!H4s2I", 20, "abcd", 6, 7)
>>>ss
"\x00\x14abcd\x00\x00\x00\x06\x00\x00\x00\x07" #ss是一个字符串 相似c结构体的字节流(二进制)的字符串表示
>>>struct.unpack("!H4s2I", ss)
(20, 'abcd', 6, 7)
复制代码

  H表示 一个unsigned short的id, 4s表示4字节长的字符串, 2I表示有两个unsigned int类型的数据

  struct中支持的格式以下表

Format C Type Python 字节数
x pad byte no value 1
c char string of length 1 1
b signed char integer 1
B unsigned char integer 1
? _Bool bool 1
h short integer 2
H unsigned short integer 2
i int integer 4
I unsigned int integer or long 4
l long integer 4
L unsigned long long 4
q long long long 8
Q unsigned long long long 8
f float float 4
d double float 8
s char[] string 1
p char[] string 1
P void * long

  另外一方面, 打包的后的字节顺序默认上是由操做系统的决定的, 固然struct模块也提供了自定义字节顺序的功能, 能够指定大端存储、小端存储等特定的字节顺序, 对于底层通讯的字节顺序是十分重要的, 不一样的字节顺序和存储方式也会致使字节大小的不一样; 在format字符串前面加上特定的符号便可以表示不一样的字节顺序存储方式, 例如采用小端存储 s = struct.Struct(‘<I3sf’)就能够了, 官方api library 也提供了相应的对照列表:

Character Byte order Size and alignment
@ native native            凑够4个字节
= native standard        按原字节数
< little-endian standard        按原字节数
> big-endian standard       按原字节数
! network (= big-endian)

standard       按原字节数

  利用struct解析BMP文件头, 首先找一个bmp文件, 没有的话用“画图”画一个, 读入前30个字节来分析:

>>> s = b'\x42\x4d\x38\x8c\x0a\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00\x80\x02\x00\x00\x68\x01\x00\x00\x01\x00\x18\x00'

  BMP格式采用小端方式存储数据,文件头的结构按顺序以下:  两个字节:'BM'表示Windows位图,'BA'表示OS/2位图; 一个4字节整数:表示位图大小; 一个4字节整数:保留位,始终为0; 一个4字节整数:实际图像的偏移量; 一个4字节整数:Header的字节数; 一个4字节整数:图像宽度; 一个4字节整数:图像高度; 一个2字节整数:始终为1; 一个2字节整数:颜色数。  因此,组合起来用unpack读取:

>>> struct.unpack('<ccIIIIIIHH', s)
(b'B', b'M', 691256, 0, 54, 40, 640, 360, 1, 24)

  结果显示,b'B'、b'M'说明是Windows位图,位图大小为640x360,颜色数为24。

42.快速建立字典

  {}.from_keys(list, defaultValue)

  dict((key1, value1), (key2, value2), (key3, value3)...)

  zip([key1, key2, key3...], [value1, value2, value3...])

  dict(name = "John", "age" = 26)

43.判断字典中键名是否存在的两种方法

#第一种
d.has_key()

#第二种
"" in d.keys()

44.判断对象中属性/方法是否存在

hasattr(object, attr)
attr in dir(object)

45.动态调用方法

def _execute(self, sql, params, isMany):
    func = "executemany" if isMany else "execute"
    func = getattr(self._db["cur"], func)
    return func(sql, params)

46.False, 0, '', (), [], {}均可以视为假

47.列表内数据惟一(相似PHP中array_unique)

set([1, 2, 1]) -- set([1, 2])

48.根据一个对象建立另外一个对象

obj.__class__(...)

49.collections模块

  collections.namedtuple 建立可命名的tuple

import collections as cs
Point = cs.namedtuple("Point", ["x", "y", "z"])
p = Point(1, 2, 3)

print p.x, p.y, p.z

  collections.deque 为了高效实现插入和删除操做的双向列表,增删效率高于 list,也可使用 deque(maxlen = 10) 来限制列表长度,超出时添加会把头尾的元素挤出。

复制代码
import collections as cs
q = cs.deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
print q

>>>deque(['y', 'a', 'b', 'c', 'x'])
复制代码

  collections.defaultdict 使用dict时,若是引用的Key不存在,就会抛出KeyError。若是但愿key不存在时,返回一个默认值,就能够用defaultdict,也能够直接建立多维字典。

复制代码
import collections as cs

tree = lambda: collections.defaultdict(tree)

d = tree()
d["names"]["John"] = "ABC"
复制代码

  collections.OrderedDict 建立按key值遍历时有序的dict(普通dict无序排列) 使用

50.禁止建立对象属性字典。每一个类都有实例属性,默认用一个字典保存一个对象的实例属性,容许咱们设置任意属性,可是可能会浪费不少内存。使用__slots__高速Python不要使用字典,并且只给一个固定集合的属性分配空间。

复制代码
class MyClass(obj ect) :
__slots__ = [ ' name' , ' identifier' ]
def __init__(self, name, identifier) :
self. name = name
self. identifier = identifier
self. set_up()
复制代码

51.文件遍历

复制代码
with open("foo.txt", "r") as f:
    for line in f:
        # do_something(line)

for line in open("foo.txt", "r"):
    # do_something(line)
复制代码

52.打印格式化的json

import json
print json.dumps({"name": "John"}, indent = 2)

53.格式化输出字典

print("I'm %(name)s. I'm %(age)d year old" % {'name':'Vamei', 'age':99})

54.字典和集合也有列表推导式,都使用{}包围,分别返回字典和集合

#快速兑换字典键—值
mca={"a":1, "b":2, "c":3, "d":4}
dicts={v:k for k,v in mca.items()}
#{1: 'a', 2: 'b', 3: 'c', 4: 'd'}

55.

 G、http://python.jobbole.com/85668/

原文出处: 张 颖   

使用 pdb 进行调试

pdb 是 python 自带的一个包,为 python 程序提供了一种交互的源代码调试功能,主要特性包括设置断点、单步调试、进入函数调试、查看当前代码、查看栈片断、动态改变变量的值等。pdb 提供了一些经常使用的调试命令,详情见表 1。

表 1. pdb 经常使用命令
命令 解释
break 或 b 设置断点 设置断点
continue 或 c 继续执行程序
list 或 l 查看当前行的代码段
step 或 s 进入函数
return 或 r 执行代码直到从当前函数返回
exit 或 q 停止并退出
next 或 n 执行下一行
pp 打印变量的值
help 帮助

下面结合具体的实例讲述如何使用 pdb 进行调试。

清单 1. 测试代码示例

开始调试:直接运行脚本,会停留在 pdb.set_trace() 处,选择 n+enter 能够执行当前的 statement。在第一次按下了 n+enter 以后能够直接按 enter 表示重复执行上一条 debug 命令。

清单 2. 利用 pdb 调试

退出 debug:使用 quit 或者 q 能够退出当前的 debug,可是 quit 会以一种很是粗鲁的方式退出程序,其结果是直接 crash。

清单 3. 退出 debug

打印变量的值:若是须要在调试过程当中打印变量的值,能够直接使用 p 加上变量名,可是须要注意的是打印仅仅在当前的 statement 已经被执行了以后才能看到具体的值,不然会报 NameError: 错误。

清单 4. debug 过程当中打印变量

使用 c 能够中止当前的 debug 使程序继续执行。若是在下面的程序中继续有 set_statement() 的申明,则又会从新进入到 debug 的状态,读者能够在代码 print final 以前再加上 set_trace() 验证。

清单 5. 中止 debug 继续执行程序

显示代码:在 debug 的时候不必定能记住当前的代码块,如要要查看具体的代码块,则能够经过使用 list 或者 l 命令显示。list 会用箭头 -> 指向当前 debug 的语句。

清单 6. debug 过程当中显示代码

在使用函数的状况下进行 debug

清单 7. 使用函数的例子

若是直接使用 n 进行 debug 则到 final=combine(a,b) 这句的时候会将其当作普通的赋值语句处理,进入到 print final。若是想要对函数进行 debug 如何处理呢 ? 能够直接使用 s 进入函数块。函数里面的单步调试与上面的介绍相似。若是不想在函数里单步调试能够在断点处直接按 r 退出到调用的地方。

清单 8. 对函数进行 debug

在调试的时候动态改变值 。在调试的时候能够动态改变变量的值,具体以下实例。须要注意的是下面有个错误,缘由是 b 已经被赋值了,若是想从新改变 b 的赋值,则应该使用! B。

清单 9. 在调试的时候动态改变值

pdb 调试有个明显的缺陷就是对于多线程,远程调试等支持得不够好,同时没有较为直观的界面显示,不太适合大型的 python 项目。而在较大的 python 项目中,这些调试需求比较常见,所以须要使用更为高级的调试工具。接下来将介绍 PyCharm IDE 的调试方法 .

使用 PyCharm 进行调试

PyCharm 是由 JetBrains 打造的一款 Python IDE,具备语法高亮、Project 管理、代码跳转、智能提示、自动完成、单元测试、版本控制等功能,同时提供了对 Django 开发以及 Google App Engine 的支持。分为我的独立版和商业版,须要 license 支持,也能够获取免费的 30 天试用。试用版本的 Pycharm 能够在官网上下载,下载地址为:http://www.jetbrains.com/pycharm/download/index.html。 PyCharm 同时提供了较为完善的调试功能,支持多线程,远程调试等,能够支持断点设置,单步模式,表达式求值,变量查看等一系列功能。PyCharm IDE 的调试窗口布局如图 1 所示。

图 1. PyCharm IDE 窗口布局

image001

下面结合实例讲述如何利用 PyCharm 进行多线程调试。具体调试所用的代码实例见清单 10。

清单 10. PyCharm 调试代码实例

在调试以前一般须要设置断点,断点能够设置在循环或者条件判断的表达式处或者程序的关键点。设置断点的方法很是简单:在代码编辑框中将光标移动到须要设置断点的行,而后直接按 Ctrl+F8 或者选择菜单”Run”->”Toggle Line Break Point”,更为直接的方法是双击代码编辑处左侧边缘,能够看到出现红色的小圆点(如图 2)。当调试开始的时候,当前正在执行的代码会直接显示为蓝色。下图中设置了三个断点,蓝色高亮显示的为正在执行的代码。

图 2. 断点设置

image002

表达式求值:在调试过程当中有的时候须要追踪一些表达式的值来发现程序中的问题,Pycharm 支持表达式求值,能够经过选中该表达式,而后选择“Run”->”Evaluate Expression”,在出现的窗口中直接选择 Evaluate 即可以查看。

Pychar 同时提供了 Variables 和 Watches 窗口,其中调试步骤中所涉及的具体变量的值能够直接在 variable 一栏中查看。

图 3. 变量查看

image003

若是要动态的监测某个变量能够直接选中该变量并选择菜单”Run”->”Add Watch”添加到 watches 栏中。当调试进行到该变量所在的语句时,在该窗口中能够直接看到该变量的具体值。

图 4. 监测变量

image004

对于多线程程序来讲,一般会有多个线程,当须要 debug 的断点分别设置在不一样线程对应的线程体中的时候,一般须要 IDE 有良好的多线程调试功能的支持。 Pycharm 中在主线程启动子线程的时候会自动产生一个 Dummy 开头的名字的虚拟线程,每个 frame 对应各自的调试帧。如图 5,本实例中一共有四个线程,其中主线程生成了三个线程,分别为 Dummy-4,Dummy-5,Dummy-6. 其中 Dummy-4 对应线程 1,其他分别对应线程 2 和线程 3。

图 5. 多线程窗口

image005

当调试进入到各个线程的子程序时,Frame 会自动切换到其所对应的 frame,相应的变量栏中也会显示与该过程对应的相关变量,如图 6,直接控制调试按钮,如 setp in,step over 即可以方便的进行调试。

图 6. 子线程调试

image006

查看大图

使用 PyDev 进行调试

PyDev 是一个开源的的 plugin,它能够方便的和 Eclipse 集成,提供方便强大的调试功能。同时做为一个优秀的 Python IDE 还提供语法错误提示、源代码编辑助手、Quick Outline、Globals Browser、Hierarchy View、运行等强大功能。下面讲述如何将 PyDev 和 Eclipse 集成。在安装 PyDev 以前,须要先安装 Java 1.4 或更高版本、Eclipse 以及 Python。 第一步:启动 Eclipse,在 Eclipse 菜单栏中找到 Help 栏,选择 Help > Install New Software,并选择 Add button,添加 Ptdev 的下载站点 http://pydev.org/updates。选择 PyDev 以后完成余下的步骤即可以安装 PyDev。

图 7. 安装 PyDev

image007

安装完成以后须要配置 Python 解释器,在 Eclipse 菜单栏中,选择 Window > Preferences > Pydev > Interpreter – Python。Python 安装在 C:Python27 路径下。单击 New,选择 Python 解释器 python.exe,打开后显示出一个包含不少复选框的窗口,选择须要加入系统 PYTHONPATH 的路径,单击 OK。

图 8. 配置 PyDev

image008

在配置完 Pydev 以后,能够经过在 Eclipse 菜单栏中,选择 File > New > Project > Pydev >Pydev Project,单击 Next 建立 Python 项目,下面的内容假设 python 项目已经建立,而且有个须要调试的脚本 remote.py(具体内容以下),它是一个登录到远程机器上去执行一些命令的脚本,在运行的时候须要传入一些参数,下面将详细讲述如何在调试过程当中传入参数 .

清单 11. Pydev 调试示例代码

在调试的时候有些状况须要传入一些参数,在调试以前须要进行相应的配置以便接收所须要的参数,选择须要调试的程序(本例 remote.py),该脚本在 debug 的过程当中须要输入四个参数:host,user,password 以及命令。在 eclipse 的工程目录下选择须要 debug 的程序,单击右键,选择“Debug As”->“Debug Configurations”,在 Arguments Tab 页中选择“Variables”。以下 图 9 所示 .

图 9. 配置变量

image009

在窗口”Select Variable”以后选择“Edit Varuables” ,出现以下窗口,在下图中选择”New” 并在弹出的窗口中输入对应的变量名和值。特别须要注意的是在值的后面必定要有空格,否则全部的参数都会被当作第一个参数读入。

图 10. 添加具体变量

image010

按照以上方式依次配置完全部参数,而后在”select variable“窗口中安装参数所须要的顺序依次选择对应的变量。配置完成以后状态以下图 11 所示。

图 11. 完成配置

image011

选择 Debug 即可以开始程序的调试,调试方法与 eclipse 内置的调试功能的使用类似,而且支持多线程的 debug,这方面的文章已经有不少,读者能够自行搜索阅读,或者参考”使用 Eclipse 平台进行调试“一文。

使用日志功能达到调试的目的

日志信息是软件开发过程当中进行调试的一种很是有用的方式,特别是在大型软件开发过程须要不少相关人员进行协做的状况下。开发人员经过在代码中加入一些特定的可以记录软件运行过程当中的各类事件信息可以有利于甄别代码中存在的问题。这些信息可能包括时间,描述信息以及错误或者异常发生时候的特定上下文信息。 最原始的 debug 方法是经过在代码中嵌入 print 语句,经过输出一些相关的信息来定位程序的问题。但这种方法有必定的缺陷,正常的程序输出和 debug 信息混合在一块儿,给分析带来必定困难,当程序调试结束再也不须要 debug 输出的时候,一般没有很简单的方法将 print 的信息屏蔽掉或者定位到文件。python 中自带的 logging 模块能够比较方便的解决这些问题,它提供日志功能,将 logger 的 level 分为五个级别,能够经过 Logger.setLevel(lvl) 来设置。默认的级别为 warning。

表 2. 日志的级别
Level 使用情形
DEBUG 详细的信息,在追踪问题的时候使用
INFO 正常的信息
WARNING 一些不可预见的问题发生,或者将要发生,如磁盘空间低等,但不影响程序的运行
ERROR 因为某些严重的问题,程序中的一些功能受到影响
CRITICAL 严重的错误,或者程序自己不可以继续运行

logging lib 包含 4 个主要对象

  • logger:logger 是程序信息输出的接口。它分散在不一样的代码中使得程序能够在运行的时候记录相应的信息,并根据设置的日志级别或 filter 来决定哪些信息须要输出并将这些信息分发到其关联的 handler。经常使用的方法有 Logger.setLevel(),Logger.addHandler() ,Logger.removeHandler() ,Logger.addFilter() ,Logger.debug(), Logger.info(), Logger.warning(), Logger.error(),getLogger() 等。logger 支持层次继承关系,子 logger 的名称一般是父 logger.name 的方式。若是不建立 logger 的实例,则使用默认的 root logger,经过 logging.getLogger() 或者 logging.getLogger(“”) 获得 root logger 实例。
  • Handler:Handler 用来处理信息的输出,能够将信息输出到控制台,文件或者网络。能够经过 Logger.addHandler() 来给 logger 对象添加 handler,经常使用的 handler 有 StreamHandler 和 FileHandler 类。StreamHandler 发送错误信息到流,而 FileHandler 类用于向文件输出日志信息,这两个 handler 定义在 logging 的核心模块中。其余的 hander 定义在 logging.handles 模块中,如 HTTPHandler,SocketHandler。
  • Formatter:Formatter 则决定了 log 信息的格式 , 格式使用相似于 %()s 的形式来定义,如’%(asctime)s – %(levelname)s – %(message)s’,支持的 key 能够在 python 自带的文档 LogRecord attributes 中查看。
  • Filter:Filter 用来决定哪些信息须要输出。能够被 handler 和 logger 使用,支持层次关系,好比若是设置了 filter 为名称为 A.B 的 logger,则该 logger 和其子 logger 的信息会被输出,如 A.B,A.B.C.
清单 12. 日志使用示例

上例设置了 filter b,则 b.c 为 b 的子 logger,所以知足过滤条件该 logger 相关的日志信息会 被输出,而其余不知足条件的 logger(这里是 d.e)会被过滤掉。

清单 13. 输出结果

logging 的使用很是简单,同时它是线程安全的,下面结合多线程的例子讲述如何使用 logging 进行 debug。

清单 14. 多线程使用 logging

总结

全文介绍了 python 中 debug 的几种不一样的方式,包括 pdb 模块、利用 PyDev 和 Eclipse 集成进行调试、PyCharm 以及 Debug 日志进行调试,但愿能给相关 python 使用者一点参考。更多关于 python debugger 的资料能够参见参考资料。

参考资料

学习