美文网首页
Fluent Python手册(二)

Fluent Python手册(二)

作者: plutoese | 来源:发表于2017-06-12 19:10 被阅读57次

控制流程:使用期物处理并发

期物指一种对象,表示异步执行的操作。

(1)示例:网络下载的三种风格

依序下载的脚本

"""Download flags of top 20 countries by population

Sequential version

Sample run::

    $ python3 flags.py
    BD BR CD CN DE EG ET FR ID IN IR JP MX NG PH PK RU TR US VN
    20 flags downloaded in 10.16s

"""
# BEGIN FLAGS_PY
import os
import time
import sys

import requests  # <1>

POP20_CC = ('CN IN US ID BR PK NG BD RU JP '
            'MX PH VN ET EG DE IR TR CD FR').split()  # <2>

BASE_URL = 'http://flupy.org/data/flags'  # <3>

DEST_DIR = 'downloads/'  # <4>


def save_flag(img, filename):  # <5>
    path = os.path.join(DEST_DIR, filename)
    with open(path, 'wb') as fp:
        fp.write(img)


def get_flag(cc):  # <6>
    url = '{}/{cc}/{cc}.gif'.format(BASE_URL, cc=cc.lower())
    resp = requests.get(url)
    return resp.content


def show(text):  # <7>
    print(text, end=' ')
    sys.stdout.flush()


def download_many(cc_list):  # <8>
    for cc in sorted(cc_list):  # <9>
        image = get_flag(cc)
        show(cc)
        save_flag(image, cc.lower() + '.gif')

    return len(cc_list)


def main(download_many):  # <10>
    t0 = time.time()
    count = download_many(POP20_CC)
    elapsed = time.time() - t0
    msg = '\n{} flags downloaded in {:.2f}s'
    print(msg.format(count, elapsed))


if __name__ == '__main__':
    main(download_many)

使用concurrent.futures模块下载

concurrent.futures模块的主要特色是ThreadPoolExecutor和ProcessPoolExecutor类。这两个类在内部维护着一个工作线程或进程池,以及要执行的任务队列。

"""Download flags of top 20 countries by population

ThreadPoolExecutor version

Sample run::

    $ python3 flags_threadpool.py
    BD retrieved.
    EG retrieved.
    CN retrieved.
    ...
    PH retrieved.
    US retrieved.
    IR retrieved.
    20 flags downloaded in 0.93s

"""
# BEGIN FLAGS_THREADPOOL
from concurrent import futures

from flags import save_flag, get_flag, show, main  # <1>

MAX_WORKERS = 20  # <2>


def download_one(cc):  # <3>
    image = get_flag(cc)
    show(cc)
    save_flag(image, cc.lower() + '.gif')
    return cc


def download_many(cc_list):
    workers = min(MAX_WORKERS, len(cc_list))  # <4>
    with futures.ThreadPoolExecutor(workers) as executor:  # <5>
        res = executor.map(download_one, sorted(cc_list))  # <6>

    return len(list(res))  # <7>


if __name__ == '__main__':
    main(download_many)

(2)实验Executor.map方法

若想并发运行多个可调用的对象,最简单的方式是使用Executor.map方法。

"""
Experiment with ``ThreadPoolExecutor.map``
"""

from time import sleep, strftime
from concurrent import futures

def display(*args):  
    print(strftime('[%H:%M:%S]'), end=' ')
    print(*args)

def loiter(n): 
    msg = '{}loiter({}): doing nothing for {}s...'
    display(msg.format('\t'*n, n, n))
    sleep(n)
    msg = '{}loiter({}): done.'
    display(msg.format('\t'*n, n))
    return n * 10  

def main():
    display('Script starting.')
    executor = futures.ThreadPoolExecutor(max_workers=3) 
    results = executor.map(loiter, range(5))  
    display('results:', results) 
    display('Waiting for individual results:')
    for i, result in enumerate(results):  
        display('result {}: {}'.format(i, result))

main()

控制流程:使用asyncio包处理并发

期物指一种对象,表示异步执行的操作。

(1)示例:网络下载的三种风格

(2)使用动态属性转换数据

(3)使用动态属性转换数据

元编程:动态属性和特征

在Python中,数据的属性和处理数据的方法统称属性。不管服务是由存储还是计算实现的,一个模块提供的所有服务都应该通过统一的方法使用。

(1)使用动态属性转换数据

首先是使用动态属性访问JSON类数据,我们实现FrozenJSON类,只能访问数据。不过,这个类能地柜,自动处理嵌套的映射和列表。这个类的关键是__getattr__()方法。

