├── chapter8 ├── webxample-package │ ├── README.md │ ├── webxample │ │ ├── __init__.py │ │ ├── conf │ │ │ ├── __init__.py │ │ │ ├── wsgi.py │ │ │ ├── urls.py │ │ │ └── settings.py │ │ ├── myapp │ │ │ ├── __init__.py │ │ │ ├── static │ │ │ │ ├── js │ │ │ │ │ └── myapp.js │ │ │ │ └── sass │ │ │ │ │ └── myapp.scss │ │ │ ├── migrations │ │ │ │ └── __init__.py │ │ │ ├── tests.py │ │ │ ├── admin.py │ │ │ ├── apps.py │ │ │ ├── views.py │ │ │ ├── templates │ │ │ │ ├── index.html │ │ │ │ └── some_view.html │ │ │ └── models.py │ │ ├── manage.py │ │ └── locale │ │ │ ├── en │ │ │ └── LC_MESSAGES │ │ │ │ └── django.po │ │ │ ├── de │ │ │ └── LC_MESSAGES │ │ │ │ └── django.po │ │ │ └── pl │ │ │ └── LC_MESSAGES │ │ │ └── django.po │ ├── circus.ini │ ├── MANIFEST.in │ ├── fabfile.py │ ├── fabutils.py │ └── setup.py └── _NOTES.md ├── chapter9 ├── fibonacci_c │ ├── fibonacci.egg-info │ │ ├── dependency_links.txt │ │ ├── top_level.txt │ │ ├── SOURCES.txt │ │ └── PKG-INFO │ ├── setup.py │ └── fibonacci.c ├── fibonacci_cython │ ├── setup.py │ └── fibonacci.pyx ├── fibonacci_cythonize │ ├── setup.py │ └── fibonacci.py ├── fibonacci_cython_nogil │ ├── setup.py │ └── fibonacci.pyx ├── ctypes_libc_printf.py ├── fibonacci_c_error_handling │ ├── setup.py │ └── fibonacci.c ├── fibonacci_c_releasing_gil │ ├── setup.py │ └── fibonacci.c ├── fibonacci_cythonize_optionally │ ├── fibonacci.py │ └── setup.py ├── _NOTES.md ├── cffi_qsort.py └── ctypes_qsort.py ├── chapter1 ├── _NOTES.md └── example_compat.py ├── chapter5 ├── hyllo.hy ├── py_hyllo.py ├── _NOTES.md ├── nonzero.py ├── instance_counting.py └── metaclasses.py ├── chapter7 ├── explicit_namespace_package │ ├── acme │ │ ├── __init__.py │ │ └── templating │ │ │ └── __init__.py │ └── setup.py ├── implicit_namespace_package │ ├── setup.py │ └── acme │ │ └── templating │ │ └── __init__.py ├── example_with_version │ ├── example_with_version │ │ └── __init__.py │ └── setup.py ├── example_with_readme_conversion │ ├── example_with_readme_conversion │ │ └── __init__.py │ ├── README.md │ └── setup.py └── _NOTES.md ├── chapter14 ├── _NOTES.md ├── memoize_lru_cache.py └── memoize_decorator.py ├── chapter6 ├── _NOTES.md ├── private_variables.py ├── options.py ├── name_mangling.py ├── custom_container.py └── private_attributes.py ├── chapter13 ├── _NOTES.md ├── myapp.py ├── cprofile_profiling.py ├── graphing_backreferences.py ├── cyclic_references.py └── cprofile_decorator.py ├── chapter3 ├── enums_flags.py ├── enums_ints.py ├── enums_auto.py ├── yield_fibonacci.py ├── enums_statuses.py ├── iterators_countdown.py ├── _NOTES.md ├── iterators_countdown_with_state.py ├── context_manager_as_class.py ├── yield_chaining_generators.py ├── context_manager_as_function.py ├── decorators_repeat.py ├── lists.py ├── yield_psychologist.py └── decorators_repeat_with_metadata.py ├── chapter12 ├── primes.py ├── pytest_testing │ ├── primes.py │ └── test_primes.py ├── unittest_testing │ ├── primes.py │ └── test_primes.py ├── _NOTES.md ├── test_with_mock_patch │ ├── test_mailer.py │ └── mailer.py ├── test_with_mock │ ├── test_mailer.py │ └── mailer.py └── test_with_fake │ ├── mailer.py │ └── test_mailer.py ├── chapter16 ├── _NOTES.md ├── topic_based_events.py ├── tkinter_gui.py ├── web_application.py └── subject_based_events.py ├── chapter17 ├── creational_borg.py ├── _NOTES.md ├── creational_singleton.py ├── structural_adapter.py ├── interfaces_zope.py ├── observer.py ├── interfaces_abc.py └── interfaces_annotations.py ├── chapter2 ├── docker-compose.yml ├── docker-compose.services.yml ├── docker-compose.networks-b.yml ├── docker-compose.networks-a.yml ├── _NOTES.md ├── Dockerfile ├── Dockerfile.alpine ├── pythonstartup ├── Dockerfile.multistage └── Vagrantfile ├── chapter15 ├── asyncrates.py ├── async_print.py ├── multiprocessing_sharedctypes.py ├── _NOTES.md ├── multiprocessing_basics.py ├── async_cooperative_wait.py ├── multiprocessing_forks.py ├── multiprocessing_pipes.py ├── synchronous.py ├── async_aiohttp.py ├── multiprocessing_dummy.py ├── multiprocessing_process_pool.py ├── threads_one_per_item.py ├── async_futures.py ├── threads_thread_pool.py ├── threads_two_way_queues.py └── threads_exceptions_and_throttling.py ├── chapter4 ├── _NOTES.md ├── folder.py ├── vector_as_dataclass.py ├── vector.py ├── pizza.py ├── descriptors_revealing_access.py ├── descriptors_init_on_access.py ├── properties_decorator.py ├── distinctdict.py ├── properties_explicit.py └── descriptors_lazy_class_attribute.py ├── README.md └── LICENSE /chapter8/webxample-package/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/conf/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/static/js/myapp.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chapter9/fibonacci_c/fibonacci.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /chapter9/fibonacci_c/fibonacci.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | fibonacci 2 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/static/sass/myapp.scss: -------------------------------------------------------------------------------- 1 | #foo { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /chapter1/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * "バージョン間の互換性を保つ時によく利用されるツールやテクニック" 4 | * `example_compat.py` 5 | -------------------------------------------------------------------------------- /chapter5/hyllo.hy: -------------------------------------------------------------------------------- 1 | ;; 「Hy」の節で登場するサンプルコード 2 | ;; PythonベースのLisp方言 3 | (defn hello [] (print "hello world!")) 4 | -------------------------------------------------------------------------------- /chapter7/explicit_namespace_package/acme/__init__.py: -------------------------------------------------------------------------------- 1 | __import__('pkg_resources').declare_namespace(__name__) 2 | -------------------------------------------------------------------------------- /chapter14/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * 決定的キャッシュ 4 | * `memoize_decorator.py` 5 | * `memoize_lru_cache.py` 6 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /chapter5/py_hyllo.py: -------------------------------------------------------------------------------- 1 | import hy # this import statement enables Hy language import hooks 2 | 3 | import hyllo 4 | 5 | 6 | if __name__ == "__main__": 7 | hyllo.hello() -------------------------------------------------------------------------------- /chapter7/implicit_namespace_package/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | setup( 5 | name='acme.templating', 6 | packages=['acme.templating'], 7 | ) 8 | -------------------------------------------------------------------------------- /chapter8/webxample-package/circus.ini: -------------------------------------------------------------------------------- 1 | [watcher:webxample] 2 | cmd = /var/projects/webxample/.envs/webxample/bin/gunicorn webxample.conf.wsgi:application 3 | numprocesses = 1 4 | 5 | -------------------------------------------------------------------------------- /chapter7/example_with_version/example_with_version/__init__.py: -------------------------------------------------------------------------------- 1 | # 比較しやすいようにタプル形式でのバージョン表記 2 | VERSION = (0, 0, 1) 3 | # 矛盾が生じないようにタプルから文字列を生成 4 | __version__ = ".".join([str(x) for x in VERSION]) 5 | -------------------------------------------------------------------------------- /chapter7/explicit_namespace_package/acme/templating/__init__.py: -------------------------------------------------------------------------------- 1 | # 比較しやすいようにタプル形式でのバージョン表記 2 | VERSION = (0, 0, 1) 3 | # 矛盾が生じないようにタプルから文字列を生成 4 | __version__ = ".".join([str(x) for x in VERSION]) 5 | -------------------------------------------------------------------------------- /chapter7/implicit_namespace_package/acme/templating/__init__.py: -------------------------------------------------------------------------------- 1 | # 比較しやすいようにタプル形式でのバージョン表記 2 | VERSION = (0, 0, 1) 3 | # 矛盾が生じないようにタプルから文字列を生成 4 | __version__ = ".".join([str(x) for x in VERSION]) 5 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/apps.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from django.apps import AppConfig 4 | 5 | 6 | class MyappConfig(AppConfig): 7 | name = 'myapp' 8 | -------------------------------------------------------------------------------- /chapter9/fibonacci_cython/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from Cython.Build import cythonize 3 | 4 | 5 | setup( 6 | name='fibonacci', 7 | ext_modules=cythonize(['fibonacci.pyx']) 8 | ) 9 | -------------------------------------------------------------------------------- /chapter7/explicit_namespace_package/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | setup( 5 | name='acme.templating', 6 | packages=['acme.templating'], 7 | namespace_packages=['acme'], 8 | ) 9 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | 4 | # Create your views here. 5 | def delay(request): 6 | import time; time.sleep(2) 7 | return "foo" 8 | -------------------------------------------------------------------------------- /chapter9/fibonacci_cythonize/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from Cython.Build import cythonize 3 | 4 | 5 | setup( 6 | name='fibonacci', 7 | ext_modules=cythonize(['fibonacci.py']) 8 | ) 9 | -------------------------------------------------------------------------------- /chapter7/example_with_readme_conversion/example_with_readme_conversion/__init__.py: -------------------------------------------------------------------------------- 1 | # 比較しやすいようにタプル形式でのバージョン表記 2 | VERSION = (0, 0, 1) 3 | # 矛盾が生じないようにタプルから文字列を生成 4 | __version__ = ".".join([str(x) for x in VERSION]) 5 | -------------------------------------------------------------------------------- /chapter9/fibonacci_cython_nogil/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from Cython.Build import cythonize 3 | 4 | 5 | setup( 6 | name='fibonacci', 7 | ext_modules=cythonize(['fibonacci.pyx']) 8 | ) 9 | -------------------------------------------------------------------------------- /chapter6/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * 定数 4 | * `options.py` 5 | 6 | * プロパティ 7 | * `custom_container.py` 8 | 9 | * パブリック変数とプライベート変数 10 | * `private_variables.py` 11 | * `private_attributes.py` 12 | -------------------------------------------------------------------------------- /chapter9/fibonacci_c/fibonacci.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | fibonacci.c 2 | setup.py 3 | fibonacci.egg-info/PKG-INFO 4 | fibonacci.egg-info/SOURCES.txt 5 | fibonacci.egg-info/dependency_links.txt 6 | fibonacci.egg-info/top_level.txt -------------------------------------------------------------------------------- /chapter9/fibonacci_c/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, Extension 2 | 3 | 4 | setup( 5 | name='fibonacci', 6 | ext_modules=[ 7 | Extension('fibonacci', ['fibonacci.c']), 8 | ] 9 | ) 10 | -------------------------------------------------------------------------------- /chapter13/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * マクロプロファイリング 4 | * `cprofile_profiling.py` 5 | * `cprofile_decorator.py` 6 | 7 | * メモリー使用量のプロファイル 8 | * `graphing_backreferences.py` 9 | * `cyclic_references.py` 10 | -------------------------------------------------------------------------------- /chapter3/enums_flags.py: -------------------------------------------------------------------------------- 1 | from enum import Flag, auto 2 | 3 | 4 | class Side(Flag): 5 | GUACAMOLE = auto() 6 | TORTILLA = auto() 7 | FRIES = auto() 8 | BEER = auto() 9 | POTATO_SALAD = auto() 10 | -------------------------------------------------------------------------------- /chapter9/ctypes_libc_printf.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | from ctypes.util import find_library 3 | 4 | libc = ctypes.cdll.LoadLibrary(find_library('c')) 5 | 6 | 7 | if __name__ == "__main__": 8 | libc.printf(b"Hello world!\n") 9 | -------------------------------------------------------------------------------- /chapter3/enums_ints.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Weekday(Enum): 5 | MONDAY = 0 6 | TUESDAY = 1 7 | WEDNESDAY = 2 8 | THURSDAY = 3 9 | FRIDAY = 4 10 | SATURDAY = 5 11 | SUNDAY = 6 -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/templates/some_view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /chapter9/fibonacci_c_error_handling/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, Extension 2 | 3 | 4 | setup( 5 | name='fibonacci', 6 | ext_modules=[ 7 | Extension('fibonacci', ['fibonacci.c']), 8 | ] 9 | ) 10 | -------------------------------------------------------------------------------- /chapter9/fibonacci_c_releasing_gil/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, Extension 2 | 3 | 4 | setup( 5 | name='fibonacci', 6 | ext_modules=[ 7 | Extension('fibonacci', ['fibonacci.c']), 8 | ] 9 | ) 10 | -------------------------------------------------------------------------------- /chapter7/example_with_readme_conversion/README.md: -------------------------------------------------------------------------------- 1 | # example README 2 | 3 | This is example of `README` file with package long description 4 | using Markdown text markup. This will be translated to reStructuredText 5 | on upload to PyPI. 6 | -------------------------------------------------------------------------------- /chapter5/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * `__new__()` を使ってインスタンス生成処理をオーバーライドする 4 | * `instance_counting.py` 5 | * `nonzero.py` 6 | 7 | * メタクラス 8 | * `metaclasses.py` 9 | 10 | * Hy 11 | * `hyllo.hy` 12 | * `py_hyllo.py` 13 | -------------------------------------------------------------------------------- /chapter6/private_variables.py: -------------------------------------------------------------------------------- 1 | _observers = [] 2 | 3 | 4 | def add_observer(observer): 5 | _observers.append(observer) 6 | 7 | 8 | def get_observers(): 9 | """_observersが変更されないようにします。""" 10 | return tuple(_observers) 11 | -------------------------------------------------------------------------------- /chapter12/primes.py: -------------------------------------------------------------------------------- 1 | def is_prime(number): 2 | if number < 0 or number in (0, 1): 3 | return False 4 | 5 | for element in range(2, number): 6 | if number % element == 0: 7 | return False 8 | 9 | return True 10 | -------------------------------------------------------------------------------- /chapter7/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * よくあるパターン 4 | * `example_with_version/setup.py` 5 | * `example_with_readme_conversion/setup.py` 6 | 7 | * 名前空間パッケージ 8 | * `implicit_namespace_package/setup.py` 9 | * `explicit_namespace_package/setup.py` 10 | -------------------------------------------------------------------------------- /chapter12/pytest_testing/primes.py: -------------------------------------------------------------------------------- 1 | def is_prime(number): 2 | if number < 0 or number in (0, 1): 3 | return False 4 | 5 | for element in range(2, number): 6 | if number % element == 0: 7 | return False 8 | 9 | return True 10 | -------------------------------------------------------------------------------- /chapter12/unittest_testing/primes.py: -------------------------------------------------------------------------------- 1 | def is_prime(number): 2 | if number < 0 or number in (0, 1): 3 | return False 4 | 5 | for element in range(2, number): 6 | if number % element == 0: 7 | return False 8 | 9 | return True 10 | -------------------------------------------------------------------------------- /chapter3/enums_auto.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, auto 2 | 3 | 4 | class Weekday(Enum): 5 | MONDAY = auto() 6 | TUESDAY = auto() 7 | WEDNESDAY = auto() 8 | THURSDAY = auto() 9 | FRIDAY = auto() 10 | SATURDAY = auto() 11 | SUNDAY = auto() 12 | -------------------------------------------------------------------------------- /chapter16/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * GUIにおけるイベント駆動プログラミング 4 | * `tkinter_gui.py` 5 | 6 | * イベント駆動通信 7 | * `web_application.py` 8 | 9 | * Subject-based スタイル 10 | * `subject_based_style.py` 11 | 12 | * Topic-based スタイル 13 | * `topic_signaling_style.p` 14 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/myapp/models.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import ugettext as _ 2 | from django.db import models 3 | 4 | # Create your models here. 5 | 6 | MESSAGES = ( 7 | _("Hello!"), 8 | _('Bye!'), 9 | _('Thank you!'), 10 | ) 11 | -------------------------------------------------------------------------------- /chapter9/fibonacci_c/fibonacci.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.0 2 | Name: fibonacci 3 | Version: 0.0.0 4 | Summary: UNKNOWN 5 | Home-page: UNKNOWN 6 | Author: UNKNOWN 7 | Author-email: UNKNOWN 8 | License: UNKNOWN 9 | Description: UNKNOWN 10 | Platform: UNKNOWN 11 | -------------------------------------------------------------------------------- /chapter17/creational_borg.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「生成に関するパターン」の節で登場するサンプルコード 3 | PythonでBorgを実装する別の方法 4 | 5 | """ 6 | class Borg: 7 | _state = {} 8 | 9 | def __new__(cls, *args, **kwargs): 10 | ob = super().__new__(cls, *args, **kwargs) 11 | ob.__dict__ = cls._state 12 | return ob 13 | -------------------------------------------------------------------------------- /chapter2/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | webserver: 5 | # docker-composeにローカルディレクトリ(.)の 6 | # Dockerfileをもとにイメージを作るように伝える 7 | build: . 8 | 9 | # "docke run"の"-p"オプションと同等 10 | ports: 11 | - "80:80" 12 | 13 | # "docke run"の"-t"オプションと同等 14 | tty: true -------------------------------------------------------------------------------- /chapter2/docker-compose.services.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | webserver: 5 | build: . 6 | ports: 7 | - "80:80" 8 | tty: true 9 | environment: 10 | - DATABASE_HOSTNAME=database 11 | - DATABASE_PORT=5432 12 | 13 | database: 14 | image: postgres 15 | restart: always -------------------------------------------------------------------------------- /chapter9/fibonacci_cythonize/fibonacci.py: -------------------------------------------------------------------------------- 1 | """Python module that provides fibonacci sequence function""" 2 | 3 | 4 | def fibonacci(n): 5 | """Return nth Fibonacci sequence number computed recursively.""" 6 | if n < 2: 7 | return 1 8 | else: 9 | return fibonacci(n - 1) + fibonacci(n - 2) 10 | -------------------------------------------------------------------------------- /chapter9/fibonacci_cythonize_optionally/fibonacci.py: -------------------------------------------------------------------------------- 1 | """Python module that provides fibonacci sequence function""" 2 | 3 | 4 | def fibonacci(n): 5 | """Return nth Fibonacci sequence number computed recursively.""" 6 | if n < 2: 7 | return 1 8 | else: 9 | return fibonacci(n - 1) + fibonacci(n - 2) 10 | -------------------------------------------------------------------------------- /chapter17/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * 生成に関するパターン 4 | * `creational_singleton.py` 5 | * `creational_borg.py` 6 | 7 | * アダプター 8 | * `structural_adapter.py` 9 | 10 | * インターフェイス 11 | * `interfaces_zope.py` 12 | * `interfaces_abc.py` 13 | * `interfaces_annotations.py` 14 | 15 | * Observerパターン 16 | * `observer.py` 17 | -------------------------------------------------------------------------------- /chapter6/options.py: -------------------------------------------------------------------------------- 1 | OPTIONS = {} 2 | 3 | 4 | def register_option(name): 5 | return OPTIONS.setdefault(name, 1 << len(OPTIONS)) 6 | 7 | 8 | def has_option(options, name): 9 | return bool(options & name) 10 | 11 | 12 | # オプションを定義する 13 | BLUE = register_option('BLUE') 14 | RED = register_option('RED') 15 | WHITE = register_option('WHITE') 16 | -------------------------------------------------------------------------------- /chapter12/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * Pythonの標準テストツール (unittest) 4 | * `unittest_testing/test_primes.py` 5 | 6 | * 代替のユニットテストフレームワーク (pytest) 7 | * `pytest_testing/test_primes.py` 8 | 9 | * スタブの構築 10 | * `test_with_fake/test_mailer.py` 11 | 12 | * モックの使用 13 | * `test_with_mock/test_mailer.py` 14 | * `test_with_mock_patch/test_mailer.py` 15 | -------------------------------------------------------------------------------- /chapter8/webxample-package/MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include webxample/myapp/templates *.html 2 | recursive-include webxample/myapp/static *.js *.css 3 | recursive-inlcude webxample/myapp/static *.css 4 | recursive-include webxample/locale *.po *.mo 5 | 6 | recursive-exclude * __pycache__ 7 | recursive-exclude * *.py[co] 8 | 9 | include README.md 10 | include MANIFEST.in 11 | -------------------------------------------------------------------------------- /chapter8/_NOTES.md: -------------------------------------------------------------------------------- 1 | 8章の `webxample` パッケージを構成するスクリプトで、章内のさまざまな節で登場します。 2 | 3 | スクリプトが登場する節 4 | 5 | * Fabricを用いたデプロイの自動化 6 | * `webxample-package/fabfile.py` 7 | * `webxample-package/fabutils.py` 8 | 9 | * Deployment using a package 10 | * `webxample-package/setup.py` 11 | * `webxample-package/webxample/*` 12 | 13 | * プロセス監視ツールを使う 14 | * `webxample-package/circus.ini` 15 | -------------------------------------------------------------------------------- /chapter13/myapp.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | def medium(): 4 | time.sleep(0.01) 5 | 6 | def light(): 7 | time.sleep(0.001) 8 | 9 | def heavy(): 10 | for i in range(100): 11 | light() 12 | medium() 13 | medium() 14 | time.sleep(2) 15 | 16 | def main(): 17 | for i in range(2): 18 | heavy() 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /chapter2/docker-compose.networks-b.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | networks: 4 | default: 5 | external: 6 | name: my-interservice-network 7 | 8 | services: 9 | other-service: 10 | build: . 11 | ports: 12 | - "80:80" 13 | tty: true 14 | 15 | environment: 16 | - DATABASE_HOSTNAME=database 17 | - DATABASE_PORT=5432 18 | - WEBSERVER_ADDRESS=http://webserver:80 -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | 5 | 6 | def main(): 7 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webxample.conf.settings") 8 | 9 | from django.core.management import execute_from_command_line 10 | 11 | execute_from_command_line(sys.argv) 12 | 13 | 14 | if __name__ == "__main__": 15 | main() 16 | -------------------------------------------------------------------------------- /chapter2/docker-compose.networks-a.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | networks: 4 | default: 5 | external: 6 | name: my-interservice-network 7 | 8 | services: 9 | webserver: 10 | build: . 11 | ports: 12 | - "80:80" 13 | tty: true 14 | 15 | environment: 16 | - DATABASE_HOSTNAME=database 17 | - DATABASE_PORT=5432 18 | 19 | database: 20 | image: postgres 21 | restart: always -------------------------------------------------------------------------------- /chapter15/asyncrates.py: -------------------------------------------------------------------------------- 1 | import aiohttp 2 | 3 | ACCESS_KEY = '' 4 | 5 | 6 | async def get_rates(session: aiohttp.ClientSession, base: str): 7 | async with session.get( 8 | f"http://api.exchangeratesapi.io/latest?access_key={ACCESS_KEY}&base={base}" 9 | ) as response: 10 | rates = (await response.json())['rates'] 11 | rates[base] = 1. 12 | 13 | return base, rates 14 | -------------------------------------------------------------------------------- /chapter9/fibonacci_cython/fibonacci.pyx: -------------------------------------------------------------------------------- 1 | """Cython module that provides fibonacci sequence function""" 2 | 3 | cdef long long fibonacci_cc(unsigned int n): 4 | if n < 2: 5 | return n 6 | else: 7 | return fibonacci_cc(n - 1) + fibonacci_cc(n - 2) 8 | 9 | 10 | def fibonacci(unsigned int n): 11 | """Return nth Fibonacci sequence number computed recursively.""" 12 | return fibonacci_cc(n) 13 | -------------------------------------------------------------------------------- /chapter2/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * Vagrantを使った仮想的な開発環境 4 | * `Vagrantfile` 5 | 6 | * Dockerfile入門 7 | * `Dockerfile` 8 | 9 | * 複雑な環境の設定 10 | * `docker-compose.yml` 11 | 12 | * コンテナサイズの削減 13 | * `Dockerfile.alpine` 14 | 15 | * docker-compose環境内でのサービスの宛先指定 16 | * `docker-compose.services.yml` 17 | 18 | * 複数のdocker-compose環境間の通信 19 | * `docker-compose.networks-a.yml` 20 | * `docker-compose.networks-b.yml` -------------------------------------------------------------------------------- /chapter9/fibonacci_cython_nogil/fibonacci.pyx: -------------------------------------------------------------------------------- 1 | """Cython module that provides fibonacci sequence function""" 2 | 3 | cdef long long fibonacci_cc(unsigned int n) nogil: 4 | if n < 2: 5 | return n 6 | else: 7 | return fibonacci_cc(n - 1) + fibonacci_cc(n - 2) 8 | 9 | 10 | def fibonacci(unsigned int n): 11 | """Return nth Fibonacci sequence number computed recursively.""" 12 | return fibonacci_cc(n) 13 | -------------------------------------------------------------------------------- /chapter3/yield_fibonacci.py: -------------------------------------------------------------------------------- 1 | def fibonacci(): 2 | a, b = 0, 1 3 | 4 | while True: 5 | yield b 6 | a, b = b, a + b 7 | 8 | 9 | if __name__: 10 | fib = fibonacci() 11 | 12 | print("フィボナッチ関数の返り値の型:", type(fib)) 13 | print( 14 | "最初の10個のフィボナッチ数 (next利用):", 15 | [next(fib) for _ in range(10)] 16 | ) 17 | print( 18 | "次の10個のフィボナッチ数 (継続):", 19 | [next(fib) for _ in range(10)] 20 | ) -------------------------------------------------------------------------------- /chapter12/test_with_mock_patch/test_mailer.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import patch 2 | from mailer import send 3 | 4 | 5 | def test_send(): 6 | with patch('smtplib.SMTP') as mock: 7 | instance = mock.return_value 8 | instance.sendmail.return_value = {} 9 | res = send( 10 | 'john.doe@example.com', 11 | 'john.doe@example.com', 12 | 'topic', 13 | 'body' 14 | ) 15 | assert res == {} 16 | -------------------------------------------------------------------------------- /chapter15/async_print.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「非同期プログラミング」の節で登場するサンプルコード 3 | 数字列を非同期に表示する 4 | 5 | """ 6 | import asyncio 7 | 8 | 9 | async def print_number(number): 10 | print(number) 11 | 12 | 13 | if __name__ == "__main__": 14 | loop = asyncio.get_event_loop() 15 | 16 | loop.run_until_complete( 17 | asyncio.wait([ 18 | loop.create_task(print_number(number)) 19 | for number in range(10) 20 | ]) 21 | ) 22 | loop.close() 23 | -------------------------------------------------------------------------------- /chapter4/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * データクラスを利用したボイラープレートの削除 4 | * `vector.py` 5 | * `vector_as_dataclass.py` 6 | 7 | * 組み込みクラスのサブクラス化 8 | * `distinctdict.py` 9 | * `folder.py` 10 | 11 | * MROとスーパークラスからメソッドへのアクセス 12 | * `pizza.py` 13 | 14 | * ディスクリプタ 15 | * `descriptors_revealing_access.py` 16 | * `descriptors_init_on_access.py` 17 | * `descriptors_lazy_class_attribute.py` 18 | 19 | * プロパティ 20 | * `properties_explicit.py` 21 | * `properties_decorator.py` -------------------------------------------------------------------------------- /chapter4/folder.py: -------------------------------------------------------------------------------- 1 | from collections import UserList 2 | 3 | 4 | class Folder(UserList): 5 | def __init__(self, name): 6 | self.name = name 7 | 8 | def dir(self, nesting=0): 9 | offset = " " * nesting 10 | print('%s%s/' % (offset, self.name)) 11 | 12 | for element in self: 13 | if hasattr(element, 'dir'): 14 | element.dir(nesting + 1) 15 | else: 16 | print("%s %s" % (offset, element)) 17 | -------------------------------------------------------------------------------- /chapter9/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * ピュアC拡張 4 | * `fibonacci_c/*` 5 | * `fibonacci_c_error_handling/*` 6 | * `fibonacci_c_releasing_gil/*` 7 | 8 | * トランスコンパイラとしてのCython 9 | * `fibonacci_cythonize/*` 10 | * `fibonacci_cythonize_optionally/*` 11 | 12 | * 言語としてのCython 13 | * `fibonacci_cython/*` 14 | * `fibonacci_cython_nogil/*` 15 | 16 | * C言語の関数をctypes経由で呼び出す 17 | * `ctypes_libc_printf.py` 18 | * `ctypes_qsort.py` 19 | 20 | * CFFI 21 | * `cffi_qsort.py` 22 | -------------------------------------------------------------------------------- /chapter12/test_with_mock/test_mailer.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | from unittest.mock import MagicMock 3 | from mailer import send 4 | 5 | 6 | def test_send(monkeypatch): 7 | smtp_mock = MagicMock() 8 | smtp_mock.sendmail.return_value = {} 9 | 10 | monkeypatch.setattr(smtplib, 'SMTP', MagicMock(return_value=smtp_mock)) 11 | 12 | res = send( 13 | 'john.doe@example.com', 14 | 'john.doe@example.com', 15 | 'topic', 16 | 'body' 17 | ) 18 | assert res == {} 19 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/conf/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for webxample project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webxample.conf.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /chapter6/name_mangling.py: -------------------------------------------------------------------------------- 1 | class Base: 2 | def __secret(self): 3 | print("秘密です") 4 | 5 | def public(self): 6 | self.__secret() 7 | 8 | 9 | class Derived(Base): 10 | def __secret(self): 11 | print("参照されません") 12 | 13 | 14 | if __name__ == "__main__": 15 | 16 | print("Baseクラスの属性:", dir(Base)) 17 | print("Derivedクラスの属性:", dir(Derived)) 18 | 19 | print("Base.public() の結果:") 20 | Base().public() 21 | 22 | print("Derived.public() の結果:") 23 | Derived().public() 24 | -------------------------------------------------------------------------------- /chapter1/example_compat.py: -------------------------------------------------------------------------------- 1 | """このモジュールはPythonバージョン間で変更があったものを 2 | 選択する、互換レイヤーを提供します 3 | """ 4 | import sys 5 | 6 | if sys.version_info < (3, 0, 0): 7 | import urlparse # noqa 8 | 9 | 10 | def is_string(s): 11 | """値が文字列ならTrueを返す""" 12 | return isinstance(s, basestring) 13 | 14 | else: 15 | # メモ: Python 3ではurlparseはurllib.parseに移動した 16 | from urllib import parse as urlparse # noqa 17 | 18 | 19 | def is_string(s): 20 | """値が文字列ならTrueを返す""" 21 | return isinstance(s, str) -------------------------------------------------------------------------------- /chapter14/memoize_lru_cache.py: -------------------------------------------------------------------------------- 1 | """ 2 | "Deterministic caching" section example of caching 3 | approach with simple `functools.lrs_cache` decorator. 4 | """ 5 | from functools import lru_cache 6 | 7 | 8 | @lru_cache(maxsize=None) 9 | def fibonacci(n): 10 | """Return nth Fibonacci sequence number computed recursively""" 11 | if n < 2: 12 | return 1 13 | else: 14 | return fibonacci(n - 1) + fibonacci(n - 2) 15 | 16 | 17 | if __name__ == "__main__": 18 | print([fibonacci(x) for x in range(30)]) 19 | -------------------------------------------------------------------------------- /chapter15/multiprocessing_sharedctypes.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「マルチプロセス」の節で登場するサンプルコード 3 | sharedctypesサブモジュールを使ってプロセス間でデータを共有する方法 4 | 5 | """ 6 | from multiprocessing import Process, Value, Array 7 | 8 | 9 | def f(n, a): 10 | n.value = 3.1415927 11 | for i in range(len(a)): 12 | a[i] = -a[i] 13 | 14 | if __name__ == '__main__': 15 | num = Value('d', 0.0) 16 | arr = Array('i', range(10)) 17 | 18 | p = Process(target=f, args=(num, arr)) 19 | p.start() 20 | p.join() 21 | 22 | print(num.value) 23 | print(arr[:]) 24 | -------------------------------------------------------------------------------- /chapter16/topic_based_events.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | 3 | from blinker import signal 4 | 5 | 6 | class SelfWatch: 7 | _new_id = itertools.count(1) 8 | 9 | def __init__(self): 10 | self._id = next(self._new_id) 11 | init_signal = signal("SelfWatch.init") 12 | init_signal.send(self) 13 | init_signal.connect(self.receiver) 14 | 15 | def receiver(self, sender): 16 | print(f"{self}: received event from {sender}") 17 | 18 | def __str__(self): 19 | return f"<{self.__class__.__name__}: {self._id}>" -------------------------------------------------------------------------------- /chapter5/nonzero.py: -------------------------------------------------------------------------------- 1 | class NonZero(int): 2 | def __new__(cls, value): 3 | return super().__new__(cls, value) if value != 0 else None 4 | 5 | def __init__(self, skipped_value): 6 | # このケースでは __init__ の実装は不要ですが、 7 | # このメソッドが呼ばれないケースがあることを 8 | # 確認するために残してあります 9 | print("__init__() called") 10 | super().__init__() 11 | 12 | 13 | if __name__ == "__main__": 14 | print("NonZero(-12) =", NonZero(-12)) 15 | print("NonZero(-3.123) =", NonZero(-3.123)) 16 | print("NonZero(0) =", NonZero(0)) 17 | -------------------------------------------------------------------------------- /chapter2/Dockerfile: -------------------------------------------------------------------------------- 1 | # ベースイメージを設定 2 | # "python"はオフィシャルなPythonイメージ 3 | # "slim"バージョンは、とりあえずで指定するには軽量で実用的な選択 4 | FROM python:3.9-slim 5 | 6 | # イメージをクリーンにするためにワークディレクトリを変更 7 | # "/app/"はこの目的で一般的に利用される 8 | WORKDIR /app/ 9 | 10 | # ここで静的ファイルをプロジェクトソースツリーから現在の 11 | # ワークディレクトリにコピー 12 | COPY static/ static/ 13 | 14 | # "python -m http.server"をローカルで実行したいので 15 | # エントリーポイントに設定 16 | ENTRYPOINT ["python3", "-m", "http.server"] 17 | 18 | # static/ディレクトリのファイルをポート80でデフォルトで提供する 19 | # ため、以下の設定をPythonの組み込みのHTTPサーバーデフォルト引数 20 | # に設定 21 | CMD ["--directory", "static/", "80"] 22 | -------------------------------------------------------------------------------- /chapter12/test_with_fake/mailer.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | import email.message 3 | 4 | 5 | def send( 6 | sender, to, 7 | subject='None', 8 | body='None', 9 | server='localhost' 10 | ): 11 | """メッセージの送信""" 12 | message = email.message.Message() 13 | message['To'] = to 14 | message['From'] = sender 15 | message['Subject'] = subject 16 | message.set_payload(body) 17 | 18 | server = smtplib.SMTP(server) 19 | try: 20 | return server.sendmail(sender, to, message.as_string()) 21 | finally: 22 | server.quit() 23 | -------------------------------------------------------------------------------- /chapter12/test_with_mock/mailer.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | import email.message 3 | 4 | 5 | def send( 6 | sender, to, 7 | subject='None', 8 | body='None', 9 | server='localhost' 10 | ): 11 | """メッセージの送信""" 12 | message = email.message.Message() 13 | message['To'] = to 14 | message['From'] = sender 15 | message['Subject'] = subject 16 | message.set_payload(body) 17 | 18 | server = smtplib.SMTP(server) 19 | try: 20 | return server.sendmail(sender, to, message.as_string()) 21 | finally: 22 | server.quit() 23 | -------------------------------------------------------------------------------- /chapter12/test_with_mock_patch/mailer.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | import email.message 3 | 4 | 5 | def send( 6 | sender, to, 7 | subject='None', 8 | body='None', 9 | server='localhost' 10 | ): 11 | """メッセージの送信""" 12 | message = email.message.Message() 13 | message['To'] = to 14 | message['From'] = sender 15 | message['Subject'] = subject 16 | message.set_payload(body) 17 | 18 | server = smtplib.SMTP(server) 19 | try: 20 | return server.sendmail(sender, to, message.as_string()) 21 | finally: 22 | server.quit() 23 | -------------------------------------------------------------------------------- /chapter3/enums_statuses.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, auto 2 | 3 | 4 | class OrderStatus(Enum): 5 | PENDING = auto() 6 | PROCESSING = auto() 7 | PROCESSED = auto() 8 | 9 | 10 | class Order: 11 | def __init__(self): 12 | self.status = OrderStatus.PENDING 13 | 14 | def process(self): 15 | if self.status == OrderStatus.PROCESSED: 16 | raise RuntimeError( 17 | "この命令ははすでに処理中なので、処理を進めることができません。" 18 | ) 19 | 20 | self.status = OrderStatus.PROCESSING 21 | ... 22 | self.status = OrderStatus.PROCESSED 23 | -------------------------------------------------------------------------------- /chapter3/iterators_countdown.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | 4 | class CountDown: 5 | def __init__(self, step): 6 | self.step = step 7 | 8 | def __next__(self): 9 | """次の値を返す""" 10 | if self.step <= 0: 11 | raise StopIteration 12 | self.step -= 1 13 | return self.step 14 | 15 | def __iter__(self): 16 | """自分をイテレータとして返す""" 17 | return self 18 | 19 | 20 | if __name__ == "__main__": 21 | print("カウントダウン:") 22 | 23 | for element in CountDown(10): 24 | print('*', element) 25 | sleep(0.2) 26 | -------------------------------------------------------------------------------- /chapter12/unittest_testing/test_primes.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from primes import is_prime 4 | 5 | 6 | class PrimesTests(unittest.TestCase): 7 | def test_is_prime(self): 8 | self.assertTrue(is_prime(5)) 9 | self.assertTrue(is_prime(7)) 10 | 11 | self.assertFalse(is_prime(8)) 12 | self.assertFalse(is_prime(0)) 13 | self.assertFalse(is_prime(1)) 14 | 15 | self.assertFalse(is_prime(-1)) 16 | self.assertFalse(is_prime(-3)) 17 | self.assertFalse(is_prime(-6)) 18 | 19 | 20 | if __name__ == "__main__": 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /chapter4/vector_as_dataclass.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class Vector: 6 | x: int 7 | y: int 8 | 9 | def __add__(self, other): 10 | """+演算子を使ったベクトルの足し算""" 11 | return Vector( 12 | self.x + other.x, 13 | self.y + other.y, 14 | ) 15 | 16 | def __sub__(self, other): 17 | """-演算子を使ったベクトルの引き算""" 18 | return Vector( 19 | self.x - other.x, 20 | self.y - other.y, 21 | ) 22 | 23 | 24 | @dataclass(frozen=True) 25 | class FrozenVector: 26 | x: int 27 | y: int -------------------------------------------------------------------------------- /chapter15/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * マルチスレッド 4 | * `synchronous.py` 5 | * `threads_one_per_item.py` 6 | * `threads_thread_pool.py` 7 | * `threads_two_way_queues.py` 8 | * `threads_exceptions_and_throttling.py` 9 | 10 | * マルチプロセス 11 | * `multiprocessing_forks.py` 12 | * `multiprocessing_basics.py` 13 | * `multiprocessing_pipes.py` 14 | * `multiprocessing_process_pool.py` 15 | * `multiprocessing_dummy.py` 16 | * `multiprocessing_sharedctypes.py` 17 | 18 | * 非同期プログラミング 19 | * `async_print.py` 20 | * `async_cooperative_wait.py` 21 | * `async_aiohttp.py` 22 | * `async_futures.py` 23 | -------------------------------------------------------------------------------- /chapter17/creational_singleton.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「生成に関するパターン」の節で登場するサンプルコード 3 | シングルトンの別の実装方法 4 | 5 | """ 6 | class Singleton: 7 | _instance = None 8 | 9 | def __new__(cls, *args, **kwargs): 10 | if cls._instance is None: 11 | cls._instance = super().__new__(cls, *args, **kwargs) 12 | 13 | return cls._instance 14 | 15 | 16 | class MetaSingleton(type): 17 | _instances = {} 18 | 19 | def __call__(cls, *args, **kwargs): 20 | if cls not in cls._instances: 21 | cls._instances[cls] = super().__call__(*args, **kwargs) 22 | return cls._instances[cls] 23 | -------------------------------------------------------------------------------- /chapter15/multiprocessing_basics.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「マルチプロセス」の節で登場するサンプルコード 3 | `multiprocessing` モジュールを用いて新しいプロセスを生成する 4 | 5 | """ 6 | from multiprocessing import Process 7 | import os 8 | 9 | 10 | def work(identifier): 11 | print(f'こんにちは、私はプロセス {identifier}, pid: {os.getpid()} です') 12 | 13 | 14 | def main(): 15 | processes = [ 16 | Process(target=work, args=(number,)) 17 | for number in range(5) 18 | ] 19 | for process in processes: 20 | process.start() 21 | 22 | while processes: 23 | processes.pop().join() 24 | 25 | 26 | if __name__ == "__main__": 27 | main() 28 | -------------------------------------------------------------------------------- /chapter3/_NOTES.md: -------------------------------------------------------------------------------- 1 | スクリプトが登場する節 2 | 3 | * リストとタプル 4 | * `lists.py` 5 | 6 | * enumモジュールのシンボル列挙型 7 | * `enums_ints.py` 8 | * `enums_auto.py` 9 | * `enums_statuses.py` 10 | * `enums_flags.py` 11 | 12 | * イテレータ 13 | * `iterators_countdown.py` 14 | * `iterators_countdown_with_state.py` 15 | 16 | * ジェネレータとyield文 17 | * `yield_fibonacci.py` 18 | * `yield_chaining_generators.py` 19 | * `yield_psychologist.py` 20 | 21 | * デコレータ 22 | * `decorators_repeat.py` 23 | * `decorators_repeat_with_metadata.py` 24 | 25 | * コンテキストマネージャ - with構文 26 | * `context_manager_as_class.py` 27 | * `context_manager_as_function.py` -------------------------------------------------------------------------------- /chapter2/Dockerfile.alpine: -------------------------------------------------------------------------------- 1 | # Here we use bare alpine to illustrate 2 | # package management as it lacks Python 3 | # by default. For Python projects in general 4 | # the 'python:3.7-alpine' is probably better 5 | # choice. 6 | FROM alpine:3.7 7 | 8 | # Add python3 package as alpine image lacks it by default 9 | RUN apk add python3 10 | 11 | # Run multiple commands in single RUN instruction 12 | # so space can be reclaimed after the 'apk del py3-pip' 13 | # command because image layer is committed only after 14 | # whole whole instruction. 15 | RUN apk add py3-pip && \ 16 | pip3 install django && \ 17 | apk del py3-pip 18 | 19 | # (...) -------------------------------------------------------------------------------- /chapter13/cprofile_profiling.py: -------------------------------------------------------------------------------- 1 | """ 2 | "Macro-profiling" section example of invoking cProfile 3 | Python profiles from Python script 4 | 5 | """ 6 | import time 7 | import cProfile 8 | 9 | 10 | def medium(): 11 | time.sleep(0.01) 12 | 13 | 14 | def light(): 15 | time.sleep(0.001) 16 | 17 | 18 | def heavy(): 19 | for i in range(100): 20 | light() 21 | medium() 22 | medium() 23 | time.sleep(2) 24 | 25 | 26 | def main(): 27 | for i in range(2): 28 | heavy() 29 | 30 | 31 | if __name__ == '__main__': 32 | profiler = cProfile.Profile() 33 | profiler.runcall(main) 34 | profiler.print_stats() 35 | -------------------------------------------------------------------------------- /chapter2/pythonstartup: -------------------------------------------------------------------------------- 1 | # Pythonスタートアップファイル 2 | try: 3 | import readline 4 | except ImportError: 5 | print("Completion unavailable: readline module not available") 6 | else: 7 | import rlcompleter 8 | # タブ補完 9 | readline.parse_and_bind('tab: complete') 10 | 11 | # ユーザーのホームディレクトリ内のヒストリー情報ファイルのパス 12 | # 好きなパスを設定可能 13 | history_file = os.path.join(os.environ['HOME'], '.python_shell_history') 14 | try: 15 | readline.read_history_file(history_file) 16 | except IOError: 17 | pass 18 | 19 | atexit.register(readline.write_history_file, history_file) 20 | del os, history_file, readline, rlcompleter 21 | 22 | -------------------------------------------------------------------------------- /chapter16/tkinter_gui.py: -------------------------------------------------------------------------------- 1 | import this 2 | from tkinter import * 3 | from tkinter import messagebox 4 | 5 | rot13 = str.maketrans( 6 | "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz", 7 | "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm" 8 | ) 9 | 10 | 11 | def main_window(root): 12 | frame = Frame(root, width=100, height=100) 13 | zen_button = Button(root, text="Python Zen", command=show_zen) 14 | zen_button.pack() 15 | 16 | 17 | def show_zen(): 18 | messagebox.showinfo( 19 | "Zen of Python", 20 | this.s.translate(rot13) 21 | ) 22 | 23 | 24 | if __name__ == "__main__": 25 | root = Tk() 26 | main_window(root) 27 | root.mainloop() -------------------------------------------------------------------------------- /chapter2/Dockerfile.multistage: -------------------------------------------------------------------------------- 1 | # ここはビルド用のコンテナ(拡張のビルドが不要ならこちらもslimで可) 2 | FROM python:3.9-buster as builder 3 | 4 | WORKDIR /opt/app 5 | 6 | COPY requirements.lock /opt/app 7 | RUN pip3 install -r requirements.lock 8 | 9 | # ここからは実行用コンテナの準備 10 | FROM python:3.9-slim-buster as runner 11 | 12 | COPY --from=builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages 13 | 14 | # もしPostgreSQLとかで必要なOSパッケージがあれば入れる 15 | RUN apt update \ 16 | && apt install -y libpq5 libxml2 \ 17 | && apt-get clean \ 18 | && rm -rf /var/lib/apt/lists/* 19 | 20 | COPY deploy/uwsgi.ini /opt/app 21 | COPY src /opt/app/src 22 | 23 | EXPOSE 8000 24 | CMD ["python", "/opt/app/src/server.py"] 25 | -------------------------------------------------------------------------------- /chapter15/async_cooperative_wait.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「非同期プログラミング」の節で登場するサンプルコード 3 | ブロックする命令の呼び出し時にイベントループの制御を解放し、2つのコルーチンを協調的に動作させる。 4 | 5 | """ 6 | import random 7 | import asyncio 8 | 9 | 10 | async def waiter(name): 11 | for _ in range(4): 12 | time_to_sleep = random.randint(1, 3) / 4 13 | await asyncio.sleep(time_to_sleep) 14 | print(f"{name} は {time_to_sleep} 秒待ちました") 15 | 16 | 17 | async def main(): 18 | await asyncio.wait([ 19 | asyncio.create_task(waiter("first")), 20 | asyncio.create_task(waiter("second")) 21 | ]) 22 | 23 | 24 | if __name__ == "__main__": 25 | loop = asyncio.get_event_loop() 26 | loop.run_until_complete(main()) 27 | loop.close() 28 | -------------------------------------------------------------------------------- /chapter6/custom_container.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | 3 | 4 | class Container: 5 | _contents = [] 6 | 7 | def append(self, item): 8 | self._contents.append(item) 9 | 10 | @property 11 | def unique_items(self): 12 | return set(self._contents) 13 | 14 | @property 15 | def ordered_items(self): 16 | return list(self._contents) 17 | 18 | 19 | if __name__ == "__main__": 20 | container = Container() 21 | 22 | for _ in range(20): 23 | value = randint(0, 10) 24 | print(f"{value} を追加") 25 | container.append(value) 26 | 27 | print(f"Ordered items: {container.ordered_items}") 28 | print(f"Unique items: {container.unique_items}") 29 | -------------------------------------------------------------------------------- /chapter12/pytest_testing/test_primes.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from primes import is_prime 4 | 5 | 6 | @pytest.fixture() 7 | def prime_numbers(): 8 | return [3, 5, 7] 9 | 10 | 11 | @pytest.fixture() 12 | def non_prime_numbers(): 13 | return [8, 0, 1] 14 | 15 | 16 | @pytest.fixture() 17 | def negative_numbers(): 18 | return [-1, -3, -6] 19 | 20 | 21 | def test_is_prime_true(prime_numbers): 22 | for number in prime_numbers: 23 | assert is_prime(number) 24 | 25 | 26 | def test_is_prime_false(non_prime_numbers, negative_numbers): 27 | for number in non_prime_numbers: 28 | assert not is_prime(number) 29 | 30 | for number in negative_numbers: 31 | assert not is_prime(number) 32 | -------------------------------------------------------------------------------- /chapter4/vector.py: -------------------------------------------------------------------------------- 1 | class Vector: 2 | def __init__(self, x, y): 3 | self.x = x 4 | self.y = y 5 | 6 | def __add__(self, other): 7 | """+演算子を使ったベクトルの足し算""" 8 | return Vector( 9 | self.x + other.x, 10 | self.y + other.y, 11 | ) 12 | 13 | def __sub__(self, other): 14 | """-演算子を使ったベクトルの引き算""" 15 | return Vector( 16 | self.x - other.x, 17 | self.y - other.y, 18 | ) 19 | 20 | def __repr__(self): 21 | """ベクトルのテキスト表現を返す""" 22 | return f"" 23 | 24 | def __eq__(self, other): 25 | """二つのベクトルの等価比較""" 26 | return self.x == other.x and self.y == other.y -------------------------------------------------------------------------------- /chapter15/multiprocessing_forks.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「マルチプロセス」の節で登場するサンプルコード 3 | POSIXシステムで os.fork を使って新しいプロセスを生成する 4 | 5 | """ 6 | import os 7 | 8 | pid_list = [] 9 | 10 | 11 | def main(): 12 | pid_list.append(os.getpid()) 13 | child_pid = os.fork() 14 | 15 | if child_pid == 0: 16 | pid_list.append(os.getpid()) 17 | print() 18 | print("子: こんにちは、私は子プロセスです") 19 | print("子: 私が知っているPID番号は %s です" % pid_list) 20 | 21 | else: 22 | pid_list.append(os.getpid()) 23 | print() 24 | print("親: こんにちは、私は親プロセスです") 25 | print("親: 子プロセスのPID番号は %d です" % child_pid) 26 | print("親: 私が知っているPID番号は %s です" % pid_list) 27 | 28 | 29 | if __name__ == "__main__": 30 | main() 31 | -------------------------------------------------------------------------------- /chapter3/iterators_countdown_with_state.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | 4 | class CounterState: 5 | def __init__(self, step): 6 | self.step = step 7 | 8 | def __next__(self): 9 | """カウンタ値を1つずつ0まで変更する""" 10 | if self.step <= 0: 11 | raise StopIteration 12 | self.step -= 1 13 | return self.step 14 | 15 | 16 | class CountDown: 17 | def __init__(self, steps): 18 | self.steps = steps 19 | 20 | def __iter__(self): 21 | """自分をイテレータとして返す""" 22 | return CounterState(self.steps) 23 | 24 | 25 | if __name__ == "__main__": 26 | print("カウントダウン:") 27 | 28 | for element in CountDown(10): 29 | print('*', element) 30 | sleep(0.2) 31 | -------------------------------------------------------------------------------- /chapter4/pizza.py: -------------------------------------------------------------------------------- 1 | class Pizza: 2 | def __init__(self, toppings): 3 | self.toppings = toppings 4 | 5 | def __repr__(self): 6 | return "と".join(self.toppings) + "がトッピングされたピザ" 7 | 8 | @classmethod 9 | def recommend(cls): 10 | """さまざまなトッピングが入ったおすすめのピザ""" 11 | return cls(['スパム', 'ハム', '卵']) 12 | 13 | 14 | class VikingPizza(Pizza): 15 | @classmethod 16 | def recommend(cls): 17 | """基本のおすすめトッピングにスパムを追加""" 18 | recommended = super(VikingPizza, cls).recommend() 19 | recommended.toppings += ['スパム'] * 5 20 | return recommended 21 | 22 | 23 | if __name__ == "__main__": 24 | print("一般的なピザのおすすめ:", Pizza.recommend()) 25 | print("海賊ピザのおすすめ:", VikingPizza.recommend()) 26 | -------------------------------------------------------------------------------- /chapter3/context_manager_as_class.py: -------------------------------------------------------------------------------- 1 | class ContextIllustration: 2 | def __enter__(self): 3 | print('コンテキストに入った') 4 | 5 | def __exit__(self, exc_type, exc_value, traceback): 6 | print('コンテキストから出た') 7 | 8 | if exc_type is None: 9 | print('エラーなし') 10 | else: 11 | print(f'エラーあり ({exc_value})') 12 | 13 | 14 | if __name__ == "__main__": 15 | print("コンテキストマネージャ内での処理の実行(エラーなし)") 16 | 17 | with ContextIllustration(): 18 | print(">> コンテキスト内") 19 | print() 20 | 21 | print("コンテキストマネージャ内での処理の実行(エラーあり)") 22 | try: 23 | with ContextIllustration(): 24 | print(">> コンテキスト内") 25 | raise RuntimeError("コンテキストマネージャ内部でのエラー") 26 | except RuntimeError: 27 | pass -------------------------------------------------------------------------------- /chapter3/yield_chaining_generators.py: -------------------------------------------------------------------------------- 1 | def capitalize(values): 2 | for value in values: 3 | yield value.upper() 4 | 5 | 6 | def hyphenate(values): 7 | for value in values: 8 | yield f"-{value}-" 9 | 10 | 11 | def leetspeak(values): 12 | for value in values: 13 | if value in {'t', 'T'}: 14 | yield '7' 15 | elif value in {'e', 'E'}: 16 | yield '3' 17 | else: 18 | yield value 19 | 20 | 21 | def join(values): 22 | return "".join(values) 23 | 24 | 25 | if __name__ == "__main__": 26 | text = "This is processed text" 27 | 28 | print("join(leetspeak(text)) result:") 29 | print(join(leetspeak(text))) 30 | print("join(hyphenate(text.split())) result:") 31 | print(join(hyphenate(text.split()))) 32 | -------------------------------------------------------------------------------- /chapter7/example_with_readme_conversion/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import os 3 | 4 | try: 5 | from pypandoc import convert 6 | 7 | def read_asciidoc(file_path): 8 | return convert(file_path, to='rst', format='asciidoc') 9 | 10 | except ImportError: 11 | convert = None 12 | print( 13 | "warning: pypandoc module not found, " 14 | "could not convert Asciidoc to RST" 15 | ) 16 | 17 | def read_asciidoc(file_path): 18 | with open(file_path, encoding='utf-8') as f: 19 | return f.read() 20 | 21 | README = os.path.join(os.path.dirname(__file__), 'README') 22 | 23 | setup( 24 | name='some-package', 25 | long_description=read_asciidoc(README), 26 | long_description_content_type='text/x-rst', 27 | # ... 28 | ) 29 | -------------------------------------------------------------------------------- /chapter13/graphing_backreferences.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | import objgraph 3 | 4 | 5 | def graph_references(*objects): 6 | objgraph.show_refs( 7 | objects, 8 | filename='show_refs.png', 9 | refcounts=True, 10 | # 見やすさのためにフィルターを追加する 11 | too_many=5, 12 | filter=lambda x: not isinstance(x, dict), 13 | ) 14 | objgraph.show_backrefs( 15 | objects, 16 | filename='show_backrefs.png', 17 | refcounts=True 18 | ) 19 | 20 | 21 | if __name__ == "__main__": 22 | quote = """ 23 | People who think they know everything are a 24 | great annoyance to those of us who do. 25 | """ 26 | words = quote.lower().strip().split() 27 | counts = Counter(words) 28 | graph_references(words, quote, counts) 29 | -------------------------------------------------------------------------------- /chapter3/context_manager_as_function.py: -------------------------------------------------------------------------------- 1 | from contextlib import contextmanager 2 | 3 | 4 | @contextmanager 5 | def context_illustration(): 6 | print('コンテキストに入った') 7 | try: 8 | yield 9 | except Exception as e: 10 | print('コンテキストから出た') 11 | print(f'エラーあり ({e})') 12 | # 例外を送出し直す必要がある 13 | raise 14 | else: 15 | print('コンテキストから出た') 16 | print('エラーなし') 17 | 18 | 19 | if __name__ == "__main__": 20 | print("コンテキストマネージャ内での処理の実行(エラーがなし)") 21 | 22 | with context_illustration(): 23 | print(">> inside context") 24 | print() 25 | 26 | print("コンテキストマネージャ内での処理の実行(エラーがあり)") 27 | try: 28 | with context_illustration(): 29 | print(">> コンテキスト内") 30 | raise RuntimeError("コンテキストマネージャ内部でのエラー") 31 | except RuntimeError: 32 | pass -------------------------------------------------------------------------------- /chapter12/test_with_fake/test_mailer.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | import pytest 3 | from mailer import send 4 | 5 | 6 | class FakeSMTP(object): 7 | def __init__(self, *args, **kw): 8 | # このサンプルでは引数は影響を与えません 9 | pass 10 | 11 | def quit(self): 12 | pass 13 | 14 | def sendmail(self, *args, **kw): 15 | return {} 16 | 17 | 18 | @pytest.yield_fixture() 19 | def patch_smtplib(): 20 | # setup処理: smtplibに対するモンキーパッチ 21 | old_smtp = smtplib.SMTP 22 | smtplib.SMTP = FakeSMTP 23 | 24 | yield 25 | 26 | # teardown処理: 27 | # smtplibをモンキーパッチ適用前の状態に戻す 28 | smtplib.SMTP = old_smtp 29 | 30 | 31 | def test_send(patch_smtplib): 32 | res = send( 33 | 'john.doe@example.com', 34 | 'john.doe@example.com', 35 | 'topic', 36 | 'body' 37 | ) 38 | assert res == {} 39 | -------------------------------------------------------------------------------- /chapter14/memoize_decorator.py: -------------------------------------------------------------------------------- 1 | """ 2 | "Deterministic caching" section example of caching 3 | approach with simple `memoize()` decorator function. 4 | """ 5 | 6 | 7 | def memoize(function): 8 | """Memoize the call to single-argument function""" 9 | call_cache = {} 10 | 11 | def memoized(argument): 12 | try: 13 | return call_cache[argument] 14 | except KeyError: 15 | return call_cache.setdefault( 16 | argument, function(argument) 17 | ) 18 | 19 | return memoized 20 | 21 | 22 | @memoize 23 | def fibonacci(n): 24 | """Return nth Fibonacci sequence number computed recursively""" 25 | if n < 2: 26 | return 1 27 | else: 28 | return fibonacci(n - 1) + fibonacci(n - 2) 29 | 30 | 31 | if __name__ == "__main__": 32 | print([fibonacci(x) for x in range(30)]) 33 | -------------------------------------------------------------------------------- /chapter16/web_application.py: -------------------------------------------------------------------------------- 1 | import this 2 | 3 | from flask import Flask 4 | 5 | app = Flask(__name__) 6 | 7 | rot13 = str.maketrans( 8 | "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz", 9 | "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm" 10 | ) 11 | 12 | 13 | def simple_html(body): 14 | return f""" 15 | 16 | 17 | 18 | 19 | Book Example 20 | 21 | 22 | {body} 23 | 24 | 25 | """ 26 | 27 | 28 | @app.route('/') 29 | def hello(): 30 | return simple_html("Python Zen") 31 | 32 | 33 | @app.route('/zen') 34 | def zen(): 35 | return simple_html( 36 | "
".join(this.s.translate(rot13).split("\n")) 37 | ) 38 | 39 | if __name__ == '__main__': 40 | app.run() -------------------------------------------------------------------------------- /chapter4/descriptors_revealing_access.py: -------------------------------------------------------------------------------- 1 | class RevealAccess(object): 2 | """値を通常通り設定・返すデータディスクリプタ 3 | アクセスログも出力する 4 | """ 5 | 6 | def __init__(self, initval=None, name='変数'): 7 | self.val = initval 8 | self.name = name 9 | 10 | def __get__(self, obj, objtype): 11 | print('取得', self.name) 12 | return self.val 13 | 14 | def __set__(self, obj, val): 15 | print('更新', self.name) 16 | self.val = val 17 | 18 | 19 | class MyClass(object): 20 | x = RevealAccess(10, '変数"x"') 21 | y = 5 22 | 23 | 24 | if __name__ == "__main__": 25 | my_instance = MyClass() 26 | 27 | # x属性をセット (ログ表示される) 28 | my_instance.x = 4 29 | # x属性にアクセス (ログ表示される) 30 | assert my_instance.x == 4 31 | 32 | # y属性をセット (ログ表示されない) 33 | my_instance.y = 2 34 | # y属性にアクセス (ログ表示されない) 35 | assert my_instance.y == 2 -------------------------------------------------------------------------------- /chapter13/cyclic_references.py: -------------------------------------------------------------------------------- 1 | """ 2 | "Profiling memory" section example of how CPython 3 | deals with cyclic references in different versions 4 | of interpreter. 5 | 6 | """ 7 | import gc 8 | import platform 9 | 10 | import objgraph 11 | 12 | 13 | class WithDel(list): 14 | """ list subclass with custom __del__ implementation """ 15 | def __del__(self): 16 | pass 17 | 18 | 19 | def main(): 20 | x = WithDel() 21 | y = [] 22 | z = [] 23 | 24 | x.append(y) 25 | y.append(z) 26 | z.append(x) 27 | 28 | del x, y, z 29 | 30 | print("unreachable prior collection: %s" % gc.collect()) 31 | print("unreachable after collection: %s" % len(gc.garbage)) 32 | print("WithDel objects count: %s" % objgraph.count('WithDel')) 33 | 34 | 35 | if __name__ == "__main__": 36 | print("Python version: %s" % platform.python_version()) 37 | print() 38 | main() 39 | -------------------------------------------------------------------------------- /chapter15/multiprocessing_pipes.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「マルチプロセス」の節で登場するサンプルコード 3 | `multiprocessing` モジュールのパイプを通信用チャンネルとして使用する方法 4 | 5 | """ 6 | from multiprocessing import Process, Pipe 7 | 8 | 9 | class CustomClass: 10 | pass 11 | 12 | 13 | def work(connection): 14 | while True: 15 | instance = connection.recv() 16 | 17 | if instance: 18 | print(f"子: 受信: {instance}") 19 | 20 | else: 21 | return 22 | 23 | 24 | def main(): 25 | parent_conn, child_conn = Pipe() 26 | 27 | child = Process(target=work, args=(child_conn,)) 28 | 29 | for item in ( 30 | 42, 31 | 'some string', 32 | {'one': 1}, 33 | CustomClass(), 34 | None, 35 | ): 36 | print(f"親: 送信: {item}:") 37 | parent_conn.send(item) 38 | 39 | child.start() 40 | child.join() 41 | 42 | 43 | if __name__ == "__main__": 44 | main() 45 | -------------------------------------------------------------------------------- /chapter6/private_attributes.py: -------------------------------------------------------------------------------- 1 | class Citizen: 2 | def __init__(self, first_name, last_name): 3 | self._first_name = first_name 4 | self._last_name = last_name 5 | 6 | @property 7 | def full_name(self): 8 | return f"{self._first_name} {self._last_name}" 9 | 10 | 11 | class UnforgivingElephant: 12 | def __init__(self, name): 13 | self.name = name 14 | self._people_to_stomp_on = [] 15 | 16 | def get_slapped_by(self, name): 17 | self._people_to_stomp_on.append(name) 18 | print('痛い!') 19 | 20 | def revenge(self): 21 | print('10年後...') 22 | for person in self._people_to_stomp_on: 23 | print('%s は %s を踏みつける' % (self.name, person)) 24 | 25 | 26 | if __name__ == '__main__': 27 | joe = UnforgivingElephant('Joe') 28 | joe.get_slapped_by('Tarek') 29 | joe.get_slapped_by('Bill') 30 | joe.revenge() 31 | -------------------------------------------------------------------------------- /chapter9/fibonacci_cythonize_optionally/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from distutils.core import setup 4 | from distutils.extension import Extension 5 | 6 | try: 7 | # Cythonがインストール済みの場合のみ、Cythonソースファイルをコンパイルします。 8 | import Cython 9 | # そしてCファイルを生成するためにCythonを使用するかどうか、 10 | # 特定の環境変数により指定します。 11 | USE_CYTHON = bool(os.environ.get("USE_CYTHON")) 12 | 13 | except ImportError: 14 | USE_CYTHON = False 15 | 16 | ext = '.pyx' if USE_CYTHON else '.c' 17 | 18 | extensions = [Extension("fibonacci", ["fibonacci"+ext])] 19 | 20 | if USE_CYTHON: 21 | from Cython.Build import cythonize 22 | extensions = cythonize(extensions) 23 | 24 | setup( 25 | name='fibonacci', 26 | ext_modules=extensions, 27 | extras_require={ 28 | # '[with-cython]'をパッケージのインストール時に指定することで、 29 | # 指定したバージョンのCythonがインストールされます。 30 | 'with-cython': ['cython==0.23.4'] 31 | } 32 | ) 33 | 34 | -------------------------------------------------------------------------------- /chapter3/decorators_repeat.py: -------------------------------------------------------------------------------- 1 | def repeat(number=3): 2 | """デコレートされた関数をnumberで指定された回数繰り返す。 3 | 4 | 最後に呼ばれた関数の結果を、関数の返り値として返す。 5 | 6 | :param number: 繰り返す回数。指定しなければ3。 7 | """ 8 | def actual_decorator(function): 9 | def wrapper(*args, **kwargs): 10 | result = None 11 | for _ in range(number): 12 | result = function(*args, **kwargs) 13 | return result 14 | 15 | return wrapper 16 | 17 | return actual_decorator 18 | 19 | 20 | @repeat(5) 21 | def print_hello_world(): 22 | """もっともシンプルな"hello world"実装.""" 23 | print("Hello, world!") 24 | 25 | 26 | if __name__ == "__main__": 27 | print( 28 | "repeat(5)デコレータ(メタデータは維持しない)つきの" 29 | "print_hello_world()関数の呼び出し結果" 30 | ) 31 | print_hello_world() 32 | print() 33 | 34 | print("デコレートされた関数名:", print_hello_world.__name__) 35 | print("関数のdocstring:", print_hello_world.__doc__) -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/conf/urls.py: -------------------------------------------------------------------------------- 1 | """webxample URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.9/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | url(r'^admin/', admin.site.urls), 21 | url(r'delay/', 'webxample.myapp.views.delay'), 22 | ] 23 | -------------------------------------------------------------------------------- /chapter3/lists.py: -------------------------------------------------------------------------------- 1 | """ 2 | "リストとタプル"のセクションのリスト内包表記のサンプル 3 | """ 4 | 5 | 6 | def evens_using_for_loop(count): 7 | """ ループを回して偶数を計算 """ 8 | evens = [] 9 | for i in range(count): 10 | if i % 2 == 0: 11 | evens.append(i) 12 | return evens 13 | 14 | 15 | def evens_using_list_comprehension(count): 16 | """ リスト内包表記で偶数を計算 """ 17 | return [i for i in range(count) if i % 2 == 0] 18 | 19 | 20 | def enumerate_elements(elements): 21 | for index, element in enumerate(elements): 22 | print(index, element) 23 | 24 | 25 | if __name__ == "__main__": 26 | print( 27 | "ループを使って0-10の間の偶数を計算:", 28 | evens_using_for_loop(11) 29 | ) 30 | print() 31 | 32 | print( 33 | "リスト内包表記を使って0-10の間の偶数を計算:", 34 | evens_using_list_comprehension(11) 35 | ) 36 | print() 37 | 38 | print("0-10の偶数を列挙:") 39 | enumerate_elements(evens_using_list_comprehension(11)) 40 | print() -------------------------------------------------------------------------------- /chapter15/synchronous.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | import requests 4 | 5 | SYMBOLS = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 6 | BASES = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 7 | ACCESS_KEY = '' 8 | 9 | 10 | def fetch_rates(base): 11 | response = requests.get( 12 | f"http://api.exchangeratesapi.io/latest?access_key={ACCESS_KEY}&base={base}" 13 | ) 14 | 15 | response.raise_for_status() 16 | rates = response.json()["rates"] 17 | # note: 同じ通貨の交換レートは 1:1 となる。 18 | rates[base] = 1. 19 | 20 | rates_line = ", ".join( 21 | [f"{rates[symbol]:7.03} {symbol}" for symbol in SYMBOLS] 22 | ) 23 | print(f"1 {base} = {rates_line}") 24 | 25 | 26 | def main(): 27 | for base in BASES: 28 | fetch_rates(base) 29 | 30 | 31 | if __name__ == "__main__": 32 | started = time.time() 33 | main() 34 | elapsed = time.time() - started 35 | 36 | print() 37 | print("経過時間: {:.2f}s".format(elapsed)) 38 | -------------------------------------------------------------------------------- /chapter3/yield_psychologist.py: -------------------------------------------------------------------------------- 1 | def psychologist(): 2 | print('Please tell me your problems') 3 | while True: 4 | answer = (yield) 5 | 6 | if answer is not None: 7 | if answer.endswith('?'): 8 | print("Don't ask yourself too much questions") 9 | 10 | elif 'good' in answer: 11 | print("Ahh that's good, go on") 12 | 13 | elif 'bad' in answer: 14 | print("Don't be so negative") 15 | 16 | elif answer in ('q', 'quit'): 17 | print("Goodbye") 18 | yield 19 | return 20 | 21 | else: 22 | print("Please continue") 23 | 24 | 25 | if __name__ == "__main__": 26 | print("Starting psychologist session, type 'q' or 'quit' to end session") 27 | 28 | freud = psychologist() 29 | 30 | for phrase in freud: 31 | problem = input("> ") 32 | freud.send(problem) -------------------------------------------------------------------------------- /chapter8/webxample-package/fabfile.py: -------------------------------------------------------------------------------- 1 | from fabric import task 2 | from .fabutils import * 3 | 4 | 5 | @task 6 | def uptime(c): 7 | """ 8 | uptimeコマンドをリモートホストで実行し、接続を検証します 9 | """ 10 | c.run("uptime") 11 | 12 | 13 | @task 14 | def deploy(c): 15 | """ パッケージを作成してアプリケーションをデプロイします """ 16 | version = get_version(c) 17 | 18 | pip_path = os.path.join( 19 | REMOTE_PROJECT_LOCATION, version, 'bin', 'pip' 20 | ) 21 | 22 | if not c.run(f"test -d {REMOTE_PROJECT_LOCATION}", warn=True): 23 | # 起動直後のホストに初めてデプロイする場合、ディレクトリがないので作る 24 | c.run(f"mkdir -p {REMOTE_PROJECT_LOCATION}") 25 | 26 | with c.cd(REMOTE_PROJECT_LOCATION): 27 | # 新しい仮想環境をvenvで作る 28 | c.run(f'python3 -m venv {version}') 29 | 30 | c.run(f"{pip_path} install webxample=={version} --index-url {PYPI_URL}") 31 | 32 | switch_versions(c, version) 33 | # Circusをプロセス監視ツールとして使っていると仮定 34 | c.run('circusctl restart webxample') -------------------------------------------------------------------------------- /chapter16/subject_based_events.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | 3 | 4 | class Subject: 5 | _new_id = itertools.count(1) 6 | 7 | def __init__(self): 8 | self._id = next(self._new_id) 9 | self._observers = [] 10 | 11 | def register(self, observer): 12 | self._notify_observers(f"register({observer})") 13 | self._observers.append(observer) 14 | 15 | def _notify_observers(self, event): 16 | for observer in self._observers: 17 | observer.notify(self, event) 18 | 19 | def __str__(self): 20 | return f"<{self.__class__.__name__}: {self._id}>" 21 | 22 | 23 | class Observer: 24 | _new_id = itertools.count(1) 25 | 26 | def __init__(self): 27 | self._id = next(self._new_id) 28 | 29 | def notify(self, subject, event): 30 | print(f"{self}: received event '{event}' from {subject}") 31 | 32 | def __str__(self): 33 | return f"<{self.__class__.__name__}: {self._id}>" 34 | 35 | -------------------------------------------------------------------------------- /chapter4/descriptors_init_on_access.py: -------------------------------------------------------------------------------- 1 | class InitOnAccess: 2 | def __init__(self, klass, *args, **kwargs): 3 | self.klass = klass 4 | self.args = args 5 | self.kwargs = kwargs 6 | self._initialized = None 7 | 8 | def __get__(self, instance, owner): 9 | if self._initialized is None: 10 | print('初期化!') 11 | self._initialized = self.klass(*self.args, **self.kwargs) 12 | else: 13 | print('キャッシュ済み!') 14 | return self._initialized 15 | 16 | 17 | class MyClass: 18 | lazily_initialized = InitOnAccess(list, "argument") 19 | 20 | 21 | if __name__ == "__main__": 22 | instance = MyClass() 23 | 24 | print("instance.lazily_initializedへの初回のアクセス") 25 | print(">> instance.lazily_initialized =", instance.lazily_initialized, '\n') 26 | 27 | print("instance.lazily_initializedへの2回目のアクセス") 28 | print(">> instance.lazily_initialized =", instance.lazily_initialized, '\n') -------------------------------------------------------------------------------- /chapter4/properties_decorator.py: -------------------------------------------------------------------------------- 1 | class Rectangle: 2 | def __init__(self, x1, y1, x2, y2): 3 | self.x1, self.y1 = x1, y1 4 | self.x2, self.y2 = x2, y2 5 | 6 | @property 7 | def width(self): 8 | """長方形の幅""" 9 | return self.x2 - self.x1 10 | 11 | @width.setter 12 | def width(self, value): 13 | self.x2 = self.x1 + value 14 | 15 | @property 16 | def height(self): 17 | """長方形の高さ""" 18 | return self.y2 - self.y1 19 | 20 | @height.setter 21 | def height(self, value): 22 | self.y2 = self.y1 + value 23 | 24 | 25 | if __name__ == "__main__": 26 | rectangle = Rectangle(0, 0, 10, 10) 27 | print( 28 | f"最初の図形は {rectangle} で" 29 | f"大きさは {rectangle.width} x {rectangle.height} です" 30 | ) 31 | 32 | rectangle.width = 2 33 | rectangle.height = 8 34 | print( 35 | f"サイズを変更したあとの図形は {rectangle} で" 36 | f"大きさは {rectangle.width} x {rectangle.height} です" 37 | ) 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 『エキスパートPythonプログラミング 改訂3版』サンプルソースコード 2 | 3 | 本リポジトリには、『エキスパートPythonプログラミング 改訂3版』に掲載されているサンプルソースコードを収録しています。Pythonプログラミングその他の学習にご活用ください。 4 | 5 | ## 『エキスパートPythonプログラミング 改訂3版』について 6 | 7 | 『エキスパートPythonプログラミング 改訂3版』は、アスキードワンゴより2021年7月30日に発売されました。詳しい内容その他については、下記サイトをご覧ください。 8 | 9 | アスキードワンゴ 『エキスパートPythonプログラミング 改訂3版』 10 | 11 | また、『エキスパートPythonプログラミング 改訂3版』の原著である"Expert Python Programming Third Edition"については、下記のPackt Publishingのサイトをご覧ください。 12 | 13 | Expert Python Programming - Third Edition 14 | 15 | 原著のサンプルソースコードは、下記サイトよりダウンロードできます。 16 | 17 | Github Expert Python Programming Third Edition 18 | -------------------------------------------------------------------------------- /chapter7/example_with_version/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | import os 3 | 4 | 5 | def get_version(version_tuple): 6 | # アルファ(a)、ベータ(b)、リリース候補(rc) 7 | # といったタグを取り扱うためのコード 8 | # バージョンスキーマによっては簡略化可能 9 | if not isinstance(version_tuple[-1], int): 10 | return '.'.join( 11 | map(str, version_tuple[:-1]) 12 | ) + version_tuple[-1] 13 | return '.'.join(map(str, version_tuple)) 14 | 15 | 16 | # プロジェクトのソースツリー内のパッケージの 17 | # __init__モジュールへのパス 18 | init = os.path.join( 19 | os.path.dirname(__file__), 'src', 'some_package', 20 | '__init__.py' 21 | ) 22 | 23 | with open(init, encoding="utf-8") as f: 24 | version_line = [L for L in f if L.startswith("VERSION")][0] 25 | 26 | # VERSIONはタプルなのでversion_lineをevalする必要がある 27 | # もし、このパッケージがインストール前にもimport可能で 28 | # あれば、単純にimportする方法も使える 29 | PKG_VERSION = get_version(eval(version_line.split('=')[-1])) 30 | 31 | setup( 32 | name='example_with_version', 33 | version=PKG_VERSION, 34 | # ... 35 | ) 36 | -------------------------------------------------------------------------------- /chapter17/structural_adapter.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「Adapterパターン」の節で登場するサンプルコード 3 | アダプターの実装方法 4 | 5 | """ 6 | from os.path import split, splitext 7 | 8 | 9 | class DublinCoreAdapter: 10 | def __init__(self, filename): 11 | self._filename = filename 12 | 13 | @property 14 | def title(self): 15 | return splitext(split(self._filename)[-1])[0] 16 | 17 | @property 18 | def languages(self): 19 | return 'en', 20 | 21 | def __getitem__(self, item): 22 | return getattr(self, item, 'Unknown') 23 | 24 | 25 | class DublinCoreInfo: 26 | def summary(self, dc_dict): 27 | print(f'タイトル: {dc_dict["title"]}') 28 | print(f'著者: {dc_dict["creator"]}') 29 | print(f'言語: {", ".join(dc_dict["languages"])}') 30 | 31 | 32 | if __name__ == "__main__": 33 | file_name = 'example.txt' 34 | 35 | print( 36 | "DublinCoreAdapterで '{}' をラップして要約を取り出す" 37 | "".format(file_name) 38 | ) 39 | DublinCoreInfo().summary(DublinCoreAdapter(file_name)) 40 | -------------------------------------------------------------------------------- /chapter3/decorators_repeat_with_metadata.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | 4 | def repeat(number=3): 5 | """デコレートされた関数をnumberで指定された回数繰り返す。 6 | 7 | 最後に呼ばれた関数の結果を、関数の返り値として返す。 8 | 9 | :param number: 繰り返す回数。指定しなければ3。 10 | """ 11 | def actual_decorator(function): 12 | @wraps(function) 13 | def wrapper(*args, **kwargs): 14 | result = None 15 | for _ in range(number): 16 | result = function(*args, **kwargs) 17 | return result 18 | 19 | return wrapper 20 | 21 | return actual_decorator 22 | 23 | 24 | @repeat(5) 25 | def print_hello_world(): 26 | """もっともシンプルな"hello world"実装.""" 27 | print("Hello, world!") 28 | 29 | 30 | if __name__ == "__main__": 31 | print( 32 | "repeat(5)デコレータ(メタデータは維持する)つきの" 33 | "print_hello_world()関数の呼び出し結果" 34 | ) 35 | print_hello_world() 36 | print() 37 | 38 | print("デコレートされた関数名:", print_hello_world.__name__) 39 | print("関数のdocstring:", print_hello_world.__doc__) -------------------------------------------------------------------------------- /chapter2/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | # Every Vagrant development environment requires a box. 6 | # You can search for boxes at https://vagrantcloud.com/search. 7 | # Here we use Bionic version Ubuntu system for x64 architecture. 8 | config.vm.box = "ubuntu/bionic64" 9 | 10 | # Create a forwarded port mapping which allows access to a specific port 11 | # within the machine from a port on the host machine and only allow access 12 | # via 127.0.0.1 to disable public access 13 | 14 | config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" 15 | config.vm.provider "virtualbox" do |vb| 16 | # Display the VirtualBox GUI when booting the machine 17 | vb.gui = false 18 | # Customize the amount of memory on the VM: 19 | vb.memory = "1024" 20 | end 21 | # Enable provisioning with a shell script. 22 | config.vm.provision "shell", inline: <<-SHELL 23 | apt-get update 24 | apt-get install python3.7 -y 25 | SHELL 26 | end -------------------------------------------------------------------------------- /chapter4/distinctdict.py: -------------------------------------------------------------------------------- 1 | from collections import UserDict 2 | 3 | 4 | class DistinctError(ValueError): 5 | """distinctdictに重複した値を登録しようとした時に送出される例外です。""" 6 | 7 | 8 | class distinctdict(UserDict): 9 | """重複した値を許さない辞書です。""" 10 | 11 | def __setitem__(self, key, value): 12 | if value in self.values(): 13 | if ( 14 | (key in self and self[key] != value) or 15 | key not in self 16 | ): 17 | raise DistinctError( 18 | "この値はすでに他のキーで登録されています" 19 | ) 20 | 21 | super().__setitem__(key, value) 22 | 23 | 24 | if __name__ == "__main__": 25 | names_to_numbers = { 26 | "one": 1, 27 | "two": 2, 28 | "uno": 1, 29 | } 30 | 31 | ddict = distinctdict() 32 | for key, value in names_to_numbers.items(): 33 | try: 34 | ddict[key] = value 35 | except DistinctError: 36 | pass 37 | 38 | print("ordinary dictionary:", names_to_numbers) 39 | print("distinctdict dictionary:", ddict) -------------------------------------------------------------------------------- /chapter5/instance_counting.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | 3 | 4 | class InstanceCountingClass: 5 | instances_created = 0 6 | 7 | def __new__(cls, *args, **kwargs): 8 | print('__new__() called with:', cls, args, kwargs) 9 | instance = super().__new__(cls) 10 | instance.number = cls.instances_created 11 | cls.instances_created += 1 12 | 13 | return instance 14 | 15 | def __init__(self, attribute): 16 | print('__init__() called with:', self, attribute) 17 | self.attribute = attribute 18 | 19 | 20 | if __name__ == "__main__": 21 | print( 22 | "InstanceCountingClass.instances_created =", 23 | InstanceCountingClass.instances_created 24 | ) 25 | 26 | desired_count = randint(2, 10) 27 | print( 28 | f"Creating {desired_count} instances of InstanceCountingClass..." 29 | ) 30 | 31 | for number in range(desired_count): 32 | InstanceCountingClass(number) 33 | 34 | print( 35 | "InstanceCountingClass.instances_created =", 36 | InstanceCountingClass.instances_created 37 | ) -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/locale/en/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2016-02-13 15:27+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | 20 | #: myapp/models.py:7 21 | msgid "Hello!" 22 | msgstr "" 23 | 24 | #: myapp/models.py:8 25 | msgid "Bye!" 26 | msgstr "" 27 | 28 | #: myapp/models.py:9 29 | msgid "Thank you!" 30 | msgstr "" 31 | 32 | #: webxample/settings.py:124 33 | msgid "German" 34 | msgstr "" 35 | 36 | #: webxample/settings.py:125 37 | msgid "English" 38 | msgstr "" 39 | 40 | #: webxample/settings.py:126 41 | msgid "Polish" 42 | msgstr "" 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter15/async_aiohttp.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「非同期プログラミング」の節で登場するサンプルコード 3 | aiohttpを使って非同期にHTTPのリクエストを送信する方法 4 | 5 | """ 6 | import asyncio 7 | import time 8 | 9 | import aiohttp 10 | 11 | from asyncrates import get_rates 12 | 13 | SYMBOLS = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 14 | BASES = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 15 | 16 | 17 | async def fetch_rates(session, place): 18 | return await get_rates(session, place) 19 | 20 | 21 | async def present_result(result): 22 | base, rates = (await result) 23 | 24 | rates_line = ", ".join( 25 | [f"{rates[symbol]:7.03} {symbol}" for symbol in SYMBOLS] 26 | ) 27 | print(f"1 {base} = {rates_line}") 28 | 29 | 30 | async def main(): 31 | async with aiohttp.ClientSession() as session: 32 | await asyncio.wait([ 33 | asyncio.create_task(present_result(fetch_rates(session, base))) 34 | for base in BASES 35 | ]) 36 | 37 | 38 | if __name__ == "__main__": 39 | started = time.time() 40 | loop = asyncio.get_event_loop() 41 | loop.run_until_complete(main()) 42 | elapsed = time.time() - started 43 | 44 | print() 45 | print(f"経過時間: {elapsed:.2f}s") 46 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/locale/de/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2016-02-13 15:27+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 | 21 | #: myapp/models.py:7 22 | msgid "Hello!" 23 | msgstr "" 24 | 25 | #: myapp/models.py:8 26 | msgid "Bye!" 27 | msgstr "" 28 | 29 | #: myapp/models.py:9 30 | msgid "Thank you!" 31 | msgstr "" 32 | 33 | #: webxample/settings.py:124 34 | msgid "German" 35 | msgstr "" 36 | 37 | #: webxample/settings.py:125 38 | msgid "English" 39 | msgstr "" 40 | 41 | #: webxample/settings.py:126 42 | msgid "Polish" 43 | msgstr "" 44 | -------------------------------------------------------------------------------- /chapter15/multiprocessing_dummy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「マルチプロセス」の節で登場するサンプルコード 3 | ``multiprocessing.dummy`` を抽象レイヤーとしてスレッドを利用する方法 4 | 5 | """ 6 | from multiprocessing import Pool as ProcessPool 7 | from multiprocessing.dummy import Pool as ThreadPool 8 | 9 | from gmaps import Geocoding 10 | 11 | api = Geocoding() 12 | 13 | 14 | PLACES = ( 15 | 'Reykjavik', 'Vien', 'Zadar', 'Venice', 16 | 'Wrocław', 'Bolognia', 'Berlin', 'Słubice', 17 | 'New York', 'Dehli', 18 | ) 19 | 20 | POOL_SIZE = 4 21 | 22 | 23 | def fetch_place(place): 24 | return api.geocode(place)[0] 25 | 26 | 27 | def present_result(geocoded): 28 | print("{:>25s}, {:6.2f}, {:6.2f}".format( 29 | geocoded['formatted_address'], 30 | geocoded['geometry']['location']['lat'], 31 | geocoded['geometry']['location']['lng'], 32 | )) 33 | 34 | 35 | def main(use_threads=False): 36 | if use_threads: 37 | pool_cls = ThreadPool 38 | else: 39 | pool_cls = ProcessPool 40 | 41 | with pool_cls(POOL_SIZE) as pool: 42 | results = pool.map(fetch_place, PLACES) 43 | 44 | for result in results: 45 | present_result(result) 46 | 47 | 48 | if __name__ == "__main__": 49 | main() 50 | -------------------------------------------------------------------------------- /chapter15/multiprocessing_process_pool.py: -------------------------------------------------------------------------------- 1 | import time 2 | from multiprocessing import Pool 3 | 4 | import requests 5 | 6 | 7 | SYMBOLS = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 8 | BASES = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 9 | ACCESS_KEY = '' 10 | 11 | POOL_SIZE = 4 12 | 13 | 14 | def fetch_rates(base): 15 | response = requests.get( 16 | f"http://api.exchangeratesapi.io/latest?access_key={ACCESS_KEY}&base={base}" 17 | ) 18 | 19 | response.raise_for_status() 20 | rates = response.json()["rates"] 21 | # note: 同じ通貨の交換レートは 1:1 となる。 22 | rates[base] = 1. 23 | return base, rates 24 | 25 | 26 | def present_result(base, rates): 27 | rates_line = ", ".join( 28 | [f"{rates[symbol]:7.03} {symbol}" for symbol in SYMBOLS] 29 | ) 30 | print(f"1 {base} = {rates_line}") 31 | 32 | 33 | def main(): 34 | with Pool(POOL_SIZE) as pool: 35 | results = pool.map(fetch_rates, BASES) 36 | 37 | for result in results: 38 | present_result(*result) 39 | 40 | 41 | if __name__ == "__main__": 42 | started = time.time() 43 | main() 44 | elapsed = time.time() - started 45 | 46 | print() 47 | print("経過時間: {:.2f}s".format(elapsed)) 48 | 49 | -------------------------------------------------------------------------------- /chapter5/metaclasses.py: -------------------------------------------------------------------------------- 1 | print(" >>> defining RevealingMeta(type)") 2 | 3 | 4 | class RevealingMeta(type): 5 | def __new__(mcs, name, bases, namespace, **kwargs): 6 | print(mcs, "__new__ called") 7 | return super().__new__(mcs, name, bases, namespace) 8 | 9 | @classmethod 10 | def __prepare__(mcs, name, bases, **kwargs): 11 | print(mcs, "__prepare__ called") 12 | return super().__prepare__(name, bases, **kwargs) 13 | 14 | def __init__(cls, name, bases, namespace, **kwargs): 15 | print(cls, "__init__ called") 16 | super().__init__(name, bases, namespace) 17 | 18 | def __call__(cls, *args, **kwargs): 19 | print(cls, "__call__ called") 20 | return super().__call__(*args, **kwargs) 21 | 22 | 23 | print(" >>> defining RevealingClass(metaclass=RevealingMeta)") 24 | 25 | 26 | class RevealingClass(metaclass=RevealingMeta): 27 | def __new__(cls): 28 | print(cls, "__new__ called") 29 | return super().__new__(cls) 30 | 31 | def __init__(self): 32 | print(self, "__init__ called") 33 | super().__init__() 34 | 35 | 36 | if __name__ == "__main__": 37 | print(" >>> Creating RevealingClass()") 38 | instance = RevealingClass() 39 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/locale/pl/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2016-02-13 15:27+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " 20 | "|| n%100>=20) ? 1 : 2);\n" 21 | 22 | #: myapp/models.py:7 23 | msgid "Hello!" 24 | msgstr "" 25 | 26 | #: myapp/models.py:8 27 | msgid "Bye!" 28 | msgstr "" 29 | 30 | #: myapp/models.py:9 31 | msgid "Thank you!" 32 | msgstr "" 33 | 34 | #: webxample/settings.py:124 35 | msgid "German" 36 | msgstr "" 37 | 38 | #: webxample/settings.py:125 39 | msgid "English" 40 | msgstr "" 41 | 42 | #: webxample/settings.py:126 43 | msgid "Polish" 44 | msgstr "" 45 | -------------------------------------------------------------------------------- /chapter9/cffi_qsort.py: -------------------------------------------------------------------------------- 1 | from random import shuffle 2 | 3 | from cffi import FFI 4 | 5 | ffi = FFI() 6 | 7 | ffi.cdef(""" 8 | void qsort(void *base, size_t nel, size_t width, 9 | int (*compar)(const void *, const void *)); 10 | """) 11 | C = ffi.dlopen(None) 12 | 13 | 14 | @ffi.callback("int(void*, void*)") 15 | def cffi_int_compare(a, b): 16 | # コールバックのシグネチャは完全に一致する必要があります。 17 | # ctypesに比べてより「魔法」が少なくなるというメリットがあるものの、 18 | # 明示的なキャストが必要になります。 19 | int_a = ffi.cast('int*', a)[0] 20 | int_b = ffi.cast('int*', b)[0] 21 | print(" %s cmp %s" % (int_a, int_b)) 22 | 23 | # qsort の仕様により、戻り値は 24 | # * a < b のとき: 負 25 | # * a = b のとき: 0 26 | # * a > b のとき: 正 27 | return int_a - int_b 28 | 29 | 30 | def main(): 31 | numbers = list(range(5)) 32 | shuffle(numbers) 33 | print("shuffled: ", numbers) 34 | 35 | c_array = ffi.new("int[]", numbers) 36 | 37 | C.qsort( 38 | # ソート対象の配列へのポインタ 39 | c_array, 40 | # 配列の長さ 41 | len(c_array), 42 | # 配列の各要素の大きさ 43 | ffi.sizeof('int'), 44 | # コールバック (Cの比較関数へのポインタ) 45 | cffi_int_compare, 46 | ) 47 | print("sorted: ", list(c_array)) 48 | 49 | if __name__ == "__main__": 50 | main() 51 | -------------------------------------------------------------------------------- /chapter4/properties_explicit.py: -------------------------------------------------------------------------------- 1 | class Rectangle: 2 | def __init__(self, x1, y1, x2, y2): 3 | self.x1, self.y1 = x1, y1 4 | self.x2, self.y2 = x2, y2 5 | 6 | def _width_get(self): 7 | return self.x2 - self.x1 8 | 9 | def _width_set(self, value): 10 | self.x2 = self.x1 + value 11 | 12 | def _height_get(self): 13 | return self.y2 - self.y1 14 | 15 | def _height_set(self, value): 16 | self.y2 = self.y1 + value 17 | 18 | width = property( 19 | _width_get, _width_set, 20 | doc="長方形の幅" 21 | ) 22 | height = property( 23 | _height_get, _height_set, 24 | doc="長方形の高さ" 25 | ) 26 | 27 | def __repr__(self): 28 | return "{}({}, {}, {}, {})".format( 29 | self.__class__.__name__, 30 | self.x1, self.y1, self.x2, self.y2 31 | ) 32 | 33 | 34 | if __name__ == "__main__": 35 | rectangle = Rectangle(0, 0, 10, 10) 36 | print( 37 | f"最初の図形は {rectangle} で" 38 | f"大きさは {rectangle.width} x {rectangle.height} です" 39 | ) 40 | 41 | rectangle.width = 2 42 | rectangle.height = 8 43 | print( 44 | f"サイズを変更したあとの図形は {rectangle} で" 45 | f"大きさは {rectangle.width} x {rectangle.height} です" 46 | ) 47 | -------------------------------------------------------------------------------- /chapter15/threads_one_per_item.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「スレッドを使用したアプリケーション例」の節で登場するサンプルコード 3 | `threading` モジュールの使い方 (アイテムごとに1スレッドを使う) 4 | 5 | """ 6 | import time 7 | from threading import Thread 8 | 9 | import requests 10 | 11 | SYMBOLS = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 12 | BASES = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 13 | ACCESS_KEY = '' 14 | 15 | 16 | def fetch_rates(base): 17 | response = requests.get( 18 | f"http://api.exchangeratesapi.io/latest?access_key={ACCESS_KEY}&base={base}" 19 | ) 20 | 21 | response.raise_for_status() 22 | rates = response.json()["rates"] 23 | # note: 同じ通貨の交換レートは 1:1 となる。 24 | rates[base] = 1. 25 | 26 | rates_line = ", ".join( 27 | [f"{rates[symbol]:7.03} {symbol}" for symbol in SYMBOLS] 28 | ) 29 | print(f"1 {base} = {rates_line}") 30 | 31 | 32 | def main(): 33 | threads = [] 34 | for base in BASES: 35 | thread = Thread(target=fetch_rates, args=[base]) 36 | thread.start() 37 | threads.append(thread) 38 | 39 | while threads: 40 | threads.pop().join() 41 | 42 | 43 | if __name__ == "__main__": 44 | started = time.time() 45 | main() 46 | elapsed = time.time() - started 47 | 48 | print() 49 | print("経過時間: {:.2f}s".format(elapsed)) 50 | -------------------------------------------------------------------------------- /chapter17/interfaces_zope.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「インターフェイス」の節で登場するサンプルコード 3 | `zope.interface` パッケージを使ってインターフェイスを実現する方法 4 | 5 | """ 6 | from zope.interface import Interface, Attribute, implementer 7 | 8 | 9 | class IRectangle(Interface): 10 | width = Attribute("長方形の幅") 11 | height = Attribute("長方形の高さ") 12 | 13 | def area(): 14 | """ 長方形の面積を返す 15 | """ 16 | 17 | def perimeter(): 18 | """ 長方形の周の長さを返す 19 | """ 20 | 21 | 22 | @implementer(IRectangle) 23 | class Square: 24 | """ 長方形のインターフェイスを持つ正方形の具象クラス 25 | """ 26 | 27 | def __init__(self, size): 28 | self.size = size 29 | 30 | @property 31 | def width(self): 32 | return self.size 33 | 34 | @property 35 | def height(self): 36 | return self.size 37 | 38 | def area(self): 39 | return self.size ** 2 40 | 41 | def perimeter(self): 42 | return 4 * self.size 43 | 44 | 45 | @implementer(IRectangle) 46 | class Rectangle: 47 | """ 長方形の具象クラス 48 | """ 49 | def __init__(self, width, height): 50 | self.width = width 51 | self.height = height 52 | 53 | def area(self): 54 | return self.width * self.height 55 | 56 | def perimeter(self): 57 | return self.width * 2 + self.height * 2 58 | -------------------------------------------------------------------------------- /chapter9/fibonacci_c/fibonacci.c: -------------------------------------------------------------------------------- 1 | #define PY_SSIZE_T_CLEAN 2 | #include 3 | 4 | 5 | long long fibonacci(unsigned int n) { 6 | if (n < 2) { 7 | return 1; 8 | } else { 9 | return fibonacci(n-2) + fibonacci(n-1); 10 | } 11 | } 12 | 13 | static PyObject* fibonacci_py(PyObject* self, PyObject* args) { 14 | PyObject *result = NULL; 15 | long n; 16 | if (PyArg_ParseTuple(args, "l", &n)) { 17 | result = Py_BuildValue("L", fibonacci((unsigned int)n)); 18 | } 19 | return result; 20 | } 21 | 22 | 23 | static const char fibonacci_docs[] = 24 | "fibonacci(n): Return nth Fibonacci sequence number " 25 | "computed recursively\n"; 26 | 27 | 28 | static PyMethodDef fibonacci_module_methods[] = { 29 | {"fibonacci", (PyCFunction)fibonacci_py, 30 | METH_VARARGS, fibonacci_docs}, 31 | {NULL, NULL, 0, NULL} 32 | }; 33 | 34 | 35 | static struct PyModuleDef fibonacci_module_definition = { 36 | PyModuleDef_HEAD_INIT, 37 | "fibonacci", 38 | "Extension module that provides fibonacci sequence function", 39 | -1, 40 | fibonacci_module_methods 41 | }; 42 | 43 | 44 | PyMODINIT_FUNC PyInit_fibonacci(void) { 45 | Py_Initialize(); 46 | return PyModule_Create(&fibonacci_module_definition); 47 | } 48 | -------------------------------------------------------------------------------- /chapter9/ctypes_qsort.py: -------------------------------------------------------------------------------- 1 | from random import shuffle 2 | 3 | import ctypes 4 | from ctypes.util import find_library 5 | 6 | libc = ctypes.cdll.LoadLibrary(find_library('c')) 7 | 8 | CMPFUNC = ctypes.CFUNCTYPE( 9 | # 戻り値の型 10 | ctypes.c_int, 11 | # 1つめの引数の型 12 | ctypes.POINTER(ctypes.c_int), 13 | # 2つめの引数の型 14 | ctypes.POINTER(ctypes.c_int), 15 | ) 16 | 17 | 18 | def ctypes_int_compare(a, b): 19 | # 引数はポインタなので[0]インデックスでアクセスする 20 | print(" %s cmp %s" % (a[0], b[0])) 21 | 22 | # qsort の仕様により、戻り値は 23 | # * a < b のとき: 負 24 | # * a = b のとき: 0 25 | # * a > b のとき: 正 26 | return a[0] - b[0] 27 | 28 | 29 | def main(): 30 | numbers = list(range(5)) 31 | shuffle(numbers) 32 | print("shuffled: ", numbers) 33 | 34 | # numbers と同じ長さの配列を表す新しい型を作る 35 | NumbersArray = ctypes.c_int * len(numbers) 36 | # その型を使ってC配列を作る 37 | c_array = NumbersArray(*numbers) 38 | 39 | libc.qsort( 40 | # ソート対象の配列へのポインタ 41 | c_array, 42 | # 配列の長さ 43 | len(c_array), 44 | # 配列の各要素の大きさ 45 | ctypes.sizeof(ctypes.c_int), 46 | # コールバック (Cの比較関数へのポインタ) 47 | CMPFUNC(ctypes_int_compare) 48 | ) 49 | print("sorted: ", list(c_array)) 50 | 51 | 52 | if __name__ == "__main__": 53 | main() 54 | -------------------------------------------------------------------------------- /chapter17/observer.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「Observerパターン」の節で登場するサンプルコード 3 | オブザーバーパターンによるシンプルなイベントの監視方法 4 | 5 | """ 6 | class Event: 7 | _observers = [] 8 | 9 | def __init__(self, subject): 10 | self.subject = subject 11 | 12 | @classmethod 13 | def register(cls, observer): 14 | if observer not in cls._observers: 15 | cls._observers.append(observer) 16 | 17 | @classmethod 18 | def unregister(cls, observer): 19 | if observer in cls._observers: 20 | cls._observers.remove(observer) 21 | 22 | @classmethod 23 | def notify(cls, subject): 24 | event = cls(subject) 25 | for observer in cls._observers: 26 | observer(event) 27 | 28 | 29 | class WriteEvent(Event): 30 | def __repr__(self): 31 | return 'WriteEvent' 32 | 33 | 34 | def log(event): 35 | print( 36 | '{!r} が subject "{}" により発火しました' 37 | ''.format(event, event.subject) 38 | ) 39 | 40 | 41 | class AnotherObserver: 42 | def __call__(self, event): 43 | print( 44 | "{!r} は {} のアクションを呼び出しました" 45 | "".format(event, self.__class__.__name__) 46 | ) 47 | 48 | 49 | WriteEvent.register(log) 50 | WriteEvent.register(AnotherObserver()) 51 | 52 | 53 | if __name__ == "__main__": 54 | Event.notify("電話が鳴りました") 55 | -------------------------------------------------------------------------------- /chapter4/descriptors_lazy_class_attribute.py: -------------------------------------------------------------------------------- 1 | class lazy_class_attribute(object): 2 | def __init__(self, function): 3 | self.fget = function 4 | 5 | def __get__(self, obj, cls): 6 | value = self.fget(obj or cls) 7 | # note: クラスレベルのアクセスか、インスタンスレベルの 8 | # アクセスかに関係なく、すべてをクラスオブジェクト 9 | # に格納する 10 | setattr(cls, self.fget.__name__, value) 11 | return value 12 | 13 | 14 | class MyComplexClass: 15 | @lazy_class_attribute 16 | def evaluated_only_once(self): 17 | print("メソッドの評価中!") 18 | return sum(x ** 2 for x in range(200)) 19 | 20 | 21 | if __name__ == "__main__": 22 | instance = MyComplexClass() 23 | 24 | print("インスタンスのレベルで、属性への初回アクセス") 25 | print("instance.evaluated_only_once =", 26 | instance.evaluated_only_once, 27 | '\n') 28 | 29 | print("インスタンスのレベルで、属性への2回目のアクセス") 30 | print("instance.evaluated_only_once =", 31 | instance.evaluated_only_once, 32 | '\n') 33 | 34 | print("クラスのレベルで、属性へのアクセス") 35 | print("MyComplexClass.evaluated_only_once =", 36 | MyComplexClass.evaluated_only_once, 37 | '\n') 38 | 39 | print("まったく新しいインスタンスからの、属性へのアクセス") 40 | print("MyComplexClass().evaluated_only_once =", 41 | MyComplexClass().evaluated_only_once, 42 | '\n') 43 | -------------------------------------------------------------------------------- /chapter8/webxample-package/fabutils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # 'devpi'を使って専用のパッケージインデックスを作ったとします 4 | PYPI_URL = 'http://devpi.webxample.example.com' 5 | 6 | # これはリリース版をインストールするリモートサーバーのパス 7 | # です。リリースディレクトリはプロジェクトのバージョンごとに 8 | # 分かれていて、それぞれが独立した仮想環境ディレクトリです。 9 | # 'current' は最後にデプロイされたバージョンを指すシンボリッ 10 | # クリンクです。このシンボリックリンクはプロセス監視ツール 11 | # などで参照されるディレクトリパスです。例: 12 | # . 13 | # ├── 0.0.1 14 | # ├── 0.0.2 15 | # ├── 0.0.3 16 | # ├── 0.1.0 17 | # └── current -> 0.1.0/ 18 | 19 | REMOTE_PROJECT_LOCATION = "/var/projects/webxample" 20 | 21 | 22 | def prepare_release(c): 23 | """ 新しいリリースのために、ソース配布物を作って専用の 24 | パッケージインデックスにアップロードします 25 | """ 26 | c.local(f'python setup.py build sdist') 27 | c.local(f'twine upload --repository-url {PYPI_URL}') 28 | 29 | 30 | def get_version(c): 31 | """ setuptools経由で、現在のバージョンを取得します """ 32 | return c.local('python setup.py --version').stdout.strip() 33 | 34 | 35 | def switch_versions(c, version): 36 | """ シンボリックリンクを差し替えることでアトミックにバージョンを切り替えます """ 37 | new_version_path = os.path.join(REMOTE_PROJECT_LOCATION, version) 38 | temporary = os.path.join(REMOTE_PROJECT_LOCATION, 'next') 39 | desired = os.path.join(REMOTE_PROJECT_LOCATION, 'current') 40 | 41 | # 既にある場合も強制的に(-f)シンボリックリンクを作成します 42 | c.run(f"ln -fsT {new_version_path} {temporary}") 43 | # mv -T によってこの操作をアトミックに行います 44 | c.run(f"mv -Tf {temporary} {desired}") -------------------------------------------------------------------------------- /chapter9/fibonacci_c_error_handling/fibonacci.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | long long fibonacci(unsigned int n) { 4 | if (n < 2) { 5 | return 1; 6 | } else { 7 | return fibonacci(n-2) + fibonacci(n-1); 8 | } 9 | } 10 | 11 | 12 | static PyObject* fibonacci_py(PyObject* self, PyObject* args) { 13 | PyObject *result = NULL; 14 | long n; 15 | long long fib; 16 | 17 | if (PyArg_ParseTuple(args, "l", &n)) { 18 | if (n<0) { 19 | PyErr_SetString(PyExc_ValueError, 20 | "n must not be less than 0"); 21 | } else { 22 | result = Py_BuildValue("L", fibonacci((unsigned int)n)); 23 | } 24 | } 25 | return result; 26 | } 27 | 28 | 29 | static char fibonacci_docs[] = 30 | "fibonacci(n): Return nth Fibonacci sequence number " 31 | "computed recursively\n"; 32 | 33 | 34 | static PyMethodDef fibonacci_module_methods[] = { 35 | {"fibonacci", (PyCFunction)fibonacci_py, 36 | METH_VARARGS, fibonacci_docs}, 37 | {NULL, NULL, 0, NULL} 38 | }; 39 | 40 | 41 | static struct PyModuleDef fibonacci_module_definition = { 42 | PyModuleDef_HEAD_INIT, 43 | "fibonacci", 44 | "Extension module that provides fibonacci sequence function", 45 | -1, 46 | fibonacci_module_methods 47 | }; 48 | 49 | 50 | PyMODINIT_FUNC PyInit_fibonacci(void) { 51 | Py_Initialize(); 52 | return PyModule_Create(&fibonacci_module_definition); 53 | } 54 | -------------------------------------------------------------------------------- /chapter15/async_futures.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「非同期プログラミング」の節で登場するサンプルコード 3 | 非同期に対応していないライブラリをasyncioベースのアプリケーションで利用するために 4 | `futures` やマルチスレッド・マルチプロセスを使う方法  5 | 6 | """ 7 | import asyncio 8 | import time 9 | 10 | import requests 11 | 12 | SYMBOLS = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 13 | BASES = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 14 | ACCESS_KEY = '' 15 | 16 | THREAD_POOL_SIZE = 4 17 | 18 | 19 | async def fetch_rates(base): 20 | loop = asyncio.get_event_loop() 21 | response = await loop.run_in_executor( 22 | None, requests.get, 23 | f"http://api.exchangeratesapi.io/latest?access_key={ACCESS_KEY}&base={base}" 24 | ) 25 | response.raise_for_status() 26 | rates = response.json()["rates"] 27 | # note: 同じ通貨の交換レートは 1:1 となる。 28 | rates[base] = 1. 29 | return base, rates 30 | 31 | 32 | async def present_result(result): 33 | base, rates = (await result) 34 | 35 | rates_line = ", ".join( 36 | [f"{rates[symbol]:7.03} {symbol}" for symbol in SYMBOLS] 37 | ) 38 | print(f"1 {base} = {rates_line}") 39 | 40 | 41 | async def main(): 42 | await asyncio.wait([ 43 | asyncio.create_task(present_result(fetch_rates(base))) 44 | for base in BASES 45 | ]) 46 | 47 | 48 | if __name__ == "__main__": 49 | started = time.time() 50 | loop = asyncio.get_event_loop() 51 | loop.run_until_complete(main()) 52 | elapsed = time.time() - started 53 | 54 | print() 55 | print("経過時間: {:.2f}s".format(elapsed)) 56 | -------------------------------------------------------------------------------- /chapter9/fibonacci_c_releasing_gil/fibonacci.c: -------------------------------------------------------------------------------- 1 | #define PY_SSIZE_T_CLEAN 2 | #include 3 | 4 | long long fibonacci(unsigned int n) { 5 | if (n < 2) { 6 | return 1; 7 | } else { 8 | return fibonacci(n-2) + fibonacci(n-1); 9 | } 10 | } 11 | 12 | 13 | static PyObject* fibonacci_py(PyObject* self, PyObject* args) { 14 | PyObject *result = NULL; 15 | long n; 16 | long long fib; 17 | 18 | if (PyArg_ParseTuple(args, "l", &n)) { 19 | if (n < 0) { 20 | PyErr_SetString(PyExc_ValueError, 21 | "n must not be less than 0"); 22 | } else { 23 | Py_BEGIN_ALLOW_THREADS; 24 | fib = fibonacci(n); 25 | Py_END_ALLOW_THREADS; 26 | 27 | result = Py_BuildValue("L", fib); 28 | } 29 | } 30 | return result; 31 | } 32 | 33 | 34 | static char fibonacci_docs[] = 35 | "fibonacci(n): Return nth Fibonacci sequence number " 36 | "computed recursively\n"; 37 | 38 | 39 | static PyMethodDef fibonacci_module_methods[] = { 40 | {"fibonacci", (PyCFunction)fibonacci_py, 41 | METH_VARARGS, fibonacci_docs}, 42 | {NULL, NULL, 0, NULL} 43 | }; 44 | 45 | 46 | static struct PyModuleDef fibonacci_module_definition = { 47 | PyModuleDef_HEAD_INIT, 48 | "fibonacci", 49 | "Extension module that provides fibonacci sequence function", 50 | -1, 51 | fibonacci_module_methods 52 | }; 53 | 54 | 55 | PyMODINIT_FUNC PyInit_fibonacci(void) { 56 | Py_Initialize(); 57 | return PyModule_Create(&fibonacci_module_definition); 58 | } 59 | -------------------------------------------------------------------------------- /chapter15/threads_thread_pool.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「スレッドを使用したアプリケーション例」の節で登場するサンプルコード 3 | シンプルなスレッドプールの実装方法 4 | 5 | """ 6 | import time 7 | from queue import Queue, Empty 8 | from threading import Thread 9 | 10 | import requests 11 | 12 | THREAD_POOL_SIZE = 4 13 | 14 | 15 | SYMBOLS = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 16 | BASES = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 17 | ACCESS_KEY = '' 18 | 19 | 20 | def fetch_rates(base): 21 | response = requests.get( 22 | f"http://api.exchangeratesapi.io/latest?access_key={ACCESS_KEY}&base={base}" 23 | ) 24 | 25 | response.raise_for_status() 26 | rates = response.json()["rates"] 27 | # note: 同じ通貨の交換レートは 1:1 となる。 28 | rates[base] = 1. 29 | 30 | rates_line = ", ".join( 31 | [f"{rates[symbol]:7.03} {symbol}" for symbol in SYMBOLS] 32 | ) 33 | print(f"1 {base} = {rates_line}") 34 | 35 | 36 | def worker(work_queue): 37 | while not work_queue.empty(): 38 | try: 39 | item = work_queue.get(block=False) 40 | except Empty: 41 | break 42 | else: 43 | fetch_rates(item) 44 | work_queue.task_done() 45 | 46 | 47 | def main(): 48 | work_queue = Queue() 49 | 50 | for base in BASES: 51 | work_queue.put(base) 52 | 53 | threads = [ 54 | Thread(target=worker, args=(work_queue,)) 55 | for _ in range(THREAD_POOL_SIZE) 56 | ] 57 | 58 | for thread in threads: 59 | thread.start() 60 | 61 | work_queue.join() 62 | 63 | while threads: 64 | threads.pop().join() 65 | 66 | 67 | if __name__ == "__main__": 68 | started = time.time() 69 | main() 70 | elapsed = time.time() - started 71 | 72 | print() 73 | print("経過時間: {:.2f}s".format(elapsed)) 74 | -------------------------------------------------------------------------------- /chapter15/threads_two_way_queues.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「スレッドを使用したアプリケーション例」の節で登場するサンプルコード 3 | 2つのキューで双方向に通信する方法 4 | 5 | """ 6 | import time 7 | from queue import Queue, Empty 8 | from threading import Thread 9 | 10 | import requests 11 | 12 | 13 | SYMBOLS = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 14 | BASES = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 15 | ACCESS_KEY = '' 16 | 17 | THREAD_POOL_SIZE = 4 18 | 19 | 20 | def fetch_rates(base): 21 | response = requests.get( 22 | f"http://api.exchangeratesapi.io/latest?access_key={ACCESS_KEY}&base={base}" 23 | ) 24 | 25 | response.raise_for_status() 26 | rates = response.json()["rates"] 27 | # note: 同じ通貨の交換レートは 1:1 となる。 28 | rates[base] = 1. 29 | return base, rates 30 | 31 | 32 | def present_result(base, rates): 33 | rates_line = ", ".join( 34 | [f"{rates[symbol]:7.03} {symbol}" for symbol in SYMBOLS] 35 | ) 36 | print(f"1 {base} = {rates_line}") 37 | 38 | 39 | def worker(work_queue, results_queue): 40 | while not work_queue.empty(): 41 | try: 42 | item = work_queue.get(block=False) 43 | except Empty: 44 | break 45 | else: 46 | results_queue.put( 47 | fetch_rates(item) 48 | ) 49 | work_queue.task_done() 50 | 51 | 52 | def main(): 53 | work_queue = Queue() 54 | results_queue = Queue() 55 | 56 | for base in BASES: 57 | work_queue.put(base) 58 | 59 | threads = [ 60 | Thread(target=worker, args=(work_queue, results_queue)) 61 | for _ in range(THREAD_POOL_SIZE) 62 | ] 63 | 64 | for thread in threads: 65 | thread.start() 66 | 67 | work_queue.join() 68 | 69 | while threads: 70 | threads.pop().join() 71 | 72 | while not results_queue.empty(): 73 | present_result(*results_queue.get()) 74 | 75 | 76 | if __name__ == "__main__": 77 | started = time.time() 78 | main() 79 | elapsed = time.time() - started 80 | 81 | print() 82 | print("経過時間: {:.2f}s".format(elapsed)) 83 | -------------------------------------------------------------------------------- /chapter8/webxample-package/setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from setuptools import setup 4 | from setuptools import find_packages 5 | from distutils.cmd import Command 6 | from distutils.command.build import build as _build 7 | 8 | try: 9 | from django.core.management.commands.compilemessages \ 10 | import Command as CompileCommand 11 | except ImportError: 12 | # 注意: Djangoのインストール前にはimportできません 13 | CompileCommand = None 14 | 15 | # この環境変数はCompileCommandを実行するのに必須です 16 | os.environ.setdefault( 17 | "DJANGO_SETTINGS_MODULE", "webxample.conf.settings" 18 | ) 19 | 20 | 21 | class build_messages(Command): 22 | """ カスタムコマンド: Django内のgettextメッセージをビルド 23 | """ 24 | description = """compile gettext messages""" 25 | user_options = [] 26 | 27 | def initialize_options(self): 28 | pass 29 | 30 | def finalize_options(self): 31 | pass 32 | 33 | def run(self): 34 | if CompileCommand: 35 | CompileCommand().handle( 36 | verbosity=2, locale=[], exclude=[], 37 | ignore_patterns=[], fuzzy=False 38 | ) 39 | else: 40 | raise RuntimeError("could not build translations") 41 | 42 | 43 | class build(_build): 44 | """ 既存のbuildコマンドを上書きして、ビルド手順を追加 45 | """ 46 | sub_commands = [ 47 | ('build_messages', None), 48 | ('build_sass', None), 49 | ] + _build.sub_commands 50 | 51 | 52 | setup( 53 | name='webxample', 54 | setup_requires=[ 55 | 'libsass == 0.20.1', 56 | 'django == 3.1.4', 57 | ], 58 | install_requires=[ 59 | 'django == 3.1.4', 60 | 'gunicorn == 20.0.4', 61 | 'djangorestframework == 3.12.2', 62 | 'django-allauth == 0.44.0', 63 | ], 64 | packages=find_packages('.'), 65 | sass_manifests={ 66 | 'webxample.myapp': ('static/sass', 'static/css') 67 | }, 68 | cmdclass={ 69 | 'build_messages': build_messages, 70 | 'build': build, 71 | }, 72 | entry_points={ 73 | 'console_scripts': { 74 | 'webxample = webxample.manage:main', 75 | } 76 | } 77 | ) -------------------------------------------------------------------------------- /chapter17/interfaces_abc.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「インターフェイス」の節で登場するサンプルコード 3 | 抽象基底クラスを使って暗黙的なインターフェイス定義し振る舞いを検証する方法 4 | 5 | """ 6 | from abc import ( 7 | ABCMeta, 8 | abstractmethod 9 | ) 10 | 11 | 12 | class IRectangle(metaclass=ABCMeta): 13 | 14 | @property 15 | @abstractmethod 16 | def width(self): 17 | return 18 | 19 | @property 20 | @abstractmethod 21 | def height(self): 22 | return 23 | 24 | @abstractmethod 25 | def area(self): 26 | """ 長方形の面積を返す 27 | """ 28 | 29 | @abstractmethod 30 | def perimeter(self): 31 | """ 長方形の周の長さを返す 32 | """ 33 | 34 | @classmethod 35 | def __subclasshook__(cls, C): 36 | if cls is IRectangle: 37 | if all([ 38 | any("area" in B.__dict__ for B in C.__mro__), 39 | any("perimeter" in B.__dict__ for B in C.__mro__), 40 | any("width" in B.__dict__ for B in C.__mro__), 41 | any("height" in B.__dict__ for B in C.__mro__), 42 | ]): 43 | return True 44 | return NotImplemented 45 | 46 | 47 | class Rectangle(IRectangle): 48 | def __init__(self, width, height): 49 | self._width = width 50 | self._height = height 51 | 52 | @property 53 | def width(self): 54 | return self._width 55 | 56 | @property 57 | def height(self): 58 | return self._height 59 | 60 | def area(self): 61 | return self.width * self.height 62 | 63 | def perimeter(self): 64 | return self.width * 2 + self.height * 2 65 | 66 | 67 | class ImplicitRectangle: 68 | def __init__(self, width, height): 69 | self._width = width 70 | self._height = height 71 | 72 | @property 73 | def width(self): 74 | return self._width 75 | 76 | @property 77 | def height(self): 78 | return self._height 79 | 80 | def area(self): 81 | return self.width * self.height 82 | 83 | def perimeter(self): 84 | return self.width * 2 + self.height * 2 85 | 86 | 87 | if __name__ == "__main__": 88 | rectangle = Rectangle(10, 10) 89 | 90 | print("インスタンスの型:", type(rectangle)) 91 | print("インスタンスのメソッド解決順序(MRO): ", rectangle.__class__.mro()) 92 | print("isinstance(rectangle, IRectangle) =", 93 | isinstance(rectangle, IRectangle)) 94 | print() 95 | 96 | rectangle = ImplicitRectangle(10, 10) 97 | print("インスタンスの型:", type(rectangle)) 98 | print("インスタンスのメソッド解決順序: ", rectangle.__class__.mro()) 99 | print("isinstance(rectangle, IRectangle) =", 100 | isinstance(rectangle, IRectangle)) 101 | print() 102 | -------------------------------------------------------------------------------- /chapter13/cprofile_decorator.py: -------------------------------------------------------------------------------- 1 | import time 2 | import tempfile 3 | import cProfile 4 | import pstats 5 | 6 | 7 | def profile(column='time', list=3): 8 | def parametrized_decorator(function): 9 | def decorated(*args, **kw): 10 | s = tempfile.mktemp() 11 | 12 | profiler = cProfile.Profile() 13 | profiler.runcall(function, *args, **kw) 14 | profiler.dump_stats(s) 15 | 16 | p = pstats.Stats(s) 17 | print("=" * 5, f"{function.__name__}() profile", "=" * 5) 18 | p.sort_stats(column).print_stats(list) 19 | return decorated 20 | 21 | return parametrized_decorator 22 | 23 | 24 | def medium(): 25 | time.sleep(0.01) 26 | 27 | 28 | @profile('time') 29 | def heavy(): 30 | for i in range(100): 31 | medium() 32 | medium() 33 | time.sleep(2) 34 | 35 | 36 | @profile('time') 37 | def main(): 38 | for i in range(2): 39 | heavy() 40 | 41 | 42 | if __name__ == '__main__': 43 | main() 44 | 45 | 46 | """ 47 | $ python3 cprofile_decorator.py 48 | ===== heavy() profile ===== 49 | Wed Apr 10 03:08:18 2019 /var/folders/jy/wy13kx0s7sb1dx2rfsqdvzdw0000gq/T/tmpwh6lb0y1 50 | 51 | 603 function calls in 4.462 seconds 52 | 53 | Ordered by: internal time 54 | 55 | ncalls tottime percall cumtime percall filename:lineno(function) 56 | 301 4.456 0.015 4.456 0.015 {built-in method time.sleep} 57 | 200 0.002 0.000 2.327 0.012 cprofile_decorator.py:25(medium) 58 | 1 0.002 0.002 4.462 4.462 cprofile_decorator.py:33(heavy) 59 | 100 0.001 0.000 0.129 0.001 cprofile_decorator.py:29(light) 60 | 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 61 | 62 | 63 | ===== heavy() profile ===== 64 | Wed Apr 10 03:08:23 2019 /var/folders/jy/wy13kx0s7sb1dx2rfsqdvzdw0000gq/T/tmpsp6h0mb5 65 | 66 | 603 function calls in 4.430 seconds 67 | 68 | Ordered by: internal time 69 | 70 | ncalls tottime percall cumtime percall filename:lineno(function) 71 | 301 4.425 0.015 4.425 0.015 {built-in method time.sleep} 72 | 1 0.002 0.002 4.430 4.430 cprofile_decorator.py:33(heavy) 73 | 200 0.002 0.000 2.295 0.011 cprofile_decorator.py:25(medium) 74 | 100 0.001 0.000 0.129 0.001 cprofile_decorator.py:29(light) 75 | 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 76 | 77 | 78 | ===== main() profile ===== 79 | Wed Apr 10 03:08:23 2019 /var/folders/jy/wy13kx0s7sb1dx2rfsqdvzdw0000gq/T/tmpenh1xtz7 80 | 81 | 64 function calls in 8.896 seconds 82 | 83 | Ordered by: internal time 84 | List reduced from 27 to 5 due to restriction <5> 85 | 86 | ncalls tottime percall cumtime percall filename:lineno(function) 87 | 1 8.896 8.896 8.896 8.896 {method 'enable' of '_lsprof.Profiler' objects} 88 | 1 0.000 0.000 0.000 0.000 {built-in method posix.lstat} 89 | 8 0.000 0.000 0.000 0.000 /usr/local/Cellar/python/3.7.2_2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/random.py:224(_randbelow) 90 | 1 0.000 0.000 8.896 8.896 cprofile_decorator.py:42(main) 91 | 8 0.000 0.000 0.000 0.000 /usr/local/Cellar/python/3.7.2_2/Frameworks/Python.framework/Versions/3.7/lib/python3.7/random.py:256(choice) 92 | 93 | """ 94 | -------------------------------------------------------------------------------- /chapter17/interfaces_annotations.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「インターフェイス」の節で登場するサンプルコード 3 | 抽象基底クラスで定義したインターフェイスの検証/チェックを、関数アノテーションを利用して行う方法 4 | 5 | """ 6 | from abc import ( 7 | ABCMeta, 8 | abstractmethod, 9 | ) 10 | 11 | 12 | class IRectangle(metaclass=ABCMeta): 13 | 14 | @property 15 | @abstractmethod 16 | def width(self): 17 | return 18 | 19 | @property 20 | @abstractmethod 21 | def height(self): 22 | return 23 | 24 | @abstractmethod 25 | def area(self): 26 | """ Return rectangle area 27 | """ 28 | 29 | @abstractmethod 30 | def perimeter(self): 31 | """ Return rectangle perimeter 32 | """ 33 | 34 | @classmethod 35 | def __subclasshook__(cls, C): 36 | if cls is IRectangle: 37 | if all([ 38 | any("area" in B.__dict__ for B in C.__mro__), 39 | any("perimeter" in B.__dict__ for B in C.__mro__), 40 | any("width" in B.__dict__ for B in C.__mro__), 41 | any("height" in B.__dict__ for B in C.__mro__), 42 | ]): 43 | return True 44 | return NotImplemented 45 | 46 | 47 | class Rectangle(IRectangle): 48 | def __init__(self, width, height): 49 | self._width = width 50 | self._height = height 51 | 52 | @property 53 | def width(self): 54 | return self._width 55 | 56 | @property 57 | def height(self): 58 | return self._height 59 | 60 | def area(self): 61 | return self.width * self.height 62 | 63 | def perimeter(self): 64 | return self.width * 2 + self.height * 2 65 | 66 | 67 | class ImplicitRectangle: 68 | def __init__(self, width, height): 69 | self._width = width 70 | self._height = height 71 | 72 | @property 73 | def width(self): 74 | return self._width 75 | 76 | @property 77 | def height(self): 78 | return self._height 79 | 80 | def area(self): 81 | return self.width * self.height 82 | 83 | def perimeter(self): 84 | return self.width * 2 + self.height * 2 85 | 86 | from functools import wraps 87 | import inspect 88 | 89 | 90 | def ensure_interface(function): 91 | signature = inspect.signature(function) 92 | parameters = signature.parameters 93 | 94 | @wraps(function) 95 | def wrapped(*args, **kwargs): 96 | bound = signature.bind(*args, **kwargs) 97 | for name, value in bound.arguments.items(): 98 | annotation = parameters[name].annotation 99 | 100 | if not isinstance(annotation, ABCMeta): 101 | continue 102 | 103 | if not isinstance(value, annotation): 104 | raise TypeError( 105 | "{} は {} インターフェイスを実装していません" 106 | "".format(value, annotation) 107 | 108 | ) 109 | 110 | function(*args, **kwargs) 111 | 112 | return wrapped 113 | 114 | 115 | @ensure_interface 116 | def draw_rectangle(rectangle: IRectangle): 117 | print( 118 | "{} × {} の長方形を描画します" 119 | "".format(rectangle.width, rectangle.height) 120 | ) 121 | 122 | 123 | def attempt_draw(instance): 124 | print(instance, "の描画を試みます") 125 | try: 126 | draw_rectangle(instance) 127 | except TypeError as error: 128 | print("次の理由で描画に失敗しました:", error) 129 | else: 130 | print("描画に成功しました") 131 | 132 | 133 | if __name__ == "__main__": 134 | for maybe_rectangle in ( 135 | "foo", 136 | ImplicitRectangle(10, 12), 137 | Rectangle(10,5), 138 | (10, 23) 139 | ): 140 | attempt_draw(maybe_rectangle) 141 | print() 142 | -------------------------------------------------------------------------------- /chapter15/threads_exceptions_and_throttling.py: -------------------------------------------------------------------------------- 1 | """ 2 | 「スレッドを使用したアプリケーション例」の節で登場するサンプルコード 3 | マルチスレッドを使用したアプリケーションにおける、スロットリング / 使用制限の実装方法 4 | 5 | """ 6 | import random 7 | import time 8 | from queue import Queue, Empty 9 | from threading import Thread, Lock 10 | 11 | import requests 12 | 13 | 14 | SYMBOLS = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 15 | BASES = ('USD', 'EUR', 'PLN', 'NOK', 'CZK') 16 | ACCESS_KEY = '' 17 | 18 | THREAD_POOL_SIZE = 4 19 | 20 | 21 | class Throttle: 22 | def __init__(self, rate): 23 | self._consume_lock = Lock() 24 | self.rate = rate 25 | self.tokens = 0.0 26 | self.last = 0 27 | 28 | def consume(self, amount=1): 29 | if amount > self.rate: 30 | raise ValueError("amountはrate以下でなければなりません") 31 | 32 | with self._consume_lock: 33 | while True: 34 | now = time.time() 35 | 36 | # 経過時間の初期化を最初のリクエスト時刻で行い、 37 | # 初期の大量リクエスト送信を防止 38 | if self.last == 0: 39 | self.last = now 40 | 41 | # 経過時間に応じてトークンを増やす 42 | elapsed = now - self.last 43 | self.tokens += elapsed * self.rate 44 | self.last = now 45 | 46 | # バケット溢れを防止 47 | if self.tokens > self.rate: 48 | self.tokens = self.rate 49 | 50 | # トークンが利用可能なら消費して返す 51 | if self.tokens >= amount: 52 | self.tokens -= amount 53 | return amount 54 | 55 | # トークンがたまるまで待つ 56 | time.sleep((amount - self.tokens) / self.rate) 57 | 58 | 59 | def fetch_rates(base): 60 | response = requests.get( 61 | f"http://api.exchangeratesapi.io/latest?access_key={ACCESS_KEY}&base={base}" 62 | ) 63 | 64 | if random.randint(0, 5) < 1: 65 | # ステータスコードを上書きすることで、エラーを再現します。 66 | response.status_code = 429 67 | 68 | response.raise_for_status() 69 | rates = response.json()["rates"] 70 | # note: 同じ通貨の交換レートは 1:1 となる。 71 | rates[base] = 1. 72 | return base, rates 73 | 74 | 75 | def present_result(base, rates): 76 | rates_line = ", ".join( 77 | [f"{rates[symbol]:7.03} {symbol}" for symbol in SYMBOLS] 78 | ) 79 | print(f"1 {base} = {rates_line}") 80 | 81 | 82 | def worker(work_queue, results_queue, throttle): 83 | while not work_queue.empty(): 84 | try: 85 | item = work_queue.get(block=False) 86 | except Empty: 87 | break 88 | else: 89 | 90 | while not throttle.consume(): 91 | pass 92 | 93 | try: 94 | result = fetch_rates(item) 95 | except Exception as err: 96 | results_queue.put(err) 97 | else: 98 | results_queue.put(result) 99 | finally: 100 | work_queue.task_done() 101 | 102 | 103 | def main(): 104 | work_queue = Queue() 105 | results_queue = Queue() 106 | throttle = Throttle(10) 107 | 108 | for base in BASES: 109 | work_queue.put(base) 110 | 111 | threads = [ 112 | Thread(target=worker, args=(work_queue, results_queue, throttle)) 113 | for _ in range(THREAD_POOL_SIZE) 114 | ] 115 | 116 | for thread in threads: 117 | thread.start() 118 | 119 | work_queue.join() 120 | 121 | while threads: 122 | threads.pop().join() 123 | 124 | while not results_queue.empty(): 125 | result = results_queue.get() 126 | if isinstance(result, Exception): 127 | raise result 128 | 129 | present_result(*result) 130 | 131 | 132 | if __name__ == "__main__": 133 | started = time.time() 134 | main() 135 | elapsed = time.time() - started 136 | 137 | print() 138 | print("経過時間: {:.2f}s".format(elapsed)) 139 | -------------------------------------------------------------------------------- /chapter8/webxample-package/webxample/conf/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for webxample project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.9.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.9/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '6j#h#1hd5u3%zu4-a5pzc9^)a$88pn6**_q%nxc))9+89j-rtr' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 41 | 'webxample.myapp', 42 | 'rest_framework', 43 | 'allauth', 44 | ] 45 | 46 | MIDDLEWARE_CLASSES = [ 47 | 'django.middleware.security.SecurityMiddleware', 48 | 'django.contrib.sessions.middleware.SessionMiddleware', 49 | 'django.middleware.common.CommonMiddleware', 50 | 'django.middleware.csrf.CsrfViewMiddleware', 51 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 52 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 53 | 'django.contrib.messages.middleware.MessageMiddleware', 54 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 55 | ] 56 | 57 | ROOT_URLCONF = 'webxample.conf.urls' 58 | 59 | TEMPLATES = [ 60 | { 61 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 62 | 'DIRS': [], 63 | 'APP_DIRS': True, 64 | 'OPTIONS': { 65 | 'context_processors': [ 66 | 'django.template.context_processors.debug', 67 | 'django.template.context_processors.request', 68 | 'django.contrib.auth.context_processors.auth', 69 | 'django.contrib.messages.context_processors.messages', 70 | ], 71 | }, 72 | }, 73 | ] 74 | 75 | WSGI_APPLICATION = 'webxample.conf.wsgi.application' 76 | 77 | 78 | # Database 79 | # https://docs.djangoproject.com/en/1.9/ref/settings/#databases 80 | 81 | DATABASES = { 82 | 'default': { 83 | 'ENGINE': 'django.db.backends.sqlite3', 84 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 85 | } 86 | } 87 | 88 | 89 | # Password validation 90 | # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators 91 | 92 | AUTH_PASSWORD_VALIDATORS = [ 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 101 | }, 102 | { 103 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 104 | }, 105 | ] 106 | 107 | 108 | # Internationalization 109 | # https://docs.djangoproject.com/en/1.9/topics/i18n/ 110 | 111 | LANGUAGE_CODE = 'en-us' 112 | 113 | from django.utils.translation import ugettext_lazy as _ 114 | 115 | from os.path import abspath, join, dirname 116 | 117 | PROJECT_ROOT = dirname(dirname(abspath(__file__))) 118 | 119 | LOCALE_PATHS = ( 120 | join(PROJECT_ROOT, 'locale'), 121 | ) 122 | 123 | LANGUAGES = [ 124 | ('de', _('German')), 125 | ('en', _('English')), 126 | ('pl', _('Polish')), 127 | ] 128 | 129 | TIME_ZONE = 'UTC' 130 | 131 | USE_I18N = True 132 | 133 | USE_L10N = True 134 | 135 | USE_TZ = True 136 | 137 | 138 | # Static files (CSS, JavaScript, Images) 139 | # https://docs.djangoproject.com/en/1.9/howto/static-files/ 140 | 141 | STATIC_URL = '/static/' 142 | --------------------------------------------------------------------------------