├── .gitignore ├── LICENSE ├── README.md ├── errata.md ├── images ├── BackCover-1.JPG ├── P02-17-1.JPG ├── P03-8-1.JPG ├── P05-10-1.JPG ├── P05-30-1.JPG ├── P08-16-1.JPG ├── P08-19-1.JPG ├── P11-04-1.JPG ├── P11-06-1.JPG ├── P11-20-1.JPG ├── P11-23-1.JPG ├── P11-29-1.JPG ├── P11-36-1.JPG ├── P11-36-2.JPG ├── P11-48-1.JPG ├── P12-12-1.JPG ├── P14-10-1.JPG └── P14-36-1.JPG └── samples-labs-exercises ├── exercises ├── CH03 │ └── exercises │ │ ├── exercise1.py │ │ └── exercise2.py ├── CH04 │ └── exercises │ │ ├── exercise1.py │ │ ├── exercise2.py │ │ ├── exercise3.py │ │ └── exercise4.py ├── CH05 │ └── exercises │ │ ├── exercise1.py │ │ ├── exercise2.py │ │ ├── exercise3.py │ │ └── exercise4.py ├── CH06 │ └── exercises │ │ ├── exercise1.py │ │ └── exercise2.py ├── CH07 │ └── exercises │ │ ├── exercise1.py │ │ ├── exercise2.py │ │ └── exercise3.py ├── CH08 │ └── exercises │ │ ├── exercise1.py │ │ ├── exercise2.py │ │ └── exercise3.py ├── CH09 │ └── exercises │ │ ├── exercise1.py │ │ └── exercise2.py ├── CH10 │ └── exercises │ │ ├── exercise1.py │ │ └── exercise2.py ├── CH11 │ └── exercises │ │ ├── exercise1.py │ │ ├── exercise2.py │ │ └── exercise3.py ├── CH12 │ └── exercise │ │ ├── dvdlib1.py │ │ ├── dvdlib2.py │ │ ├── exercise1.py │ │ └── exercise2.py ├── CH13 │ └── exercise │ │ ├── exercise1.py │ │ └── pool.py └── CH14 │ └── exercise │ ├── exercise1.py │ └── total_ordering_demo.py ├── labs ├── CH05 │ ├── object-oriented1 │ │ ├── bank.py │ │ ├── bank_demo.py │ │ └── workspace.pth │ ├── object-oriented2 │ │ ├── bank.py │ │ └── bank_demo.py │ ├── object-oriented3 │ │ ├── bank.py │ │ └── bank_demo.py │ └── object-oriented4 │ │ ├── bank.py │ │ └── bank_demo.py ├── CH06 │ ├── game1 │ │ └── rpg.py │ ├── game2 │ │ ├── rpg.py │ │ └── rpg_demo.py │ ├── game3 │ │ ├── rpg.py │ │ └── rpg_demo.py │ ├── game4 │ │ ├── rpg.py │ │ └── rpg_demo.py │ └── inheritance │ │ ├── bank.py │ │ ├── bank_demo.py │ │ └── xabc_demo.py ├── CH07 │ └── exceptions │ │ ├── bank.py │ │ └── bank_demo.py ├── CH09 │ ├── collection_advanced │ │ ├── chainable.py │ │ ├── chainmap.py │ │ ├── chainmap2.py │ │ ├── counter.py │ │ └── group.py │ └── object_protocols │ │ ├── orderable_types.py │ │ ├── point_demo.py │ │ ├── test.py │ │ └── tools.py └── CH10 │ └── object_serialization │ ├── dvdlib_pickle.py │ └── dvdlib_shelve.py └── samples ├── B ├── mysite │ ├── manage.py │ ├── mysite │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ └── polls │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ └── views.py ├── mysite2 │ ├── manage.py │ ├── mysite │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ └── polls │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ │ ├── models.py │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py ├── mysite3 │ ├── manage.py │ ├── mysite │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ └── polls │ │ ├── __init__.py │ │ ├── admin.py │ │ ├── apps.py │ │ ├── migrations │ │ ├── 0001_initial.py │ │ └── __init__.py │ │ ├── models.py │ │ ├── templates │ │ └── polls │ │ │ ├── detail.html │ │ │ └── index.html │ │ ├── tests.py │ │ ├── urls.py │ │ └── views.py └── mysite4 │ ├── manage.py │ ├── mysite │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py │ └── polls │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ ├── 0001_initial.py │ └── __init__.py │ ├── models.py │ ├── templates │ └── polls │ │ ├── detail.html │ │ ├── index.html │ │ └── results.html │ ├── tests.py │ ├── urls.py │ └── views.py ├── C └── bs_demo │ └── download_imgs.py ├── CH02 ├── hello.py ├── hello2.py ├── hello3.py ├── hello4.py ├── hello_prj │ ├── hello3.py │ └── openhome │ │ ├── __init__.py │ │ └── hello2.py ├── hello_prj2 │ ├── hello3.py │ └── openhome │ │ ├── __init__.py │ │ └── hello2.py ├── hello_prj3 │ └── hello.py └── hello_prj4 │ └── openhome │ ├── __init__.py │ ├── hello.py │ └── hi.py ├── CH03 └── operator │ ├── bitwise_demo.py │ ├── compare.py │ ├── decimal_demo.py │ ├── groups.py │ ├── shift_demo.py │ └── uppers.py ├── CH04 ├── basic │ ├── gcd.py │ ├── gcd2.py │ ├── grade.py │ ├── hello.py │ ├── is_odd.py │ ├── is_odd2.py │ ├── is_prime.py │ ├── lucky5.py │ ├── odds.py │ ├── show_uppers.py │ ├── square.py │ └── uppers.py ├── func │ ├── filter_demo.py │ ├── filter_demo2.py │ ├── filter_demo3.py │ ├── filter_map_demo.py │ ├── gcd.py │ ├── grade.py │ ├── map_demo.py │ ├── producer_consumer.py │ ├── scope_demo.py │ ├── scope_demo2.py │ ├── scope_demo3.py │ ├── sele_sort.py │ └── yield_demo.py └── type_hints │ ├── account.py │ ├── add.py │ └── users.py ├── CH05 ├── classes │ ├── xlogging.py │ ├── xlogging_demo.py │ └── xmath.py ├── modules │ ├── bank.py │ ├── bank_demo.py │ └── workspace.pth ├── object-oriented1 │ ├── bank.py │ └── bank_demo.py ├── object-oriented2 │ ├── bank.py │ └── bank_demo.py ├── object-oriented3 │ ├── bank.py │ └── bank_demo.py └── object-oriented4 │ ├── bank.py │ └── bank_demo.py ├── CH06 ├── docs │ └── openhome │ │ ├── __init__.py │ │ └── abc.py ├── game1 │ ├── rpg.py │ └── rpg_demo.py ├── game2 │ ├── rpg.py │ └── rpg_demo.py ├── game3 │ ├── rpg.py │ └── rpg_demo.py ├── game4 │ ├── rpg.py │ └── rpg_demo.py └── inheritance │ ├── bank.py │ ├── bank_demo.py │ ├── xabc.py │ └── xabc_demo.py ├── CH07 ├── clean-up │ ├── average.py │ ├── context_manager_demo.py │ ├── context_manager_demo2.py │ ├── context_manager_demo3.py │ ├── context_manager_demo4.py │ ├── context_manager_demo5.py │ ├── context_manager_demo6.py │ ├── context_manager_demo7.py │ ├── finallly_demo.py │ ├── read_files.py │ └── read_files2.py └── exceptions │ ├── average.py │ ├── average2.py │ ├── average3.py │ ├── bank.py │ ├── bank_demo.py │ ├── excepthook_demo.py │ ├── for_in.py │ ├── stacktrace_demo.py │ ├── traceback_demo.py │ └── warnings_demo.py ├── CH08 └── basicio │ ├── stdin_demo.py │ ├── test.txt │ ├── test_ch.txt │ ├── test_ch2.txt │ └── upper.py ├── CH09 ├── collection_advanced │ ├── chainable.py │ ├── chainmap.py │ ├── chainmap2.py │ ├── counter.py │ └── group.py └── object_protocols │ ├── orderable_types.py │ ├── point_demo.py │ ├── test.py │ └── tools.py ├── CH10 ├── country_data.xml ├── data_formats │ ├── MI_5MINS_HIST.csv │ └── index_history.py └── object_serialization │ ├── dvdlib_pickle.py │ └── dvdlib_shelve.py ├── CH11 ├── files_dirs │ ├── glob_search.py │ ├── list_all.py │ ├── list_all2.py │ └── list_all3.py ├── logging_demo │ ├── basic_logger.py │ ├── basic_logger2.py │ ├── basic_logger3.py │ ├── config_demo.py │ ├── config_demo2.py │ ├── filter_demo.py │ ├── formatter_demo.py │ ├── handler_demo.py │ ├── logconf.json │ └── logconf.py ├── regex │ └── regex.py └── urllib_abc │ ├── download_imgs.py │ ├── search_books.py │ └── search_google.py ├── CH12 ├── doctest_demo │ ├── util.py │ ├── util2.py │ └── util_doctest.txt ├── pdb_demo │ ├── filter_demo2.py │ └── filter_demo3.py ├── profile_demo │ ├── numbers.py │ ├── sele_stats.py │ ├── select_stats │ ├── sorting.py │ ├── sorting_cprof.py │ └── sorting_prof.py └── unittest_demo │ ├── calc.py │ ├── calc_test.py │ ├── dvdlib1.py │ └── dvdlib2.py ├── CH13 ├── async_io │ ├── async_ctx_manager.py │ ├── async_ctx_manager2.py │ ├── await_demo.py │ ├── download.py │ ├── download2.py │ └── page_sizes.py ├── concurrent_demo │ ├── async_callback.py │ ├── async_callback2.py │ ├── async_callback3.py │ ├── download.py │ ├── download2.py │ ├── fib.py │ ├── fib2.py │ ├── fib3.py │ └── yield_from_demo.py ├── multiprocessing_demo │ ├── data1.txt │ ├── data2.txt │ ├── data3.txt │ ├── lock_demo.py │ ├── lock_demo2.py │ ├── multi_process.py │ ├── multi_process2.py │ └── no_lock.py ├── subprocess_demo │ ├── data1.txt │ ├── data2.txt │ ├── data3.txt │ ├── hi.py │ ├── loop.py │ ├── multi_process.py │ └── one_process.py └── threading_demo │ ├── condition_demo.py │ ├── deadlock_demo.py │ ├── download.py │ ├── download2.py │ ├── join_demo.py │ ├── lock_demo.py │ ├── lock_demo2.py │ ├── queue_demo.py │ ├── race_demo.py │ ├── stop_demo.py │ ├── tortoise_hare_race.py │ ├── tortoise_hare_race2.py │ └── tortoise_hare_race3.py └── CH14 ├── attributes ├── descriptor.py └── prop_demo.py ├── decorators ├── burgers.py ├── burgers2.py ├── burgers3.py ├── burgers4.py ├── burgers5.py ├── burgers6.py ├── classmth_demo.py ├── method_demo.py └── staticmth_demo.py ├── generics ├── bound_demo.py ├── contravariance_demo.py └── covariance_demo.py └── metaclass_demo ├── call_demo.py ├── call_demo2.py ├── myabc.py └── type_demo.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | All Rights Reserved. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python37Tutorial 2 | 3 | Python 3.7 技術手冊資料。 4 | 5 | - samples(書中範例) 6 | - labs(建議動手的實作) 7 | - exercises(課後練習解答) 8 | - [一刷勘誤](errata.md) 9 | -------------------------------------------------------------------------------- /errata.md: -------------------------------------------------------------------------------- 1 | 《Python 3.7 技術手冊》堪誤 2 | 3 | # 封底 4 | 5 | ![BackCover-1](images/BackCover-1.JPG) 6 | 7 | # P02-17 8 | 9 | ![P02-17](images/P02-17-1.JPG) 10 | 11 | # P03-8 12 | 13 | ![P03-8](images/P03-8-1.JPG) 14 | 15 | # P05-10 16 | 17 | ![P05-10](images/P05-10-1.JPG) 18 | 19 | # P05-30 20 | 21 | ![P05-30](images/P05-30-1.JPG) 22 | 23 | # P08-16 24 | 25 | ![P08-16](images/P08-16-1.JPG) 26 | 27 | # P08-19 28 | 29 | ![P08-19](images/P08-19-1.JPG) 30 | 31 | # P11-04 32 | 33 | ![P11-04](images/P11-04-1.JPG) 34 | 35 | # P11-06 36 | 37 | ![P11-06](images/P11-06-1.JPG) 38 | 39 | # P11-20 40 | 41 | ![P11-20](images/P11-20-1.JPG) 42 | 43 | # P11-23 44 | 45 | ![P11-23](images/P11-23-1.JPG) 46 | 47 | # P11-29 48 | 49 | ![P11-29](images/P11-29-1.JPG) 50 | 51 | # P11-36 52 | 53 | ![P11-36](images/P11-36-1.JPG) 54 | 55 | # P11-36 56 | 57 | ![P11-36](images/P11-36-2.JPG) 58 | 59 | # P11-48 60 | 61 | ![P11-48](images/P11-48-1.JPG) 62 | 63 | # P12-12 64 | 65 | ![P12-12](images/P12-12-1.JPG) 66 | 67 | # P14-10 68 | 69 | ![P14-10](images/P14-10-1.JPG) 70 | 71 | # P14-36 72 | 73 | ![P14-36](images/P14-36-1.JPG) -------------------------------------------------------------------------------- /images/BackCover-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/BackCover-1.JPG -------------------------------------------------------------------------------- /images/P02-17-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P02-17-1.JPG -------------------------------------------------------------------------------- /images/P03-8-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P03-8-1.JPG -------------------------------------------------------------------------------- /images/P05-10-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P05-10-1.JPG -------------------------------------------------------------------------------- /images/P05-30-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P05-30-1.JPG -------------------------------------------------------------------------------- /images/P08-16-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P08-16-1.JPG -------------------------------------------------------------------------------- /images/P08-19-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P08-19-1.JPG -------------------------------------------------------------------------------- /images/P11-04-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P11-04-1.JPG -------------------------------------------------------------------------------- /images/P11-06-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P11-06-1.JPG -------------------------------------------------------------------------------- /images/P11-20-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P11-20-1.JPG -------------------------------------------------------------------------------- /images/P11-23-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P11-23-1.JPG -------------------------------------------------------------------------------- /images/P11-29-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P11-29-1.JPG -------------------------------------------------------------------------------- /images/P11-36-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P11-36-1.JPG -------------------------------------------------------------------------------- /images/P11-36-2.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P11-36-2.JPG -------------------------------------------------------------------------------- /images/P11-48-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P11-48-1.JPG -------------------------------------------------------------------------------- /images/P12-12-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P12-12-1.JPG -------------------------------------------------------------------------------- /images/P14-10-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P14-10-1.JPG -------------------------------------------------------------------------------- /images/P14-36-1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/images/P14-36-1.JPG -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH03/exercises/exercise1.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | words = set(sys.argv[1:]) 4 | print('有 {} 個不重複字串:{}'.format(len(words), words)) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH03/exercises/exercise2.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | keyword = sys.argv[1] 4 | words = sys.argv[2:] 5 | 6 | print('{} 出現了 {} 次。'.format(keyword, words.count(keyword))) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH04/exercises/exercise1.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from functools import reduce 3 | 4 | def to_digits(num: int) -> List[int]: 5 | return [] if num == 0 else ([num % 10] + to_digits(num // 10)) 6 | 7 | def is_narcissistic(number: int) -> bool: 8 | digits = to_digits(number) 9 | return reduce(lambda sum, d: sum + d ** len(digits), 10 | digits, 0) == number 11 | 12 | def narcissistic(n: int) -> List[int]: 13 | return [i for i in range(1, 10 ** (n if n < 40 else 39)) 14 | if is_narcissistic(i)] 15 | 16 | print(narcissistic(3)) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH04/exercises/exercise2.py: -------------------------------------------------------------------------------- 1 | def fibonacci(n: int, fib = [0, 1]) -> int: 2 | if n >= len(fib): 3 | for i in range(len(fib), n + 1): 4 | fib.append(fib[i - 1] + fib[i - 2]) 5 | return fib[n] 6 | 7 | n = int(input('求幾個費式數?')) 8 | for i in range(0, n): 9 | print(fibonacci(i), end=' ') -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH04/exercises/exercise3.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | from functools import reduce 3 | 4 | class Card: 5 | def __init__(self, suit: str, symbol: str) -> None: 6 | self.suit = suit 7 | self.symbol = symbol 8 | 9 | def __str__(self): 10 | return self.suit + self.symbol 11 | 12 | class Poker: 13 | cards = [Card( 14 | {0: "桃", 1: "心", 2: "磚", 3: "梅"}[i // 13], 15 | {0: "K ", 1: "A ", 11: "J ", 12: "Q "}.get( 16 | (i + 1) % 13, "%-2d" % ((i + 1) % 13)) 17 | ) for i in range(52)] 18 | 19 | @staticmethod 20 | def shuffle(): 21 | def swap(cards, i, j): 22 | a, b = sorted([i, j]) 23 | return cards if a == b else (cards[0:a] + [cards[b]] + 24 | cards[a + 1:b] + [cards[a]] + cards[b + 1:]) 25 | return reduce(lambda cards, i: swap(cards, i, randint(0, 51)), 26 | range(len(Poker.cards)), Poker.cards) 27 | 28 | cards = Poker.shuffle() 29 | for i in range(len(cards)): 30 | print(cards[i], end = "\n" if (i + 1) % 13 == 0 else " ") -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH04/exercises/exercise4.py: -------------------------------------------------------------------------------- 1 | print([(a,b,c) for c in range(1, 11) for b in range(1, c + 1) for a in range(1, b + 1) if a ** 2 + b ** 2 == c ** 2 and a + b + c == 24]) 2 | 3 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH05/exercises/exercise1.py: -------------------------------------------------------------------------------- 1 | def hanoi(n, A, B, C): 2 | if n == 1: 3 | return [(A, C)] 4 | else: 5 | return hanoi(n-1, A, C, B) + hanoi(1, A, B, C) + hanoi(n-1, B, A, C) 6 | 7 | n = input('請輸入整數:') 8 | for move in hanoi(int(n), 'A', 'B', 'C'): 9 | print('盤由 %c 移至 %c' % move) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH05/exercises/exercise3.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, List 2 | from functools import reduce 3 | 4 | Pt = Tuple[int, int] 5 | 6 | class Knight: 7 | @staticmethod 8 | def travel(start: Pt) -> List[Pt]: 9 | route = [start] 10 | current = start 11 | for m in range(1, 64): 12 | possibleSteps = Knight.possible(route, current) 13 | if len(possibleSteps) == 0: 14 | break; 15 | if len(possibleSteps) == 1: 16 | current = possibleSteps[0] 17 | else: 18 | current = Knight.hard(route, possibleSteps) 19 | route.append(current) 20 | return route 21 | 22 | @staticmethod 23 | def possible(route: List[Pt], step: Pt) -> List[Pt]: 24 | dirs = [(-2, 1), (-1, 2), (1, 2), (2, 1), 25 | (2, -1), (1, -2), (-1, -2), (-2, -1)] 26 | steps = [(step[0] + dir[0], step[1] + dir[1]) for dir in dirs] 27 | return [step for step in steps if Knight.isVisitable(route, step)] 28 | 29 | @staticmethod 30 | def isVisitable(route: List[Pt], step: Pt) -> bool: 31 | return -1 < step[0] < 8 and -1 < step[1] < 8 and not step in route 32 | 33 | @staticmethod 34 | def hard(route: List[Pt], steps: List[Pt]) -> Pt: 35 | allSteps = [Knight.possible(route, step) for step in steps] 36 | minIndex = reduce( 37 | lambda c, i: i if len(allSteps[i]) < len(allSteps[c]) else c, 38 | range(1, len(steps)), 0) 39 | return steps[minIndex] 40 | 41 | x = int(input('x = ')) 42 | y = int(input('y =' )) 43 | route = Knight.travel((x, y)) 44 | for i in range(8): 45 | for j in range(8): 46 | print('%3d' % (route.index((i, j)) + 1), end='') 47 | print() -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH05/exercises/exercise4.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, List 2 | 3 | Pt = Tuple[int, int] 4 | 5 | def queenss(n: int) -> List[List[Pt]]: 6 | def placeQueens(k: int) -> List[List[Pt]]: 7 | return [[]] if k == 0 \ 8 | else [[(k, column)] + queens 9 | for queens in placeQueens(k - 1) 10 | for column in range(1, n + 1) 11 | if isSafe((k, column), queens)] 12 | return placeQueens(n) 13 | 14 | def isSafe(queen: Pt, queens: List[Pt]) -> bool: 15 | return all(not inCheck(queen, q) for q in queens) 16 | 17 | def inCheck(q1: Pt, q2: Pt) -> bool: 18 | return (q1[0] == q2[0] or # 同列 19 | q1[1] == q2[1] or # 同行 20 | abs(q1[0] - q2[0]) == abs(q1[1] - q2[1])) # 對角線 21 | 22 | def printQueens(qs: List[Pt]): 23 | board = [ 24 | [0, 0, 0, 0, 0, 0, 0, 0], 25 | [0, 0, 0, 0, 0, 0, 0, 0], 26 | [0, 0, 0, 0, 0, 0, 0, 0], 27 | [0, 0, 0, 0, 0, 0, 0, 0], 28 | [0, 0, 0, 0, 0, 0, 0, 0], 29 | [0, 0, 0, 0, 0, 0, 0, 0], 30 | [0, 0, 0, 0, 0, 0, 0, 0], 31 | [0, 0, 0, 0, 0, 0, 0, 0] 32 | ] 33 | 34 | for q in qs: 35 | board[q[0] - 1][q[1] - 1] = 1 36 | 37 | for row in board: 38 | for p in row: 39 | print(' Q' if p else ' .', end = '') 40 | print() 41 | 42 | for qs in queenss(8): 43 | printQueens(qs) 44 | print() -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH06/exercises/exercise1.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta, abstractmethod 2 | 3 | import random 4 | 5 | class GuessGame(metaclass=ABCMeta): 6 | @abstractmethod 7 | def show(self, msg: str): 8 | pass 9 | 10 | @abstractmethod 11 | def user_input(self, prompt: str): 12 | pass 13 | 14 | def go(self): 15 | number = random.randint(0, 9) 16 | guess = -1 17 | while guess != number: 18 | guess = self.user_input('輸入數字:') 19 | 20 | self.show('猜中了!') 21 | 22 | class ConsoleGame(GuessGame): 23 | def show(self, msg: str): 24 | print(msg) 25 | 26 | def user_input(self, prompt: str): 27 | return int(input(prompt)) 28 | 29 | game = ConsoleGame() 30 | game.go() -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH06/exercises/exercise2.py: -------------------------------------------------------------------------------- 1 | from functools import total_ordering 2 | 3 | @total_ordering 4 | class Rational: 5 | def __init__(self, numer: int, denom: int) -> None: 6 | self.numer = numer 7 | self.denom = denom 8 | 9 | def __add__(self, that): 10 | return Rational( 11 | self.numer * that.denom + that.numer * self.denom, 12 | self.denom * that.denom 13 | ) 14 | 15 | def __sub__(self, that): 16 | return Rational( 17 | self.numer * that.denom - that.numer * self.denom, 18 | self.denom * that.denom 19 | ) 20 | 21 | def __mul__(self, that): 22 | return Rational( 23 | self.numer * that.numer, 24 | self.denom * that.denom 25 | ) 26 | 27 | def __truediv__(self, that): 28 | return Rational( 29 | self.numer * that.denom, 30 | self.denom * that.denom 31 | ) 32 | 33 | def __str__(self): 34 | return f'{self.numer}/{self.denom}' 35 | 36 | def __repr__(self): 37 | return self.__str__() 38 | 39 | @staticmethod 40 | def __can_eq__(other): 41 | return hasattr(other, 'numer') and hasattr(other, 'denom') 42 | 43 | def __eq__(self, other): 44 | return __class__.__can_eq__(other) and (self.numer * other.denom == self.denom * other.numer) 45 | 46 | def __gt__(self, other): 47 | return __class__.__can_eq__(other) and (self.numer / self.denom) > (other.numer / other.denom) 48 | 49 | def __ge__(self, other): 50 | return __class__.__can_eq__(other) and (self.numer / self.denom) >= (other.numer / other.denom) 51 | 52 | r1 = Rational(1, 2) 53 | r2 = Rational(2, 4) 54 | 55 | print(r1 == r2) 56 | print(r1 > r2) 57 | print(r1 <= r2) 58 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH07/exercises/exercise2.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from typing import Type, Optional 3 | from types import TracebackType 4 | 5 | class Suppress: 6 | def __init__(self, ex_type: Type[BaseException]) -> None: 7 | self.ex_type = ex_type 8 | 9 | def __enter__(self): 10 | return None 11 | 12 | def __exit__(self, exc_type: Optional[Type[BaseException]], 13 | exc_value: Optional[BaseException], 14 | traceback: Optional[TracebackType]) -> Optional[bool]: 15 | return exc_type == self.ex_type 16 | 17 | with Suppress(FileNotFoundError): 18 | for line in open(sys.argv[1]): 19 | print(line, end='') 20 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH07/exercises/exercise3.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from types import TracebackType 3 | from typing import Type, Any, Generator, Callable, Optional, ContextManager 4 | 5 | WrappedFunc = Callable[..., Generator] 6 | CtxMgrWrapper = Callable[[Any], ContextManager] 7 | 8 | def contextmanager(func: WrappedFunc) -> CtxMgrWrapper: 9 | def wraps(*args: Any, **kwargs: Any) -> ContextManager: 10 | g = func(*args, **kwargs) 11 | 12 | class ContextDecorator: 13 | def __enter__(self): 14 | return next(g) 15 | 16 | def __exit__(self, exc_type: Optional[Type[BaseException]], 17 | exc_value: Optional[BaseException], 18 | traceback: Optional[TracebackType]) -> Optional[bool]: 19 | if exc_type: 20 | try: 21 | g.throw(exc_type, exc_value, traceback) 22 | except StopIteration: 23 | pass 24 | return True 25 | return False 26 | 27 | return ContextDecorator() 28 | 29 | return wraps 30 | 31 | def suppress0(ex_type: Type[BaseException]) -> Generator: 32 | try: 33 | yield 34 | except ex_type: 35 | pass 36 | 37 | suppress: CtxMgrWrapper = contextmanager(suppress0) 38 | 39 | with suppress(FileNotFoundError): 40 | for line in open(sys.argv[1]): 41 | print(line, end='') 42 | 43 | def closing0(thing: Any) -> Generator: 44 | try: 45 | yield thing 46 | finally: 47 | thing.close() 48 | 49 | closing: CtxMgrWrapper = contextmanager(closing0) 50 | 51 | class Some: 52 | def __init__(self, name: str) -> None: 53 | self.name = name 54 | 55 | def close(self): 56 | print(self.name, 'is closed.') 57 | 58 | 59 | with closing(Some('Resource')) as res: 60 | print(res.name) 61 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH08/exercises/exercise1.py: -------------------------------------------------------------------------------- 1 | from typing import BinaryIO 2 | import urllib.request 3 | 4 | def dump(src: BinaryIO, dest: BinaryIO): 5 | with src, dest: 6 | dest.write(src.read()) 7 | 8 | dump( 9 | urllib.request.urlopen('http://openhome.cc'), 10 | open('index.html', 'wb') 11 | ) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH08/exercises/exercise2.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | 3 | def dump(src_path: str, dest_path: str): 4 | try: 5 | with open(src_path, 'rb') as src, open(dest_path, 'wb') as dest: 6 | dest.write(src.read()) 7 | except: 8 | with open('exception.log', 'a', encoding='UTF-8') as f: 9 | traceback.print_exc(file = f) 10 | 11 | dump('src.jpg', 'dest.jpg') -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH08/exercises/exercise3.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from typing import TextIO 3 | 4 | def dump(src: TextIO, dest: TextIO): 5 | with src, dest: 6 | dest.write(src.read()) 7 | 8 | src_path = sys.argv[1] 9 | encoding = sys.argv[2] 10 | dest_path = sys.argv[3] 11 | 12 | dump( 13 | open(src_path, 'r', encoding=encoding), 14 | open(dest_path, 'w', encoding='UTF-8') 15 | ) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH09/exercises/exercise1.py: -------------------------------------------------------------------------------- 1 | from typing import Generic, TypeVar, Dict, DefaultDict 2 | from collections import defaultdict 3 | from collections.abc import MutableMapping 4 | 5 | KT = TypeVar('KT') 6 | VT = TypeVar('VT') 7 | 8 | class MultiMap(Generic[KT, VT], MutableMapping): 9 | def __init__(self, *tulp: Dict[KT, VT]) -> None: 10 | self.map: DefaultDict = defaultdict(set) 11 | for m in tulp: 12 | for k in m: 13 | self.map[k].add(m[k]) 14 | 15 | def __getitem__(self, key: KT) -> VT: 16 | if key in self.map: 17 | return self.map[key] 18 | raise KeyError(key) 19 | 20 | def __setitem__(self, key: KT, value: VT): 21 | self.map[key].add(value) 22 | 23 | def __delitem__(self, key: KT): 24 | del self.map[key] 25 | 26 | def __iter__(self): 27 | return iter(self.map) 28 | 29 | def __len__(self): 30 | return len(self.map) 31 | 32 | def __str__(self): 33 | return str(self.map)[len("defaultdict(, ") : -1] 34 | 35 | mmap = MultiMap({'A' : 'Justin'}, {'A' : 'Monica', 'B' : 'Irene'}) 36 | print(mmap) # 顯示 {'B': {'Irene'}, 'A': {'Justin', 'Monica'}} 37 | 38 | mmap['B'] = 'Pika' 39 | print(mmap) # 顯示 {'B': {'Irene', 'Pika'}, 'A': {'Justin', 'Monica'}} 40 | 41 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH09/exercises/exercise2.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | def is_reversed_word(word: str) -> bool: 4 | d = deque(word) 5 | while len(d) > 1: 6 | if d.pop() != d.popleft(): 7 | return False 8 | return True 9 | 10 | words = ['RADAR', 'WARTER START', 'MILK KLIM', 'RESERVERED','IWI', "ABBA"] 11 | for word in words: 12 | if is_reversed_word(word): 13 | print(word) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH10/exercises/exercise1.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import sqlite3 3 | 4 | db_name = 'dvd_lib.sqlite3' 5 | 6 | def connect(name: str) -> sqlite3.Connection: 7 | create = not os.path.exists(name) 8 | conn = sqlite3.connect(name) 9 | if create: 10 | cursor = conn.cursor() 11 | cursor.execute("CREATE TABLE dvds (" 12 | "id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, " 13 | "title TEXT NOT NULL, " 14 | "year INTEGER NOT NULL, " 15 | "duration INTEGER NOT NULL, " 16 | "director_id TEXT NOT NULL)") 17 | conn.commit() 18 | 19 | return conn 20 | 21 | class DVD: 22 | def __init__(self, title: str, year: int, duration: int, director: str) -> None: 23 | self.title = title 24 | self.year = year 25 | self.duration = duration 26 | self.director = director 27 | 28 | def save(self): 29 | with connect(db_name) as conn: 30 | conn.cursor().execute("INSERT INTO dvds (title, year, duration, director_id) VALUES (?, ?, ?, ?)", 31 | (self.title, self.year, self.duration, self.director)) 32 | 33 | @staticmethod 34 | def load(title: str) -> 'DVD': 35 | with connect(db_name) as conn: 36 | c = conn.cursor() 37 | fields = c.execute('SELECT title, year, duration, director_id FROM dvds WHERE title =?', (title,)).fetchone() 38 | return DVD(*fields) 39 | 40 | def __str__(self): 41 | return repr(self) 42 | 43 | def __repr__(self): 44 | return "DVD('{0}', {1}, {2}, '{3}')".format( 45 | self.title, self.year, self.duration, self.director) 46 | 47 | dvd1 = DVD('Birds', 2018, 8, 'Justin Lin') 48 | dvd1.save() 49 | dvd2 = DVD.load('Birds') 50 | print(dvd2) # 顯示DVD('Birds', 2018, 8, 'Justin Lin') 51 | 52 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH10/exercises/exercise2.py: -------------------------------------------------------------------------------- 1 | from xml.etree.ElementTree import Element, tostring 2 | 3 | def dict_to_xml(rt: str, dt: dict) -> str: 4 | elem = Element(rt) 5 | for key, val in dt.items(): 6 | child = Element(key) 7 | child.text = str(val) 8 | elem.append(child) 9 | return tostring(elem) 10 | 11 | print(dict_to_xml('user', {'name' : 'Justin', 'age' : 40})) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH11/exercises/exercise1.py: -------------------------------------------------------------------------------- 1 | from time import gmtime, struct_time, strftime 2 | from datetime import date, timedelta 3 | 4 | def first_day_of_month(time_tuple: struct_time): 5 | return date(time_tuple.tm_year, time_tuple.tm_mon, 1) 6 | 7 | def last_day_of_month(time_tuple: struct_time): 8 | twenty_night_days = first_day_of_month(time_tuple) + timedelta(days = 28) 9 | one_day_delta = timedelta(days=1) 10 | for d in range(3): 11 | if (twenty_night_days + one_day_delta * d).month > twenty_night_days.month: 12 | return 28 + d 13 | return 31 14 | 15 | def print_title(time_tuple: struct_time): 16 | print(' {}'.format(strftime('%B %Y', first_day_of_month(time_tuple).timetuple()))) 17 | wday_names = ['MO', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'] 18 | for wday_name in wday_names: 19 | print('{} '.format(wday_name), end = '') 20 | print() 21 | 22 | def print_days(time_tuple: struct_time): 23 | wday_count = time_tuple.tm_wday + 1 24 | for i in range(wday_count - 1): 25 | print(' ', end = '') 26 | 27 | last = last_day_of_month(time_tuple) 28 | for day in range(1, last + 1): 29 | print('{0:2d} '.format(day), end = ('\n' if wday_count % 7 == 0 else '')) 30 | wday_count += 1 31 | 32 | today = gmtime() 33 | print_title(today) 34 | print_days(today) 35 | 36 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH11/exercises/exercise2.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | file = input('檔案位置:') 4 | encoding = input('檔案編碼:') 5 | 6 | with open(file, encoding=encoding) as f: 7 | html = ''.join(f.readlines()) 8 | 9 | with open(file, 'w', encoding=encoding) as f: 10 | f.write(re.sub(r'()', r'\1', html)) 11 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH11/exercises/exercise3.py: -------------------------------------------------------------------------------- 1 | from urllib.parse import urlencode 2 | from urllib.request import urlopen 3 | import json 4 | import os 5 | import datetime 6 | 7 | def download(date: str, file: str): 8 | params = urlencode({'response': 'json', 'date': date}) 9 | url = f'http://www.twse.com.tw/indicesReport/MI_5MINS_HIST?{params}' 10 | with urlopen(url) as resp, open(file, 'w', encoding='UTF-8') as f: 11 | f.write(resp.read().decode('UTF-8')) 12 | 13 | def load(file: str): 14 | with open(file, 'r', encoding='UTF-8') as f: 15 | return json.load(f) 16 | 17 | def show(history: dict): 18 | print(history['title'], end='\n\n') 19 | for field in history['fields']: 20 | print(f'{field:<8}\t', end='') 21 | 22 | print() 23 | for d in history['data']: 24 | print('\t'.join(d)) 25 | 26 | 27 | year = input('西元:') 28 | month = input('月份:') 29 | date = f'{year}{month:0>2}01' 30 | file = f'{date}.json' 31 | today = datetime.date.today() 32 | 33 | if not os.path.exists(file) or (today.year == int(year) and today.month == int(month)): 34 | download(date, file) 35 | 36 | show(load(file)) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH12/exercise/exercise1.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from dvdlib1 import ContentRating, Customer, Movie, Rental 3 | 4 | class CustomerTestCase(unittest.TestCase): 5 | def setUp(self): 6 | self.customer = Customer('test') 7 | movies = [ 8 | Movie('ABC', ContentRating.new_release), 9 | Movie('XYZ', ContentRating.regular), 10 | Movie('123', ContentRating.children) 11 | ] 12 | for movie in movies: 13 | self.customer.add_rental(Rental(movie, 7)) 14 | 15 | def test_statement(self): 16 | statement = self.customer.statement() 17 | self.assertTrue( 18 | 'ABC 21' in statement and 19 | 'XYZ 9.5' in statement and 20 | '123 7.5' in statement and 21 | 'Amount owed is 38.0' in statement and 22 | 'You earned 4 frequent renter points' in statement 23 | ) 24 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH12/exercise/exercise2.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from dvdlib2 import ContentRating, Customer, Movie, Rental 3 | 4 | class CustomerTestCase(unittest.TestCase): 5 | def setUp(self): 6 | self.customer = Customer('test') 7 | movies = [ 8 | Movie('ABC', ContentRating.new_release), 9 | Movie('XYZ', ContentRating.regular), 10 | Movie('123', ContentRating.children) 11 | ] 12 | for movie in movies: 13 | self.customer.add_rental(Rental(movie, 7)) 14 | 15 | def test_statement(self): 16 | statement = self.customer.statement() 17 | self.assertTrue( 18 | 'ABC 21' in statement and 19 | 'XYZ 9.5' in statement and 20 | '123 7.5' in statement and 21 | 'Amount owed is 38.0' in statement and 22 | 'You earned 4 frequent renter points' in statement 23 | ) 24 | 25 | def test_get_total_charge(self): 26 | total = self.customer.get_total_charge() 27 | self.assertEqual(38.0, total) 28 | 29 | def test_get_total_freq_renter_points(self): 30 | total_freq_renter_points = self.customer.get_total_freq_renter_points() 31 | self.assertEqual(4, total_freq_renter_points) -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH13/exercise/exercise1.py: -------------------------------------------------------------------------------- 1 | import pool, threading 2 | 3 | class Service: # 模擬服務端 4 | def __init__(self): 5 | self.pool = pool.WorkerThreadPool() 6 | 7 | def accept(self, task): 8 | self.pool.apply(task) 9 | 10 | class Client: # 模擬客戶端 11 | def __init__(self, service): 12 | self.service = service 13 | 14 | def run(self): 15 | while True: 16 | self.service.accept(lambda: print('執行客戶請求...XD')) 17 | 18 | service = Service() 19 | for i in range(5): 20 | client = Client(service) 21 | threading.Thread(target = client.run).start() 22 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH13/exercise/pool.py: -------------------------------------------------------------------------------- 1 | import threading, time 2 | 3 | class WorkerThread(threading.Thread): 4 | def __init__(self): 5 | super().__init__() 6 | self.is_continue = True 7 | self.task = None 8 | self.cond = threading.Condition() 9 | 10 | def idle(self): 11 | return self.task == None 12 | 13 | def apply(self, task): 14 | with self.cond: 15 | if self.idle(): 16 | self.task = task 17 | self.cond.notify() 18 | 19 | def run(self): 20 | with self.cond: 21 | while self.is_continue: 22 | self.cond.wait() 23 | self.task() 24 | self.task = None 25 | 26 | def terminate(self): 27 | self.is_continue = False 28 | self.apply(WorkerThread.nope) 29 | 30 | @staticmethod 31 | def nope(): 32 | pass 33 | 34 | 35 | class WorkerThreadPool: 36 | def __init__(self): 37 | self.workers = [] 38 | self.lock = threading.RLock() 39 | 40 | def apply(self, task): 41 | with self.lock: 42 | if self.fail_to_allocate(task): 43 | worker = self.create_worker() 44 | worker.apply(task) 45 | 46 | def fail_to_allocate(self, task): 47 | for worker in self.workers: 48 | if worker.idle(): 49 | worker.apply(task) 50 | return False 51 | return True 52 | 53 | def create_worker(self): 54 | worker = WorkerThread() 55 | worker.start() 56 | self.workers.append(worker) 57 | time.sleep(1) # 給點時間啟動 58 | return worker 59 | 60 | def clean_idle(self): 61 | with self.lock: 62 | for worker in self.workers: 63 | if worker.idle(): 64 | self.workers.remove(worker) 65 | worker.terminate() 66 | 67 | -------------------------------------------------------------------------------- /samples-labs-exercises/exercises/CH14/exercise/total_ordering_demo.py: -------------------------------------------------------------------------------- 1 | from exercise1 import total_ordering 2 | 3 | @total_ordering 4 | class Some: 5 | def __init__(self, x): 6 | self.x = x 7 | def __eq__(self, other): 8 | return self.x == other.x 9 | def __gt__(self, other): 10 | return self.x > other.x 11 | 12 | s1 = Some(10) 13 | s2 = Some(20) 14 | print(s1 >= s2) 15 | print(s1 <= s2) 16 | 17 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH05/object-oriented1/bank.py: -------------------------------------------------------------------------------- 1 | def account(name: str, number: str, balance: float) -> dict: 2 | return {'name': name, 'number': number, 'balance': balance} 3 | 4 | def deposit(acct, amount): 5 | if amount <= 0: 6 | print('存款金額不得為負') 7 | else: 8 | acct['balance'] += amount 9 | 10 | def withdraw(acct, amount): 11 | if amount > acct['balance']: 12 | print('餘額不足') 13 | else: 14 | acct['balance'] -= amount 15 | 16 | def desc(acct): 17 | return f'Account:{acct}' -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH05/object-oriented1/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.account('Justin', '123-4567', 1000) 4 | bank.deposit(acct, 500) 5 | bank.withdraw(acct, 200) 6 | 7 | # 顯示 Account:{'balance': 1300, 'number': '123-4567', 'name': 'Justin'} 8 | print(bank.desc(acct)) -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH05/object-oriented1/workspace.pth: -------------------------------------------------------------------------------- 1 | C:\workspace\libs 2 | C:\workspace\third-party 3 | C:\workspace\devs -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH05/object-oriented2/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | pass 3 | 4 | def account(name, number, balance): 5 | acct = Account() 6 | acct.name = name 7 | acct.number = number 8 | acct.balance = balance 9 | return acct 10 | 11 | def deposit(acct, amount): 12 | if amount <= 0: 13 | print('存款金額不得為負') 14 | else: 15 | acct.balance += amount 16 | 17 | def withdraw(acct, amount): 18 | if amount > acct.balance: 19 | print('餘額不足') 20 | else: 21 | acct.balance -= amount 22 | 23 | def desc(acct): 24 | return f"Account('{acct.name}', '{acct.number}', {acct.balance})" 25 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH05/object-oriented2/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.account('Justin', '123-4567', 1000) 4 | bank.deposit(acct, 500) 5 | bank.withdraw(acct, 200) 6 | 7 | # 顯示 Account(Justin, 123-4567, 1300) 8 | print(bank.desc(acct)) -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH05/object-oriented3/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name: str, number: str, balance: float) -> None: 3 | self.name = name 4 | self.number = number 5 | self.balance = balance 6 | 7 | def deposit(self, amount: float): 8 | if amount <= 0: 9 | print('存款金額不得為負') 10 | else: 11 | self.balance += amount 12 | 13 | def withdraw(self, amount: float): 14 | if amount > self.balance: 15 | print('餘額不足') 16 | else: 17 | self.balance -= amount 18 | 19 | def __str__(self): 20 | return f"Account('{self.name}', '{self.number}', {self.balance})" 21 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH05/object-oriented3/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.Account('Justin', '123-4567', 1000) 4 | acct.deposit(500) 5 | acct.withdraw(200) 6 | # 顯示 Account('Justin', '123-4567', 1300) 7 | print(acct) 8 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH05/object-oriented4/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name: str, number: str, balance: float) -> None: 3 | self.__name = name 4 | self.__number = number 5 | self.__balance = balance 6 | 7 | def deposit(self, amount: float): 8 | if amount <= 0: 9 | print('存款金額不得為負') 10 | else: 11 | self.__balance += amount 12 | 13 | def withdraw(self, amount: float): 14 | if amount > self.__balance: 15 | print('餘額不足') 16 | else: 17 | self.__balance -= amount 18 | 19 | def __str__(self): 20 | return f"Account('{self.__name}', '{self.__number}', {self.__balance})" 21 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH05/object-oriented4/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.Account('Justin', '123-4567', 1000) 4 | acct.deposit(500) 5 | acct.withdraw(200) 6 | 7 | # 顯示 Account('Justin', '123-4567', 1300) 8 | print(acct) 9 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/game1/rpg.py: -------------------------------------------------------------------------------- 1 | class SwordsMan: 2 | def __init__(self, name: str, level: int, blood: int) -> None: 3 | self.name = name # 角色名稱 4 | self.level = level # 角色等級 5 | self.blood = blood # 角色血量 6 | 7 | def fight(self): 8 | print('揮劍攻擊') 9 | 10 | def __str__(self): 11 | return "('{name}', {level}, {blood})".format(**vars(self)) 12 | 13 | def __repr__(self): 14 | return self.__str__() 15 | 16 | class Magician: 17 | def __init__(self, name: str, level: int, blood: int) -> None: 18 | self.name = name # 角色名稱 19 | self.level = level # 角色等級 20 | self.blood = blood # 角色血量 21 | 22 | def fight(self): 23 | print('魔法攻擊') 24 | 25 | def cure(self): 26 | print('魔法治療') 27 | 28 | def __str__(self): 29 | return "('{name}', {level}, {blood})".format(**vars(self)) 30 | 31 | def __repr__(self): 32 | return self.__str__() 33 | 34 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/game2/rpg.py: -------------------------------------------------------------------------------- 1 | class Role: 2 | def __init__(self, name: str, level: int, blood: int) -> None: 3 | self.name = name # 角色名稱 4 | self.level = level # 角色等級 5 | self.blood = blood # 角色血量 6 | 7 | def __str__(self): 8 | return "('{name}', {level}, {blood})".format(**vars(self)) 9 | 10 | def __repr__(self): 11 | return self.__str__() 12 | 13 | class SwordsMan(Role): 14 | def fight(self): 15 | print('揮劍攻擊') 16 | 17 | class Magician(Role): 18 | def fight(self): 19 | print('魔法攻擊') 20 | 21 | def cure(self): 22 | print('魔法治療') 23 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/game2/rpg_demo.py: -------------------------------------------------------------------------------- 1 | import rpg 2 | 3 | swordsman = rpg.SwordsMan('Justin', 1, 200) 4 | print('SwordsMan', swordsman) 5 | 6 | magician = rpg.Magician('Monica', 1, 100) 7 | print('Magician', magician) -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/game3/rpg.py: -------------------------------------------------------------------------------- 1 | class Role: 2 | def __init__(self, name: str, level: int, blood: int) -> None: 3 | self.name = name # 角色名稱 4 | self.level = level # 角色等級 5 | self.blood = blood # 角色血量 6 | 7 | def __str__(self): 8 | return "('{name}', {level}, {blood})".format(**vars(self)) 9 | 10 | def __repr__(self): 11 | return self.__str__() 12 | 13 | class SwordsMan(Role): 14 | def fight(self): 15 | print('揮劍攻擊') 16 | 17 | class Magician(Role): 18 | def fight(self): 19 | print('魔法攻擊') 20 | 21 | def cure(self): 22 | print('魔法治療') 23 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/game3/rpg_demo.py: -------------------------------------------------------------------------------- 1 | import rpg 2 | 3 | def draw_fight(role): 4 | print(role, end = '') 5 | role.fight() 6 | 7 | swordsman = rpg.SwordsMan('Justin', 1, 200) 8 | draw_fight(swordsman) 9 | 10 | magician = rpg.Magician('Monica', 1, 100) 11 | draw_fight(magician) 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/game4/rpg.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta, abstractmethod 2 | 3 | class Role(metaclass=ABCMeta): 4 | def __init__(self, name: str, level: int, blood: int) -> None: 5 | self.name = name # 角色名稱 6 | self.level = level # 角色等級 7 | self.blood = blood # 角色血量 8 | 9 | @abstractmethod 10 | def fight(self): 11 | pass 12 | 13 | def __str__(self): 14 | return "('{name}', {level}, {blood})".format(**vars(self)) 15 | 16 | def __repr__(self): 17 | return self.__str__() 18 | 19 | class SwordsMan(Role): 20 | def fight(self): 21 | print('揮劍攻擊') 22 | 23 | def __str__(self): 24 | return f'SwordsMan{super().__str__()}' 25 | 26 | class Magician(Role): 27 | def fight(self): 28 | print('魔法攻擊') 29 | 30 | def cure(self): 31 | print('魔法治療') 32 | 33 | def __str__(self): 34 | return f'Magician{super().__str__()}' -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/game4/rpg_demo.py: -------------------------------------------------------------------------------- 1 | from rpg import Role, SwordsMan, Magician 2 | 3 | def draw_fight(role: Role): 4 | print(role, end = '') 5 | role.fight() 6 | 7 | swordsman = SwordsMan('Justin', 1, 200) 8 | draw_fight(swordsman) 9 | 10 | magician = Magician('Monica', 1, 100) 11 | draw_fight(magician) 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/inheritance/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name: str, number: str, balance: float) -> None: 3 | self.__name = name 4 | self.__number = number 5 | self.__balance = balance 6 | 7 | def deposit(self, amount: float): 8 | if amount <= 0: 9 | print('存款金額不得為負') 10 | else: 11 | self.__balance += amount 12 | 13 | def withdraw(self, amount: float): 14 | if amount > self.__balance: 15 | print('餘額不足') 16 | else: 17 | self.__balance -= amount 18 | 19 | @property 20 | def name(self) -> str: 21 | return self.__name 22 | 23 | @property 24 | def number(self) -> str: 25 | return self.__number 26 | 27 | @property 28 | def balance(self) -> float: 29 | return self.__balance 30 | 31 | def __str__(self): 32 | return f"Account('{self.__name}', '{self.__number}', {self.__balance})" 33 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/inheritance/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | savingsAcct = bank.SavingsAccount('Justin', '123-4567', 1000, 0.02) 4 | 5 | savingsAcct.deposit(500) 6 | savingsAcct.withdraw(200) 7 | 8 | print(savingsAcct) -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH06/inheritance/xabc_demo.py: -------------------------------------------------------------------------------- 1 | class Ball: 2 | def __init__(self, radius): 3 | self.radius = radius 4 | 5 | def __eq__(self, other): 6 | return hasattr(other, 'radius') and self.radius == other.radius 7 | 8 | def __gt__(self, other): 9 | return hasattr(other, 'radius') and self.radius > other.radius 10 | 11 | def __ge__(self, other): 12 | return self > other or self == other 13 | 14 | def __lt__(self, other): 15 | return not (self > other and self == other) 16 | 17 | def __le__(self, other): 18 | return (not self >= other) or self == other 19 | 20 | def __ne__(self, other): 21 | return not self == other 22 | 23 | b1 = Ball(10) 24 | b2 = Ball(20) 25 | b3 = Ball(10) 26 | 27 | print(b1 > b2) 28 | print(b1 <= b2) 29 | print(b1 == b2) 30 | 31 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH07/exceptions/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name: str, number: str, balance: float) -> None: 3 | self.name = name 4 | self.number = number 5 | self.balance = balance 6 | 7 | def deposit(self, amount: float): 8 | if amount <= 0: 9 | print('存款金額不得為負') 10 | else: 11 | self.balance += amount 12 | 13 | def withdraw(self, amount: float): 14 | if amount > self.balance: 15 | print('餘額不足') 16 | else: 17 | self.balance -= amount 18 | 19 | def __str__(self): 20 | return f"Account('{self.name}', '{self.number}', {self.balance})" 21 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH07/exceptions/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.Account('Justin', '123-4567', 1000) 4 | 5 | def withdraw(acct): 6 | try: 7 | acct.withdraw(2000) 8 | except bank.BankingException as ex: 9 | print(ex) 10 | print('你要進行借貸嗎?') 11 | # 其他借貸流程 12 | 13 | withdraw(acct) 14 | 15 | 16 | def deposit(acct): 17 | try: 18 | acct.deposit(-500) 19 | except ValueError as err: 20 | import logging, datetime 21 | logging.getLogger(__name__).log( 22 | logging.ERROR, 23 | 'Logging: {time}, {number}, {message}'.format( 24 | time = datetime.datetime.now(), 25 | number = acct.number, 26 | message = err 27 | ) 28 | ) 29 | raise bank.BankingException('輸入金額為負的行為已記錄') from err 30 | 31 | deposit(acct) 32 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH09/collection_advanced/chainable.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Callable 2 | from collections import UserList 3 | 4 | Consume = Callable[[Any], None] 5 | Predicate = Callable[[Any], bool] 6 | Mapper = Callable[[Any], Any] 7 | 8 | class MthChainList(UserList): 9 | def for_each(self, consume: Consume): 10 | for elem in self: 11 | consume(elem) 12 | 13 | def filter(self, predicate: Predicate): 14 | return MthChainList(elem for elem in self if predicate(elem)) 15 | 16 | def map(self, mapper: Mapper): 17 | return MthChainList(mapper(elem) for elem in self) 18 | 19 | lt = MthChainList(['a', 'B', 'c', 'd', 'E', 'f', 'G']) 20 | lt.filter(str.islower).map(str.upper).for_each(print) -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH09/collection_advanced/chainmap.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, Hashable, Optional 2 | 3 | class ChainMap: 4 | def __init__(self, *tulp: Dict) -> None: 5 | self.dictLt = list(tulp) 6 | 7 | def lookup(self, key: Hashable) -> Optional[Dict]: 8 | for m in self.dictLt: 9 | if key in m: 10 | return m 11 | return None 12 | 13 | def __getitem__(self, key: Hashable) -> Any: 14 | m = self.lookup(key) 15 | if m: 16 | return m[key] 17 | else: 18 | raise KeyError(key) 19 | 20 | def __setitem__(self, key: Hashable, value: Any): 21 | m = self.lookup(key) 22 | if m: 23 | m[key] = value 24 | else: 25 | self.dictLt.append({key: value}) 26 | 27 | def __delitem__(self, key: Hashable): 28 | m = self.lookup(key) 29 | if m: 30 | del m[key] 31 | if len(m) == 0: 32 | self.dictLt.remove(m) 33 | else: 34 | raise KeyError(key) 35 | 36 | 37 | c = ChainMap({'A' : 'Justin'}, {'A' : 'Monica', 'B' : 'Irene'}) 38 | print(c.dictLt) 39 | 40 | print(c['A']) 41 | 42 | c['A'] = 'caterpillar' 43 | print(c.dictLt) 44 | 45 | del c['A'] 46 | print(c.dictLt) -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH09/collection_advanced/chainmap2.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Set, Dict, Hashable, Optional 2 | from collections.abc import MutableMapping 3 | 4 | class ChainMap(MutableMapping): 5 | def __init__(self, *tulp: Dict) -> None: 6 | self.dictLt = list(tulp) 7 | 8 | def lookup(self, key: Hashable) -> Optional[Dict]: 9 | for m in self.dictLt: 10 | if key in m: 11 | return m 12 | return None 13 | 14 | 15 | # 完成未實作之協定 16 | 17 | def key_set(self) -> Set: 18 | keys: Set = set() 19 | for m in self.dictLt: 20 | keys.update(m.keys()) 21 | return keys 22 | 23 | def __iter__(self): 24 | return iter(self.key_set()) 25 | 26 | def __len__(self): 27 | return len(self.key_set()) 28 | 29 | 30 | c = ChainMap({'A' : 'Justin'}, {'A' : 'Monica', 'B' : 'Irene'}) 31 | print(list(c)) 32 | print(len(c)) 33 | print(c.pop('A')) 34 | print(list(c.keys())) 35 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH09/collection_advanced/counter.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from operator import itemgetter 3 | 4 | def count(text): 5 | counter = defaultdict(int) 6 | for c in text: 7 | counter[c] += 1 8 | return counter.items() 9 | 10 | text = 'Your right brain has nothing left.' 11 | for c, n in sorted(count(text), key = itemgetter(0)): 12 | print(c, ':', n) -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH09/collection_advanced/group.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | names = ['Justin', 'Monica', 'Irene', 'Pika', 'caterpillar'] 4 | 5 | grouped_by_len = defaultdict(list) 6 | 7 | for name in names: 8 | key = len(name) 9 | grouped_by_len[key].append(name) 10 | 11 | for length in grouped_by_len: 12 | print(length, grouped_by_len[length]) 13 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH09/object_protocols/orderable_types.py: -------------------------------------------------------------------------------- 1 | class Customer: 2 | def __init__(self, name, symbol, age): 3 | self.name = name 4 | self.symbol = symbol 5 | self.age = age 6 | 7 | def __lt__(self, other): 8 | return self.name < other.name 9 | 10 | def __str__(self): 11 | return "Customer('{name}', '{symbol}', {age})".format(**vars(self)) 12 | 13 | def __repr__(self): 14 | return self.__str__() 15 | 16 | customers = [ 17 | Customer('Justin', 'A', 40), 18 | Customer('Irene', 'C', 8), 19 | Customer('Monica', 'B', 37) 20 | ] 21 | 22 | print(sorted(customers)) -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH09/object_protocols/point_demo.py: -------------------------------------------------------------------------------- 1 | class Point: 2 | def __init__(self, x: int, y: int) -> None: 3 | self.x = x 4 | self.y = y 5 | 6 | def __eq__(self, that): 7 | if hasattr(that, 'x') and hasattr(that, 'y'): 8 | return self.x == that.x and self.y == that.y 9 | return False 10 | 11 | def __hash__(self): 12 | return 41 * (41 + self.x) + self.y 13 | 14 | def __str__(self): 15 | return self.__repr__() 16 | 17 | def __repr__(self): 18 | return 'Point({}, {})'.format(self.x, self.y) 19 | 20 | p1 = Point(1, 1) 21 | p2 = Point(2, 2) 22 | p3 = Point(1, 1) 23 | ps = {p1, p2, p3} 24 | print(ps) 25 | 26 | p2.x = 1 27 | p2.y = 1 28 | print(ps) 29 | 30 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH09/object_protocols/test.py: -------------------------------------------------------------------------------- 1 | names = ['Justin', 'Monica', 'Irene', 'Pika', 'caterpillar'] 2 | 3 | grouped_by_len = {} 4 | for name in names: 5 | key = len(name) 6 | if key not in grouped_by_len: 7 | grouped_by_len[key] = [] 8 | grouped_by_len[key].append(name) 9 | 10 | for length in grouped_by_len: 11 | print(length, grouped_by_len[length]) 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH09/object_protocols/tools.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | class Repeat: 4 | def __init__(self, elem: Any, n: int) -> None: 5 | self.elem = elem 6 | self.n = n 7 | 8 | def __iter__(self): 9 | elem = self.elem 10 | n = self.n 11 | 12 | class _Iter: 13 | def __init__(self): 14 | self.count = 0 15 | 16 | def __next__(self): 17 | if self.count < n: 18 | self.count += 1 19 | return elem 20 | raise StopIteration 21 | 22 | def __iter__(self): 23 | return self 24 | 25 | return _Iter() 26 | 27 | for elem in Repeat('A', 5): 28 | print(elem, end = '') 29 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH10/object_serialization/dvdlib_pickle.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | 3 | class DVD: 4 | def __init__(self, title: str, year: int, duration: int, director: str) -> None: 5 | self.title = title 6 | self.year = year 7 | self.duration = duration 8 | self.director = director 9 | self.filename = self.title.replace(' ', '_') + '.pickle' 10 | 11 | 12 | # 實作 save 與 load 13 | 14 | def __str__(self): 15 | return repr(self) 16 | 17 | def __repr__(self): 18 | return "DVD('{0}', {1}, {2}, '{3}')".format( 19 | self.title, self.year, self.duration, self.director) 20 | 21 | dvd1 = DVD('Birds', 2018, 8, 'Justin Lin') 22 | dvd1.save() 23 | dvd2 = DVD.load('Birds.pickle') 24 | print(dvd2) 25 | -------------------------------------------------------------------------------- /samples-labs-exercises/labs/CH10/object_serialization/dvdlib_shelve.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | import shelve 3 | 4 | class DVD: 5 | def __init__(self, title: str, year: int, duration: int, director: str) -> None: 6 | self.title = title 7 | self.year = year 8 | self.duration = duration 9 | self.director = director 10 | 11 | def __str__(self): 12 | return repr(self) 13 | 14 | def __repr__(self): 15 | return ("DVD('{title}', {year}, {duration}, '{director}')" 16 | .format(**vars(self))) 17 | 18 | class DvdDao: 19 | def __init__(self, dbname: str) -> None: 20 | self.dbname = dbname 21 | 22 | # 實作 save、all、load、remove 23 | 24 | 25 | 26 | dao = DvdDao('dvdlib.shelve') 27 | dvd1 = DVD('Birds', 2018, 1, 'Justin Lin') 28 | dvd2 = DVD('Dogs', 2018, 7, 'Monica Huang') 29 | 30 | dao.save(dvd1) 31 | dao.save(dvd2) 32 | print(dao.all()) 33 | print(dao.load('Birds')) 34 | dao.remove('Birds') 35 | print(dao.all()) 36 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/mysite/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite/mysite/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/mysite/urls.py: -------------------------------------------------------------------------------- 1 | """mysite URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.1/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: path('', 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: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | 19 | urlpatterns = [ 20 | path('admin/', admin.site.urls), 21 | ] 22 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite 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/2.1/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', 'mysite.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/polls/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite/polls/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/polls/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/polls/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PollsConfig(AppConfig): 5 | name = 'polls' 6 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/polls/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2018-09-01 06:25 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Choice', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('choice_text', models.CharField(max_length=200)), 20 | ('votes', models.IntegerField(default=0)), 21 | ], 22 | ), 23 | migrations.CreateModel( 24 | name='Question', 25 | fields=[ 26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 27 | ('question_text', models.CharField(max_length=200)), 28 | ('pub_date', models.DateTimeField(verbose_name='date published')), 29 | ], 30 | ), 31 | migrations.AddField( 32 | model_name='choice', 33 | name='question', 34 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question'), 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/polls/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite/polls/migrations/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/polls/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Question(models.Model): 4 | question_text = models.CharField(max_length=200) 5 | pub_date = models.DateTimeField('date published') 6 | 7 | def was_published_recently(self): 8 | return self.pub_date >= timezone.now() - datetime.timedelta(days=1) 9 | 10 | def __str__(self): 11 | return self.question_text 12 | 13 | class Choice(models.Model): 14 | question = models.ForeignKey(Question, on_delete=models.CASCADE) 15 | choice_text = models.CharField(max_length=200) 16 | votes = models.IntegerField(default=0) 17 | 18 | def __str__(self): 19 | return self.choice_text 20 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/polls/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite/polls/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/mysite/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite2/mysite/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/mysite/urls.py: -------------------------------------------------------------------------------- 1 | """mysite URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.1/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: path('', 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: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | from django.conf.urls import url, include 19 | 20 | urlpatterns = [ 21 | url(r'^polls/', include('polls.urls')), 22 | path('admin/', admin.site.urls), 23 | ] 24 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite 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/2.1/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', 'mysite.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/polls/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite2/polls/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/polls/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/polls/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PollsConfig(AppConfig): 5 | name = 'polls' 6 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/polls/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2018-09-01 06:25 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Choice', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('choice_text', models.CharField(max_length=200)), 20 | ('votes', models.IntegerField(default=0)), 21 | ], 22 | ), 23 | migrations.CreateModel( 24 | name='Question', 25 | fields=[ 26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 27 | ('question_text', models.CharField(max_length=200)), 28 | ('pub_date', models.DateTimeField(verbose_name='date published')), 29 | ], 30 | ), 31 | migrations.AddField( 32 | model_name='choice', 33 | name='question', 34 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question'), 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/polls/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite2/polls/migrations/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/polls/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Question(models.Model): 4 | question_text = models.CharField(max_length=200) 5 | pub_date = models.DateTimeField('date published') 6 | 7 | def was_published_recently(self): 8 | return self.pub_date >= timezone.now() - datetime.timedelta(days=1) 9 | 10 | def __str__(self): 11 | return self.question_text 12 | 13 | class Choice(models.Model): 14 | question = models.ForeignKey(Question, on_delete=models.CASCADE) 15 | choice_text = models.CharField(max_length=200) 16 | votes = models.IntegerField(default=0) 17 | 18 | def __str__(self): 19 | return self.choice_text 20 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/polls/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/polls/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | # ex: /polls/ 7 | url(r'^$', views.index, name='index'), 8 | # ex: /polls/5/ 9 | url(r'^(?P[0-9]+)/$', views.detail, name='detail'), 10 | # ex: /polls/5/results/ 11 | url(r'^(?P[0-9]+)/results/$', views.results, name='results'), 12 | # ex: /polls/5/vote/ 13 | url(r'^(?P[0-9]+)/vote/$', views.vote, name='vote'), 14 | ] 15 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite2/polls/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | 3 | def index(request): 4 | return HttpResponse('Hello, world. You\'re at the poll index.') 5 | 6 | def detail(request, question_id): 7 | return HttpResponse( 8 | 'You\'re looking at question {id}.'.format(id = question_id)) 9 | 10 | def results(request, question_id): 11 | return HttpResponse( 12 | 'You\'re looking at the results of question {id}.'.format(id = question_id)) 13 | 14 | def vote(request, question_id): 15 | return HttpResponse( 16 | 'You\'re voting on question {id}.'.format(id = question_id)) 17 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/mysite/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite3/mysite/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/mysite/urls.py: -------------------------------------------------------------------------------- 1 | """mysite URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.1/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: path('', 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: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | from django.conf.urls import url, include 19 | 20 | urlpatterns = [ 21 | url(r'^polls/', include('polls.urls')), 22 | path('admin/', admin.site.urls), 23 | ] 24 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite 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/2.1/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', 'mysite.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite3/polls/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PollsConfig(AppConfig): 5 | name = 'polls' 6 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2018-09-01 06:25 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Choice', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('choice_text', models.CharField(max_length=200)), 20 | ('votes', models.IntegerField(default=0)), 21 | ], 22 | ), 23 | migrations.CreateModel( 24 | name='Question', 25 | fields=[ 26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 27 | ('question_text', models.CharField(max_length=200)), 28 | ('pub_date', models.DateTimeField(verbose_name='date published')), 29 | ], 30 | ), 31 | migrations.AddField( 32 | model_name='choice', 33 | name='question', 34 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question'), 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite3/polls/migrations/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Question(models.Model): 4 | question_text = models.CharField(max_length=200) 5 | pub_date = models.DateTimeField('date published') 6 | 7 | def was_published_recently(self): 8 | return self.pub_date >= timezone.now() - datetime.timedelta(days=1) 9 | 10 | def __str__(self): 11 | return self.question_text 12 | 13 | class Choice(models.Model): 14 | question = models.ForeignKey(Question, on_delete=models.CASCADE) 15 | choice_text = models.CharField(max_length=200) 16 | votes = models.IntegerField(default=0) 17 | 18 | def __str__(self): 19 | return self.choice_text 20 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/templates/polls/detail.html: -------------------------------------------------------------------------------- 1 |

