├── 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 |
--------------------------------------------------------------------------------