osconfeed.json文件中的记录如下

{ "Schedule": 
  { "conferences": [{"serial": 115 }],
    "events": [
      { "serial": 34505,
        "name": "Why Schools Don´t Use Open Source to Teach Programming",
        "event_type": "40-minute conference session",
        "time_start": "2014-07-23 11:30:00",
        "time_stop": "2014-07-23 12:10:00",
        "venue_serial": 1462,
        "description": "Aside from the fact that high school programming...",
        "website_url": "http://oscon.com/oscon2014/public/schedule/detail/34505", 
        "speakers": [157509],
        "categories": ["Education"] }
    ],
    "speakers": [
      { "serial": 157509,
        "name": "Robert Lefkowitz",
        "photo": null,
        "url": "http://sharewave.com/",
        "position": "CTO",
        "affiliation": "Sharewave",
        "twitter": "sharewaveteam",
        "bio": "Robert ´r0ml´ Lefkowitz is the CTO at Sharewave, a startup..." }
    ],
    "venues": [
      { "serial": 1462,
        "name": "F151",
        "category": "Conference Venues" }
    ]
  }
}

把一个JSON数据集转换成一个嵌套着FronzenJSON对象,列表和简单类型的FrozenJSON对象。

"""
explore0.py: Script to explore the OSCON schedule feed

# BEGIN EXPLORE0_DEMO
    >>> from osconfeed import load
    >>> raw_feed = load()
    >>> feed = FrozenJSON(raw_feed)  # <1>
    >>> len(feed.Schedule.speakers)  # <2>
    357
    >>> sorted(feed.Schedule.keys())  # <3>
    ['conferences', 'events', 'speakers', 'venues']
    >>> for key, value in sorted(feed.Schedule.items()): # <4>
    ...     print('{:3} {}'.format(len(value), key))
    ...
      1 conferences
    484 events
    357 speakers
     53 venues
    >>> feed.Schedule.speakers[-1].name  # <5>
    'Carina C. Zona'
    >>> talk = feed.Schedule.events[40]
    >>> type(talk)  # <6>
    <class 'explore0.FrozenJSON'>
    >>> talk.name
    'There *Will* Be Bugs'
    >>> talk.speakers  # <7>
    [3471, 5199]
    >>> talk.flavor  # <8>
    Traceback (most recent call last):
      ...
    KeyError: 'flavor'

# END EXPLORE0_DEMO

"""

# BEGIN EXPLORE0
from collections import abc


class FrozenJSON:
    """A read-only façade for navigating a JSON-like object
       using attribute notation
    """

    def __init__(self, mapping):
        self.__data = dict(mapping)  # <1>

    def __getattr__(self, name):  # <2>
        if hasattr(self.__data, name):
            return getattr(self.__data, name)  # <3>
        else:
            return FrozenJSON.build(self.__data[name])  # <4>

    @classmethod
    def build(cls, obj):  # <5>
        if isinstance(obj, abc.Mapping):  # <6>
            return cls(obj)
        elif isinstance(obj, abc.MutableSequence):  # <7>
            return [cls.build(item) for item in obj]
        else:  # <8>
            return obj
# END EXPLORE0

使用__new__方法以灵活的方式创建对象。

"""
explore2.py: Script to explore the OSCON schedule feed

    >>> from osconfeed import load
    >>> raw_feed = load()
    >>> feed = FrozenJSON(raw_feed)
    >>> len(feed.Schedule.speakers)
    357
    >>> sorted(feed.Schedule.keys())
    ['conferences', 'events', 'speakers', 'venues']
    >>> feed.Schedule.speakers[-1].name
    'Carina C. Zona'
    >>> talk = feed.Schedule.events[40]
    >>> talk.name
    'There *Will* Be Bugs'
    >>> talk.speakers
    [3471, 5199]
    >>> talk.flavor
    Traceback (most recent call last):
      ...
    KeyError: 'flavor'

"""

# BEGIN EXPLORE2
from collections import abc


class FrozenJSON:
    """A read-only façade for navigating a JSON-like object
       using attribute notation
    """

    def __new__(cls, arg):  # <1>
        if isinstance(arg, abc.Mapping):
            return super().__new__(cls)  # <2>
        elif isinstance(arg, abc.MutableSequence):  # <3>
            return [cls(item) for item in arg]
        else:
            return arg

    def __init__(self, mapping):
        self.__data = {}
        for key, value in mapping.items():
            if iskeyword(key):
                key += '_'
            self.__data[key] = value

    def __getattr__(self, name):
        if hasattr(self.__data, name):
            return getattr(self.__data, name)
        else:
            return FrozenJSON(self.__data[name])  # <4>
