python学习笔记之迭代器和函数(第三天)

时间:2021-09-04 10:10:48

银角大王之三:

http://www.cnblogs.com/wupeiqi/articles/4911365.html

一、collection系列:

1、counter计数器

如果counter(dict)是对字典的一个补充,如果counter(list)则是对列表的补充,初步测试对字典的值进行排序。

########################################################################
### Counter
######################################################################## class Counter(dict):
'''Dict subclass for counting hashable items. Sometimes called a bag
or multiset. Elements are stored as dictionary keys and their counts
are stored as dictionary values. >>> c = Counter('abcdeabcdabcaba') # count elements from a string >>> c.most_common(3) # three most common elements
[('a', 5), ('b', 4), ('c', 3)]
>>> sorted(c) # list all unique elements
['a', 'b', 'c', 'd', 'e']
>>> ''.join(sorted(c.elements())) # list elements with repetitions
'aaaaabbbbcccdde'
>>> sum(c.values()) # total of all counts >>> c['a'] # count of letter 'a'
>>> for elem in 'shazam': # update counts from an iterable
... c[elem] += 1 # by adding 1 to each element's count
>>> c['a'] # now there are seven 'a'
>>> del c['b'] # remove all 'b'
>>> c['b'] # now there are zero 'b' >>> d = Counter('simsalabim') # make another counter
>>> c.update(d) # add in the second counter
>>> c['a'] # now there are nine 'a' >>> c.clear() # empty the counter
>>> c
Counter() Note: If a count is set to zero or reduced to zero, it will remain
in the counter until the entry is deleted or the counter is cleared: >>> c = Counter('aaabbc')
>>> c['b'] -= 2 # reduce the count of 'b' by two
>>> c.most_common() # 'b' is still in, but its count is zero
[('a', 3), ('c', 1), ('b', 0)] '''
# References:
# http://en.wikipedia.org/wiki/Multiset
# http://www.gnu.org/software/smalltalk/manual-base/html_node/Bag.html
# http://www.demo2s.com/Tutorial/Cpp/0380__set-multiset/Catalog0380__set-multiset.htm
# http://code.activestate.com/recipes/259174/
# Knuth, TAOCP Vol. II section 4.6.3 def __init__(self, iterable=None, **kwds):
'''Create a new, empty Counter object. And if given, count elements
from an input iterable. Or, initialize the count from another mapping
of elements to their counts. >>> c = Counter() # a new, empty counter
>>> c = Counter('gallahad') # a new counter from an iterable
>>> c = Counter({'a': 4, 'b': 2}) # a new counter from a mapping
>>> c = Counter(a=4, b=2) # a new counter from keyword args '''
super(Counter, self).__init__()
self.update(iterable, **kwds) def __missing__(self, key):
""" 对于不存在的元素,返回计数器为0 """
'The count of elements not in the Counter is zero.'
# Needed so that self[missing_item] does not raise KeyError
return 0 def most_common(self, n=None):
""" 数量大于等n的所有元素和计数器 """
'''List the n most common elements and their counts from the most
common to the least. If n is None, then list all element counts. >>> Counter('abcdeabcdabcaba').most_common(3)
[('a', 5), ('b', 4), ('c', 3)] '''
# Emulate Bag.sortedByCount from Smalltalk
if n is None:
return sorted(self.iteritems(), key=_itemgetter(1), reverse=True)
return _heapq.nlargest(n, self.iteritems(), key=_itemgetter(1)) def elements(self):
""" 计数器中的所有元素,注:此处非所有元素集合,而是包含所有元素集合的迭代器 """
'''Iterator over elements repeating each as many times as its count. >>> c = Counter('ABCABC')
>>> sorted(c.elements())
['A', 'A', 'B', 'B', 'C', 'C'] # Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1
>>> prime_factors = Counter({2: 2, 3: 3, 17: 1})
>>> product = 1
>>> for factor in prime_factors.elements(): # loop over factors
... product *= factor # and multiply them
>>> product Note, if an element's count has been set to zero or is a negative
number, elements() will ignore it. '''
# Emulate Bag.do from Smalltalk and Multiset.begin from C++.
return _chain.from_iterable(_starmap(_repeat, self.iteritems())) # Override dict methods where necessary @classmethod
def fromkeys(cls, iterable, v=None):
# There is no equivalent method for counters because setting v=1
# means that no element can have a count greater than one.
raise NotImplementedError(
'Counter.fromkeys() is undefined. Use Counter(iterable) instead.') def update(self, iterable=None, **kwds):
""" 更新计数器,其实就是增加;如果原来没有,则新建,如果有则加一 """
'''Like dict.update() but add counts instead of replacing them. Source can be an iterable, a dictionary, or another Counter instance. >>> c = Counter('which')
>>> c.update('witch') # add elements from another iterable
>>> d = Counter('watch')
>>> c.update(d) # add elements from another counter
>>> c['h'] # four 'h' in which, witch, and watch '''
# The regular dict.update() operation makes no sense here because the
# replace behavior results in the some of original untouched counts
# being mixed-in with all of the other counts for a mismash that
# doesn't have a straight-forward interpretation in most counting
# contexts. Instead, we implement straight-addition. Both the inputs
# and outputs are allowed to contain zero and negative counts. if iterable is not None:
if isinstance(iterable, Mapping):
if self:
self_get = self.get
for elem, count in iterable.iteritems():
self[elem] = self_get(elem, 0) + count
else:
super(Counter, self).update(iterable) # fast path when counter is empty
else:
self_get = self.get
for elem in iterable:
self[elem] = self_get(elem, 0) + 1
if kwds:
self.update(kwds) def subtract(self, iterable=None, **kwds):
""" 相减,原来的计数器中的每一个元素的数量减去后添加的元素的数量 """
'''Like dict.update() but subtracts counts instead of replacing them.
Counts can be reduced below zero. Both the inputs and outputs are
allowed to contain zero and negative counts. Source can be an iterable, a dictionary, or another Counter instance. >>> c = Counter('which')
>>> c.subtract('witch') # subtract elements from another iterable
>>> c.subtract(Counter('watch')) # subtract elements from another counter
>>> c['h'] # 2 in which, minus 1 in witch, minus 1 in watch
>>> c['w'] # 1 in which, minus 1 in witch, minus 1 in watch
-1 '''
if iterable is not None:
self_get = self.get
if isinstance(iterable, Mapping):
for elem, count in iterable.items():
self[elem] = self_get(elem, 0) - count
else:
for elem in iterable:
self[elem] = self_get(elem, 0) - 1
if kwds:
self.subtract(kwds) def copy(self):
""" 拷贝 """
'Return a shallow copy.'
return self.__class__(self) def __reduce__(self):
""" 返回一个元组(类型,元组) """
return self.__class__, (dict(self),) def __delitem__(self, elem):
""" 删除元素 """
'Like dict.__delitem__() but does not raise KeyError for missing values.'
if elem in self:
super(Counter, self).__delitem__(elem) def __repr__(self):
if not self:
return '%s()' % self.__class__.__name__
items = ', '.join(map('%r: %r'.__mod__, self.most_common()))
return '%s({%s})' % (self.__class__.__name__, items) # Multiset-style mathematical operations discussed in:
# Knuth TAOCP Volume II section 4.6.3 exercise 19
# and at http://en.wikipedia.org/wiki/Multiset
#
# Outputs guaranteed to only include positive counts.
#
# To strip negative and zero counts, add-in an empty counter:
# c += Counter() def __add__(self, other):
'''Add counts from two counters. >>> Counter('abbb') + Counter('bcc')
Counter({'b': 4, 'c': 2, 'a': 1}) '''
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
for elem, count in self.items():
newcount = count + other[elem]
if newcount > 0:
result[elem] = newcount
for elem, count in other.items():
if elem not in self and count > 0:
result[elem] = count
return result def __sub__(self, other):
''' Subtract count, but keep only results with positive counts. >>> Counter('abbbc') - Counter('bccd')
Counter({'b': 2, 'a': 1}) '''
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
for elem, count in self.items():
newcount = count - other[elem]
if newcount > 0:
result[elem] = newcount
for elem, count in other.items():
if elem not in self and count < 0:
result[elem] = 0 - count
return result def __or__(self, other):
'''Union is the maximum of value in either of the input counters. >>> Counter('abbb') | Counter('bcc')
Counter({'b': 3, 'c': 2, 'a': 1}) '''
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
for elem, count in self.items():
other_count = other[elem]
newcount = other_count if count < other_count else count
if newcount > 0:
result[elem] = newcount
for elem, count in other.items():
if elem not in self and count > 0:
result[elem] = count
return result def __and__(self, other):
''' Intersection is the minimum of corresponding counts. >>> Counter('abbb') & Counter('bcc')
Counter({'b': 1}) '''
if not isinstance(other, Counter):
return NotImplemented
result = Counter()
for elem, count in self.items():
other_count = other[elem]
newcount = count if count < other_count else other_count
if newcount > 0:
result[elem] = newcount
return result Counter Counter