{{ question.question_text }}

2 |
    3 | {% for choice in question.choice_set.all %} 4 |
  • {{ choice.choice_text }}
  • 5 | {% endfor %} 6 |
7 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/templates/polls/index.html: -------------------------------------------------------------------------------- 1 | {% if latest_question_list %} 2 | 7 | {% else %} 8 |

No polls are available.

9 | {% endif %} 10 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | # ex: /polls/ 7 | url(r'^$', views.index, name='index'), 8 | # ex: /polls/5/ 9 | url(r'^(?P[0-9]+)/$', views.detail, name='detail'), 10 | # ex: /polls/5/results/ 11 | url(r'^(?P[0-9]+)/results/$', views.results, name='results'), 12 | # ex: /polls/5/vote/ 13 | url(r'^(?P[0-9]+)/vote/$', views.vote, name='vote'), 14 | ] 15 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite3/polls/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse 2 | from django.template import loader 3 | 4 | from django.http import Http404 5 | from django.shortcuts import render 6 | 7 | from .models import Question 8 | 9 | def index(request): 10 | latest_question_list = Question.objects.order_by('-pub_date')[:5] 11 | template = loader.get_template('polls/index.html') 12 | context = { 13 | 'latest_question_list': latest_question_list, 14 | } 15 | return HttpResponse(template.render(context, request)) 16 | 17 | def detail(request, question_id): 18 | try: 19 | question = Question.objects.get(pk=question_id) 20 | except Question.DoesNotExist: 21 | raise Http404("Question does not exist") 22 | return render(request, 'polls/detail.html', {'question': question}) 23 | 24 | def results(request, question_id): 25 | return HttpResponse( 26 | 'You\'re looking at the results of question {id}.'.format(id = question_id)) 27 | 28 | def vote(request, question_id): 29 | return HttpResponse( 30 | 'You\'re voting on question {id}.'.format(id = question_id)) 31 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/mysite/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite4/mysite/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/mysite/urls.py: -------------------------------------------------------------------------------- 1 | """mysite URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.1/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: path('', 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: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | from django.conf.urls import url, include 19 | 20 | urlpatterns = [ 21 | url(r'^polls/', include('polls.urls')), 22 | path('admin/', admin.site.urls), 23 | ] 24 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/mysite/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for mysite 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/2.1/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', 'mysite.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite4/polls/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class PollsConfig(AppConfig): 5 | name = 'polls' 6 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2018-09-01 06:25 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Choice', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('choice_text', models.CharField(max_length=200)), 20 | ('votes', models.IntegerField(default=0)), 21 | ], 22 | ), 23 | migrations.CreateModel( 24 | name='Question', 25 | fields=[ 26 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 27 | ('question_text', models.CharField(max_length=200)), 28 | ('pub_date', models.DateTimeField(verbose_name='date published')), 29 | ], 30 | ), 31 | migrations.AddField( 32 | model_name='choice', 33 | name='question', 34 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.Question'), 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/B/mysite4/polls/migrations/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Question(models.Model): 4 | question_text = models.CharField(max_length=200) 5 | pub_date = models.DateTimeField('date published') 6 | 7 | def was_published_recently(self): 8 | return self.pub_date >= timezone.now() - datetime.timedelta(days=1) 9 | 10 | def __str__(self): 11 | return self.question_text 12 | 13 | class Choice(models.Model): 14 | question = models.ForeignKey(Question, on_delete=models.CASCADE) 15 | choice_text = models.CharField(max_length=200) 16 | votes = models.IntegerField(default=0) 17 | 18 | def __str__(self): 19 | return self.choice_text 20 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/templates/polls/detail.html: -------------------------------------------------------------------------------- 1 |