# END EXPLORE2

(2)使用特性验证属性

LineItem类第2版:能验证值的特性。

class LineItem:

    def __init__(self, description, weight, price):
        self.description = description
        self.weight = weight  # <1>
        self.price = price

    def subtotal(self):
        return self.weight * self.price

    @property  # <2>
    def weight(self):  # <3>
        return self.__weight  # <4>

    @weight.setter  # <5>
    def weight(self, value):
        if value > 0:
            self.__weight = value  # <6>
        else:
            raise ValueError('value must be > 0')  # <7>

(3)定义一个特性工厂函数

我们将定义一个名为quantity的特性工厂函数。

"""

A line item for a bulk food order has description, weight and price fields::

    >>> raisins = LineItem('Golden raisins', 10, 6.95)
    >>> raisins.weight, raisins.description, raisins.price
    (10, 'Golden raisins', 6.95)

A ``subtotal`` method gives the total price for that line item::

    >>> raisins.subtotal()
    69.5

The weight of a ``LineItem`` must be greater than 0::

    >>> raisins.weight = -20
    Traceback (most recent call last):
        ...
    ValueError: value must be > 0

No change was made::

    >>> raisins.weight
    10

The value of the attributes managed by the properties are stored in
instance attributes, created in each ``LineItem`` instance::

# BEGIN LINEITEM_V2_PROP_DEMO
    >>> nutmeg = LineItem('Moluccan nutmeg', 8, 13.95)
    >>> nutmeg.weight, nutmeg.price  # <1>
    (8, 13.95)
    >>> sorted(vars(nutmeg).items())  # <2>
    [('description', 'Moluccan nutmeg'), ('price', 13.95), ('weight', 8)]

# END LINEITEM_V2_PROP_DEMO

"""


# BEGIN LINEITEM_V2_PROP_FACTORY_FUNCTION
def quantity(storage_name):  # <1>

    def qty_getter(instance):  # <2>
        return instance.__dict__[storage_name]  # <3>

    def qty_setter(instance, value):  # <4>
        if value > 0:
            instance.__dict__[storage_name] = value  # <5>
        else:
            raise ValueError('value must be > 0')

    return property(qty_getter, qty_setter)  # <6>
# END LINEITEM_V2_PROP_FACTORY_FUNCTION


# BEGIN LINEITEM_V2_PROP_CLASS
class LineItem:
    weight = quantity('weight')  # <1>
    price = quantity('price')  # <2>

    def __init__(self, description, weight, price):
        self.description = description
        self.weight = weight  # <3>
        self.price = price

    def subtotal(self):
        return self.weight * self.price  # <4>
# END LINEITEM_V2_PROP_CLASS

(4)处理属性的重要属性和函数

(5)定义一个特性工厂函数

相关文章

  • Fluent Python手册(二)

    控制流程:使用期物处理并发 期物指一种对象,表示异步执行的操作。 (1)示例:网络下载的三种风格 依序下载的脚本 ...

  • Fluent Python手册(一)

    把函数视为对象:一等函数 把函数视为对象 python函数是对象。 高阶函数 函数式编程的特点之一是使用高阶函数。...

  • 2019-05-12

    Netflix 混沌工程手册 Flogger: A Fluent Logging API for Java 利用 ...

  • Fluent系列3

    Fluent Python Notebook Part Three 标签(空格分隔): Python Object...

  • 《流畅的Python》分享下载

    书籍信息 书名:《流畅的Python》 原作名:Fluent Python 作者:[巴西] Luciano Ram...

  • 一个针对 Python 语句执行顺序的练习

    摘自 Fluent Python evalsupport.py evaltime.py evaltime_meta.py

  • 5 Fluent Python

    以实践为基础测试驱动开发TDD:精髓就是先写测试,对自定义类的每一个方法都编写doctest。核心语言特性:迭代、...

  • fluent python 1

    1 用*来获取不确定数量的参数 用*来获取不确定数量的参数 2 用*运算符来把一个可迭代对象的参数拆开作为函数的参...

  • Python自悟:Python中的Sequence Type

    主要内容源自解读《Fluent Python》,理解如有错误敬请指正:-) Python标准库提供了大量使用C来实...

  • 流畅的Python(Fluent Python)

    为了夯实自己的python基础,已经看了2周fluent python。今天终于上手编写了点脚本。 本次脚本主要测...

网友评论

      本文标题:Fluent Python手册(二)

      本文链接:https://www.haomeiwen.com/subject/dufrqxtx.html