Counter

实例说明:(python2.7和python3.4使用方法一样)


import collections

a = collections.Counter('aabadsfasfasfadfasdfsadfa')
b = collections.Counter('1234qwrqrasfzvzvxzv')
print(a.most_common(3))            #显示从大到小的n个数
print(a)
a.update(b)                                #叠加

a.subtract(b)                              #相减

for aa in a.elements():                 #作为迭代器,主要用于循环
print(aa)

a.clear()


[('a', 9), ('f', 6), ('s', 5)]
Counter({'a': 9, 'f': 6, 's': 5, 'd': 4, 'b': 1})


2、有序字典(orderedDict )

用法同dict,只是在内部维护了个列表,并对列表进行排序,即对字典的keys作了sort

class OrderedDict(dict):
'Dictionary that remembers insertion order'
# An inherited dict maps keys to values.
# The inherited dict provides __getitem__, __len__, __contains__, and get.
# The remaining methods are order-aware.
# Big-O running times for all methods are the same as regular dictionaries. # The internal self.__map dict maps keys to links in a doubly linked list.
# The circular doubly linked list starts and ends with a sentinel element.
# The sentinel element never gets deleted (this simplifies the algorithm).
# Each link is stored as a list of length three: [PREV, NEXT, KEY]. def __init__(self, *args, **kwds):
'''Initialize an ordered dictionary. The signature is the same as
regular dictionaries, but keyword arguments are not recommended because
their insertion order is arbitrary. '''
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__root
except AttributeError:
self.__root = root = [] # sentinel node
root[:] = [root, root, None]
self.__map = {}
self.__update(*args, **kwds) def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link at the end of the linked list,
# and the inherited dictionary is updated with the new key/value pair.
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) def __delitem__(self, key, dict_delitem=dict.__delitem__):
'od.__delitem__(y) <==> del od[y]'
# Deleting an existing item uses self.__map to find the link which gets
# removed by updating the links in the predecessor and successor nodes.
dict_delitem(self, key)
link_prev, link_next, _ = self.__map.pop(key)
link_prev[1] = link_next # update link_prev[NEXT]
link_next[0] = link_prev # update link_next[PREV] def __iter__(self):
'od.__iter__() <==> iter(od)'
# Traverse the linked list in order.
root = self.__root
curr = root[1] # start at the first node
while curr is not root:
yield curr[2] # yield the curr[KEY]
curr = curr[1] # move to next node def __reversed__(self):
'od.__reversed__() <==> reversed(od)'
# Traverse the linked list in reverse order.
root = self.__root
curr = root[0] # start at the last node
while curr is not root:
yield curr[2] # yield the curr[KEY]
curr = curr[0] # move to previous node def clear(self):
'od.clear() -> None. Remove all items from od.'
root = self.__root
root[:] = [root, root, None]
self.__map.clear()
dict.clear(self) # -- the following methods do not depend on the internal structure -- def keys(self):
'od.keys() -> list of keys in od'
return list(self) def values(self):
'od.values() -> list of values in od'
return [self[key] for key in self] def items(self):
'od.items() -> list of (key, value) pairs in od'
return [(key, self[key]) for key in self] def iterkeys(self):
'od.iterkeys() -> an iterator over the keys in od'
return iter(self) def itervalues(self):
'od.itervalues -> an iterator over the values in od'
for k in self:
yield self[k] def iteritems(self):
'od.iteritems -> an iterator over the (key, value) pairs in od'
for k in self:
yield (k, self[k]) update = MutableMapping.update __update = update # let subclasses override update without breaking __init__ __marker = object() def pop(self, key, default=__marker):
'''od.pop(k[,d]) -> v, remove specified key and return the corresponding
value. If key is not found, d is returned if given, otherwise KeyError
is raised. '''
if key in self:
result = self[key]
del self[key]
return result
if default is self.__marker:
raise KeyError(key)
return default def setdefault(self, key, default=None):
'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
if key in self:
return self[key]
self[key] = default
return default def popitem(self, last=True):
'''od.popitem() -> (k, v), return and remove a (key, value) pair.
Pairs are returned in LIFO order if last is true or FIFO order if false. '''
if not self:
raise KeyError('dictionary is empty')
key = next(reversed(self) if last else iter(self))
value = self.pop(key)
return key, value def __repr__(self, _repr_running={}):
'od.__repr__() <==> repr(od)'
call_key = id(self), _get_ident()
if call_key in _repr_running:
return '...'
_repr_running[call_key] = 1
try:
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())
finally:
del _repr_running[call_key] def __reduce__(self):
'Return state information for pickling'
items = [[k, self[k]] for k in self]
inst_dict = vars(self).copy()
for k in vars(OrderedDict()):
inst_dict.pop(k, None)
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,) def copy(self):
'od.copy() -> a shallow copy of od'
return self.__class__(self) @classmethod
def fromkeys(cls, iterable, value=None):
'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
If not specified, the value defaults to None. '''
self = cls()
for key in iterable:
self[key] = value
return self def __eq__(self, other):
'''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
while comparison to a regular mapping is order-insensitive. '''
if isinstance(other, OrderedDict):
return dict.__eq__(self, other) and all(_imap(_eq, self, other))
return dict.__eq__(self, other) def __ne__(self, other):
'od.__ne__(y) <==> od!=y'
return not self == other # -- the following methods support python 3.x style dictionary views -- def viewkeys(self):
"od.viewkeys() -> a set-like object providing a view on od's keys"
return KeysView(self) def viewvalues(self):
"od.viewvalues() -> an object providing a view on od's values"
return ValuesView(self) def viewitems(self):
"od.viewitems() -> a set-like object providing a view on od's items"
return ItemsView(self) OrderedDict

ordereddict

实例:


>>> a = collections.OrderedDict()

>>> a['a'] = 1
>>> a['b'] = 2
>>> a['c'] = 2
>>> a
OrderedDict([('a', 1), ('b', 2), ('c', 2)])
>>> a['d'] = 1
>>> a
OrderedDict([('a', 1), ('b', 2), ('c', 2), ('d', 1)])
>>> b = {'a':1,'b':2,'c':2,'d':1}
>>> b
{'a': 1, 'c': 2, 'b': 2, 'd': 1}


3、默认字典(defaultdict) 

即为字典中的values设置一个默认类型:

defaultdict的参数默认是dict,也可以为list,tuple

class defaultdict(dict):
"""
defaultdict(default_factory[, ...]) --> dict with default factory The default factory is called without arguments to produce
a new value when a key is not present, in __getitem__ only.
A defaultdict compares equal to a dict with the same items.
All remaining arguments are treated the same as if they were
passed to the dict constructor, including keyword arguments.
"""
def copy(self): # real signature unknown; restored from __doc__
""" D.copy() -> a shallow copy of D. """
pass def __copy__(self, *args, **kwargs): # real signature unknown
""" D.copy() -> a shallow copy of D. """
pass def __getattribute__(self, name): # real signature unknown; restored from __doc__
""" x.__getattribute__('name') <==> x.name """
pass def __init__(self, default_factory=None, **kwargs): # known case of _collections.defaultdict.__init__
"""
defaultdict(default_factory[, ...]) --> dict with default factory The default factory is called without arguments to produce
a new value when a key is not present, in __getitem__ only.
A defaultdict compares equal to a dict with the same items.
All remaining arguments are treated the same as if they were
passed to the dict constructor, including keyword arguments. # (copied from class doc)
"""
pass def __missing__(self, key): # real signature unknown; restored from __doc__
"""
__missing__(key) # Called by __getitem__ for missing key; pseudo-code:
if self.default_factory is None: raise KeyError((key,))
self[key] = value = self.default_factory()
return value
"""
pass def __reduce__(self, *args, **kwargs): # real signature unknown
""" Return state information for pickling. """
pass def __repr__(self): # real signature unknown; restored from __doc__
""" x.__repr__() <==> repr(x) """
pass default_factory = property(lambda self: object(), lambda self, v: None, lambda self: None) # default
"""Factory for default value called by __missing__().""" defaultdict

defaultdict

实例说明:


在使用的dict时,无法指定values的类型,在赋值时要进行判断,具体如下:

values = [11,22,33,44,55,66,77,88,99,90]

my_dict = {}

for value in values:
    if value>66:
        if my_dict.has_key('k1'):
             my_dict['k1'].append(value)
        else:
             my_dict['k1'] = [value]
    else:
        if my_dict.has_key('k2'):
             my_dict['k2'].append(value)
        else:
             my_dict['k2'] = [value]

而在使用了defaultdict时,代码进行了简化:

from collections import defaultdict

values = [11, 22, 33,44,55,66,77,88,99,90]

my_dict = defaultdict(list)

for value in values:
     if value>66:
          my_dict['k1'].append(value)
     else:
          my_dict['k2'].append(value)


4、可命名元组(namedtuple) 

创建一个自己的可扩展tuple的类(包含tuple所有功能以及其他功能的类型),在根据类创建对象,然后调用对象

最长用于坐标,普通的元组类似于列表以index编号来访问,而自定义可扩展的可以类似于字典的keys进行访问

class Mytuple(__builtin__.tuple)
| Mytuple(x, y)
|
| Method resolution order:
| Mytuple
| __builtin__.tuple
| __builtin__.object
|
| Methods defined here:
|
| __getnewargs__(self)
| Return self as a plain tuple. Used by copy and pickle.
|
| __getstate__(self)
| Exclude the OrderedDict from pickling
|
| __repr__(self)
| Return a nicely formatted representation string
|
| _asdict(self)
| Return a new OrderedDict which maps field names to their values
|
| _replace(_self, **kwds)
| Return a new Mytuple object replacing specified fields with new values
|
| ----------------------------------------------------------------------
| Class methods defined here:
|
| _make(cls, iterable, new=<built-in method __new__ of type object>, len=<built-in function len>) from __builtin__.type
| Make a new Mytuple object from a sequence or iterable
|
| ----------------------------------------------------------------------
| Static methods defined here:
|
| __new__(_cls, x, y)
| Create new instance of Mytuple(x, y)
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| Return a new OrderedDict which maps field names to their values
|
| x
| Alias for field number 0
|
| y
| Alias for field number 1
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| _fields = ('x', 'y')
|
| ----------------------------------------------------------------------
| Methods inherited from __builtin__.tuple:
|
| __add__(...)
| x.__add__(y) <==> x+y
|
| __contains__(...)
| x.__contains__(y) <==> y in x
|
| __eq__(...)
| x.__eq__(y) <==> x==y
|
| __ge__(...)
| x.__ge__(y) <==> x>=y
|
| __getattribute__(...)
| x.__getattribute__('name') <==> x.name
|
| __getitem__(...)
| x.__getitem__(y) <==> x[y]
|
| __getslice__(...)
| x.__getslice__(i, j) <==> x[i:j]
|
| Use of negative indices is not supported.
|
| __gt__(...)
| x.__gt__(y) <==> x>y
|
| __hash__(...)
| x.__hash__() <==> hash(x)
|
| __iter__(...)
| x.__iter__() <==> iter(x)
|
| __le__(...)
| x.__le__(y) <==> x<=y
|
| __len__(...)
| x.__len__() <==> len(x)
|
| __lt__(...)
| x.__lt__(y) <==> x<y
|
| __mul__(...)
| x.__mul__(n) <==> x*n
|
| __ne__(...)
| x.__ne__(y) <==> x!=y
|
| __rmul__(...)
| x.__rmul__(n) <==> n*x
|
| __sizeof__(...)
| T.__sizeof__() -- size of T in memory, in bytes
|
| count(...)
| T.count(value) -> integer -- return number of occurrences of value
|
| index(...)
| T.index(value, [start, [stop]]) -> integer -- return first index of value.
| Raises ValueError if the value is not present. Mytuple Mytuple

namedtuple

实例:


mytuple = collections.namedtuple('mytuple',['x','y','z'])

>>> a = mytuple(5,8,3)
>>> a
mytuple(x=5, y=8, z=3)
>>> a.x
5
>>> a.y
8
>>> a.z
3
>>> a.x * a.y /a.z
13


5、队列(deque)

二种队列都是线程安全

单项队列 是先进先出(FIFO),使用了Queue模块,其中单项和双项队列均有。

class Queue:
"""Create a queue object with a given maximum size. If maxsize is <= 0, the queue size is infinite.
"""
def __init__(self, maxsize=0):
self.maxsize = maxsize
self._init(maxsize)
# mutex must be held whenever the queue is mutating. All methods
# that acquire mutex must release it before returning. mutex
# is shared between the three conditions, so acquiring and
# releasing the conditions also acquires and releases mutex.
self.mutex = _threading.Lock()
# Notify not_empty whenever an item is added to the queue; a
# thread waiting to get is notified then.
self.not_empty = _threading.Condition(self.mutex)
# Notify not_full whenever an item is removed from the queue;
# a thread waiting to put is notified then.
self.not_full = _threading.Condition(self.mutex)
# Notify all_tasks_done whenever the number of unfinished tasks
# drops to zero; thread waiting to join() is notified to resume
self.all_tasks_done = _threading.Condition(self.mutex)
self.unfinished_tasks = 0 def task_done(self):
"""Indicate that a formerly enqueued task is complete. Used by Queue consumer threads. For each get() used to fetch a task,
a subsequent call to task_done() tells the queue that the processing
on the task is complete. If a join() is currently blocking, it will resume when all items
have been processed (meaning that a task_done() call was received
for every item that had been put() into the queue). Raises a ValueError if called more times than there were items
placed in the queue.
"""
self.all_tasks_done.acquire()
try:
unfinished = self.unfinished_tasks - 1
if unfinished <= 0:
if unfinished < 0:
raise ValueError('task_done() called too many times')
self.all_tasks_done.notify_all()
self.unfinished_tasks = unfinished
finally:
self.all_tasks_done.release() def join(self):
"""Blocks until all items in the Queue have been gotten and processed. The count of unfinished tasks goes up whenever an item is added to the
queue. The count goes down whenever a consumer thread calls task_done()
to indicate the item was retrieved and all work on it is complete. When the count of unfinished tasks drops to zero, join() unblocks.
"""
self.all_tasks_done.acquire()
try:
while self.unfinished_tasks:
self.all_tasks_done.wait()
finally:
self.all_tasks_done.release() def qsize(self):
"""Return the approximate size of the queue (not reliable!)."""
self.mutex.acquire()
n = self._qsize()
self.mutex.release()
return n def empty(self):
"""Return True if the queue is empty, False otherwise (not reliable!)."""
self.mutex.acquire()
n = not self._qsize()
self.mutex.release()
return n def full(self):
"""Return True if the queue is full, False otherwise (not reliable!)."""
self.mutex.acquire()
n = 0 < self.maxsize == self._qsize()
self.mutex.release()
return n def put(self, item, block=True, timeout=None):
"""Put an item into the queue. If optional args 'block' is true and 'timeout' is None (the default),
block if necessary until a free slot is available. If 'timeout' is
a non-negative number, it blocks at most 'timeout' seconds and raises
the Full exception if no free slot was available within that time.
Otherwise ('block' is false), put an item on the queue if a free slot
is immediately available, else raise the Full exception ('timeout'
is ignored in that case).
"""
self.not_full.acquire()
try:
if self.maxsize > 0:
if not block:
if self._qsize() == self.maxsize:
raise Full
elif timeout is None:
while self._qsize() == self.maxsize:
self.not_full.wait()
elif timeout < 0:
raise ValueError("'timeout' must be a non-negative number")
else:
endtime = _time() + timeout
while self._qsize() == self.maxsize:
remaining = endtime - _time()
if remaining <= 0.0:
raise Full
self.not_full.wait(remaining)
self._put(item)
self.unfinished_tasks += 1
self.not_empty.notify()
finally:
self.not_full.release() def put_nowait(self, item):
"""Put an item into the queue without blocking. Only enqueue the item if a free slot is immediately available.
Otherwise raise the Full exception.
"""
return self.put(item, False) def get(self, block=True, timeout=None):
"""Remove and return an item from the queue. If optional args 'block' is true and 'timeout' is None (the default),
block if necessary until an item is available. If 'timeout' is
a non-negative number, it blocks at most 'timeout' seconds and raises
the Empty exception if no item was available within that time.
Otherwise ('block' is false), return an item if one is immediately
available, else raise the Empty exception ('timeout' is ignored
in that case).
"""
self.not_empty.acquire()
try:
if not block:
if not self._qsize():
raise Empty
elif timeout is None:
while not self._qsize():
self.not_empty.wait()
elif timeout < 0:
raise ValueError("'timeout' must be a non-negative number")
else:
endtime = _time() + timeout
while not self._qsize():
remaining = endtime - _time()
if remaining <= 0.0:
raise Empty
self.not_empty.wait(remaining)
item = self._get()
self.not_full.notify()
return item
finally:
self.not_empty.release() def get_nowait(self):
"""Remove and return an item from the queue without blocking. Only get an item if one is immediately available. Otherwise
raise the Empty exception.
"""
return self.get(False) # Override these methods to implement other queue organizations
# (e.g. stack or priority queue).
# These will only be called with appropriate locks held # Initialize the queue representation
def _init(self, maxsize):
self.queue = deque() def _qsize(self, len=len):
return len(self.queue) # Put a new item in the queue
def _put(self, item):
self.queue.append(item) # Get an item from the queue
def _get(self):
return self.queue.popleft() Queue.Queue

queue

实例分析:


>>> import Queue

>>> dir(Queue)
['Empty', 'Full', 'LifoQueue', 'PriorityQueue', 'Queue', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_threading', '_time', 'deque', 'heapq']
>>> q = Queue.Queue(10)
>>> q.put(1)
>>> q
<Queue.Queue instance at 0x7f105f87b248>
>>> q.put(2)
>>> q.put('a')
>>> q.get()
1
>>> q.get()
2
>>> q.get()
'a'
>>> q.get()                                                         ###为空的时候阻塞,等待取最新值###

>>> q.put(1,block=False)                                     ###指定插入不阻塞,默认是阻塞的###
>>> q
<Queue.Queue instance at 0x7ff590ed3098>
>>> q.put_nowait(3)                                            ###指定插入不阻塞,默认是阻塞的###
>>> q
<Queue.Queue instance at 0x7ff590ed3098>
>>> q.get()
1
>>> q.get(timeout=2)                                           ###指定取出阻塞,且超时2秒###
3
>>> q.get(timeout=2)                                           ###为空的时候抛出错误###
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/python279/lib/python2.7/Queue.py", line 176, in get
raise Empty
Queue.Empty
>>> q.get_nowait()                                               ###为空的时候抛出错误###
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/python279/lib/python2.7/Queue.py", line 190, in get_nowait
return self.get(False)
File "/usr/local/python279/lib/python2.7/Queue.py", line 165, in get
raise Empty
Queue.Empty


双向队列,被取的数据会被锁

class deque(object):
"""
deque([iterable[, maxlen]]) --> deque object Build an ordered collection with optimized access from its endpoints.
"""
def append(self, *args, **kwargs): # real signature unknown
""" Add an element to the right side of the deque. """
pass def appendleft(self, *args, **kwargs): # real signature unknown
""" Add an element to the left side of the deque. """
pass def clear(self, *args, **kwargs): # real signature unknown
""" Remove all elements from the deque. """
pass def count(self, value): # real signature unknown; restored from __doc__
""" D.count(value) -> integer -- return number of occurrences of value """
return 0 def extend(self, *args, **kwargs): # real signature unknown
""" Extend the right side of the deque with elements from the iterable """
pass def extendleft(self, *args, **kwargs): # real signature unknown
""" Extend the left side of the deque with elements from the iterable """
pass def pop(self, *args, **kwargs): # real signature unknown
""" Remove and return the rightmost element. """
pass def popleft(self, *args, **kwargs): # real signature unknown
""" Remove and return the leftmost element. """
pass def remove(self, value): # real signature unknown; restored from __doc__
""" D.remove(value) -- remove first occurrence of value. """
pass def reverse(self): # real signature unknown; restored from __doc__
""" D.reverse() -- reverse *IN PLACE* """
pass def rotate(self, *args, **kwargs): # real signature unknown
""" Rotate the deque n steps to the right (default n=1). If n is negative, rotates left. """
pass def __copy__(self, *args, **kwargs): # real signature unknown
""" Return a shallow copy of a deque. """
pass def __delitem__(self, y): # real signature unknown; restored from __doc__
""" x.__delitem__(y) <==> del x[y] """
pass def __eq__(self, y): # real signature unknown; restored from __doc__
""" x.__eq__(y) <==> x==y """
pass def __getattribute__(self, name): # real signature unknown; restored from __doc__
""" x.__getattribute__('name') <==> x.name """
pass def __getitem__(self, y): # real signature unknown; restored from __doc__
""" x.__getitem__(y) <==> x[y] """
pass def __ge__(self, y): # real signature unknown; restored from __doc__
""" x.__ge__(y) <==> x>=y """
pass def __gt__(self, y): # real signature unknown; restored from __doc__
""" x.__gt__(y) <==> x>y """
pass def __iadd__(self, y): # real signature unknown; restored from __doc__
""" x.__iadd__(y) <==> x+=y """
pass def __init__(self, iterable=(), maxlen=None): # known case of _collections.deque.__init__
"""
deque([iterable[, maxlen]]) --> deque object Build an ordered collection with optimized access from its endpoints.
# (copied from class doc)
"""
pass def __iter__(self): # real signature unknown; restored from __doc__
""" x.__iter__() <==> iter(x) """
pass def __len__(self): # real signature unknown; restored from __doc__
""" x.__len__() <==> len(x) """
pass def __le__(self, y): # real signature unknown; restored from __doc__
""" x.__le__(y) <==> x<=y """
pass def __lt__(self, y): # real signature unknown; restored from __doc__
""" x.__lt__(y) <==> x<y """
pass @staticmethod # known case of __new__
def __new__(S, *more): # real signature unknown; restored from __doc__
""" T.__new__(S, ...) -> a new object with type S, a subtype of T """
pass def __ne__(self, y): # real signature unknown; restored from __doc__
""" x.__ne__(y) <==> x!=y """
pass def __reduce__(self, *args, **kwargs): # real signature unknown
""" Return state information for pickling. """
pass def __repr__(self): # real signature unknown; restored from __doc__
""" x.__repr__() <==> repr(x) """
pass def __reversed__(self): # real signature unknown; restored from __doc__
""" D.__reversed__() -- return a reverse iterator over the deque """
pass def __setitem__(self, i, y): # real signature unknown; restored from __doc__
""" x.__setitem__(i, y) <==> x[i]=y """
pass def __sizeof__(self): # real signature unknown; restored from __doc__
""" D.__sizeof__() -- size of D in memory, in bytes """
pass maxlen = property(lambda self: object(), lambda self, v: None, lambda self: None) # default
"""maximum size of a deque or None if unbounded""" __hash__ = None deque

deque

实例分析:


>>> a = collections.deque()
>>> a.append(1)
>>> a.append(2)                            ###追加值到右边###
>>> a
deque([1, 2])
>>> a.appendleft(3)                        ###追加值到左边###
>>> a
deque([3, 1, 2])
>>> a.appendleft(3)
>>> a.appendleft(1)
>>> a.appendleft(2)
>>> a
deque([2, 1, 3, 3, 1, 2])
>>> a.count(3)
2
>>> a.extend(['a','b'])                   ###将一个iterable进行遍历追加到右边###
>>> a
deque([2, 1, 3, 3, 1, 2, 'a', 'b'])
>>> a.extend('abc')
>>> a
deque([2, 1, 3, 3, 1, 2, 'a', 'b', 'a', 'b', 'c'])
>>> a.extendleft('abc')                    ###将一个iterable进行遍历追加到左边###
>>> a
>>> a
deque(['c', 'b', 'a', 2, 1, 3, 3, 1, 2, 'a', 'b', 'a', 'b', 'c'])
>>>

>>> a.pop()
'c'
>>> a.popleft()
'c'
>>> a.popleft()
'b'
>>> a.remove(2)
>>> a
deque(['a', 1, 3, 3, 1, 2, 'a', 'b', 'a', 'b'])
>>> a.remove(2)
>>> a
deque(['a', 1, 3, 3, 1, 'a', 'b', 'a', 'b'])
>>> a.reverse()
>>> a
deque(['b', 'a', 'b', 'a', 1, 3, 3, 1, 'a'])


二、迭代器和生成器:

在list中有个__iter__方法,就是个迭代器,其类里必须有个next方法。需要通过遍历来具体输出

class listiterator(object)
| Methods defined here:
|
| __getattribute__(...)
| x.__getattribute__('name') <==> x.name
|
| __iter__(...)
| x.__iter__() <==> iter(x)
|
| __length_hint__(...)
| Private method returning an estimate of len(list(it)).
|
| next(...)
| x.next() -> the next value, or raise StopIteration

listiterator

举例:

定义:一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator),如果函数中包含yield语法,那这个函数就会变成生成器 

yield

作用:

这个yield的主要效果呢,就是可以使函数中断,并保存中断状态,中断后,代码可以继续往下执行,过一段时间还可以再重新调用这个函数,从上次yield的下一句开始执行。

另外,还可通过yield实现在单线程的情况下实现并发运算的效果

import time
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield ###接收send的变量值 print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) def producer(name):
c = consumer('A')
c2 = consumer('B')
c.next() ###调用consumer函数
c2.next() ###因yield中断函数,回到并执行c2.next
print("老子开始准备做包子啦!") ###因yield中断函数,并输入
for i in range(10):
time.sleep(1)
print("做了2个包子!")
c.send(i) ###返回i到yield
c2.send(i) producer("alex") 结果如下: A 准备吃包子啦!
B 准备吃包子啦!
老子开始准备做包子啦!
做了2个包子!
包子[0]来了,被[A]吃了!
包子[0]来了,被[B]吃了!
做了2个包子!
包子[1]来了,被[A]吃了!
包子[1]来了,被[B]吃了!

yield异步

生成器内部基于yield创建,即:对于生成器只有使用时才创建,从而不避免内存浪费

range不是生成器 和 xrange 是生成器

readlines不是生成器 和 xreadlines 是生成器


range(1000)

会导致生成一个 1000 个元素的 List,而代码:

xrange(1000)

则不会生成一个 1000 个元素的 List,而是在每次迭代中返回下一个数值,内存空间占用很小。因为 xrange 不返回 List,而是返回一个 iterable 对象。

带有 yield 的函数在 Python 中被称之为 generator(生成器),例:


def kevin_readlines():
    seek = 0
    while True:
          with open('D:/eclipse/workspace/python27/first_python27/file/file.txt','r') as f:

#with打开文件无需使用close来结束读取文件
                f.seek(seek)
                data =  f.readline()
                if data:
                    seek = f.tell()
                    yield data
                else:
                    return            #直接返回,退出函数

for line in kevin_readlines():
    print(line)


注:yeild生成器需要用循环来一行一行读取。yeild经常用于读取函数的中间值,适合用于多线程之类的情况。使用next来一次一次调用函数值。

 
三、函数参数说明:

def login(name,info,passwd = '123456')

函数参数可以有默认值,调用函数时:

1、如果只传二个参数,则有默认值的一定要放到最后;

def login(name,passwd = '123456',info='welcome to you')

2、如果传二个参数,一定要指明形参;

login(user)

login(user,passwd)

login(user,info='欢迎')

login(user,info='欢迎',passwd='123456')


def login(*arg)        函数参数个数不定,传参数的时候可以多个,包装为列表;例:

def list_show(*args):

for name in args:
        print(name)
        
list_show('a','b','c','d',1,2,3,4)        #传多个参数
list_show(['a','b','c',1,2,3])             #直接传个列表参数


def login(**arg)      函数参数个数不定,传参数的时候可以多个,包装为字典;例:

def dict_show(**args):
    for name in args.items():
        print(name)

dict_show(name='kevin',age=23)       #传多个参数时,格式为key=value
print('##################')

dict = {'name':'kevin','age':23}

dict_show(**dict)                    #直接传个字典参数时,字典前加二个**

四、邮件函数介绍:

具体可参考:

python2.7版本:

http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386832745198026a685614e7462fb57dbf733cc9f3ad000

python3版本:

http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001432005226355aadb8d4b2f3f42f6b1d6f2c5bd8d5263000

python脚本发邮件,一般会用到smtplib和email这两个模块。看看该模块怎么使用,先看smtplib模块。

smtplib模块定义了一个简单的SMTP客户端,可以用来在互联网上发送邮件。
定义的类有如下:

1
2
3
class smtplib.SMTP([host[, port[, local_hostname[, timeout]]]])
class smtplib.SMTP_SSL([host[, port[, local_hostname[, keyfile[, certfile[, timeout]]]]]])
class smtplib.LMTP([host[, port[, local_hostname]]])

还有一些已经定义好的异常

1
2
3
4
5
6
7
8
9
exception smtplib.SMTPException
exception smtplib.SMTPServerDisconnected
exception smtplib.SMTPResponseException
exception smtplib.SMTPSenderRefused
exception smtplib.SMTPRecipientsRefused
exception smtplib.SMTPDataError
exception smtplib.SMTPConnectError
exception smtplib.SMTPHeloError
exception smtplib.SMTPAuthenticationError

这么多已定义的类中,我们最常用的的还是smtplib.SMTP类,就具体看看该类的用法:
    smtp实例封装一个smtp连接,它支持所有的SMTP和ESMTP操作指令,如果host和port参数被定义,则smtp会在初始化期间自动调用connect()方法,如果connect()方法失败,则会触发SMTPConnectError异常,timeout参数设置了超时时间。在一般的调用过程中,应该遵connetc()、sendmail()、quit()步骤。

下面我们来看看该类的方法:

SMTP.set_debuglevel(level)
    设置输出debug调试信息,默认不输出调试信息。
SMTP.docmd(cmd[, argstring])
    发送一个command到smtp服务器,
SMTP.connect([host[, port]])
    连接到指定的smtp服务器,默认是本机的25端口。也可以写成hostname:port的形式。
SMTP.helo([hostname])
    使用helo指令向smtp服务器确认你的身份。
SMTP.ehlo([hostname])
    使用ehlo指令向esmtp服务器确认你的身份。
SMTP.ehlo_or_helo_if_needed()
    如果在以前的会话连接中没有提供ehlo或者helo指令,这个方法调用ehlo()或者helo()。
SMTP.has_extn(name)
    判断指定的名称是否在smtp服务器上。
SMTP.verify(address)
    判断邮件地址是否在smtp服务器上存在。
SMTP.login(user, password)
    登陆需要验证的smtp服务器,如果之前没有提供ehlo或者helo指令,则会先尝试ESMTP的ehlo指令。
SMTP.starttls([keyfile[, certfile]])
    使smtp连接运行在TLS模式,所有的smtp指令都会被加密。
SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])
    发送邮件,该方法需要一些邮件地址和消息。
SMTP.quit()
    终止smtp会话并且关闭连接。

经过搜索学习发现网上大多都是用smtp类的sendmail这个方法来发邮件,那就先看看这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/python
import smtplib
from_mail='xxx@126.com'
to_mail='yyy@qq.com'
server=smtplib.SMTP('smtp.126.com')
server.docmd('ehlo','xxx@126.com')
server.login('xxx@126.com','password')
msg='''from:xxx@126.com
to:yyy@qq.com
subject:I am guol
I'm come 126
.
'''
server.sendmail(from_mail,to_mail,msg)
server.quit()

上例是使用sendmail方式,采用邮箱验证的模式来发邮件,因为现在大多数邮件系统都有反垃圾邮件机制及验证机制,我在开始实验非验证模式时就被126当作垃圾邮件而拒绝发送。

下面这个例子采用原始的smtp指令来发邮件。常用的smtp指令如下:

HELO 向服务器标识用户身份
    MAIL 初始化邮件传输 mail from:
    RCPT 标识单个的邮件接收人;常在MAIL命令后面,可有多个rcpt to:
    DATA 在单个或多个RCPT命令后,表示所有的邮件接收人已标识,并初始化数据传输,以.结束
    VRFY 用于验证指定的用户/邮箱是否存在;由于安全方面的原因,服务器常禁止此命令
    EXPN 验证给定的邮箱列表是否存在,扩充邮箱列表,也常被禁用
    HELP 查询服务器支持什么命令
    NOOP 无操作,服务器应响应OK
    QUIT 结束会话
    RSET 重置会话,当前传输被取消
    MAIL FROM 指定发送者地址
    RCPT TO 指明的接收者地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/python
import base64
import smtplib
from_mail='xxx@126.com'
to_mail='yyy@qq.com'
user=base64.encodestring('xxx@126.com').strip()
passwd=base64.encodestring('password').strip()
server=smtplib.SMTP('smtp.126.com')
server.set_debuglevel(1)
server.docmd('ehlo','xxx@126.com')
server.docmd('auth login')
server.docmd(user)
server.docmd(passwd)
server.docmd('mail FROM:<%s>' % from_mail)
server.docmd('rcpt TO:<%s>' % to_mail)
server.docmd('data')
server.docmd('''from:xxx@126.com
to:yyy@qq.com
subject:I am guol
I'm come here
.
''')
server.getreply()
server.quit()

注意在以上两个例子中在发送消息的subject后面书写正文时,需要空一行,正文以'.'结尾。

果然简单,如果想在邮件中携带附件、使用html书写邮件,附带图片等等,就需要使用email模块及其子模块。下面来看看email包,email包是用来管理email信息的,它包括MIME和其他基于RFC 2822的消息格式。email包的主要特征是在它内部解析和生成email信息是分开的模块来实现的。

MIME消息由消息头和消息体两大部分组成,在邮件里就是邮件头和邮件体。邮件头与邮件体之间以空行进行分隔。

邮件头包含了发件人、收件人、主题、时间、MIME版本、邮件内容的类型等重要信息。每条信息称为一个域,由域名后加“: ”和信息内容构成,可以是一行,较长的也可以占用多行。域的首行必须“顶头”写,即左边不能有空白字符(空格和制表符);续行则必须以空白字符打头,且第一个空白字符不是信息本身固有的。

邮件体包含邮件的内容,它的类型由邮件头的“Content-Type”域指出。最常见的类型有text/plain(纯文本)和text/html(超文本)。邮件体被分为多个段,每个段又包含段头和段体两部分,这两部分之间也以空行分隔。常见的multipart类型有三种:multipart/mixed, multipart/related和multipart/alternative。

在email的包里面包含了很多模块:

email.message
email.parser
email.generator
email.mime   创建email和MIME对象
email.header
email.charset
email.encoders
email.ereors
email.utils
email.iterators

主要来看看email.mime,在邮件中携带附件、图片、音频时,主要使用的是该模块。一般情况下,你通过解析一个文件或者一段text来生成一个消息对象结构,你也可以从头开始建立一个消息结构,实际上,你可以给一个已经存在的消息结构追加一个新的消息对象。你可以通过创建message实例来创建一个对象结构,然后给该结构追加附件和头部信息。email包提供了一些子类使得该操作变得很容易。

email.mime中常用的类如下:

email.mime.base    email.mime.base.MIMEBase(_maintype, _subtype, **_params)
email.mime.nonmultipart   email.mime.nonmultipart.MIMENonMultipart
email.mime.multipart    email.mime.multipart.MIMEMultipart([_subtype[, boundary[, _subparts[, _params]]]])

1
A subclass of MIMEBase, this is an intermediate base class for MIME messages that are multipart. Optional _subtype defaults to mixed, but can be used to specify the subtype of the message. A Content-Type header of multipart/_subtype will be added to the message object. A MIME-Version header will also be added.

email.mime.application    email.mime.application.MIMEApplication(_data[, _subtype[, _encoder[, **_params]]]) 
email.mime.audio    email.mime.audio.MIMEAudio(_audiodata[, _subtype[, _encoder[, **_params]]]) 
email.mime.image    email.mime.image.MIMEImage(_imagedata[, _subtype[, _encoder[, **_params]]])

1
A subclass of MIMENonMultipart, the MIMEImage class is used to create MIME message objects of major type image. _imagedata is a string containing the raw image data.

email.mime.message    email.mime.message.MIMEMessage(_msg[, _subtype]) 
email.mime.text    email.mime.text.MIMEText(_text[, _subtype[, _charset]])

1
A subclass of MIMENonMultipart, the MIMEText class is used to create MIME objects of major type text. _text is the string for the payload. _subtype is the minor type and defaults to plain. _charset is the character set of the text and is passed as a parameter to the MIMENonMultipart constructor; it defaults to us-ascii. If _text is unicode, it is encoded using the output_charset of _charset, otherwise it is used as-is.

只解释了常用的几个类,详细信息见: http://docs.python.org/2/library/email.mime.html

模拟在邮件内容中携带图片,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from_mail='xxx@126.com'
to_mail='yyy@qq.com'
msg=MIMEMultipart()
msg['From']=from_mail
msg['To']=to_mail
msg['Subject']='I am from email package'
body='I am come 126,i content with pic'
con=MIMEText('<b>%s</b><br><img src="cid:/opt/25343674.png"><br>' % body,'html')
msg.attach(con)
img=MIMEImage(file('/opt/25343674.png','rb').read())
img.add_header('Content-ID','/opt/25343674.png')
msg.attach(img)
server=smtplib.SMTP('smtp.126.com')
server.docmd('ehlo','xxx@126.com')
server.login('yyy@126.com','password')
server.sendmail(from_mail,to_mail,msg.as_string())
server.quit()

模拟在 邮件中携带附件 ,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from_mail='xxx@126.com'
to_mail='yyy@qq.com'
msg=MIMEMultipart()
msg['From']=from_mail
msg['To']=to_mail
msg['Subject']='I am from email package'
content=MIMEText('<b>I am come 126,i with attach<b>','html')
msg.attach(content)
attac=MIMEImage(file('/opt/25343674.png','rb').read())
attac['Content-Type']='application/octet-stream'
attac.add_header('content-disposition','attachment',filename='/opt/25343674.png')
msg.attach(attac)
server=smtplib.SMTP('smtp.126.com')
server.docmd('ehlo','xxx@126.com')
server.login('yyy@126.com','password')
server.sendmail(from_mail,to_mail,msg.as_string())
server.quit()

以上代码均在python2.7下经过测试。