Python–fluent
文章目录
- Python–fluent
-
-
- #.1.python数据模型
- #.2.序列构成的数组
- #.3.字典与集合
- #.4.文本和字节序列
- #.5.一等函数
- #.6.使用一等函数实现设计模式
- #.7.函数装饰器和闭包
- #.8.对象引用、可变性和垃圾回收
- #.9.符合python风格的对象
- #.10.序列的修改、散列和切片
- #.11.接口:从协议到抽象基类
- #.12.继承的优缺点
- #.13.正确重载运算符
- #.14.可迭代对象、迭代器和生成器
- #.15.上下文管理器和else模块
- #.16.协程
- #.17.使用期物处理并发
- #.18.使用asyncio包处理并发
- #.19.动态属性和特性
- #.20.属性描述符
#.1.python数据模型
from collections import namedtuple
from random import choice
Card = namedtuple('Card', ['rank', 'suit'])
class FrenchDesk:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, pos):
return self._cards[pos]
test_card = FrenchDesk()
suit_values = dict(spades=3, hearts=2, clubs=1, diamonds=0)
def spaders_high(card):
rank_value = FrenchDesk.ranks.index(card.rank)
return rank_value * len(suit_values) + suit_values[card.suit]
for card in sorted(test_card, key=spaders_high):
print(card)
from math import hypot
class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __repr__(self):
return 'Vector(%r, %r)' % (self.x, self.y)
def __abs__(self):
return hypot(self.x, self.y)
def __bool__(self):
return bool(abs(self))
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Vector(x, y)
def __mul__(self, scalar):
return Vector(self.x*scalar, self.y*scalar)
a = Vector(1, 2)
b = Vector(2, 3)
print(a + b)
print(bool(a))
#.2.序列构成的数组
import random
from collections import namedtuple
import bisect
import sys
from array import array
codes = [ord(symbol) for symbol in '$¢£¥€¤']
print(codes)
beyond_ascii = list(filter(lambda c: c > 127, map(ord, '$¢£¥€¤')))
print(beyond_ascii)
symbol_ord = (ord(symbol) for symbol in '$¢£¥€¤')
print(symbol_ord)
lax_coordinates = (33.9425, -118.408056)
latitude, longitude = lax_coordinates
t = (20, 8)
print(divmod(*t))
a, b, *res, d = range(5)
print(res)
City = namedtuple('City', 'name country population coordinates')
tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
print(City._fields)
LatLong = namedtuple('LatLong', 'lat long')
delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
delhi = City._make(delhi_data)
print(delhi._asdict())
invoice = '''
... 1909 Pimoroni PiBrella $17.50 3 $52.50
... 1489 6mm Tactile Switch x20 $4.95 2 $9.90
... 1510 Panavise Jr. - PV-201 $28.00 1 $28.00
... 1601 PiTFT Mini Kit 320x240 $34.95 1 $34.95
'''
UNIT_PRICE = slice(40, 52)
DESCRIPTION = slice(6, 40)
line_items = invoice.split('\n')[2:]
for item in line_items:
print(item[UNIT_PRICE], item[DESCRIPTION])
board = [['_'] * 3 for i in range(3)]
l = [1, 2, 3]
print(id(l))
l *= 2
print(id(l))
t = (1, 2, 3)
print(id(t))
t *= 2
print(id(t))
print()
import bisect
import sys
HAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30]
NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31]
ROW_FMT = '{0:2d} @ {1:2d} {2}{0:<2d}'
def demo(bisect_fn):
for needle in reversed(NEEDLES):
position = bisect_fn(HAYSTACK, needle)
offset = position * ' |'
print(ROW_FMT.format(needle, position, offset))
if sys.argv[-1] == 'left':
bisect_fn = bisect.bisect_left
else:
bisect_fn = bisect.bisect
print('DEMO:', bisect_fn.__name__)
print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK))
demo(bisect_fn)
mylist = []
for i in range(5):
value = random.randrange(10)
bisect.insort(mylist, value)
print('%2d ->' % value, mylist)
array_test = array('d', (random.random() for i in range(10)))
print(array_test)
numbers = array('h', [-2, -1, 0, 1, 2])
memv = memoryview(numbers)
memv_oct = memv.cast('B')
print(memv_oct.tolist())
memv_oct[5] = 4
print(numbers)
#.3.字典与集合
from collections import *
from types import MappingProxyType
from dis import dis
a = dict(one=1, two=2, three=3)
b = {'one': 1, 'two': 2, 'three': 3}
c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
d = dict([('two', 2), ('one', 1), ('three', 3)])
e = dict({'three': 3, 'one': 1, 'two': 2})
print(a == b == c == d == e)
f = {i: i+10 for i in range(5)}
f['one'] = 100
print(f)
f.update(a)
print(f)
f.setdefault(10, 0)
print(f)
g = defaultdict(list)
print(g[0])
h = OrderedDict()
h[1] = 2
h[2] = 3
h[3] = 4
h.popitem()
print(h)
i = {1: 'A'}
i_proxy = MappingProxyType(i)
print(i_proxy)
i[2] = 'B'
print(i_proxy)
j = {1, 2, 3}
k = {3, 4, 5}
print(j|k, j-k, j&k, j^k)
#.4.文本和字节序列
from array import array
from unicodedata import normalize
s = 'café'
b = s.encode('utf8')
print(len(b), b, type(b))
c = b.decode('utf8')
print(len(c), c)
cafe = bytes('café', encoding='utf_8')
print(cafe)
print(cafe[0], ord('c'), cafe[:1])
cafe_arr = bytearray(cafe)
print(cafe_arr)
print(cafe_arr[-1:])
numbers = array('h', [-2, -1, 0, 1, 2])
numbyte = bytes(numbers)
print(numbyte)
s1 = 'café'
s2 = 'cafe\u0301'
print(len(s1), len(s2))
print(len(normalize('NFC', s1)), len(normalize('NFC', s2)))
print(len(normalize('NFD', s1)), len(normalize('NFD', s2)))
print(s1 == s2)
print(normalize('NFC', s1) == normalize('NFC', s2))
print(normalize('NFC', s1).casefold() == normalize('NFC', s2).casefold())
#.5.一等函数
from functools import reduce
from operator import add, mul
from functools import partial
import random
def fun_test(n):
'''返回n!'''
return n if n < 2 else n * fun_test(n-1)
print(fun_test.__doc__)
print(type(fun_test), fun_test)
fun2 = fun_test
print(fun2)
print(list(map(fun2, range(11))))
fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
print(sorted(fruits, key=len))
print(list(map(fun_test, range(6))))
print([fun_test(n) for n in range(6)])
print(list(map(fun_test, filter(lambda n: n % 2, range(6)))))
print([fun_test(n) for n in range(6) if n % 2])
print(reduce(add, range(100)))
print(sum(range(100)))
print(all([1, 1, 0]))
print(any([1, 1, 0]))
print(sorted(fruits, key=lambda word: word[::-1]))
print([callable(ob) for ob in (abs, str, 12)])
class A:
def __init__(self, item):
self._item = list(item)
random.shuffle(self._item)
def __call__(self, *args, **kwargs):
return self.pop_value()
def pop_value(self):
try:
return self._item.pop()
except IndexError:
raise LookupError('item is empty, can\'t pop')
a = A(range(10))
print(a.pop_value())
print(a(), callable(a))
def tag(name, *content, cls=None, **attrs):
"""生成一个或多个HTML标签"""
if cls is not None:
attrs['class'] = cls
if attrs:
attr_str = ''.join(' %s="%s"' % (attr, value) for attr, value in sorted(attrs.items()))
else:
attr_str = ''
if content:
return '\n'.join('<%s%s>%s%s>' % (name, attr_str, c, name) for c in content)
else:
return '<%s%s />' % (name, attr_str)
print(tag('br'))
print(tag('p', 'hello'))
print(tag('p', 'hello', 'world'))
print(tag('p', 'hello', id=33))
print(tag('p', 'hello', 'world', cls='sidebar'))
print(tag(content='testing', name="img"))
my_tag = {'name': 'img', 'title': 'Sunset Boulevard', 'src': 'sunset.jpg', 'cls': 'framed'}
print(tag(**my_tag))
def clip(text:str, max_len:'int > 0'=80) -> str:
"""在max_len前面或后面的第一个空格处截断文本
"""
return ''
def fact(n):
return reduce(lambda a, b: a*b, range(1, n+1))
def fact1(n):
return reduce(mul, range(1, n+1))
triple = partial(mul, 3)
print(triple(7))
print(list(map(triple, range(1,10))))
#.6.使用一等函数实现设计模式
from collections import namedtuple
from abc import ABC, abstractmethod
Customer = namedtuple('Customer', 'name fidelity')
class LineItem:
def __init__(self, product, quantity, price):
self.product = product
self.quantity = quantity
self.price = price
def total(self):
return self.price * self.quantity
class Order:
def __init__(self, customer, cart, promotion=None):
self.customer = customer
self.cart = list(cart)
self.promotion = promotion
def total(self):
if not hasattr(self, '__total'):
self.__total = sum(item.total() for item in self.cart)
return self.__total
def due(self):
if self.promotion is None:
discount = 0
else:
discount = self.promotion.discount(self)
return self.total() - discount
def __repr__(self):
fmt = ''
return fmt.format(self.total(), self.due())
class Promotion(ABC):
@abstractmethod
def discount(self, order):
"""返回折扣金额(正值)"""
class FidelityPromo(Promotion):
"""为积分为1000或以上的顾客提供5%折扣"""
def discount(self, order):
return order.total() * 0.05 if order.customer.fidelity >= 1000 else 0
class BulkItemPromo(Promotion):
"""单个商品为20个或以上时提供10%折扣"""
def discount(self, order):
discount = 0
for item in order.cart:
if item.quantity >= 20:
discount += item.total() * 0.1
return discount
class LargeOrderPromo(Promotion):
"""订单中的不同商品达到10个或以上时提供7%折扣"""
def discount(self, order):
distinct_items = {item.product for item in order.cart}
if len(distinct_items) >= 10:
return order.total() * 0.07
return 0
joe = Customer('John Doe', 0)
ann = Customer('Ann Smith', 1100)
cart = [LineItem('banana', 4, 0.5), LineItem('apple', 10, 1.5), LineItem('watermellon', 5, 5.0)]
print(Order(joe, cart, FidelityPromo()))
print(Order(ann, cart, FidelityPromo()))
banana_cart = [LineItem('banana', 30, 0.5), LineItem('apple', 10, 1.5)]
print(Order(joe, banana_cart, BulkItemPromo()))
long_order = [LineItem(str(item_code), 1, 1.0) for item_code in range(10)]
print(Order(joe, long_order, LargeOrderPromo()))
#.7.函数装饰器和闭包
from dis import dis
import time
from functools import lru_cache, wraps
import html
def deco(func):
def inner():
print('running inner function')
func()
return inner
@deco
def target():
print('running target function')
registry = []
def register(func):
print('running register(%s)' % func)
registry.append(func)
return func
@register
def f1():
print('running f1()')
@register
def f2():
print('running f2()')
def f3():
print('running f3()')
def f4():
print('running f4()')
print('registry ->', registry)
f1()
f2()
f3()
f4()
def make_averager():
series = []
def averager(new_value):
series.append(new_value)
return sum(series)/len(series)
return averager
avg = make_averager()
print(avg(10))
print(avg(11))
print(avg(12))
print(avg.__code__.co_varnames)
print(avg.__code__.co_freevars)
def make_averager1():
count = 0
total = 0
def averager(new_value):
nonlocal count, total
count += 1
total += new_value
return total / count
return averager
def clock(func):
@wraps(func)
def clocked(*args):
t0 = time.perf_counter()
result = func(*args)
elapsed = time.perf_counter() - t0
name = func.__name__
arg_str = ', '.join(repr(arg) for arg in args)
print('[%0.8fs] %s(%s) -> %r' % (elapsed, name, arg_str, result))
return result
return clocked
@clock
def snooze(seconds):
time.sleep(seconds)
@clock
def factorial(n):
return 1 if n < 2 else n*factorial(n-1)
print('*' * 40, 'Calling snooze(123)')
snooze(0.123)
print('*' * 40, 'Calling factorial(6)')
print('6! =', factorial(6))
print(factorial.__name__)
print()
@lru_cache()
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)
print(fibonacci(6))
def htmlize(obj):
content = html.escape(repr(obj))
return '{}
'.format(content)
print(htmlize({1, 2, 3}))
print(htmlize(abs))
print(htmlize('Heimlich & Co.\n- a game'))
print(htmlize(42))
print(htmlize(['alpha', 66, {3, 2, 1}]))
print()
registry1 = set()
def register1(active=True):
def decorate(func):
print('running register(active=%s)->decorate(%s)'% (active, func))
if active:
registry1.add(func)
else:
registry1.discard(func)
return func
return decorate
@register1(active=False)
def f1():
print('running f1()')
@register1()
def f2():
print('running f2()')
def f3():
print('running f3()')
f1()
print(registry1)
register1()(f3)
print(registry1)
#.8.对象引用、可变性和垃圾回收
from copy import copy, deepcopy
import weakref
a = [1, 2, 3]
b = a
b.append(4)
a.append(5)
print(a, b)
charles = {'name': 'Charles L. Dodgson', 'born': 1832, 'balance': 950}
alex = {'name': 'Charles L. Dodgson', 'born': 1832, 'balance': 950}
print(charles == alex)
print(charles is alex)
t1 = (1, 2, [30, 40])
t2 = (1, 2, [30, 40])
print(id(t1[-1]))
t1[-1].append(50)
print(id(t1[-1]))
l1 = [3, [66, 55, 44], (7, 8, 9)]
l2 = l1.copy()
l1.append(100)
l1[1].remove(55)
print('l1:', l1)
print('l2:', l2)
l2[1] += [33, 22]
l2[2] += (10, 11)
print('l1:', l1)
print('l2:', l2)
def fun(a, b):
a += b
return a
a1 = 1
b1 = 2
print(fun(a1, b1))
print(a1, b1)
a2 = [1, 2]
b2 = [3, 4]
print(fun(a2, b2))
print(a2, b2)
a3 = (1, 2)
b3 = (3, 4)
print(fun(a3, b3))
print(a3, b3)
class HauntedBus:
"""备受幽灵乘客折磨的校车"""
def __init__(self, passengers=[]):
self.passengers = passengers
def pick(self, name):
self.passengers.append(name)
def drop(self, name):
self.passengers.remove(name)
class TwilightBus:
"""让乘客销声匿迹的校车"""
def __init__(self, passengers=None):
self.passengers = passengers
def pick(self, name):
self.passengers.append(name)
def drop(self, name):
self.passengers.remove(name)
s1 = {1, 2, 3}
s2 = s1
def bye():
print('Gone with the wind...')
ender = weakref.finalize(s1, bye)
print(ender.alive)
del s1
print(ender.alive)
s2 = 'spam'
print(ender.alive)
a_set = {0, 1}
wref = weakref.ref(a_set)
print(wref)
print(wref())
a_set = {2, 3, 4}
print(wref() is None)
class Cheese:
def __init__(self, kind):
self.kind = kind
def __repr__(self):
return 'Cheese(%r)' % self.kind
stock = weakref.WeakValueDictionary()
catalog = [Cheese('Red Leicester'), Cheese('Tilsit'), Cheese('Brie'), Cheese('Parmesan')]
for cheese in catalog:
stock[cheese.kind] = cheese
print(sorted(stock.keys()))
del catalog
print(sorted(stock.keys()))
del cheese
print(sorted(stock.keys()))
tuple1 = (1, 2, 3)
tuple2 = tuple(tuple1)
tuple3 = tuple1[:]
print(tuple2 is tuple1)
print(tuple3 is tuple1)
string1 = 'abc'
string2 = 'abc'
int1 = 15
int2 = 15
print(string1 is string2)
print(int1 is int2)
#.9.符合python风格的对象
from array import array
from math import hypot
from datetime import datetime
class Vector2d:
typecode = 'd'
def __init__(self, x, y):
self.__x = float(x)
self.__y = float(y)
@property
def x(self):
return self.__x
@x.setter
def x(self, value):
self.__x = value
@x.deleter
def x(self):
del self.__x
@property
def y(self):
return self.__y
def __iter__(self):
return (i for i in (self.x, self.y))
def __repr__(self):
class_name = type(self).__name__
return '{}({!r}, {!r})'.format(class_name, *self)
def __str__(self):
return str(tuple(self))
def __bytes__(self):
return (bytes([ord(self.typecode)]) + bytes(array(self.typecode, self)))
def __eq__(self, other):
return tuple(self) == tuple(other)
def __abs__(self):
return hypot(self.x, self.y)
def __bool__(self):
return bool(abs(self))
def __format__(self, fmt_spec=''):
components = (format(c, fmt_spec) for c in self)
return '({}, {})'.format(*components)
def __hash__(self):
return hash(self.x) ^ hash(self.y)
@classmethod
def frombytes(cls, octets):
typecode = chr(octets[0])
memv = memoryview(octets[1:]).cast(typecode)
return cls(*memv)
v1 = Vector2d(3, 4)
print(v1.x, v1.y)
x, y = v1
print(x, y)
print(v1)
v1_clone = eval(repr(v1))
print(v1 == v1_clone)
print(v1_clone)
print(bytes(v1))
print(abs(v1))
print(bool(v1), bool(Vector2d(0, 0)))
v2 = Vector2d(4, 5)
print(hash(v1), hash(v2))
print({v1, v2})
print()
class Demo:
@classmethod
def klassmeth(*args):
return args
@staticmethod
def statmeth(*args):
return args
brl = 1/2.43
print(brl)
print(format(brl, '0.4f'))
print('1 BRL = {rate:0.2f} USD'.format(rate=brl))
print(format(42, 'b'))
print(format(2/3, '.1%'))
now = datetime.now()
print(format(now, '%H:%M:%S'))
print("It's now {:%I:%M %p}".format(now))
#.10.序列的修改、散列和切片
import numbers
from array import array
import reprlib
import math
from functools import reduce
import operator
from itertools import zip_longest
class Vector:
typecode = 'd'
shortcut_names = 'xyzt'
def __init__(self, components):
self._components = array(self.typecode, components)
def __iter__(self):
return iter(self._components)
def __repr__(self):
components = reprlib.repr(self._components)
components = components[components.find('['):-1]
return 'Vector({})'.format(components)
def __str__(self):
return str(tuple(self))
def __bytes__(self):
return (bytes([ord(self.typecode)]) + bytes(self._components))
def __eq__(self, other):
if len(self) != len(other):
return False
for a, b in zip(self, other):
if a != b:
return False
return True
def __hash__(self):
hashes = map(hash, self._components)
return reduce(operator.xor, hashes, 0)
def __abs__(self):
return math.sqrt(sum(x * x for x in self))
def __bool__(self):
return bool(abs(self))
def __len__(self):
return len(self._components)
def __getitem__(self, index):
cls = type(self)
if isinstance(index, slice):
return cls(self._components[index])
elif isinstance(index, numbers.Integral):
return self._components[index]
else:
msg = '{cls.__name__} indices must be integers'
raise TypeError(msg.format(cls=cls))
def __getattr__(self, name):
cls = type(self)
if len(name) == 1:
pos = cls.shortcut_names.find(name)
if 0 <= pos < len(self._components):
return self._components[pos]
msg = '{.__name__!r} object has no attribute {!r}'
raise AttributeError(msg.format(cls, name))
def __setattr__(self, name, value):
cls = type(self)
if len(name) == 1:
if name in cls.shortcut_names:
error = 'readonly attribute {attr_name!r}'
elif name.islower():
error = "can't set attributes 'a' to 'z' in {cls_name!r}"
else:
error = ''
if error:
msg = error.format(cls_name=cls.__name__, attr_name=name)
raise AttributeError(msg)
super().__setattr__(name, value)
def __neg__(self):
return Vector(-x for x in self)
def __pos__(self):
return Vector(self)
def __add__(self, other):
try:
pairs = zip_longest(self, other, fillvalue=0.0)
return Vector(a + b for a, b in pairs)
except TypeError:
raise NotImplemented
def __radd__(self, other):
return self + other
def __mul__(self, scalar):
if isinstance(scalar, numbers.Real):
return Vector(n * scalar for n in self)
else:
return NotImplemented
def __rmul__(self, scalar):
return self * scalar
def __ne__(self, other):
eq_result = self == other
if eq_result is NotImplemented:
return NotImplemented
else:
return not eq_result
@classmethod
def frombytes(cls, octets):
typecode = chr(octets[0])
memv = memoryview(octets[1:]).cast(typecode)
return cls(memv)
a = Vector(range(5))
print(a.t)
#.11.接口:从协议到抽象基类
from collections import namedtuple, MutableSequence
from random import choice, shuffle, SystemRandom, randrange
import abc
class Foo:
def __getitem__(self, pos):
return range(0, 30, 10)[pos]
f = Foo()
for i in f:
print(i)
Card = namedtuple('Card', ['rank', 'suit'])
class FrenchDesk:
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, pos):
return self._cards[pos]
def set_card(deck, position, card):
deck._cards[position] = card
deck = FrenchDesk()
FrenchDesk.__setitem__ = set_card
shuffle(deck)
print(deck[:5])
class FrenchDesk2(MutableSequence):
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, pos):
return self._cards[pos]
def __setitem__(self, position, value):
self._cards[position] = value
def __delitem__(self, position):
del self._cards[position]
def insert(self, position, value):
self._cards.insert(position, value)
class Tombola(abc.ABC):
@abc.abstractmethod
def load(self, iterable):
"""从可迭代对象中添加元素。"""
@abc.abstractmethod
def pick(self):
"""随机删除元素,然后将其返回。
如果实例为空,这个方法应该抛出`LookupError`。
"""
def loaded(self):
"""如果至少有一个元素,返回`True`,否则返回`False`。"""
return bool(self.inspect())
def inspect(self):
"""返回一个有序元组,由当前元素构成。"""
items = []
while True:
try:
items.append(self.pick())
except LookupError:
break
self.load(items)
return tuple(sorted(items))
class BingoCage(Tombola):
def __init__(self, items):
self._randomizer = SystemRandom()
self._items = []
self.load(items)
def load(self, items):
self._items.extend(items)
self._randomizer.shuffle(self._items)
def pick(self):
try:
return self._items.pop()
except IndexError:
raise LookupError('pick from empty BingoCage')
def __call__(self):
self.pick()
class LotteryBlower(Tombola):
def __init__(self, iterable):
self._balls = list(iterable)
def load(self, iterable):
self._balls.extend(iterable)
def pick(self):
try:
position = randrange(len(self._balls))
except ValueError:
raise LookupError('pick from empty LotteryBlower')
return self._balls.pop(position)
def loaded(self):
return bool(self._balls)
def inspect(self):
return tuple(sorted(self._balls))
@Tombola.register
class TomboList(list):
def pick(self):
if self:
position = randrange(len(self))
return self.pop(position)
else:
raise LookupError('pop from empty TomboList')
load = list.extend
def loaded(self):
return bool(self)
def inspect(self):
return tuple(sorted(self))
#.12.继承的优缺点
from collections import UserDict
from numbers import Integral
class DoppelDict(dict):
def __setitem__(self, key, value):
super().__setitem__(key, [value] * 2)
dd = DoppelDict(one=1)
dd['two'] = 2
dd.update(three=3)
print(dd)
class AnswerDict(dict):
def __getitem__(self, key):
return 42
ad = AnswerDict(a='foo')
print(ad, ad['a'])
ad_copy = {}
ad_copy.update(ad)
print(ad_copy, ad_copy['a'])
class DoppelDict2(UserDict):
def __setitem__(self, key, value):
super().__setitem__(key, [value] * 2)
dd = DoppelDict2(one=1)
dd['two'] = 2
dd.update(three=3)
print(dd)
class A:
def ping(self):
print('ping_a:', self)
class B(A):
def pong(self):
print('pong_b:', self)
class C(A):
def pong(self):
print('pong_c:', self)
class D(B, C):
def ping(self):
super().ping()
print('ping_d_myself:', self)
def pingpong(self):
self.ping()
super().ping()
self.pong()
super().pong()
C.pong(self)
print(D.__mro__)
d = D()
print(Integral.__mro__)
#.13.正确重载运算符
#.14.可迭代对象、迭代器和生成器
import re
import reprlib
from collections.abc import Iterable, Iterator, Generator
from fractions import Fraction
import itertools
import operator
RE_WORD = re.compile('\w+')
class Sentence:
def __init__(self, text):
self.text = text
self.words = RE_WORD.findall(text)
def __iter__(self):
return SentenceIterator(self.words)
def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text)
class SentenceIterator:
def __init__(self, words):
self.words = words
self.index = 0
def __next__(self):
try:
word = self.words[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return word
def __iter__(self):
return self
class SentenceGenerator:
def __init__(self, text):
self.text = text
self.words = RE_WORD.findall(text)
def __iter__(self):
for word in self.words:
yield word
def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text)
class SentenceGeneratorInert:
def __init__(self, text):
self.text = text
def __iter__(self):
for match in RE_WORD.finditer(self.text):
yield match.group()
def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text)
class SentenceGeneratorExpr:
def __init__(self, text):
self.text = text
def __iter__(self):
return (match.group() for match in RE_WORD.finditer(self.text))
def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text)
s = Sentence('"The time has come," the Walrus said,')
print(s)
print(iter(s))
for word in s:
print(word, end=' ')
print()
print(list(s))
s = 'ABC'
for char in s:
print(char, end=' ')
print()
it = iter(s)
while True:
try:
print(next(it), end=' ')
except StopIteration:
del it
break
print()
def generator_test():
for x in range(5):
yield x
g = generator_test()
print(next(g))
for i in g:
print(i, end=' ')
print()
class ArithmeticProgression:
def __init__(self, begin, step, end=None):
self.begin = begin
self.step = step
self.end = end
def __iter__(self):
result = type(self.begin + self.step)(self.begin)
forever = self.end is None
index = 0
while forever or result < self.end:
yield result
index += 1
result = self.begin + self.step * index
def aritprog_gen(begin, step, end=None):
result = type(begin + step)(begin)
forever = end is None
index = 0
while forever or result < end:
yield result
index += 1
result = begin + step * index
ap = ArithmeticProgression(0, 1, 3)
ap2 = ArithmeticProgression(0, Fraction(1, 3), 1)
print(list(ap2))
print(itertools.count(1, 0.5))
gen = itertools.takewhile(lambda n: n < 3, itertools.count(1, 0.5))
print(list(gen))
print()
def vowel(c):
return c.lower() in 'aeiou'
def filter_gen():
print(list(filter(vowel, 'Aardvark')))
print(list(itertools.filterfalse(vowel, 'Aardvark')))
print(list(itertools.dropwhile(vowel, 'Aardvark')))
print(list(itertools.takewhile(vowel, 'Aardvark')))
print(list(itertools.compress('Aardvark', (1,0,1,1,0,1))))
print(list(itertools.islice('Aardvark', 4)))
print(list(itertools.islice('Aardvark', 4, 7)))
print(list(itertools.islice('Aardvark', 1, 7, 2)))
sample = [5, 4, 2, 8, 7, 6, 3, 0, 9, 1]
def map_gen():
print(list(itertools.accumulate(sample)))
print(list(itertools.accumulate(sample, min)))
print(list(itertools.accumulate(sample, max)))
print(list(itertools.accumulate(sample, operator.mul)))
print(list(enumerate('albatroz', 1)))
print(list(map(operator.mul, range(11), range(11))))
print(list(itertools.starmap(operator.mul, enumerate('albatroz', 1))))
def merge_gen():
print(list(itertools.chain('ABC', range(2))))
print(list(itertools.chain(enumerate('ABC'))))
print(list(itertools.chain.from_iterable(enumerate('ABC'))))
print(list(zip('ABC', range(5))))
print(list(zip('ABC', range(5), [10, 20, 30, 40])))
print(list(itertools.zip_longest('ABC', range(5))))
print(list(itertools.zip_longest('ABC', range(5), fillvalue='?')))
print(list(itertools.product('ABC', range(2))))
def ext_gen():
print(list(itertools.islice(itertools.count(1, 0.3), 3)))
print(list(itertools.islice(itertools.cycle('ABC'), 7)))
print(list(itertools.repeat(8, 4)))
print(list(itertools.combinations('ABC', 2)))
print(list(itertools.combinations_with_replacement('ABC', 2)))
print(list(itertools.permutations('ABC', 2)))
animals = ['duck', 'eagle', 'rat', 'giraffe', 'bear', 'bat', 'dolphin', 'shark', 'lion']
animals.sort(key=len, reverse=True)
def rearrange_gen():
print(list(itertools.groupby('LLLLAAGGG')))
for length, group in itertools.groupby(animals, len):
print(length, '->', list(group), end=' ')
print()
print(list(itertools.tee('ABC')))
def chain(*iterables):
for it in iterables:
for i in it:
yield i
def chain2(*iterables):
for i in iterables:
yield from i
s = 'ABC'
t = tuple(range(3))
print(list(chain2(s, t)))
#.15.上下文管理器和else模块
#.16.协程
from inspect import getgeneratorstate
from functools import wraps
from collections import namedtuple
def simple_coroutine():
for _ in range(5):
print('-> coroutine started')
x = yield
print('-> coroutine received:', x)
def simple_coro2(a):
while True:
print('-> Started: a =', a)
b = yield a
print('-> Received: b =', b)
c = yield a + b
print('-> Received: c =', c)
def averager():
total = 0.0
count = 0
average = None
while True:
term = yield average
total += term
count += 1
average = total / count
def coroutine(func):
"""装饰器:向前执行到第一个`yield`表达式,预激`func`"""
@wraps(func)
def primer(*args, **kwargs):
gen = func(*args, **kwargs)
next(gen)
return gen
return primer
class DemoException(Exception):
"""为这次演示定义的异常类型。"""
def demo_exc_handling():
print('-> coroutine started')
while True:
try:
x = yield
except DemoException:
print('*** DemoException handled. Continuing...')
else:
print('-> coroutine received: {!r}'.format(x))
exc_coro = demo_exc_handling()
next(exc_coro)
exc_coro.send(11)
exc_coro.send(22)
exc_coro.close()
Result = namedtuple('Result', 'count average')
def averager2():
total = 0.0
count = 0
average = None
while True:
term = yield
if term is None:
break
total += term
count += 1
average = total/count
return Result(count, average)
coro_avg = averager2()
next(coro_avg)
coro_avg.send(10)
coro_avg.send(30)
coro_avg.send(6.5)
result = Result(4, 5)
try:
coro_avg.send(None)
except StopIteration as exc:
result = exc.value
print(result)
def grouper(results, key):
while True:
results[key] = yield from averager2()
def mainfun(data):
results = {}
for key, values in data.items():
group = grouper(results, key)
next(group)
for value in values:
group.send(value)
group.send(None)
report(results)
def report(results):
for key, result in sorted(results.items()):
group, unit = key.split(';')
print('{:2} {:5} averaging {:.2f}{}'.format(
result.count, group, result.average, unit))
data = {
'girls;kg': [40.9, 38.5, 44.3, 42.2, 45.2, 41.7, 44.5, 38.0, 40.6, 44.5],
'girls;m': [1.6, 1.51, 1.4, 1.3, 1.41, 1.39, 1.33, 1.46, 1.45, 1.43],
'boys;kg': [39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
'boys;m': [1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46],
}
mainfun(data)
#.17.使用期物处理并发
import os
import time
import sys
import requests
from concurrent import futures
POP20_CC = ('CN IN US ID BR PK NG BD RU JP '
'MX PH VN ET EG DE IR TR CD FR').split()
BASE_URL = 'http://flupy.org/data/flags'
DEST_DIR = 'downloads/'
def save_flag(img, filename):
path = os.path.join(DEST_DIR, filename)
with open(path, 'wb') as fp:
fp.write(img)
def get_flag(cc):
url = '{}/{cc}/{cc}.gif'.format(BASE_URL, cc=cc.lower())
resp = requests.get(url)
return resp.content
def show(text):
print(text, end=' ')
def download_many(cc_list):
for cc in sorted(cc_list):
image = get_flag(cc)
show(cc)
save_flag(image, cc.lower() + '.gif')
return len(cc_list)
def mainfun(download_many):
t0 = time.time()
count = download_many(POP20_CC)
elapsed = time.time() - t0
msg = '\n{} flags downloaded in {:.2f}s'
print(msg.format(count, elapsed))
MAX_WORKERS = 20
def download_one(cc):
image = get_flag(cc)
show(cc)
save_flag(image, cc.lower() + '_futures.gif')
return cc
def download_many2(cc_list):
workers = min(MAX_WORKERS, len(cc_list))
with futures.ThreadPoolExecutor(workers) as executor:
res = executor.map(download_one, sorted(cc_list))
return len(list(res))
def download_many3(cc_list):
cc_list = cc_list[:5]
with futures.ThreadPoolExecutor(max_workers=3) as executor:
to_do = []
for cc in sorted(cc_list):
future = executor.submit(download_one, cc)
to_do.append(future)
msg = 'Scheduled for {}: {}'
print(msg.format(cc, future))
results = []
for future in futures.as_completed(to_do):
res = future.result()
msg = '{} result: {!r}'
print(msg.format(future, res))
results.append(res)
return len(results)
#.18.使用asyncio包处理并发
import threading
import itertools
import time
import sys
class Signal:
go = True
def spin(msg, signal):
write, flush = sys.stdout.write, sys.stdout.flush
for char in itertools.cycle('|/-\\'):
status = char + ' ' + msg
write(status)
flush()
write('\x08' * len(status))
time.sleep(.1)
if not signal.go:
break
write(' ' * len(status) + '\x08' * len(status))
def slow_function():
time.sleep(3)
return 42
def supervisor():
signal = Signal()
spinner = threading.Thread(target=spin,
args=('thinking!', signal))
print('spinner object:', spinner)
spinner.start()
result = slow_function()
signal.go = False
spinner.join()
return result
def mainfun():
result = supervisor()
print('Answer:', result)
mainfun()
#.19.动态属性和特性
from collections import abc
import json
import keyword
import shelve
import warnings
JSON = 'testjs.json'
with open(JSON) as f:
feed = json.load(f)
class FrozenJSON:
"""一个只读接口,使用属性表示法访问JSON类对象
"""
def __init__(self, mapping):
self.__data = dict()
for key, value in mapping.items():
if keyword.iskeyword(key):
key += '_'
self.__data[key] = value
def __getattr__(self, name):
if hasattr(self.__data, name):
return getattr(self.__data, name)
else:
return FrozenJSON.build(self.__data[name])
@classmethod
def build(cls, obj):
if isinstance(obj, abc.Mapping):
return cls(obj)
elif isinstance(obj, abc.MutableSequence):
return [cls.build(item) for item in obj]
else:
return obj
grad = FrozenJSON({'name': 'Jim Bo', 'class': 1982})
print(grad.class_)
class FrozenJSON2:
"""一个只读接口,使用属性表示法访问JSON类对象
"""
def __new__(cls, arg):
if isinstance(arg, abc.Mapping):
return super().__new__(cls)
elif isinstance(arg, abc.MutableSequence):
return [cls(item) for item in arg]
else:
return arg
def __init__(self, mapping):
self.__data = {}
for key, value in mapping.items():
if keyword.iskeyword(key):
key += '_'
self.__data[key] = value
def __getattr__(self, name):
if hasattr(self.__data, name):
return getattr(self.__data, name)
else:
return FrozenJSON2(self.__data[name])
grad2 = FrozenJSON2({'name': ['Jim Bo', 'a'], 'class': 1982})
print(grad2.name)
DB_NAME = 'schedule1_db'
CONFERENCE = 'conference.115'
class Record:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def load_db(db):
raw_data = feed
warnings.warn('loading ' + DB_NAME)
for collection, rec_list in raw_data['Schedule'].items():
record_type = collection[:-1]
for record in rec_list:
key = '{}.{}'.format(record_type, record['serial'])
record['serial'] = key
db[key] = Record(**record)
db = shelve.open(DB_NAME)
if CONFERENCE not in db:
load_db(db)
speaker = db['speaker.157509']
print(type(db))
if hasattr(speaker, 'name') and hasattr(speaker, 'twitter'):
print(speaker.name, speaker.twitter)
db.close()
class A:
data = 'the class data attr'
@property
def prop(self):
return 'the prop value'
a = A()
print(vars(a))
print(a.data)
a.data = 'bar'
print(a.__dict__)
print(A.__dict__)
print(a.prop)
a.__dict__['prop'] = 'foo'
print(a.prop)
print(a.__dict__)
A.prop = 'baz'
print(a.prop)
print(A.data)
print(a.data)
A.data = property(lambda self: 'the "data" prop value')
print(a.data)
del A.data
print(a.data)
#.20.属性描述符
import collections
class Quantity:
def __init__(self, storage_name):
self.storage_name = storage_name
def __set__(self, instance, value):
if value > 0:
instance.__dict__[self.storage_name] = value
else:
raise ValueError('value must be > 0')
class LineItem:
weight = Quantity('weight')
price = Quantity('price')
def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price
truffle = LineItem('White truffle', 100, 20)
class Quantity2:
__counter = 0
def __init__(self):
cls = self.__class__
prefix = cls.__name__
index = cls.__counter
self.storage_name = '_{}#{}'.format(prefix, index)
cls.__counter += 1
def __get__(self, instance, owner):
print(owner)
return getattr(instance, self.storage_name)
def __set__(self, instance, value):
if value > 0:
setattr(instance, self.storage_name, value)
else:
raise ValueError('value must be > 0')
class LineItem2:
weight = Quantity2()
price = Quantity2()
def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price
def subtotal(self):
return self.weight * self.price
def cls_name(obj_or_cls):
cls = type(obj_or_cls)
if cls is type:
cls = obj_or_cls
return cls.__name__.split('.')[-1]
def display(obj):
cls = type(obj)
if cls is type:
return ''.format(obj.__name__)
elif cls in [type(None), int]:
return repr(obj)
else:
return '<{} object>'.format(cls_name(obj))
def print_args(name, *args):
pseudo_args = ', '.join(display(x) for x in args)
print('-> {}.__{}__({})'.format(cls_name(args[0]), name, pseudo_args))
class Overriding:
"""也称数据描述符或强制描述符"""
def __get__(self, instance, owner):
print_args('get', self, instance, owner)
def __set__(self, instance, value):
print_args('set', self, instance, value)
class OverridingNoGet:
"""没有``__get__``方法的覆盖型描述符"""
def __set__(self, instance, value):
print_args('set', self, instance, value)
class OverridingNoSet:
"""没有``__set__``,也称非数据描述符或遮盖型描述符"""
def __get__(self, instance, owner):
print_args('get', self, instance, owner)
class Managed:
over = Overriding()
over_no_get = OverridingNoGet()
non_over = OverridingNoSet()
def spam(self):
print('-> Managed.spam({})'.format(display(self)))
class Text(collections.UserString):
def __repr__(self):
return 'Text({!r})'.format(self.data)
def reverse(self):
return self[::-1]