{{ question.question_text }}

2 | 3 | {% if error_message %}

{{ error_message }}

{% endif %} 4 | 5 |
6 | {% csrf_token %} 7 | {% for choice in question.choice_set.all %} 8 | 9 |
10 | {% endfor %} 11 | 12 |
13 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/templates/polls/index.html: -------------------------------------------------------------------------------- 1 | {% if latest_question_list %} 2 | 7 | {% else %} 8 |

No polls are available.

9 | {% endif %} 10 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/templates/polls/results.html: -------------------------------------------------------------------------------- 1 |

{{ question.question_text }}

2 | 3 |
    4 | {% for choice in question.choice_set.all %} 5 |
  • {{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}
  • 6 | {% endfor %} 7 |
8 | 9 | Vote again? 10 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from . import views 4 | 5 | app_name = 'polls' 6 | 7 | urlpatterns = [ 8 | # ex: /polls/ 9 | url(r'^$', views.index, name='index'), 10 | # ex: /polls/5/ 11 | url(r'^(?P[0-9]+)/$', views.detail, name='detail'), 12 | # ex: /polls/5/results/ 13 | url(r'^(?P[0-9]+)/results/$', views.results, name='results'), 14 | # ex: /polls/5/vote/ 15 | url(r'^(?P[0-9]+)/vote/$', views.vote, name='vote'), 16 | ] 17 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/B/mysite4/polls/views.py: -------------------------------------------------------------------------------- 1 | from django.http import HttpResponse, HttpResponseRedirect 2 | from django.template import loader 3 | from django.shortcuts import get_object_or_404, render 4 | from django.urls import reverse 5 | from django.http import Http404 6 | 7 | from .models import Question 8 | 9 | def index(request): 10 | latest_question_list = Question.objects.order_by('-pub_date')[:5] 11 | template = loader.get_template('polls/index.html') 12 | context = { 13 | 'latest_question_list': latest_question_list, 14 | } 15 | return HttpResponse(template.render(context, request)) 16 | 17 | def detail(request, question_id): 18 | try: 19 | question = Question.objects.get(pk=question_id) 20 | except Question.DoesNotExist: 21 | raise Http404("Question does not exist") 22 | return render(request, 'polls/detail.html', {'question': question}) 23 | 24 | def results(request, question_id): 25 | question = get_object_or_404(Question, pk=question_id) 26 | return render(request, 'polls/results.html', {'question': question}) 27 | 28 | def vote(request, question_id): 29 | question = get_object_or_404(Question, pk=question_id) 30 | try: 31 | selected_choice = question.choice_set.get(pk=request.POST['choice']) 32 | except (KeyError, Choice.DoesNotExist): 33 | return render(request, 'polls/detail.html', { 34 | 'question': question, 35 | 'error_message': "You didn't select a choice.", 36 | }) 37 | else: 38 | selected_choice.votes += 1 39 | selected_choice.save() 40 | return HttpResponseRedirect(reverse('polls:results', args=(question.id,))) 41 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/C/bs_demo/download_imgs.py: -------------------------------------------------------------------------------- 1 | from urllib.request import urlopen 2 | from bs4 import BeautifulSoup 3 | 4 | def save(content, filename): 5 | with open(filename, 'wb') as dest: 6 | dest.write(content) 7 | 8 | def download(urls): 9 | for url in urls: 10 | with urlopen(url) as resp: 11 | content = resp.read() 12 | filename = url.split('/')[-1] 13 | save(content, filename) 14 | 15 | def download_imgs_from(url): 16 | with urlopen('https://openhome.cc/Gossip') as resp: 17 | soup = BeautifulSoup(resp.read(), 'html.parser') 18 | srcs = (img.get('src') for img in soup.find_all('img')) 19 | download(f'{url}/{src}' for src in srcs) 20 | 21 | download_imgs_from('https://openhome.cc/Gossip') 22 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello.py: -------------------------------------------------------------------------------- 1 | print('Hello World') 2 | 3 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello2.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/CH02/hello2.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello3.py: -------------------------------------------------------------------------------- 1 | import hello2 2 | print('今天要來點什麼不同的嗎?', hello2.name, '!') 3 | 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello4.py: -------------------------------------------------------------------------------- 1 | import sys 2 | print('哈囉!', sys.argv[1], '!') 3 | 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj/hello3.py: -------------------------------------------------------------------------------- 1 | import openhome.hello2 2 | print('今天要來點什麼不同的嗎?', openhome.hello2.name, '!') 3 | 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj/openhome/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/CH02/hello_prj/openhome/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj/openhome/hello2.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/CH02/hello_prj/openhome/hello2.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj2/hello3.py: -------------------------------------------------------------------------------- 1 | import openhome.hello2 as hello 2 | print('今天要來點什麼不同的嗎?', hello.name, '!') 3 | 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj2/openhome/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/CH02/hello_prj2/openhome/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj2/openhome/hello2.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/CH02/hello_prj2/openhome/hello2.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj3/hello.py: -------------------------------------------------------------------------------- 1 | from sys import argv 2 | print('哈囉!', argv[1], '!') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj4/openhome/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/CH02/hello_prj4/openhome/__init__.py -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj4/openhome/hello.py: -------------------------------------------------------------------------------- 1 | name = input('名稱:') 2 | print('哈囉!', name, '!') 3 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH02/hello_prj4/openhome/hi.py: -------------------------------------------------------------------------------- 1 | import sys 2 | print('嗨!', sys.argv[1]) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH03/operator/bitwise_demo.py: -------------------------------------------------------------------------------- 1 | print('AND運算:') 2 | print('0 AND 0 {:5d}'.format(0 & 0)) 3 | print('0 AND 1 {:5d}'.format(0 & 1)) 4 | print('1 AND 0 {:5d}'.format(1 & 0)) 5 | print('1 AND 1 {:5d}'.format(1 & 1)) 6 | 7 | print('\nOR運算:') 8 | print('0 OR 0 {:6d}'.format(0 | 0)) 9 | print('0 OR 1 {:6d}'.format(0 | 1)) 10 | print('1 OR 0 {:6d}'.format(1 | 0)) 11 | print('1 OR 1 {:6d}'.format(1 | 1)) 12 | 13 | print('\nXOR運算:') 14 | print('0 XOR 0 {:5d}'.format(0 ^ 0)) 15 | print('0 XOR 1 {:5d}'.format(0 ^ 1)) 16 | print('1 XOR 0 {:5d}'.format(1 ^ 0)) 17 | print('1 XOR 1 {:5d}'.format(1 ^ 1)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH03/operator/compare.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | str1 = sys.argv[1] 4 | str2 = sys.argv[2] 5 | 6 | print(f'"{str1}" > "{str2}" ? {str1 > str2}') 7 | print(f'"{str1}" == "{str2}" ? {str1 == str2}') 8 | print(f'"{str1}" < "{str2}" ? {str1 < str2}') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH03/operator/decimal_demo.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import decimal 3 | 4 | n1 = float(sys.argv[1]) 5 | n2 = float(sys.argv[2]) 6 | d1 = decimal.Decimal(sys.argv[1]) 7 | d2 = decimal.Decimal(sys.argv[2]) 8 | 9 | print('# 不使用 decimal') 10 | print(f'{n1} + {n2} = {n1 + n2}') 11 | print(f'{n1} - {n2} = {n1 - n2}') 12 | print(f'{n1} * {n2} = {n1 * n2}') 13 | print(f'{n1} / {n2} = {n1 / n2}') 14 | 15 | print() # 換行 16 | 17 | print(f'{d1} + {d2} = {d1 + d2}') 18 | print(f'{d1} - {d2} = {d1 - d2}') 19 | print(f'{d1} * {d2} = {d1 * d2}') 20 | print(f'{d1} / {d2} = {d1 / d2}') 21 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH03/operator/groups.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | admins = {'Justin', 'caterpillar'} 4 | users = set(sys.argv[1:]) 5 | print('站長:{}'.format(admins & users)) 6 | print('非站長:{}'.format(users - admins)) 7 | print('全部使用者:{}'.format(admins | users)) 8 | print('身份不重複使用者:{}'.format(admins ^ users)) 9 | print('站長群包括使用者群?{}'.format(admins > users)) 10 | print('使用者群包括站長群?{}'.format(admins < users)) 11 | 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH03/operator/shift_demo.py: -------------------------------------------------------------------------------- 1 | number = 1 2 | print('2 的 0 次方: ', number); 3 | print('2 的 1 次方: ', number << 1) 4 | print('2 的 2 次方: ', number << 2) 5 | print('2 的 3 次方: ', number << 3) 6 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH03/operator/uppers.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | str1 = sys.argv[1] 4 | str2 = sys.argv[2] 5 | 6 | print('兩個都大寫?', str1.isupper() and str2.isupper()) 7 | print('有一個大寫?', str1.isupper() or str2.isupper()) 8 | print('都不是大寫?', not (str1.isupper() or str2.isupper())) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/gcd.py: -------------------------------------------------------------------------------- 1 | print('輸入兩個數字...') 2 | 3 | m = int(input('數字 1: ')) 4 | n = int(input('數字 2: ')) 5 | 6 | while n != 0: 7 | r = m % n 8 | m = n 9 | n = r 10 | if m == 1: 11 | print('互質') 12 | break 13 | else: 14 | print("最大公因數:", m) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/gcd2.py: -------------------------------------------------------------------------------- 1 | print('輸入兩個數字...') 2 | 3 | m = int(input('數字 1: ')) 4 | n = int(input('數字 2: ')) 5 | 6 | while n != 0: 7 | r = m % n 8 | m = n 9 | n = r 10 | 11 | if m == 1: 12 | print('互質') 13 | else: 14 | print("最大公因數:", m) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/grade.py: -------------------------------------------------------------------------------- 1 | score = int(input('輸入分數:')) 2 | if score >= 90: 3 | print('得 A') 4 | elif 90 > score >= 80: 5 | print('得 B') 6 | elif 80 > score >= 70: 7 | print('得 C') 8 | elif 70 > score >= 60: 9 | print('得 D') 10 | else: 11 | print('不及格') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/hello.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | name = 'Guest' 4 | if len(sys.argv) > 1: 5 | name = sys.argv[1] 6 | print(f'Hello, {name}') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/is_odd.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | number = int(sys.argv[1]) 4 | if number % 2: 5 | print('f{number} 為奇數') 6 | else: 7 | print(f'{number} 為偶數') 8 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/is_odd2.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | number = int(sys.argv[1]) 4 | print('{} 為 {}'.format(number, '奇數' if number % 2 else '偶數')) 5 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/is_prime.py: -------------------------------------------------------------------------------- 1 | number = int(input('輸入數字:')) 2 | half = number // 2 3 | for num in range(2, half + 1): 4 | if number % num == 0: 5 | print(f'{number} 不是質數') 6 | break 7 | else: 8 | print(f'{number} 是質數') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/lucky5.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | number = 0 4 | while number != 5: 5 | number = random.randint(0, 9) 6 | print(number) 7 | if number == 5: 8 | print('I hit 5....Orz') 9 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/odds.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | odds = [arg for arg in sys.argv[1:] if int(arg) % 2] 4 | print(odds) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/show_uppers.py: -------------------------------------------------------------------------------- 1 | text = input('輸入一個字串:') 2 | for letter in text: 3 | if letter.isupper(): 4 | continue 5 | print(letter, end='') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/square.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | squares = [int(arg) ** 2 for arg in sys.argv[1:]] 4 | print(squares) 5 | 6 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/basic/uppers.py: -------------------------------------------------------------------------------- 1 | import sys 2 | for arg in sys.argv: 3 | print(arg.upper()) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/filter_demo.py: -------------------------------------------------------------------------------- 1 | def filter_lt(predicate, lt): 2 | result = [] 3 | for elem in lt: 4 | if predicate(elem): 5 | result.append(elem) 6 | return result 7 | 8 | def len_greater_than_6(elem): 9 | return len(elem) > 6 10 | 11 | def len_less_than_5(elem): 12 | return len(elem) < 5 13 | 14 | def has_i(elem): 15 | return 'i' in elem 16 | 17 | lt = ['Justin', 'caterpillar', 'openhome'] 18 | print('大於 6:', filter_lt(len_greater_than_6, lt)) 19 | print('小於 5:', filter_lt(len_less_than_5, lt)) 20 | print('有個 i:', filter_lt(has_i, lt)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/filter_demo2.py: -------------------------------------------------------------------------------- 1 | def filter_lt(predicate, lt): 2 | result = [] 3 | for elem in lt: 4 | if predicate(elem): 5 | result.append(elem) 6 | return result 7 | 8 | def len_greater_than(num): 9 | def len_greater_than_num(elem): 10 | return len(elem) > num 11 | return len_greater_than_num 12 | 13 | lt = ['Justin', 'caterpillar', 'openhome'] 14 | print('大於 5:', filter_lt(len_greater_than(5), lt)) 15 | print('大於 7:', filter_lt(len_greater_than(7), lt)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/filter_demo3.py: -------------------------------------------------------------------------------- 1 | def filter_lt(predicate, lt): 2 | result = [] 3 | for elem in lt: 4 | if predicate(elem): 5 | result.append(elem) 6 | return result 7 | 8 | lt = ['Justin', 'caterpillar', 'openhome'] 9 | print('大於 6:', filter_lt(lambda elem: len(elem) > 6, lt)) 10 | print('小於 5:', filter_lt(lambda elem: len(elem) < 5, lt)) 11 | print('有個 i:', filter_lt(lambda elem: 'i' in elem, lt)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/filter_map_demo.py: -------------------------------------------------------------------------------- 1 | def len_greater_than(num): 2 | def len_greater_than_num(elem): 3 | return len(elem) > num 4 | return len_greater_than_num 5 | 6 | lt = ['Justin', 'caterpillar', 'openhome'] 7 | print(list(filter(len_greater_than(6), lt))) 8 | print(list(map(len, lt))) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/gcd.py: -------------------------------------------------------------------------------- 1 | def gcd(m, n): 2 | return m if n == 0 else gcd(n, m % n) 3 | 4 | print('輸入兩個數字...') 5 | 6 | m = int(input('數字 1: ')) 7 | n = int(input('數字 2: ')) 8 | 9 | r = gcd(m, n) 10 | if r == 1: 11 | print('互質') 12 | else: 13 | print(f'最大公因數:{r}') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/grade.py: -------------------------------------------------------------------------------- 1 | score = int(input('請輸入分數:')) 2 | level = score // 10 3 | { 4 | 10 : lambda: print('Perfect'), 5 | 9 : lambda: print('A'), 6 | 8 : lambda: print('B'), 7 | 7 : lambda: print('C'), 8 | 6 : lambda: print('D') 9 | }.get(level, lambda: print('E'))() 10 | 11 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/map_demo.py: -------------------------------------------------------------------------------- 1 | def map_lt(mapper, lt): 2 | result = [] 3 | for ele in lt: 4 | result.append(mapper(ele)) 5 | return result 6 | 7 | lt = ['Justin', 'caterpillar', 'openhome'] 8 | print(map_lt(str.upper, lt)) 9 | print(map_lt(len, lt)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/producer_consumer.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import random 3 | 4 | def producer(): 5 | while True: 6 | data = random.randint(0, 9) 7 | print('生產了:', data) 8 | yield data 9 | 10 | def consumer(): 11 | while True: 12 | data = yield 13 | print('消費了:', data) 14 | 15 | def clerk(jobs, producer, consumer): 16 | print('執行 {} 次生產與消費'.format(jobs)) 17 | p = producer() 18 | c = consumer() 19 | next(c) # 第一次觸發 consumer 產生器 20 | for i in range(jobs): 21 | data = next(p) 22 | c.send(data) 23 | 24 | clerk(int(sys.argv[1]), producer, consumer) 25 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/scope_demo.py: -------------------------------------------------------------------------------- 1 | x = 10 # 全域 2 | 3 | def outer(): 4 | y = 20 # 在 outer() 函式範圍 5 | 6 | def inner(): 7 | z = 30 8 | print('x = ', x) # 全域的 x 9 | print('y = ', y) # outer() 函式的 y 10 | print('z = ', z) # inner() 函式的z 11 | 12 | inner() 13 | 14 | print('x = ', x) # 全域的 x 15 | print('y = ', y) # 全域的 y 16 | 17 | outer() 18 | print('x = ', x) # 全域的 x -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/scope_demo2.py: -------------------------------------------------------------------------------- 1 | x = 10 2 | 3 | def outer(): 4 | y = 20 5 | 6 | def inner(): 7 | z = 30 8 | print('inner locals:', locals()) 9 | 10 | inner() 11 | print('outer locals:', locals()) 12 | 13 | outer() 14 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/scope_demo3.py: -------------------------------------------------------------------------------- 1 | x = 10 2 | def outer(): 3 | x = 100 # 這是在 outer() 函式範圍的 x 4 | def inner(): 5 | nonlocal x 6 | x = 1000 # 改變的是 outer() 函式的 x 7 | inner() 8 | print(x) # 顯示 1000 9 | 10 | outer() 11 | print(x) # 顯示 10 -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/sele_sort.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def sele_sort(number): 4 | # 找出未排序中最小值 5 | def min_index(left, right): 6 | if right == len(number): 7 | return left 8 | elif number[right] < number[left]: 9 | return min(right, right + 1) 10 | else: 11 | return min(left, right + 1) 12 | 13 | for i in range(len(number)): 14 | selected = min_index(i, i + 1) 15 | if i != selected: 16 | number[i], number[selected] = number[selected], number[i] 17 | 18 | number = [int(arg) for arg in sys.argv[1:]] 19 | sele_sort(number) 20 | print(number) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/func/yield_demo.py: -------------------------------------------------------------------------------- 1 | def xrange(n): 2 | x = 0 3 | while x != n: 4 | yield x 5 | x += 1 6 | 7 | for n in xrange(10): 8 | print(n) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/type_hints/account.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | from typing import overload 3 | 4 | @overload 5 | def account(name: str) -> Tuple[str, float]: 6 | pass 7 | 8 | @overload 9 | def account(name: str, balance: float) -> Tuple[str, float]: 10 | pass 11 | 12 | def account(name, balance = 0): 13 | return (name, balance) 14 | 15 | acct1 = account('Justin') 16 | acct2 = account('Monica', 1000) 17 | 18 | print(acct1) 19 | print(acct2) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/type_hints/add.py: -------------------------------------------------------------------------------- 1 | def add(n1: int, n2: int) -> int: 2 | return n1 + n2 3 | 4 | print(add(3.14, 6.28)) 5 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH04/type_hints/users.py: -------------------------------------------------------------------------------- 1 | def accountNumber(name: str) -> int: 2 | users = [(1234, 'Justin'), (5678, 'Monica')] 3 | for acc_num, acc_name in users: 4 | if name == acc_name: 5 | return acc_num 6 | return None 7 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/classes/xlogging.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Type 2 | 3 | TLogger = Type['Logger'] 4 | 5 | class Logger: 6 | __loggers: Dict[str, TLogger] = {} 7 | 8 | def __new__(cls: TLogger, name: str) -> TLogger: 9 | if name not in cls.__loggers: 10 | logger = object.__new__(cls) 11 | cls.__loggers[name] = logger 12 | return logger 13 | return cls.__loggers[name] 14 | 15 | def __init__(self, name: str) -> None: 16 | if 'name' not in vars(self): 17 | self.name = name 18 | 19 | def log(self, message: str): 20 | print(f'{self.name}: {message}') 21 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/classes/xlogging_demo.py: -------------------------------------------------------------------------------- 1 | import xlogging 2 | 3 | logger1 = xlogging.Logger('xlogging') 4 | logger1.log('一些日誌訊息....') 5 | 6 | logger2 = xlogging.Logger('xlogging') 7 | logger2.log('另外一些日誌訊息....') 8 | 9 | logger3 = xlogging.Logger('xlog') 10 | logger3.log('再來一些日誌訊息....') 11 | 12 | print(logger1 is logger2) 13 | print(logger1 is logger3) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/classes/xmath.py: -------------------------------------------------------------------------------- 1 | class Rational: 2 | def __init__(self, numer:int, denom: int) -> None: 3 | self.numer = numer 4 | self.denom = denom 5 | 6 | def __add__(self, that): 7 | return Rational( 8 | self.numer * that.denom + that.numer * self.denom, 9 | self.denom * that.denom 10 | ) 11 | 12 | def __sub__(self, that): 13 | return Rational( 14 | self.numer * that.denom - that.numer * self.denom, 15 | self.denom * that.denom 16 | ) 17 | 18 | def __mul__(self, that): 19 | return Rational( 20 | self.numer * that.numer, 21 | self.denom * that.denom 22 | ) 23 | 24 | def __truediv__(self, that): 25 | return Rational( 26 | self.numer * that.denom, 27 | self.denom * that.numer 28 | ) 29 | 30 | def __str__(self): 31 | return f'{self.numer}/{self.denom}' 32 | 33 | def __repr__(self): 34 | return f'Rational({self.numer}, {self.denom})' 35 | 36 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/modules/bank.py: -------------------------------------------------------------------------------- 1 | def account(name: str, number: str, balance: float) -> dict: 2 | return {'name': name, 'number': number, 'balance': balance} 3 | 4 | def deposit(acct, amount): 5 | if amount <= 0: 6 | print('存款金額不得為負') 7 | else: 8 | acct['balance'] += amount 9 | 10 | def withdraw(acct, amount): 11 | if amount > acct['balance']: 12 | print('餘額不足') 13 | else: 14 | acct['balance'] -= amount 15 | 16 | def desc(acct): 17 | return f'Account:{acct}' -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/modules/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.account('Justin', '123-4567', 1000) 4 | bank.deposit(acct, 500) 5 | bank.withdraw(acct, 200) 6 | 7 | # 顯示 Account:{'balance': 1300, 'number': '123-4567', 'name': 'Justin'} 8 | print(bank.desc(acct)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/modules/workspace.pth: -------------------------------------------------------------------------------- 1 | C:\workspace\libs 2 | C:\workspace\third-party 3 | C:\workspace\devs -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/object-oriented1/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | pass 3 | 4 | def account(name, number, balance): 5 | acct = Account() 6 | acct.name = name 7 | acct.number = number 8 | acct.balance = balance 9 | return acct 10 | 11 | def deposit(acct, amount): 12 | if amount <= 0: 13 | print('存款金額不得為負') 14 | else: 15 | acct.balance += amount 16 | 17 | def withdraw(acct, amount): 18 | if amount > acct.balance: 19 | print('餘額不足') 20 | else: 21 | acct.balance -= amount 22 | 23 | def desc(acct): 24 | return f"Account('{acct.name}', '{acct.number}', {acct.balance})" 25 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/object-oriented1/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.account('Justin', '123-4567', 1000) 4 | bank.deposit(acct, 500) 5 | bank.withdraw(acct, 200) 6 | 7 | # 顯示 Account(Justin, 123-4567, 1300) 8 | print(bank.desc(acct)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/object-oriented2/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name: str, number: str, balance: float) -> None: 3 | self.name = name 4 | self.number = number 5 | self.balance = balance 6 | 7 | def deposit(self, amount: float): 8 | if amount <= 0: 9 | print('存款金額不得為負') 10 | else: 11 | self.balance += amount 12 | 13 | def withdraw(self, amount: float): 14 | if amount > self.balance: 15 | print('餘額不足') 16 | else: 17 | self.balance -= amount 18 | 19 | def __str__(self): 20 | return f"Account('{self.name}', '{self.number}', {self.balance})" 21 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/object-oriented2/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.Account('Justin', '123-4567', 1000) 4 | acct.deposit(500) 5 | acct.withdraw(200) 6 | # 顯示 Account('Justin', '123-4567', 1300) 7 | print(acct) 8 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/object-oriented3/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name: str, number: str, balance: float) -> None: 3 | self.__name = name 4 | self.__number = number 5 | self.__balance = balance 6 | 7 | def deposit(self, amount: float): 8 | if amount <= 0: 9 | print('存款金額不得為負') 10 | else: 11 | self.__balance += amount 12 | 13 | def withdraw(self, amount: float): 14 | if amount > self.__balance: 15 | print('餘額不足') 16 | else: 17 | self.__balance -= amount 18 | 19 | def __str__(self): 20 | return f"Account('{self.__name}', '{self.__number}', {self.__balance})" 21 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/object-oriented3/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.Account('Justin', '123-4567', 1000) 4 | acct.deposit(500) 5 | acct.withdraw(200) 6 | 7 | # 顯示 Account('Justin', '123-4567', 1300) 8 | print(acct) 9 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/object-oriented4/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name: str, number: str, balance: float) -> None: 3 | self.__name = name 4 | self.__number = number 5 | self.__balance = balance 6 | 7 | def deposit(self, amount: float): 8 | if amount <= 0: 9 | print('存款金額不得為負') 10 | else: 11 | self.__balance += amount 12 | 13 | def withdraw(self, amount: float): 14 | if amount > self.__balance: 15 | print('餘額不足') 16 | else: 17 | self.__balance -= amount 18 | 19 | @property 20 | def name(self) -> str: 21 | return self.__name 22 | 23 | @property 24 | def number(self) -> str: 25 | return self.__number 26 | 27 | @property 28 | def balance(self) -> float: 29 | return self.__balance 30 | 31 | def __str__(self): 32 | return f"Account('{self.__name}', '{self.__number}', {self.__balance})" 33 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH05/object-oriented4/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.Account('Justin', '123-4567', 1000) 4 | 5 | acct.deposit(500) 6 | acct.withdraw(200) 7 | 8 | print('帳戶名稱:', acct.name) 9 | print('帳戶號碼:', acct.number) 10 | print('帳戶餘額:', acct.balance) 11 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/docs/openhome/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Libraries of openhome.cc 3 | 4 | If you can't explain it simply, you don't understand it well enough. 5 | - Albert Einstein 6 | ''' -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/docs/openhome/abc.py: -------------------------------------------------------------------------------- 1 | # Copyright 2016 openhome.cc. All Rights Reserved. 2 | # Permission to use, copy, modify, and distribute this code and its 3 | # documentation for educational purpose. 4 | 5 | """ 6 | Abstract Base Classes (ABCs) for Python Tutorial 7 | 8 | Just a demo for DocStrings. 9 | """ 10 | 11 | from abc import ABCMeta, abstractmethod 12 | 13 | class Ordering(metaclass=ABCMeta): 14 | ''' 15 | A abc for implementing rich comparison methods. 16 | 17 | The class must define __gt__() and __eq__() methods. 18 | ''' 19 | @abstractmethod 20 | def __eq__(self, other): 21 | '''Return a == b''' 22 | pass 23 | 24 | @abstractmethod 25 | def __gt__(self, other): 26 | '''Return a > b''' 27 | pass 28 | 29 | def __ge__(self, other): 30 | '''Return a >= b''' 31 | return self > other or self == other 32 | 33 | def __lt__(self, other): 34 | '''Return a < b''' 35 | return not (self > other and self == other) 36 | 37 | def __le__(self, other): 38 | '''Return a <= b''' 39 | return (not self >= other) or self == other 40 | 41 | def __ne__(self, other): 42 | '''Return a != b''' 43 | return not self == other 44 | 45 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/game1/rpg.py: -------------------------------------------------------------------------------- 1 | class Role: 2 | def __init__(self, name: str, level: int, blood: int) -> None: 3 | self.name = name # 角色名稱 4 | self.level = level # 角色等級 5 | self.blood = blood # 角色血量 6 | 7 | def __str__(self): 8 | return "('{name}', {level}, {blood})".format(**vars(self)) 9 | 10 | def __repr__(self): 11 | return self.__str__() 12 | 13 | class SwordsMan(Role): 14 | def fight(self): 15 | print('揮劍攻擊') 16 | 17 | class Magician(Role): 18 | def fight(self): 19 | print('魔法攻擊') 20 | 21 | def cure(self): 22 | print('魔法治療') 23 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/game1/rpg_demo.py: -------------------------------------------------------------------------------- 1 | import rpg 2 | 3 | swordsman = rpg.SwordsMan('Justin', 1, 200) 4 | print('SwordsMan', swordsman) 5 | 6 | magician = rpg.Magician('Monica', 1, 100) 7 | print('Magician', magician) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/game2/rpg.py: -------------------------------------------------------------------------------- 1 | class Role: 2 | def __init__(self, name: str, level: int, blood: int) -> None: 3 | self.name = name # 角色名稱 4 | self.level = level # 角色等級 5 | self.blood = blood # 角色血量 6 | 7 | def __str__(self): 8 | return "('{name}', {level}, {blood})".format(**vars(self)) 9 | 10 | def __repr__(self): 11 | return self.__str__() 12 | 13 | class SwordsMan(Role): 14 | def fight(self): 15 | print('揮劍攻擊') 16 | 17 | class Magician(Role): 18 | def fight(self): 19 | print('魔法攻擊') 20 | 21 | def cure(self): 22 | print('魔法治療') 23 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/game2/rpg_demo.py: -------------------------------------------------------------------------------- 1 | import rpg 2 | 3 | def draw_fight(role): 4 | print(role, end = '') 5 | role.fight() 6 | 7 | swordsman = rpg.SwordsMan('Justin', 1, 200) 8 | draw_fight(swordsman) 9 | 10 | magician = rpg.Magician('Monica', 1, 100) 11 | draw_fight(magician) 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/game3/rpg.py: -------------------------------------------------------------------------------- 1 | class Role: 2 | def __init__(self, name: str, level: int, blood: int) -> None: 3 | self.name = name # 角色名稱 4 | self.level = level # 角色等級 5 | self.blood = blood # 角色血量 6 | 7 | def __str__(self): 8 | return "('{name}', {level}, {blood})".format(**vars(self)) 9 | 10 | def __repr__(self): 11 | return self.__str__() 12 | 13 | class SwordsMan(Role): 14 | def fight(self): 15 | print('揮劍攻擊') 16 | 17 | def __str__(self): 18 | return f'SwordsMan{super().__str__()}' 19 | 20 | class Magician(Role): 21 | def fight(self): 22 | print('魔法攻擊') 23 | 24 | def cure(self): 25 | print('魔法治療') 26 | 27 | def __str__(self): 28 | return f'Magician{super().__str__()}' -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/game3/rpg_demo.py: -------------------------------------------------------------------------------- 1 | import rpg 2 | 3 | def draw_fight(role): 4 | print(role, end = '') 5 | role.fight() 6 | 7 | swordsman = rpg.SwordsMan('Justin', 1, 200) 8 | draw_fight(swordsman) 9 | 10 | magician = rpg.Magician('Monica', 1, 100) 11 | draw_fight(magician) 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/game4/rpg.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta, abstractmethod 2 | 3 | class Role(metaclass=ABCMeta): 4 | def __init__(self, name: str, level: int, blood: int) -> None: 5 | self.name = name # 角色名稱 6 | self.level = level # 角色等級 7 | self.blood = blood # 角色血量 8 | 9 | @abstractmethod 10 | def fight(self): 11 | pass 12 | 13 | def __str__(self): 14 | return "('{name}', {level}, {blood})".format(**vars(self)) 15 | 16 | def __repr__(self): 17 | return self.__str__() 18 | 19 | class SwordsMan(Role): 20 | def fight(self): 21 | print('揮劍攻擊') 22 | 23 | def __str__(self): 24 | return f'SwordsMan{super().__str__()}' 25 | 26 | class Magician(Role): 27 | def fight(self): 28 | print('魔法攻擊') 29 | 30 | def cure(self): 31 | print('魔法治療') 32 | 33 | def __str__(self): 34 | return f'Magician{super().__str__()}' -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/game4/rpg_demo.py: -------------------------------------------------------------------------------- 1 | from rpg import Role, SwordsMan, Magician 2 | 3 | def draw_fight(role: Role): 4 | print(role, end = '') 5 | role.fight() 6 | 7 | swordsman = SwordsMan('Justin', 1, 200) 8 | draw_fight(swordsman) 9 | 10 | magician = Magician('Monica', 1, 100) 11 | draw_fight(magician) 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/inheritance/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name: str, number: str, balance: float) -> None: 3 | self.__name = name 4 | self.__number = number 5 | self.__balance = balance 6 | 7 | def deposit(self, amount: float): 8 | if amount <= 0: 9 | print('存款金額不得為負') 10 | else: 11 | self.__balance += amount 12 | 13 | def withdraw(self, amount: float): 14 | if amount > self.__balance: 15 | print('餘額不足') 16 | else: 17 | self.__balance -= amount 18 | 19 | @property 20 | def name(self) -> str: 21 | return self.__name 22 | 23 | @property 24 | def number(self) -> str: 25 | return self.__number 26 | 27 | @property 28 | def balance(self) -> float: 29 | return self.__balance 30 | 31 | def __str__(self): 32 | return f"Account('{self.__name}', '{self.__number}', {self.__balance})" 33 | 34 | class SavingsAccount(Account): 35 | def __init__(self, name: str, number: str, 36 | balance: float, interest_rate: float) -> None: 37 | super().__init__(name, number, balance) 38 | self.__interest_rate = interest_rate 39 | 40 | def __str__(self): 41 | acctinfo = super().__str__() 42 | return f'{acctinfo}\n\tInterest rate: {self.__interest_rate}' 43 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/inheritance/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | savingsAcct = bank.SavingsAccount('Justin', '123-4567', 1000, 0.02) 4 | 5 | savingsAcct.deposit(500) 6 | savingsAcct.withdraw(200) 7 | 8 | print(savingsAcct) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/inheritance/xabc.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta, abstractmethod 2 | 3 | class Ordering(metaclass=ABCMeta): 4 | @abstractmethod 5 | def __eq__(self, other): 6 | pass 7 | 8 | @abstractmethod 9 | def __gt__(self, other): 10 | pass 11 | 12 | def __ge__(self, other): 13 | return self > other or self == other 14 | 15 | def __lt__(self, other): 16 | return not (self > other and self == other) 17 | 18 | def __le__(self, other): 19 | return (not self >= other) or self == other 20 | 21 | def __ne__(self, other): 22 | return not self == other 23 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH06/inheritance/xabc_demo.py: -------------------------------------------------------------------------------- 1 | from xabc import Ordering 2 | 3 | class Ball(Ordering): 4 | def __init__(self, radius: int) -> None: 5 | self.radius = radius 6 | 7 | def __eq__(self, other): 8 | return hasattr(other, 'radius') and self.radius == other.radius 9 | 10 | def __gt__(self, other): 11 | return hasattr(other, 'radius') and self.radius > other.radius 12 | 13 | b1 = Ball(10) 14 | b2 = Ball(20) 15 | 16 | print(b1 > b2) 17 | print(b1 <= b2) 18 | print(b1 == b2) 19 | 20 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/average.py: -------------------------------------------------------------------------------- 1 | numbers = input('輸入數字(空白區隔):').split(' ') 2 | try: 3 | ints = [int(number) for number in numbers] 4 | except ValueError as err: 5 | print(err) 6 | else: 7 | print('平均', sum(ints) / len(ints)) 8 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/context_manager_demo.py: -------------------------------------------------------------------------------- 1 | from types import TracebackType 2 | from typing import Optional, Type 3 | 4 | class Resource: 5 | def __init__(self, name: str) -> None: 6 | self.name = name 7 | 8 | def __enter__(self): 9 | print(self.name, ' __enter__') 10 | return self 11 | 12 | def __exit__(self, exc_type: Optional[Type[BaseException]], 13 | exc_value: Optional[BaseException], 14 | traceback: Optional[TracebackType]) -> Optional[bool]: 15 | print(self.name, ' __exit__') 16 | return False 17 | 18 | with Resource('res') as resource: 19 | print(resource.name) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/context_manager_demo2.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | class FileReader: 4 | def __init__(self, filename: str) -> None: 5 | self.filename = filename 6 | 7 | def __enter__(self): 8 | self.file = open(self.filename, 'r', encoding='UTF-8') 9 | return self.file 10 | 11 | def __exit__(self, exc_type, exc_value, traceback): 12 | self.file.close() 13 | return False 14 | 15 | with FileReader(sys.argv[1]) as file: 16 | for line in file: 17 | print(line, end='') 18 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/context_manager_demo3.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from contextlib import contextmanager 3 | from typing import Iterator, IO 4 | 5 | @contextmanager 6 | def file_reader(filename) -> Iterator[IO]: 7 | try: 8 | f = open(filename, 'r') 9 | yield f 10 | finally: 11 | f.close() 12 | 13 | with file_reader(sys.argv[1]) as f: 14 | for line in f: 15 | print(line, end='') 16 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/context_manager_demo4.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from contextlib import contextmanager 3 | from typing import Type, Iterator 4 | 5 | @contextmanager 6 | def suppress(ex_type: Type[BaseException]) -> Iterator[None]: 7 | try: 8 | yield 9 | except ex_type: 10 | pass 11 | 12 | with suppress(FileNotFoundError): 13 | for line in open(sys.argv[1]): 14 | print(line, end='') 15 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/context_manager_demo5.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from contextlib import suppress 3 | 4 | with suppress(FileNotFoundError): 5 | for line in open(sys.argv[1]): 6 | print(line, end='') 7 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/context_manager_demo6.py: -------------------------------------------------------------------------------- 1 | from contextlib import contextmanager 2 | from typing import Any, Iterator 3 | 4 | @contextmanager 5 | def closing(thing: Any) -> Iterator[Any]: 6 | try: 7 | yield thing 8 | finally: 9 | thing.close() 10 | 11 | class Some: 12 | def __init__(self, name: str) -> None: 13 | self.name = name 14 | 15 | def close(self): 16 | print(self.name, 'is closed.') 17 | 18 | with closing(Some('Resource')) as res: 19 | print(res.name) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/context_manager_demo7.py: -------------------------------------------------------------------------------- 1 | from contextlib import closing 2 | 3 | class Some: 4 | def __init__(self, name: str) -> None: 5 | self.name = name 6 | 7 | def close(self): 8 | print(self.name, 'is closed.') 9 | 10 | with closing(Some('Resource')) as res: 11 | print(res.name) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/finallly_demo.py: -------------------------------------------------------------------------------- 1 | def test(flag: bool): 2 | try: 3 | if flag: 4 | return 1 5 | finally: 6 | print('finally') 7 | return 0 8 | 9 | print(test(True)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/read_files.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | for arg in sys.argv[1:]: 4 | try: 5 | f = open(arg, 'r') 6 | except FileNotFoundError: 7 | print('找不到檔案', arg) 8 | else: 9 | try: 10 | print(arg, ' 有 ', len(f.readlines()), ' 行 ') 11 | finally: 12 | f.close() 13 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/clean-up/read_files2.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | for arg in sys.argv[1:]: 4 | try: 5 | with open(arg, 'r') as f: 6 | print(arg, ' 有 ', len(f.readlines()), ' 行 ') 7 | except FileNotFoundError: 8 | print('找不到檔案', arg) 9 | 10 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/average.py: -------------------------------------------------------------------------------- 1 | numbers = input('輸入數字(空白區隔):').split(' ') 2 | print('平均', sum(int(number) for number in numbers) / len(numbers)) 3 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/average2.py: -------------------------------------------------------------------------------- 1 | try: 2 | numbers = input('輸入數字(空白區隔):').split(' ') 3 | print('平均', sum(int(number) for number in numbers) / len(numbers)) 4 | except ValueError as err: 5 | print(err) 6 | 7 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/average3.py: -------------------------------------------------------------------------------- 1 | total = 0 2 | count = 0 3 | 4 | while True: 5 | number_str = '' 6 | try: 7 | number_str = input('輸入數字(0 結束):') 8 | number = int(number_str) 9 | if number == 0: 10 | break 11 | else: 12 | total += number 13 | count += 1 14 | except ValueError as err: 15 | print('非整數的輸入', number_str) 16 | 17 | print('平均', total / count) 18 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/bank.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | def __init__(self, name: str, number: str, balance: float) -> None: 3 | self.name = name 4 | self.number = number 5 | self.balance = balance 6 | 7 | def check_amount(self, amount: float): 8 | if amount <= 0: 9 | raise ValueError('金額必須是正數:' + str(amount)) 10 | 11 | def deposit(self, amount: float): 12 | self.check_amount(amount) 13 | self.balance += amount 14 | 15 | def withdraw(self, amount: float): 16 | self.check_amount(amount) 17 | if amount > self.balance: 18 | raise BankingException('餘額不足') 19 | 20 | self.balance -= amount 21 | 22 | def __str__(self): 23 | return f"Account('{self.name}', '{self.number}', {self.balance})" 24 | 25 | class BankingException(Exception): 26 | def __init__(self, message: str) -> None: 27 | super().__init__(message) 28 | 29 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/bank_demo.py: -------------------------------------------------------------------------------- 1 | import bank 2 | 3 | acct = bank.Account('Justin', '123-4567', 1000) 4 | 5 | def withdraw(acct): 6 | try: 7 | acct.withdraw(2000) 8 | except bank.BankingException as ex: 9 | print(ex) 10 | print('你要進行借貸嗎?') 11 | # 其他借貸流程 12 | 13 | withdraw(acct) 14 | 15 | 16 | def deposit(acct): 17 | try: 18 | acct.deposit(-500) 19 | except ValueError as err: 20 | import logging, datetime 21 | logging.getLogger(__name__).log( 22 | logging.ERROR, 23 | 'Logging: {time}, {number}, {message}'.format( 24 | time = datetime.datetime.now(), 25 | number = acct.number, 26 | message = err 27 | ) 28 | ) 29 | raise bank.BankingException('輸入金額為負的行為已記錄') from err 30 | 31 | deposit(acct) 32 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/excepthook_demo.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def my_excepthook(type, value, traceback): 4 | print('例外型態:', type) 5 | print('例外物件:', value) 6 | 7 | while traceback: 8 | print('..........') 9 | code = traceback.tb_frame.f_code 10 | print('檔案名稱:', code.co_filename) 11 | print('函式或模組名稱:', code.co_name) 12 | 13 | traceback = traceback.tb_next 14 | 15 | sys.excepthook = my_excepthook 16 | 17 | def test(): 18 | raise Exception('Shit happens!') 19 | 20 | test() -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/for_in.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Iterable, Callable 2 | 3 | Consume = Callable[[Any], None] 4 | 5 | def for_in(iterable: Iterable[Any], consume: Consume): 6 | iterator = iter(iterable) 7 | try: 8 | while True: 9 | consume(next(iterator)) 10 | except StopIteration: 11 | pass 12 | 13 | for_in([10, 20, 30], print) 14 | 15 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/stacktrace_demo.py: -------------------------------------------------------------------------------- 1 | def a(): 2 | text = None 3 | return text.upper() 4 | 5 | def b(): 6 | a() 7 | 8 | def c(): 9 | b() 10 | 11 | try: 12 | c() 13 | except: 14 | import traceback 15 | traceback.print_last() 16 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/traceback_demo.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def test(): 4 | raise Exception('Shit happens!') 5 | 6 | try: 7 | test() 8 | except: 9 | type, value, traceback = sys.exc_info() 10 | print('例外型態:', type) 11 | print('例外物件:', value) 12 | 13 | while traceback: 14 | print('..........') 15 | code = traceback.tb_frame.f_code 16 | print('檔案名稱:', code.co_filename) 17 | print('函式或模組名稱:', code.co_name) 18 | 19 | traceback = traceback.tb_next -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH07/exceptions/warnings_demo.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | warnings.warn('orz方法已棄用', DeprecationWarning) 3 | warnings.warn('XD使用者權限不足', UserWarning) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH08/basicio/stdin_demo.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def console_input(prompt: str) -> str: 4 | sys.stdout.write(prompt) 5 | sys.stdout.flush() 6 | return sys.stdin.readline() 7 | 8 | name = console_input('請輸入名稱:') 9 | print('哈囉, ', name) 10 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH08/basicio/test.txt: -------------------------------------------------------------------------------- 1 | 12345 -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH08/basicio/test_ch.txt: -------------------------------------------------------------------------------- 1 | 測試 -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH08/basicio/test_ch2.txt: -------------------------------------------------------------------------------- 1 | AB測試 -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH08/basicio/upper.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | src_path = sys.argv[1] 4 | dest_path = sys.argv[2] 5 | 6 | with open(src_path) as src, open(dest_path, 'w') as dest: 7 | content = src.read() 8 | dest.write(content.upper()) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH09/collection_advanced/chainable.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Callable 2 | from collections import UserList 3 | 4 | Consume = Callable[[Any], None] 5 | Predicate = Callable[[Any], bool] 6 | Mapper = Callable[[Any], Any] 7 | 8 | class MthChainList(UserList): 9 | def for_each(self, consume: Consume): 10 | for elem in self: 11 | consume(elem) 12 | 13 | def filter(self, predicate: Predicate): 14 | return MthChainList(elem for elem in self if predicate(elem)) 15 | 16 | def map(self, mapper: Mapper): 17 | return MthChainList(mapper(elem) for elem in self) 18 | 19 | lt = MthChainList(['a', 'B', 'c', 'd', 'E', 'f', 'G']) 20 | lt.filter(str.islower).map(str.upper).for_each(print) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH09/collection_advanced/chainmap.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, Hashable, Optional 2 | 3 | class ChainMap: 4 | def __init__(self, *tulp: Dict) -> None: 5 | self.dictLt = list(tulp) 6 | 7 | def lookup(self, key: Hashable) -> Optional[Dict]: 8 | for m in self.dictLt: 9 | if key in m: 10 | return m 11 | return None 12 | 13 | def __getitem__(self, key: Hashable) -> Any: 14 | m = self.lookup(key) 15 | if m: 16 | return m[key] 17 | else: 18 | raise KeyError(key) 19 | 20 | def __setitem__(self, key: Hashable, value: Any): 21 | m = self.lookup(key) 22 | if m: 23 | m[key] = value 24 | else: 25 | self.dictLt.append({key: value}) 26 | 27 | def __delitem__(self, key: Hashable): 28 | m = self.lookup(key) 29 | if m: 30 | del m[key] 31 | if len(m) == 0: 32 | self.dictLt.remove(m) 33 | else: 34 | raise KeyError(key) 35 | 36 | 37 | c = ChainMap({'A' : 'Justin'}, {'A' : 'Monica', 'B' : 'Irene'}) 38 | print(c.dictLt) 39 | 40 | print(c['A']) 41 | 42 | c['A'] = 'caterpillar' 43 | print(c.dictLt) 44 | 45 | del c['A'] 46 | print(c.dictLt) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH09/collection_advanced/chainmap2.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Set, Dict, Hashable, Optional 2 | from collections.abc import MutableMapping 3 | 4 | class ChainMap(MutableMapping): 5 | def __init__(self, *tulp: Dict) -> None: 6 | self.dictLt = list(tulp) 7 | 8 | def lookup(self, key: Hashable) -> Optional[Dict]: 9 | for m in self.dictLt: 10 | if key in m: 11 | return m 12 | return None 13 | 14 | def __getitem__(self, key: Hashable) -> Any: 15 | m = self.lookup(key) 16 | if m: 17 | return m[key] 18 | else: 19 | raise KeyError(key) 20 | 21 | def __setitem__(self, key: Hashable, value: Any): 22 | m = self.lookup(key) 23 | if m: 24 | m[key] = value 25 | else: 26 | self.dictLt.append({key: value}) 27 | 28 | def __delitem__(self, key: Hashable): 29 | m = self.lookup(key) 30 | if m: 31 | del m[key] 32 | if len(m) == 0: 33 | self.dictLt.remove(m) 34 | else: 35 | raise KeyError(key) 36 | 37 | def key_set(self) -> Set: 38 | keys: Set = set() 39 | for m in self.dictLt: 40 | keys.update(m.keys()) 41 | return keys 42 | 43 | def __iter__(self): 44 | return iter(self.key_set()) 45 | 46 | def __len__(self): 47 | return len(self.key_set()) 48 | 49 | 50 | c = ChainMap({'A' : 'Justin'}, {'A' : 'Monica', 'B' : 'Irene'}) 51 | print(list(c)) 52 | print(len(c)) 53 | print(c.pop('A')) 54 | print(list(c.keys())) 55 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH09/collection_advanced/counter.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from operator import itemgetter 3 | 4 | def count(text): 5 | counter = defaultdict(int) 6 | for c in text: 7 | counter[c] += 1 8 | return counter.items() 9 | 10 | text = 'Your right brain has nothing left.' 11 | for c, n in sorted(count(text), key = itemgetter(0)): 12 | print(c, ':', n) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH09/collection_advanced/group.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | names = ['Justin', 'Monica', 'Irene', 'Pika', 'caterpillar'] 4 | 5 | grouped_by_len = defaultdict(list) 6 | 7 | for name in names: 8 | key = len(name) 9 | grouped_by_len[key].append(name) 10 | 11 | for length in grouped_by_len: 12 | print(length, grouped_by_len[length]) 13 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH09/object_protocols/orderable_types.py: -------------------------------------------------------------------------------- 1 | class Customer: 2 | def __init__(self, name, symbol, age): 3 | self.name = name 4 | self.symbol = symbol 5 | self.age = age 6 | 7 | def __lt__(self, other): 8 | return self.name < other.name 9 | 10 | def __str__(self): 11 | return "Customer('{name}', '{symbol}', {age})".format(**vars(self)) 12 | 13 | def __repr__(self): 14 | return self.__str__() 15 | 16 | customers = [ 17 | Customer('Justin', 'A', 40), 18 | Customer('Irene', 'C', 8), 19 | Customer('Monica', 'B', 37) 20 | ] 21 | 22 | print(sorted(customers)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH09/object_protocols/point_demo.py: -------------------------------------------------------------------------------- 1 | class Point: 2 | def __init__(self, x: int, y: int) -> None: 3 | self.x = x 4 | self.y = y 5 | 6 | def __eq__(self, that): 7 | if hasattr(that, 'x') and hasattr(that, 'y'): 8 | return self.x == that.x and self.y == that.y 9 | return False 10 | 11 | def __hash__(self): 12 | return 41 * (41 + self.x) + self.y 13 | 14 | def __str__(self): 15 | return self.__repr__() 16 | 17 | def __repr__(self): 18 | return 'Point({}, {})'.format(self.x, self.y) 19 | 20 | p1 = Point(1, 1) 21 | p2 = Point(2, 2) 22 | p3 = Point(1, 1) 23 | ps = {p1, p2, p3} 24 | print(ps) 25 | 26 | p2.x = 1 27 | p2.y = 1 28 | print(ps) 29 | 30 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH09/object_protocols/test.py: -------------------------------------------------------------------------------- 1 | names = ['Justin', 'Monica', 'Irene', 'Pika', 'caterpillar'] 2 | 3 | grouped_by_len = {} 4 | for name in names: 5 | key = len(name) 6 | if key not in grouped_by_len: 7 | grouped_by_len[key] = [] 8 | grouped_by_len[key].append(name) 9 | 10 | for length in grouped_by_len: 11 | print(length, grouped_by_len[length]) 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH09/object_protocols/tools.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | class Repeat: 4 | def __init__(self, elem: Any, n: int) -> None: 5 | self.elem = elem 6 | self.n = n 7 | 8 | def __iter__(self): 9 | elem = self.elem 10 | n = self.n 11 | 12 | class _Iter: 13 | def __init__(self): 14 | self.count = 0 15 | 16 | def __next__(self): 17 | if self.count < n: 18 | self.count += 1 19 | return elem 20 | raise StopIteration 21 | 22 | def __iter__(self): 23 | return self 24 | 25 | return _Iter() 26 | 27 | for elem in Repeat('A', 5): 28 | print(elem, end = '') 29 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH10/country_data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 2008 6 | 141100 7 | 8 | 9 | 10 | 11 | 4 12 | 2011 13 | 59900 14 | 15 | 16 | 17 | 68 18 | 2011 19 | 13600 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH10/data_formats/MI_5MINS_HIST.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/CH10/data_formats/MI_5MINS_HIST.csv -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH10/data_formats/index_history.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | from typing import List, Dict, Iterator 3 | import csv 4 | 5 | IndexList = List[OrderedDict] 6 | 7 | def csv_to_list(csvfile: str) -> IndexList: 8 | with open(csvfile, encoding = 'Big5') as f: 9 | fieldnames = ['日期', '開盤指數', '最高指數', '最低指數', '收盤指數'] 10 | reader = csv.DictReader(f, fieldnames = fieldnames) 11 | return list(reader)[2:] 12 | 13 | def row_with_fields(row: OrderedDict, fields: List) -> Dict: 14 | return {field : row[field] for field in fields} 15 | 16 | def index_with_fields(indexlt: IndexList, fields: List) -> Iterator: 17 | return (row_with_fields(origin_row, fields) for origin_row in indexlt) 18 | 19 | csvfile = input('CSV檔案名稱:') 20 | fields = input('查詢欄位:').split(",") 21 | indexlt = csv_to_list(csvfile) 22 | 23 | for name in fields: 24 | print(name, end = '\t\t\t') 25 | print() 26 | 27 | for row in index_with_fields(indexlt, fields): 28 | for name in fields: 29 | print(row[name], end = '\t\t') 30 | print() 31 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH10/object_serialization/dvdlib_pickle.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | 3 | class DVD: 4 | def __init__(self, title: str, year: int, duration: int, director: str) -> None: 5 | self.title = title 6 | self.year = year 7 | self.duration = duration 8 | self.director = director 9 | self.filename = self.title.replace(' ', '_') + '.pickle' 10 | 11 | def save(self): 12 | with open(self.filename, 'wb') as fh: 13 | pickle.dump(self, fh) 14 | 15 | @staticmethod 16 | def load(filename: str) -> 'DVD': 17 | with open(filename, 'rb') as fh: 18 | return pickle.load(fh) 19 | 20 | def __str__(self): 21 | return repr(self) 22 | 23 | def __repr__(self): 24 | return "DVD('{0}', {1}, {2}, '{3}')".format( 25 | self.title, self.year, self.duration, self.director) 26 | 27 | dvd1 = DVD('Birds', 2018, 8, 'Justin Lin') 28 | dvd1.save() 29 | dvd2 = DVD.load('Birds.pickle') 30 | print(dvd2) 31 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH10/object_serialization/dvdlib_shelve.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | import shelve 3 | 4 | class DVD: 5 | def __init__(self, title: str, year: int, duration: int, director: str) -> None: 6 | self.title = title 7 | self.year = year 8 | self.duration = duration 9 | self.director = director 10 | 11 | def __str__(self): 12 | return repr(self) 13 | 14 | def __repr__(self): 15 | return ("DVD('{title}', {year}, {duration}, '{director}')" 16 | .format(**vars(self))) 17 | 18 | class DvdDao: 19 | def __init__(self, dbname: str) -> None: 20 | self.dbname = dbname 21 | 22 | def save(self, dvd: DVD): 23 | with shelve.open(self.dbname) as shelve_db: 24 | shelve_db[dvd.title] = dvd 25 | 26 | def all(self) -> List[DVD]: 27 | with shelve.open(self.dbname) as shelve_db: 28 | return [shelve_db[title] 29 | for title in sorted(shelve_db, key = str.lower)] 30 | 31 | def load(self, title: str) -> Optional[DVD]: 32 | with shelve.open(self.dbname) as shelve_db: 33 | if title in shelve_db: 34 | return shelve_db[title] 35 | return None 36 | 37 | def remove(self, title: str): 38 | with shelve.open(self.dbname) as shelve_db: 39 | del shelve_db[title] 40 | 41 | 42 | dao = DvdDao('dvdlib.shelve') 43 | dvd1 = DVD('Birds', 2018, 1, 'Justin Lin') 44 | dvd2 = DVD('Dogs', 2018, 7, 'Monica Huang') 45 | 46 | dao.save(dvd1) 47 | dao.save(dvd2) 48 | print(dao.all()) 49 | print(dao.load('Birds')) 50 | dao.remove('Birds') 51 | print(dao.all()) 52 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/files_dirs/glob_search.py: -------------------------------------------------------------------------------- 1 | import sys, os, glob 2 | 3 | try: 4 | path = sys.argv[1] 5 | pattern = sys.argv[2] 6 | except IndexError: 7 | print('請指定搜尋路徑與 glob 模式') 8 | print('例如:python glob_search.py c:\workspace **/*.py') 9 | else: 10 | os.chdir(path) 11 | for p in glob.iglob(pattern, recursive = True): 12 | print(p) 13 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/files_dirs/list_all.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | import os 3 | 4 | def list_all(dir: str, action: Callable[..., None]): 5 | action(dir) 6 | for entry in os.scandir(dir): 7 | fullpath = f'{dir}\\{entry.name}' 8 | if entry.is_dir(): 9 | list_all(fullpath, action) 10 | elif entry.is_file(): 11 | print(fullpath) 12 | 13 | list_all(r'c:\workspace', print) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/files_dirs/list_all2.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | import os 3 | 4 | def list_all(dir: str, action: Callable[..., None]): 5 | for dirpath, dirnames, filenames in os.walk(dir): 6 | action(dirpath) 7 | for filename in filenames: 8 | action(f'{dirpath}\\{filename}') 9 | 10 | list_all(r'c:\workspace', print) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/files_dirs/list_all3.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | import os, os.path 3 | 4 | def list_all(dir: str, action: Callable[..., None]): 5 | action(dir) 6 | for entry in os.scandir(dir): 7 | fullpath = os.path.join(dir, entry.name) 8 | if entry.is_dir(): 9 | list_all(fullpath, action) 10 | elif entry.is_file(): 11 | print(fullpath) 12 | 13 | list_all(r'c:\workspace', print) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/basic_logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logger = logging.getLogger(__name__) 4 | logger.log(logging.DEBUG, 'DEBUG 訊息') 5 | logger.log(logging.INFO, 'INFO 訊息') 6 | logger.log(logging.WARNING, 'WARNING 訊息') 7 | logger.log(logging.ERROR, 'ERROR 訊息') 8 | logger.log(logging.CRITICAL, 'CRITICAL 訊息') 9 | 10 | 11 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/basic_logger2.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logger = logging.getLogger(__name__) 4 | logger.setLevel(logging.ERROR) 5 | 6 | logger.log(logging.DEBUG, 'DEBUG 訊息') 7 | logger.log(logging.INFO, 'INFO 訊息') 8 | logger.log(logging.WARNING, 'WARNING 訊息') 9 | logger.log(logging.ERROR, 'ERROR 訊息') 10 | logger.log(logging.CRITICAL, 'CRITICAL 訊息') 11 | 12 | 13 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/basic_logger3.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logging.basicConfig(level = logging.DEBUG) 4 | 5 | logger = logging.getLogger(__name__) 6 | logger.log(logging.DEBUG, 'DEBUG 訊息') 7 | logger.log(logging.INFO, 'INFO 訊息') 8 | logger.log(logging.WARNING, 'WARNING 訊息') 9 | logger.log(logging.ERROR, 'ERROR 訊息') 10 | logger.log(logging.CRITICAL, 'CRITICAL 訊息') 11 | 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/config_demo.py: -------------------------------------------------------------------------------- 1 | import logconf 2 | import logging.config 3 | 4 | logging.config.dictConfig(logconf.LOGGING_CONFIG) 5 | 6 | # 建立logger 7 | logger = logging.getLogger('simple_example') 8 | 9 | # 應用程式的程式碼 10 | logger.debug('debug message') 11 | logger.info('info message') 12 | logger.warning('warn message') 13 | logger.error('error message') 14 | logger.critical('critical message') 15 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/config_demo2.py: -------------------------------------------------------------------------------- 1 | import logging, json 2 | import logging.config 3 | 4 | with open('logconf.json') as config: 5 | LOGGING_CONFIG = json.load(config) 6 | logging.config.dictConfig(LOGGING_CONFIG) 7 | 8 | # 建立logger 9 | logger = logging.getLogger('simple_example') 10 | 11 | # 應用程式的程式碼 12 | logger.debug('debug message') 13 | logger.info('info message') 14 | logger.warning('warning message') 15 | logger.error('error message') 16 | logger.critical('critical message') 17 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/filter_demo.py: -------------------------------------------------------------------------------- 1 | import logging, sys 2 | 3 | logger = logging.getLogger(__name__) 4 | logger.addFilter(lambda record: 'Orz' in record.msg) 5 | 6 | logger.log(logging.ERROR, '發生了 XD 錯誤') 7 | logger.log(logging.ERROR, '發生了 Orz 錯誤') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/formatter_demo.py: -------------------------------------------------------------------------------- 1 | import logging, sys 2 | 3 | formatter = logging.Formatter( 4 | '%(asctime)s - %(name)s - %(levelname)s - %(message)s') 5 | handler = logging.StreamHandler(sys.stderr) 6 | handler.setFormatter(formatter) 7 | 8 | logger = logging.getLogger(__name__) 9 | logger.addHandler(handler) 10 | 11 | logger.log(logging.ERROR, '發生了 XD 錯誤') 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/handler_demo.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logging.basicConfig(filename ='openhome.log') 4 | 5 | logger = logging.getLogger(__name__) 6 | logger.addHandler(logging.FileHandler('errors.log')) 7 | 8 | logger.log(logging.ERROR, 'ERROR 訊息') 9 | 10 | 11 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/logconf.json: -------------------------------------------------------------------------------- 1 | { 2 | "version" : 1, 3 | "handlers" : { 4 | "console": { 5 | "class": "logging.StreamHandler", 6 | "level": "DEBUG", 7 | "formatter": "simpleFormatter" 8 | } 9 | }, 10 | "formatters": { 11 | "simpleFormatter": { 12 | "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 13 | } 14 | }, 15 | "loggers" : { 16 | "simple_example" : { 17 | "level" : "DEBUG", 18 | "handlers" : ["console"] 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/logging_demo/logconf.py: -------------------------------------------------------------------------------- 1 | LOGGING_CONFIG = { 2 | 'version' : 1, 3 | 'handlers' : { 4 | 'console': { 5 | 'class': 'logging.StreamHandler', 6 | 'level': 'DEBUG', 7 | 'formatter': 'simpleFormatter' 8 | } 9 | }, 10 | 'formatters': { 11 | 'simpleFormatter': { 12 | 'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 13 | } 14 | }, 15 | 'loggers' : { 16 | 'simple_example' : { 17 | 'level' : 'DEBUG', 18 | 'handlers' : ['console'] 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/regex/regex.py: -------------------------------------------------------------------------------- 1 | import re, sre_constants 2 | 3 | def whereis(regex: str, text: str): 4 | try: 5 | pattern = re.compile(regex) 6 | except sre_constants.error as err: 7 | print('規則表示式有誤') 8 | print(err.msg) 9 | else: 10 | for m in pattern.finditer(text): 11 | print('從索引 {} 開始到索引 {} 之間找到符合文字 {}' 12 | .format(m.start(), m.end(), m.group())) 13 | 14 | regex = input('輸入規則表示式:') 15 | text = input('輸入要比對的文字:') 16 | whereis(regex, text) 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/urllib_abc/download_imgs.py: -------------------------------------------------------------------------------- 1 | from typing import Iterator 2 | from urllib.request import urlopen 3 | import re 4 | 5 | def save(content: bytes, filename: str): 6 | with open(filename, 'wb') as dest: 7 | dest.write(content) 8 | 9 | def download(urls: Iterator[str]): 10 | for url in urls: 11 | with urlopen(url) as resp: 12 | content = resp.read() 13 | filename = url.split('/')[-1] 14 | save(content, filename) 15 | 16 | def download_imgs_from(url: str): 17 | with urlopen('https://openhome.cc/Gossip') as resp: 18 | html = resp.read().decode('UTF-8') 19 | srcs = re.findall(r'(?s)', html) 20 | download(f'{url}/{src}' for src in srcs) 21 | 22 | download_imgs_from('https://openhome.cc/Gossip') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/urllib_abc/search_books.py: -------------------------------------------------------------------------------- 1 | import json 2 | from urllib.request import urlopen 3 | from urllib.parse import urlencode 4 | 5 | def printVolumeInfo(books: dict): 6 | for book in books['items']: 7 | print(book['volumeInfo']) 8 | 9 | params = urlencode({'q': 'python'}) 10 | url = f'https://www.googleapis.com/books/v1/volumes?{params}' 11 | with urlopen(url) as resp: 12 | printVolumeInfo(json.loads(resp.read().decode('UTF-8'))) 13 | 14 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH11/urllib_abc/search_google.py: -------------------------------------------------------------------------------- 1 | from urllib.request import urlopen, Request 2 | 3 | headers = { 4 | 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36' 5 | } 6 | request = Request('https://www.google.com.tw/search?q=python', headers=headers) 7 | 8 | with urlopen(request) as resp: 9 | print(resp.read().decode('UTF-8')) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/doctest_demo/util.py: -------------------------------------------------------------------------------- 1 | from typing import List, Callable, Any 2 | import functools 3 | 4 | Comparator = Callable[[Any, Any], int] 5 | 6 | def ascending(a: Any, b: Any): return a - b 7 | def descending(a: Any, b: Any): return -ascending(a, b) 8 | 9 | def __select(xs: List, compare: Comparator) -> List: 10 | selected = functools.reduce( 11 | lambda slt, elem: elem if compare(elem, slt) < 0 else slt, xs) 12 | remain = [elem for elem in xs if elem != selected] 13 | return (xs if not remain 14 | else [elem for elem in xs if elem == selected] 15 | + __select(remain, compare)) 16 | 17 | def sorted(xs: List, compare = ascending) -> List: 18 | ''' 19 | sorted(xs) -> new sorted list from xs' item in ascending order. 20 | sorted(xs, func) -> new sorted list. func should return a negative integer, 21 | zero, or a positive integer as the first argument is 22 | less than, equal to, or greater than the second. 23 | 24 | >>> sorted([2, 1, 3, 6, 5]) 25 | [1, 2, 3, 5, 6] 26 | >>> sorted([2, 1, 3, 6, 5], ascending) 27 | [1, 2, 3, 5, 6] 28 | >>> sorted([2, 1, 3, 6, 5], descending) 29 | [6, 5, 3, 2, 1] 30 | >>> sorted([2, 1, 3, 6, 5], lambda a, b: a - b) 31 | [1, 2, 3, 5, 6] 32 | >>> sorted([2, 1, 3, 6, 5], lambda a, b: b - a) 33 | [6, 5, 3, 2, 1] 34 | ''' 35 | 36 | return [] if not xs else __select(xs, compare) 37 | 38 | if __name__ == '__main__': 39 | import doctest 40 | doctest.testmod() -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/doctest_demo/util2.py: -------------------------------------------------------------------------------- 1 | if __name__ == '__main__': 2 | import doctest 3 | doctest.testfile("util_doctest.txt") 4 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/doctest_demo/util_doctest.txt: -------------------------------------------------------------------------------- 1 | The ``util`` module 2 | ====================== 3 | 4 | Using ``sorted`` 5 | ------------------- 6 | 7 | >>> from util import * 8 | >>> sorted([2, 1, 3, 6, 5]) 9 | [1, 2, 3, 5, 6] 10 | >>> sorted([2, 1, 3, 6, 5], ascending) 11 | [1, 2, 3, 5, 6] 12 | >>> sorted([2, 1, 3, 6, 5], descending) 13 | [6, 5, 3, 2, 1] 14 | >>> sorted([2, 1, 3, 6, 5], lambda a, b: a - b) 15 | [1, 2, 3, 5, 6] 16 | >>> sorted([2, 1, 3, 6, 5], lambda a, b: b - a) 17 | [6, 5, 3, 2, 1] -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/pdb_demo/filter_demo2.py: -------------------------------------------------------------------------------- 1 | def filter_lt(predicate, lt): 2 | result = [] 3 | for elem in lt: 4 | if predicate(elem): 5 | result.append(elem) 6 | return result 7 | 8 | def len_greater_than(num): 9 | def len_greater_than_num(elem): 10 | return len(elem) > num 11 | return len_greater_than_num 12 | 13 | lt = ['Justin', 'caterpillar', 'openhome'] 14 | print('大於 5:', filter_lt(len_greater_than(5), lt)) 15 | print('大於 7:', filter_lt(len_greater_than(7), lt)) 16 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/pdb_demo/filter_demo3.py: -------------------------------------------------------------------------------- 1 | import pdb 2 | pdb.set_trace() 3 | 4 | def filter_lt(predicate, lt): 5 | result = [] 6 | for elem in lt: 7 | if predicate(elem): 8 | result.append(elem) 9 | return result 10 | 11 | def len_greater_than(num): 12 | def len_greater_than_num(elem): 13 | return len(elem) > num 14 | return len_greater_than_num 15 | 16 | lt = ['Justin', 'caterpillar', 'openhome', 24] 17 | print('大於 5:', filter_lt(len_greater_than(5), lt)) 18 | print('大於 7:', filter_lt(len_greater_than(7), lt)) 19 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/profile_demo/numbers.py: -------------------------------------------------------------------------------- 1 | all = '' 2 | for s in [str(num) for num in range(0, 98)]: 3 | all = all + s + ',' 4 | all = all + '99' 5 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/profile_demo/sele_stats.py: -------------------------------------------------------------------------------- 1 | import cProfile, pstats, random, sorting 2 | 3 | l = list(range(500)) 4 | random.shuffle(l) 5 | cProfile.run('sorting.selectionSort(l)', 'select_stats') 6 | 7 | p = pstats.Stats('select_stats') 8 | p.strip_dirs().sort_stats('name').print_stats() 9 | p.sort_stats('cumulative').print_stats(10) 10 | p.sort_stats('time').print_stats(10) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/profile_demo/select_stats: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustinSDK/Python37Tutorial/909b3c2f99ac50475345471c9c6e5768f8dc84fc/samples-labs-exercises/samples/CH12/profile_demo/select_stats -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/profile_demo/sorting.py: -------------------------------------------------------------------------------- 1 | from functools import reduce 2 | 3 | def ascending(a, b): return a - b 4 | def descending(a, b): return -ascending(a, b) 5 | 6 | def selectionSort(xs, compare = ascending): 7 | return [] if not xs else __select(xs, compare) 8 | 9 | def __select(xs, compare): 10 | selected = reduce( 11 | lambda m, k: m if compare(m, k) < 0 else k, xs) 12 | remain = [elem for elem in xs if elem != selected] 13 | return (xs if not remain 14 | else [elem for elem in xs if elem == selected] 15 | + __select(remain, compare)) 16 | 17 | def insertionSort(xs, compare = ascending): 18 | return ([] if not xs 19 | else __insert(xs[0], 20 | insertionSort(xs[1:], compare), compare)) 21 | 22 | def __insert(x, xs, compare): 23 | return ([x] + xs if not xs or compare(x, xs[0]) <= 0 24 | else [xs[0]] + __insert(x, xs[1:], compare)) 25 | 26 | def bubbleSort(xs, compare = ascending): 27 | return [] if not xs else __up(xs, compare) 28 | 29 | def __up(xs, compare): 30 | if not xs[1:]: 31 | return xs 32 | else: 33 | s = bubbleSort(xs[1:], compare) 34 | return ([s[0]] + __up([xs[0]] + s[1:], compare) 35 | if compare(xs[0], s[0]) > 0 36 | else [xs[0]] + s) 37 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/profile_demo/sorting_cprof.py: -------------------------------------------------------------------------------- 1 | import cProfile 2 | import sorting 3 | import random 4 | 5 | l = list(range(500)) 6 | random.shuffle(l) 7 | cProfile.run('sorting.selectionSort(l)') -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/profile_demo/sorting_prof.py: -------------------------------------------------------------------------------- 1 | import timeit 2 | repeats = 10000 3 | for f in ('selectionSort', 'insertionSort', 'bubbleSort'): 4 | t = timeit.Timer('{0}([10, 9, 1, 2, 5, 3, 8, 7])'.format(f), 5 | 'from sorting import selectionSort, insertionSort, bubbleSort') 6 | sec = t.timeit(repeats) / repeats 7 | print('{f}\t{sec:.6f} sec'.format(**locals())) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/unittest_demo/calc.py: -------------------------------------------------------------------------------- 1 | def plus(a, b): 2 | return a + b 3 | 4 | def minus(a, b): 5 | return a - b 6 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH12/unittest_demo/calc_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import calc 3 | 4 | class CalcTestCase(unittest.TestCase): 5 | def setUp(self): 6 | self.args = (3, 2) 7 | 8 | def tearDown(self): 9 | self.args = None 10 | 11 | def test_plus(self): 12 | expected = 5; 13 | result = calc.plus(*self.args); 14 | self.assertEqual(expected, result) 15 | 16 | def test_minus(self): 17 | expected = 1; 18 | result = calc.minus(*self.args); 19 | self.assertEqual(expected, result) 20 | 21 | if __name__ == '__main__': 22 | unittest.main() -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/async_io/async_ctx_manager.py: -------------------------------------------------------------------------------- 1 | from types import TracebackType 2 | from typing import Optional, Type, AsyncContextManager 3 | import asyncio 4 | import time 5 | 6 | class Resource: 7 | def __init__(self, name: str) -> None: 8 | self.name = name 9 | time.sleep(5) 10 | print('resource prepared') 11 | 12 | def action(self): 13 | print(f'use {self.name} resource ...') 14 | 15 | def close(self): 16 | time.sleep(5) 17 | print('resource closed') 18 | 19 | def resource(name: str) -> AsyncContextManager[Resource]: 20 | class AsyncCtxManager: 21 | async def __aenter__(self) -> Resource: 22 | self.resource = Resource(name) 23 | return self.resource 24 | 25 | async def __aexit__(self, exc_type: Optional[Type[BaseException]], 26 | exc_value: Optional[BaseException], 27 | traceback: Optional[TracebackType]) -> Optional[bool]: 28 | self.resource.close() 29 | return False 30 | 31 | return AsyncCtxManager() 32 | 33 | async def task(): 34 | async with resource('foo') as res: 35 | res.action() 36 | 37 | loop = asyncio.get_event_loop() 38 | loop.run_until_complete(task()) 39 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/async_io/async_ctx_manager2.py: -------------------------------------------------------------------------------- 1 | from typing import AsyncIterator 2 | from contextlib import asynccontextmanager 3 | import asyncio 4 | import time 5 | 6 | class Resource: 7 | def __init__(self, name: str) -> None: 8 | self.name = name 9 | time.sleep(5) 10 | print('resource prepared') 11 | 12 | def action(self): 13 | print(f'use {self.name} resource ...') 14 | 15 | def close(self): 16 | time.sleep(5) 17 | print('resource closed') 18 | 19 | @asynccontextmanager 20 | async def resource(name: str) -> AsyncIterator[Resource]: 21 | try: 22 | res = Resource(name) 23 | yield res 24 | finally: 25 | res.close() 26 | 27 | async def task(): 28 | async with resource('foo') as res: 29 | res.action() 30 | 31 | loop = asyncio.get_event_loop() 32 | loop.run_until_complete(task()) 33 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/async_io/await_demo.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | import random 4 | 5 | async def asyncFoo(n: float): 6 | time.sleep(n) 7 | return n * random.random() 8 | 9 | async def asyncTasks(): 10 | r1 = await asyncFoo(1) 11 | r2 = await asyncFoo(r1) 12 | r3 = await asyncFoo(r2) 13 | print(r3) 14 | 15 | async def asyncMoreTasks(): 16 | await asyncTasks() 17 | await asyncTasks() 18 | 19 | loop = asyncio.get_event_loop() 20 | loop.run_until_complete(asyncFoo(1)) 21 | loop.run_until_complete(asyncTasks()) 22 | loop.run_until_complete(asyncMoreTasks()) 23 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/async_io/download.py: -------------------------------------------------------------------------------- 1 | from urllib.request import urlopen 2 | import asyncio 3 | 4 | async def download(url: str, file: str): 5 | with urlopen(url) as u, open(file, 'wb') as f: 6 | f.write(u.read()) 7 | 8 | urls = [ 9 | 'http://openhome.cc/Gossip/Encoding/', 10 | 'http://openhome.cc/Gossip/Scala/', 11 | 'http://openhome.cc/Gossip/JavaScript/', 12 | 'http://openhome.cc/Gossip/Python/' 13 | ] 14 | 15 | filenames = [ 16 | 'Encoding.html', 17 | 'Scala.html', 18 | 'JavaScript.html', 19 | 'Python.html' 20 | ] 21 | 22 | loop = asyncio.get_event_loop() 23 | tasks = [loop.create_task(download(url, filename)) 24 | for url, filename in zip(urls, filenames)] 25 | loop.run_until_complete(asyncio.wait(tasks)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/async_io/download2.py: -------------------------------------------------------------------------------- 1 | from urllib.request import urlopen 2 | import asyncio 3 | 4 | async def load_url(url: str) -> bytes: 5 | with urlopen(url) as u: 6 | return u.read() 7 | 8 | async def save(filename: str, content: bytes): 9 | with open(filename, 'wb') as f: 10 | f.write(content) 11 | 12 | async def download(url: str, filename: str): 13 | content = await load_url(url) 14 | await save(filename, content) 15 | 16 | urls = [ 17 | 'http://openhome.cc/Gossip/Encoding/', 18 | 'http://openhome.cc/Gossip/Scala/', 19 | 'http://openhome.cc/Gossip/JavaScript/', 20 | 'http://openhome.cc/Gossip/Python/' 21 | ] 22 | 23 | filenames = [ 24 | 'Encoding.html', 25 | 'Scala.html', 26 | 'JavaScript.html', 27 | 'Python.html' 28 | ] 29 | 30 | loop = asyncio.get_event_loop() 31 | tasks = [loop.create_task(download(url, filename)) 32 | for url, filename in zip(urls, filenames)] 33 | loop.run_until_complete(asyncio.wait(tasks)) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/async_io/page_sizes.py: -------------------------------------------------------------------------------- 1 | from typing import List, AsyncIterator 2 | from urllib.request import urlopen 3 | import asyncio 4 | 5 | async def fetch(urls: List[str]) -> AsyncIterator[bytes]: 6 | for url in urls: 7 | with urlopen(url) as u: 8 | yield u.read() 9 | 10 | async def sizeof(urls: List[str]) -> List[int]: 11 | return [len(content) async for content in fetch(urls)] 12 | 13 | urls = [ 14 | 'http://openhome.cc/Gossip/Encoding/', 15 | 'http://openhome.cc/Gossip/Scala/', 16 | 'http://openhome.cc/Gossip/JavaScript/', 17 | 'http://openhome.cc/Gossip/Python/' 18 | ] 19 | 20 | loop = asyncio.get_event_loop() 21 | sizes = loop.run_until_complete(sizeof(urls)) 22 | print(sizes) 23 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/concurrent_demo/async_callback.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | from concurrent.futures import ThreadPoolExecutor 3 | from urllib.request import urlopen 4 | 5 | Consume = Callable[[bytes], None] 6 | 7 | def load_url(url: str, consume: Consume): 8 | with urlopen(url) as u: 9 | consume(u.read()) 10 | 11 | def save(filename: str) -> Consume: 12 | def _save(content): 13 | with open(filename, 'wb') as f: 14 | f.write(content) 15 | return _save 16 | 17 | with ThreadPoolExecutor() as executor: 18 | url = 'https://openhome.cc/Gossip/Python/' 19 | loaded_callback = save('Python.html') 20 | executor.submit(load_url, url, loaded_callback) 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/concurrent_demo/async_callback2.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | from concurrent.futures import ThreadPoolExecutor, Future 3 | from urllib.request import urlopen 4 | 5 | Consume = Callable[[Future], None] 6 | 7 | def load_url(url: str) -> bytes: 8 | with urlopen(url) as u: 9 | return u.read() 10 | 11 | def save(filename: str) -> Consume: 12 | def _save(future): 13 | with open(filename, 'wb') as f: 14 | f.write(future.result()) 15 | return _save 16 | 17 | with ThreadPoolExecutor() as executor: 18 | url = 'https://openhome.cc/Gossip/Python/' 19 | future = executor.submit(load_url, url) 20 | future.add_done_callback(save('Python.html')) 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/concurrent_demo/async_callback3.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | from concurrent.futures import ThreadPoolExecutor, Future 3 | from urllib.request import urlopen 4 | import time 5 | 6 | Consume = Callable[[Future], None] 7 | 8 | def load_url(url: str) -> bytes: 9 | with urlopen(url) as u: 10 | return u.read() 11 | 12 | def save(filename: str) -> Consume: 13 | def _save(future): 14 | with open(filename, 'wb') as f: 15 | f.write(future.result()) 16 | return _save 17 | 18 | with ThreadPoolExecutor() as executor: 19 | url = 'https://openhome.cc/Gossip/Python/' 20 | future = executor.submit(load_url, url) 21 | future.add_done_callback(save('Python.html')) 22 | while True: 23 | if future.running(): 24 | print('.', end='') 25 | time.sleep(0.0001) 26 | else: 27 | break 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/concurrent_demo/download.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ThreadPoolExecutor 2 | from urllib.request import urlopen 3 | 4 | def download(url: str, file: str): 5 | with urlopen(url) as u, open(file, 'wb') as f: 6 | f.write(u.read()) 7 | 8 | urls = [ 9 | 'https://openhome.cc/Gossip/Encoding/', 10 | 'https://openhome.cc/Gossip/Scala/', 11 | 'https://openhome.cc/Gossip/JavaScript/', 12 | 'https://openhome.cc/Gossip/Python/' 13 | ] 14 | 15 | filenames = [ 16 | 'Encoding.html', 17 | 'Scala.html', 18 | 'JavaScript.html', 19 | 'Python.html' 20 | ] 21 | 22 | with ThreadPoolExecutor(max_workers=4) as executor: 23 | for url, filename in zip(urls, filenames): 24 | executor.submit(download, url, filename) 25 | 26 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/concurrent_demo/download2.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ThreadPoolExecutor, Future 2 | from urllib.request import urlopen 3 | 4 | def readUrlAsync(url: str, executor: ThreadPoolExecutor) -> Future: 5 | def _readUrl(): 6 | with urlopen(url) as u: 7 | return u.read() 8 | 9 | return executor.submit(_readUrl) 10 | 11 | def download(url: str, filename: str, executor: ThreadPoolExecutor): 12 | def save(content): 13 | with open(filename, 'wb') as f: 14 | f.write(content) 15 | 16 | readUrlAsync(url, executor).add_done_callback(lambda future: save(future.result())) 17 | 18 | urls = [ 19 | 'https://openhome.cc/Gossip/Encoding/', 20 | 'https://openhome.cc/Gossip/Scala/', 21 | 'https://openhome.cc/Gossip/JavaScript/', 22 | 'https://openhome.cc/Gossip/Python/' 23 | ] 24 | 25 | filenames = [ 26 | 'Encoding.html', 27 | 'Scala.html', 28 | 'JavaScript.html', 29 | 'Python.html' 30 | ] 31 | 32 | with ThreadPoolExecutor(max_workers=4) as executor: 33 | for url, filename in zip(urls, filenames): 34 | download(url, filename, executor) 35 | 36 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/concurrent_demo/fib.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | def fib(n: int) -> int: 4 | if n < 2: 5 | return 1 6 | return fib(n - 1) + fib(n - 2) 7 | 8 | begin = time.time() 9 | fibs = [fib(n) for n in range(3, 35)] 10 | print(time.time() - begin) 11 | print(fibs) 12 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/concurrent_demo/fib2.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ProcessPoolExecutor 2 | import time 3 | 4 | def fib(n: int) -> int: 5 | if n < 2: 6 | return 1 7 | return fib(n - 1) + fib(n - 2) 8 | 9 | if __name__=='__main__': 10 | with ProcessPoolExecutor() as executor: 11 | begin = time.time() 12 | futures = [executor.submit(fib, n) for n in range(3, 35)] 13 | fibs = [future.result() for future in futures] 14 | print(time.time() - begin) 15 | print(fibs) 16 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/concurrent_demo/fib3.py: -------------------------------------------------------------------------------- 1 | from concurrent.futures import ProcessPoolExecutor 2 | import time 3 | 4 | def fib(n: int) -> int: 5 | if n < 2: 6 | return 1 7 | return fib(n - 1) + fib(n - 2) 8 | 9 | if __name__=='__main__': 10 | with ProcessPoolExecutor() as executor: 11 | begin = time.time() 12 | fibs = [n for n in executor.map(fib, range(3, 35))] 13 | print(time.time() - begin) 14 | print(fibs) 15 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/concurrent_demo/yield_from_demo.py: -------------------------------------------------------------------------------- 1 | 2 | from concurrent.futures import ThreadPoolExecutor 3 | import time 4 | import random 5 | 6 | def doAsync(task): 7 | g = task() 8 | future = next(g) 9 | while True: 10 | try: 11 | future = g.send(future.result()) 12 | g.send(future.result()) 13 | except StopIteration: 14 | break 15 | 16 | def asyncFoo(n): 17 | def process(n): 18 | time.sleep(n) 19 | return n * random.random() 20 | 21 | with ThreadPoolExecutor(max_workers=4) as executor: 22 | return executor.submit(process, n) 23 | 24 | def asyncTasks(): 25 | r1 = yield asyncFoo(1) 26 | r2 = yield asyncFoo(r1) 27 | r3 = yield asyncFoo(r2) 28 | print(r3) 29 | 30 | doAsync(asyncTasks) 31 | 32 | def asyncMoreTasks(): 33 | yield from asyncTasks() 34 | yield from asyncTasks() 35 | 36 | doAsync(asyncMoreTasks) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/multiprocessing_demo/lock_demo.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | from multiprocessing.synchronize import Lock 3 | 4 | def f(lock: Lock, i: int): 5 | lock.acquire() 6 | try: 7 | print('hello world', i) 8 | print('hello world', i + 1) 9 | finally: 10 | lock.release() 11 | 12 | if __name__ == '__main__': 13 | lock: Lock = multiprocessing.Lock() 14 | 15 | for num in range(100): 16 | multiprocessing.Process(target=f, args=(lock, num)).start() -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/multiprocessing_demo/lock_demo2.py: -------------------------------------------------------------------------------- 1 | import multiprocessing 2 | from multiprocessing.synchronize import Lock 3 | 4 | def f(lock: Lock, i: int): 5 | with lock: 6 | print('hello world', i) 7 | print('hello world', i + 1) 8 | 9 | 10 | if __name__ == '__main__': 11 | lock: Lock = multiprocessing.Lock() 12 | 13 | for num in range(100): 14 | multiprocessing.Process(target=f, args=(lock, num)).start() -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/multiprocessing_demo/multi_process.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from multiprocessing import Queue, Process 3 | 4 | def foo(filename: str, queue: Queue): 5 | with open(filename) as f: 6 | text = f.read() 7 | 8 | ct = 0 9 | for ch in text: 10 | n = ord(ch.upper()) + 1 11 | if n == 67: 12 | ct += 1 13 | queue.put(ct) 14 | 15 | if __name__ == '__main__': 16 | queue: Queue = Queue() 17 | ps = [Process(target = foo, args = (filename, queue)) 18 | for filename in sys.argv[1:]] 19 | for p in ps: 20 | p.start() 21 | for p in ps: 22 | p.join() 23 | 24 | count = 0 25 | while not queue.empty(): 26 | count += queue.get() 27 | print(count) 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/multiprocessing_demo/multi_process2.py: -------------------------------------------------------------------------------- 1 | import sys, multiprocessing 2 | 3 | def foo(filename: str) -> int: 4 | with open(filename) as f: 5 | text = f.read() 6 | 7 | ct = 0 8 | for ch in text: 9 | n = ord(ch.upper()) + 1 10 | if n == 67: 11 | ct += 1 12 | return ct 13 | 14 | if __name__ == '__main__': 15 | filenames = sys.argv[1:] 16 | with multiprocessing.Pool(2) as pool: 17 | results = [pool.apply_async(foo, (filename,)) 18 | for filename in filenames] 19 | count = sum(result.get() for result in results) 20 | print(count) 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/multiprocessing_demo/no_lock.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Process, Lock 2 | 3 | def f(i: int): 4 | print('hello world', i) 5 | print('hello world', i + 1) 6 | 7 | if __name__ == '__main__': 8 | for num in range(100): 9 | Process(target=f, args=(num, )).start() -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/subprocess_demo/hi.py: -------------------------------------------------------------------------------- 1 | name = input('your name?') 2 | print('Hello, ' + name) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/subprocess_demo/loop.py: -------------------------------------------------------------------------------- 1 | while True: 2 | pass -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/subprocess_demo/multi_process.py: -------------------------------------------------------------------------------- 1 | import sys, subprocess 2 | 3 | ps = [ 4 | subprocess.Popen( 5 | ['python', 'one_process.py', filename], 6 | stdout=subprocess.PIPE 7 | ) for filename in sys.argv[1:] 8 | ] 9 | 10 | count = 0 11 | for p in ps: 12 | count += int(p.stdout.read()) 13 | 14 | print(count) 15 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/subprocess_demo/one_process.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def foo(filename: str) -> int: 4 | with open(filename) as f: 5 | text = f.read() 6 | 7 | ct = 0 8 | for ch in text: 9 | n = ord(ch.upper()) + 1 10 | if n == 67: 11 | ct += 1 12 | return ct 13 | 14 | count = 0 15 | for filename in sys.argv[1:]: 16 | count += foo(filename) 17 | 18 | print(count) 19 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/condition_demo.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | class Clerk: 4 | def __init__(self): 5 | self.product = -1 6 | self.cond = threading.Condition() 7 | 8 | def purchase(self, product: int): 9 | with self.cond: 10 | while self.product != -1: 11 | self.cond.wait() 12 | self.product = product 13 | self.cond.notify() 14 | 15 | def sellout(self) -> int: 16 | with self.cond: 17 | while self.product == -1: 18 | self.cond.wait() 19 | p = self.product 20 | self.product = -1 21 | self.cond.notify() 22 | return p 23 | 24 | def producer(clerk: Clerk): 25 | for product in range(10): 26 | clerk.purchase(product) 27 | print(f'店員進貨 ({product})') 28 | 29 | def consumer(clerk: Clerk): 30 | for product in range(10): 31 | print(f'店員賣出 ({clerk.sellout()})') 32 | 33 | 34 | clerk = Clerk(); 35 | threading.Thread(target = producer, args = (clerk, )).start() 36 | threading.Thread(target = consumer, args = (clerk, )).start() 37 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/deadlock_demo.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | class Resource: 4 | def __init__(self, name: str, resource: int) -> None: 5 | self.name = name 6 | self.resource = resource 7 | self.lock = threading.Lock() 8 | 9 | def action(self) -> int: 10 | with self.lock: 11 | self.resource += 1 12 | return self.resource 13 | 14 | def cooperate(self, other_res: 'Resource'): 15 | with self.lock: 16 | other_res.action() 17 | print(f'{self.name} 整合 {other_res.name} 的資源') 18 | 19 | def cooperate(r1: Resource, r2: Resource): 20 | for i in range(10): 21 | r1.cooperate(r2) 22 | 23 | res1 = Resource('resource 1', 10) 24 | res2 = Resource('resource 2', 20) 25 | 26 | t1 = threading.Thread(target = cooperate, args = (res1, res2)) 27 | t2 = threading.Thread(target = cooperate, args = (res2, res1)) 28 | 29 | t1.start() 30 | t2.start() 31 | 32 | 33 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/download.py: -------------------------------------------------------------------------------- 1 | from urllib.request import urlopen 2 | 3 | def download(url: str, file: str): 4 | with urlopen(url) as u, open(file, 'wb') as f: 5 | f.write(u.read()) 6 | 7 | urls = [ 8 | 'https://openhome.cc/Gossip/Encoding/', 9 | 'https://openhome.cc/Gossip/Scala/', 10 | 'https://openhome.cc/Gossip/JavaScript/', 11 | 'https://openhome.cc/Gossip/Python/' 12 | ] 13 | 14 | filenames = [ 15 | 'Encoding.html', 16 | 'Scala.html', 17 | 'JavaScript.html', 18 | 'Python.html' 19 | ] 20 | 21 | for url, filename in zip(urls, filenames): 22 | download(url, filename) 23 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/download2.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from urllib.request import urlopen 3 | 4 | def download(url: str, file: str): 5 | with urlopen(url) as u, open(file, 'wb') as f: 6 | f.write(u.read()) 7 | 8 | urls = [ 9 | 'https://openhome.cc/Gossip/Encoding/', 10 | 'https://openhome.cc/Gossip/Scala/', 11 | 'https://openhome.cc/Gossip/JavaScript/', 12 | 'https://openhome.cc/Gossip/Python/' 13 | ] 14 | 15 | filenames = [ 16 | 'Encoding.html', 17 | 'Scala.html', 18 | 'JavaScript.html', 19 | 'Python.html' 20 | ] 21 | 22 | for url, filename in zip(urls, filenames): 23 | t = threading.Thread(target = download, args = (url, filename)) 24 | t.start() 25 | 26 | 27 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/join_demo.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | def demo(): 4 | print('Thread B 開始...') 5 | for i in range(5): 6 | print('Thread B 執行...') 7 | print('Thread B 將結束...') 8 | 9 | print('Main thread 開始...') 10 | tb = threading.Thread(target = demo) 11 | tb.start() 12 | tb.join(); # Thread B 加入 Main thread 流程 13 | 14 | print('Main thread 將結束...') 15 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/lock_demo.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | from threading import Thread, Lock 3 | 4 | def setTo1(data: Dict[str, int], lock: Lock): 5 | while True: 6 | lock.acquire() 7 | try: 8 | data['Justin'] = 1 9 | if data['Justin'] != 1: 10 | raise ValueError(f'setTo1 資料不一致:{data}') 11 | finally: 12 | lock.release() 13 | 14 | def setTo2(data: Dict[str, int], lock: Lock): 15 | while True: 16 | lock.acquire() 17 | try: 18 | data['Justin'] = 2 19 | if data['Justin'] != 2: 20 | raise ValueError(f'setTo2 資料不一致:{data}') 21 | finally: 22 | lock.release() 23 | 24 | lock = Lock() 25 | data: Dict[str, int] = {} 26 | 27 | t1 = Thread(target = setTo1, args = (data, lock)) 28 | t2 = Thread(target = setTo2, args = (data, lock)) 29 | 30 | t1.start() 31 | t2.start() 32 | 33 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/lock_demo2.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | from threading import Thread, Lock 3 | 4 | def setTo1(data: Dict[str, int], lock: Lock): 5 | while True: 6 | with lock: 7 | data['Justin'] = 1 8 | if data['Justin'] != 1: 9 | raise ValueError(f'setTo1 資料不一致:{data}') 10 | 11 | def setTo2(data: Dict[str, int], lock: Lock): 12 | while True: 13 | with lock: 14 | data['Justin'] = 2 15 | if data['Justin'] != 2: 16 | raise ValueError(f'setTo2 資料不一致:{data}') 17 | 18 | lock = Lock() 19 | data: Dict[str, int] = {} 20 | 21 | t1 = Thread(target = setTo1, args = (data, lock)) 22 | t2 = Thread(target = setTo2, args = (data, lock)) 23 | 24 | t1.start() 25 | t2.start() 26 | 27 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/queue_demo.py: -------------------------------------------------------------------------------- 1 | from queue import Queue 2 | import threading 3 | 4 | def producer(clerk: Queue): 5 | for product in range(10): 6 | clerk.put(product) 7 | print(f'店員進貨 ({product})') 8 | 9 | def consumer(clerk: Queue): 10 | for product in range(10): 11 | print(f'店員賣出 ({clerk.get()})') 12 | 13 | clerk: Queue = Queue(1); 14 | threading.Thread(target = producer, args = (clerk, )).start() 15 | threading.Thread(target = consumer, args = (clerk, )).start() 16 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/race_demo.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | import threading 3 | 4 | def setTo1(data: Dict[str, int]): 5 | while True: 6 | data['Justin'] = 1 7 | if data['Justin'] != 1: 8 | raise ValueError(f'setTo1 資料不一致:{data}') 9 | 10 | def setTo2(data: Dict[str, int]): 11 | while True: 12 | data['Justin'] = 2 13 | if data['Justin'] != 2: 14 | raise ValueError(f'setTo2 資料不一致:{data}') 15 | 16 | data: Dict[str, int] = {} 17 | 18 | t1 = threading.Thread(target = setTo1, args = (data, )) 19 | t2 = threading.Thread(target = setTo2, args = (data, )) 20 | 21 | t1.start() 22 | t2.start() 23 | 24 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/stop_demo.py: -------------------------------------------------------------------------------- 1 | import threading, time 2 | 3 | class Some: 4 | def __init__(self): 5 | self.is_continue = True 6 | 7 | def terminate(self): 8 | self.is_continue = False 9 | 10 | def run(self): 11 | while self.is_continue: 12 | print('running...running') 13 | print('bye...bye...') 14 | 15 | s = Some() 16 | t = threading.Thread(target = s.run) 17 | t.start() 18 | time.sleep(2) 19 | s.terminate() -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/tortoise_hare_race.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | flags = [True, False] 4 | total_step = 10 5 | tortoise_step = 0 6 | hare_step = 0 7 | 8 | print('龜兔賽跑開始...') 9 | while tortoise_step < total_step and hare_step < total_step: 10 | tortoise_step += 1 11 | print('烏龜跑了 {} 步...'.format(tortoise_step)) 12 | sleeping = flags[int(random.random() * 10) % 2] 13 | if sleeping: 14 | print('兔子睡著了zzzz') 15 | else: 16 | hare_step += 2 17 | print('兔子跑了 {} 步...'.format(hare_step)) 18 | 19 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/tortoise_hare_race2.py: -------------------------------------------------------------------------------- 1 | import random, threading 2 | 3 | def tortoise(total_step: int): 4 | step = 0 5 | while step < total_step: 6 | step += 1 7 | print('烏龜跑了 {} 步...'.format(step)) 8 | 9 | def hare(total_step: int): 10 | step = 0 11 | flags = [True, False] 12 | while step < total_step: 13 | sleeping = flags[int(random.random() * 10) % 2] 14 | if sleeping: 15 | print('兔子睡著了zzzz') 16 | else: 17 | step += 2 18 | print('兔子跑了 {} 步...'.format(step)) 19 | 20 | t = threading.Thread(target = tortoise, args = (10,)) 21 | h = threading.Thread(target = hare, args = (10,)) 22 | 23 | t.start() 24 | h.start() 25 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH13/threading_demo/tortoise_hare_race3.py: -------------------------------------------------------------------------------- 1 | import random, threading 2 | 3 | class Tortoise(threading.Thread): 4 | def __init__(self, total_step: int) -> None: 5 | super().__init__() 6 | self.total_step = total_step 7 | 8 | def run(self): 9 | step = 0 10 | while step < self.total_step: 11 | step += 1 12 | print('烏龜跑了 {} 步...'.format(step)) 13 | 14 | class Hare(threading.Thread): 15 | def __init__(self, total_step: int) -> None: 16 | super().__init__() 17 | self.total_step = total_step 18 | 19 | def run(self): 20 | step = 0 21 | flags = [True, False] 22 | while step < self.total_step: 23 | sleeping = flags[int(random.random() * 10) % 2] 24 | if sleeping: 25 | print('兔子睡著了zzzz') 26 | else: 27 | step += 2 28 | print('兔子跑了 {} 步...'.format(step)) 29 | 30 | Tortoise(10).start() 31 | Hare(10).start() 32 | 33 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/attributes/descriptor.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Type 2 | 3 | class Descriptor: 4 | def __get__(self, instance: Any, owner: Type): 5 | print(self, instance, owner, end = '\n\n') 6 | 7 | def __set__(self, instance: Any, value: Any): 8 | print(self, instance, value, end = '\n\n') 9 | 10 | def __delete__(self, instance: Any): 11 | print(self, instance, end = '\n\n') 12 | 13 | class Some: 14 | x = Descriptor() 15 | 16 | s = Some() 17 | s.x 18 | s.x = 10 19 | del s.x 20 | 21 | Some.x 22 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/attributes/prop_demo.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Callable, Type 2 | 3 | Getter = Callable[[Any], Any] 4 | Setter = Callable[[Any, Any], None] 5 | Deleter = Callable[[Any], None] 6 | 7 | class PropDescriptor: 8 | def __init__(self, getter: Getter, setter: Setter, deleter: Deleter) -> None: 9 | self.getter = getter 10 | self.setter = setter 11 | self.deleter = deleter 12 | 13 | def __get__(self, instance: Any, owner: Type) -> Any: 14 | return self.getter(instance) 15 | 16 | def __set__(self, instance: Any, value: Any): 17 | self.setter(instance, value) 18 | 19 | def __delete__(self, instance: Any): 20 | self.deleter(instance) 21 | 22 | def prop(getter: Getter, setter: Setter, deleter: Deleter) -> PropDescriptor: 23 | return PropDescriptor(getter, setter, deleter) 24 | 25 | class Ball: 26 | def __init__(self, radius: float) -> None: 27 | if radius <= 0: 28 | raise ValueError('必須是正數') 29 | self.__radius = radius 30 | 31 | def get_radius(self) -> float: 32 | return self.__radius 33 | 34 | def set_radius(self, radius: float): 35 | self.__radius = radius 36 | 37 | def del_radius(self): 38 | del self.__radius 39 | 40 | radius = prop(get_radius, set_radius, del_radius) 41 | 42 | ball = Ball(10) 43 | print(ball.radius) 44 | ball.radius = 5 45 | print(ball.radius) 46 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/decorators/burgers.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | PriceFunc = Callable[..., float] 4 | 5 | def sidedish1(meal: PriceFunc) -> PriceFunc: 6 | return lambda: meal() + 30 7 | 8 | @sidedish1 9 | def friedchicken(): 10 | return 49.0 11 | 12 | print(friedchicken()) # 顯示 79.0 -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/decorators/burgers2.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | PriceFunc = Callable[..., float] 4 | 5 | def sidedish1(meal: PriceFunc) -> PriceFunc: 6 | return lambda: meal() + 30 7 | 8 | def sidedish2(meal: PriceFunc) -> PriceFunc: 9 | return lambda: meal() + 40 10 | 11 | @sidedish1 12 | @sidedish2 13 | def friedchicken(): 14 | return 49.0 15 | 16 | print(friedchicken()) # 顯示119.0 -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/decorators/burgers3.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | PriceFunc = Callable[..., float] 4 | SideDishDecorator = Callable[[PriceFunc], PriceFunc] 5 | 6 | def sidedish(number: int) -> SideDishDecorator: 7 | return { 8 | 1 : lambda meal: (lambda: meal() + 30), 9 | 2 : lambda meal: (lambda: meal() + 40), 10 | 3 : lambda meal: (lambda: meal() + 50), 11 | 4 : lambda meal: (lambda: meal() + 60) 12 | }.get(number, lambda meal: (lambda: meal())) 13 | 14 | @sidedish(2) 15 | @sidedish(3) 16 | def friedchicken(): 17 | return 49.0 18 | 19 | print(friedchicken()) # 顯示139.0 -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/decorators/burgers4.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | from functools import wraps 3 | 4 | PriceFunc = Callable[..., float] 5 | 6 | def sidedish1(meal: PriceFunc) -> PriceFunc: 7 | @wraps(meal) 8 | def wrapper(): 9 | return meal() + 30 10 | return wrapper 11 | 12 | @sidedish1 13 | def friedchicken(): 14 | return 49.0 15 | 16 | # 顯示 79.0 17 | print(friedchicken()) 18 | 19 | # 顯示 20 | print(friedchicken) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/decorators/burgers5.py: -------------------------------------------------------------------------------- 1 | from typing import Type 2 | from functools import wraps 3 | 4 | def sidedish1(cls: Type) -> Type: 5 | wrapped_content = cls.content 6 | wrapped_price = cls.price 7 | 8 | @wraps(wrapped_content) 9 | def content(self): 10 | return wrapped_content(self) + " | 可樂 | 薯條" 11 | 12 | @wraps(wrapped_price) 13 | def price(self): 14 | return wrapped_price(self) + 30.0 15 | 16 | cls.content = content 17 | cls.price = price 18 | 19 | return cls 20 | 21 | @sidedish1 22 | class FriedChicken: 23 | def content(self): 24 | return "不黑心炸雞" 25 | 26 | def price(self): 27 | return 49.0 28 | 29 | friedchicken = FriedChicken() 30 | print(friedchicken.content()) # 不黑心炸雞 | 可樂 | 薯條 31 | print(friedchicken.price()) # 79.0 -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/decorators/burgers6.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | from functools import wraps 3 | 4 | PriceFunc = Callable[..., float] 5 | 6 | class Sidedish1: 7 | def __init__(self, func: PriceFunc) -> None: 8 | self.func = func 9 | 10 | def __call__(self): 11 | return self.func() + 30 12 | 13 | def sidedish1(meal: PriceFunc) -> PriceFunc: 14 | sidedish1 = Sidedish1(meal) 15 | 16 | @wraps(meal) 17 | def wrapper(): 18 | return sidedish1() 19 | 20 | return wrapper 21 | 22 | @sidedish1 23 | def friedchicken(): 24 | return 49.0 25 | 26 | print(friedchicken()) # 79.0 -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/decorators/classmth_demo.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Type, Callable 2 | from functools import wraps 3 | 4 | class classmth: 5 | def __init__(self, mth: Callable) -> None: 6 | self.mth = mth 7 | 8 | def __get__(self, instance: Any, owner: Type) -> Callable: 9 | @wraps(self.mth) 10 | def wrapper(*arg, **kwargs): 11 | return self.mth(owner, *arg, **kwargs) 12 | 13 | return wrapper 14 | 15 | class Other: 16 | @classmth # 相當於 doIt = classmth(doIt) 17 | def doIt(cls, a, b): 18 | print(cls, a, b) 19 | 20 | Other.doIt(1, 2) # 相當 Other.__dict__['doIt'].__get__(None, Other)(1, 2) 21 | 22 | o = Other() 23 | o.doIt(1, 2) # 相當 Other.__dict__['doIt'].__get__(o, Other)(1, 2) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/decorators/method_demo.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | from typing import Callable 3 | 4 | def log(mth: Callable) -> Callable: 5 | @wraps(mth) 6 | def wrapper(self, *arg, **kwargs): 7 | print(self, arg, kwargs) 8 | return mth(self, *arg, **kwargs) 9 | 10 | return wrapper 11 | 12 | class Some: 13 | @log 14 | def doIt(self, a, b): 15 | return a + b 16 | 17 | s = Some() 18 | print(s.doIt(1, 2)) 19 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/decorators/staticmth_demo.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Type, Callable 2 | 3 | class staticmth: # 定義一個描述器 4 | def __init__(self, mth: Callable) -> None: 5 | self.mth = mth 6 | 7 | def __get__(self, instance: Any, owner: Type) -> Callable: 8 | return self.mth 9 | 10 | class Some: 11 | @staticmth # 相當於 doIt = staticmth(doIt) 12 | def doIt(a, b): 13 | print(a, b) 14 | 15 | Some.doIt(1, 2) # 相當於 Some.__dict__['doIt'].__get__(None, Some)(1, 2) 16 | 17 | s = Some() 18 | # 以下相當於 Some.__dict__['doIt'].__get__(s, Some)(1) 19 | # 所以以下會有錯 TypeError: doIt() missing 1 required positional argument .. 20 | s.doIt(1) 21 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/generics/bound_demo.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar 2 | from abc import ABCMeta, abstractmethod 3 | 4 | class Orderable(metaclass=ABCMeta): 5 | @abstractmethod 6 | def __lt__(self, other): 7 | pass 8 | 9 | OT = TypeVar('OT', bound=Orderable) 10 | 11 | class Ball(Orderable): 12 | def __init__(self, radius: int) -> None: 13 | self.radius = radius 14 | 15 | def __lt__(self, other): 16 | return self.radius < other.radius 17 | 18 | def orderable_min(x: OT, y: OT) -> OT: 19 | return x if x < y else y 20 | 21 | ball = orderable_min(Ball(1), Ball(2)) 22 | print(ball.radius) 23 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/generics/contravariance_demo.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar, Generic, List, Callable, Any 2 | 3 | T = TypeVar('T', contravariant=True) 4 | 5 | class Fruit: 6 | def __init__(self, weight: int, price: int) -> None: 7 | self.weight = weight 8 | self.price = price 9 | 10 | def __str__(self): 11 | return f'({self.weight}, {self.price})' 12 | 13 | class Apple(Fruit): 14 | def __init__(self, weight: int, price: int) -> None: 15 | super().__init__(weight, price) 16 | 17 | def __str__(self): 18 | return 'Apple' + super().__str__() 19 | 20 | class Banana(Fruit): 21 | def __init__(self, weight: int, price: int) -> None: 22 | super().__init__(weight, price) 23 | 24 | def __str__(self): 25 | return 'Banana' + super().__str__() 26 | 27 | class Lt(Generic[T]): 28 | def __init__(self): 29 | self.lt = [] 30 | 31 | def append(self, elem: T): 32 | self.lt.append(elem) 33 | 34 | def sort(self, key: Callable[[T], Any]): 35 | self.lt.sort(key=key) 36 | 37 | def foreach(self, consume: Callable[[T], None]): 38 | for elem in self.lt: 39 | consume(elem) 40 | 41 | 42 | class Basket(Generic[T]): 43 | def __init__(self, things: List[T]) -> None: 44 | self.things = things 45 | 46 | def dropinto(self, lt: Lt[T]): 47 | while len(self.things): 48 | lt.append(self.things.pop()) 49 | 50 | apples = Basket([Apple(25, 150), Apple(20, 100)]) 51 | bananas = Basket([Banana(15, 250), Banana(30, 500)]) 52 | 53 | fruits = Lt[Fruit]() 54 | apples.dropinto(fruits) 55 | bananas.dropinto(fruits) 56 | 57 | fruits.sort(key=lambda fruit: fruit.weight) 58 | fruits.foreach(print) 59 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/generics/covariance_demo.py: -------------------------------------------------------------------------------- 1 | from typing import TypeVar, Generic, Optional 2 | 3 | T = TypeVar('T', covariant=True) 4 | 5 | class Node(Generic[T]): 6 | def __init__(self, value: T, next: Optional['Node[T]']) -> None: 7 | self.value = value 8 | self.next = next 9 | 10 | class Fruit: 11 | pass 12 | 13 | class Apple(Fruit): 14 | def __str__(self): 15 | return 'Apple' 16 | 17 | class Banana(Fruit): 18 | def __str__(self): 19 | return 'Banana' 20 | 21 | def show(node: Node[Fruit]): 22 | n: Optional[Node[Fruit]] = node 23 | while n: 24 | print(n.value) 25 | n = n.next 26 | 27 | apple1 = Node(Apple(), None) 28 | apple2 = Node(Apple(), apple1) 29 | apple3 = Node(Apple(), apple2) 30 | 31 | banana1 = Node(Banana(), None) 32 | banana2 = Node(Banana(), banana1) 33 | banana3 = Node(Banana(), banana2) 34 | 35 | show(apple3) 36 | show(banana3) -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/metaclass_demo/call_demo.py: -------------------------------------------------------------------------------- 1 | class SomeMeta(type): 2 | def __call__(cls, *args, **kwargs): 3 | print('call __new__') 4 | instance = cls.__new__(cls, *args, **kwargs) 5 | print('call __init__') 6 | cls.__init__(instance, *args, **kwargs) 7 | return instance 8 | 9 | class Some(metaclass = SomeMeta): 10 | def __new__(cls): 11 | print('Some __new__') 12 | return object.__new__(cls) 13 | 14 | def __init__(self): 15 | print('Some __init__') 16 | 17 | s = Some() -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/metaclass_demo/call_demo2.py: -------------------------------------------------------------------------------- 1 | def metafunc(clsname, bases, attrs): 2 | print(clsname, bases, attrs) 3 | return type(clsname, bases, attrs) 4 | 5 | class Some(metaclass = metafunc): 6 | def doSome(self): 7 | print('XD') 8 | 9 | -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/metaclass_demo/myabc.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Tuple, Dict, Type, Callable 2 | 3 | Bases = Tuple[Type] 4 | Attrs = Dict[str, Callable] 5 | 6 | def abstract(func): 7 | func.__isabstract__ = True 8 | return func 9 | 10 | def absmths(cls, mths): 11 | cls.__abstractmethods__ = frozenset(mths) 12 | 13 | class Abstract(type): 14 | def __new__(mcls, clsname: str, bases: Bases, attrs: Attrs) -> Any: 15 | cls = super(mcls, mcls).__new__(mcls, clsname, bases, attrs) 16 | 17 | # 類別上定義的抽象方法 18 | abstracts = {name for name, value in attrs.items() 19 | if getattr(value, "__isabstract__", False)} 20 | 21 | # 從父類別中繼承下來的抽象方法 22 | for parent in bases: 23 | for name in getattr(parent, "__abstractmethods__", set()): 24 | value = getattr(cls, name, None) 25 | if getattr(value, "__isabstract__", False): 26 | abstracts.add(name) 27 | 28 | # 指定給 __abstractmethods__ 29 | absmths(cls, abstracts) 30 | 31 | return cls 32 | 33 | class AbstractX(metaclass=Abstract): 34 | @abstract 35 | def doSome(self): 36 | pass 37 | 38 | # TypeError: Can't instantiate abstract class AbstractX with abstract methods doSome 39 | x = AbstractX() -------------------------------------------------------------------------------- /samples-labs-exercises/samples/CH14/metaclass_demo/type_demo.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Tuple, Dict, Type, Callable 2 | 3 | Bases = Tuple[Type] 4 | Attrs = Dict[str, Callable] 5 | 6 | class SomeMeta(type): 7 | def __new__(mcls, clsname: str, bases: Bases, attrs: Attrs) -> Any: 8 | cls = super(mcls, mcls).__new__( 9 | mcls, clsname, bases, attrs) 10 | print('SomeMeta __new__', mcls, clsname, bases, attrs) 11 | return cls 12 | 13 | def __init__(self, clsname: str, bases: Bases, attrs: Attrs) -> None: 14 | super(type(self), self).__init__(clsname, bases, attrs) 15 | print('SomeMeta __init__', self, clsname, bases, attrs) 16 | 17 | Some = SomeMeta('Some', (object,), {'doSome' : (lambda self, x: print(x))}) 18 | 19 | s = Some() 20 | s.doSome(10) 21 | --------------------------------------------------------------------------------