├── .gitignore ├── Enum_tutorial.py ├── LICENSE ├── MappingProxyType_tutorial.py ├── OrderedDict_tutorial.py ├── README.md ├── __call__tutorial.py ├── __getattr__tutorial.py ├── __getitem__tutorial.py ├── __iter__tutorial.py ├── __len__tutorial.py ├── __new__tutorial.py ├── __reduce__tutorial.py ├── __str__tutorial.py ├── aiohttp_tutorial ├── README.md ├── demo_aiohttp.py ├── demo_aiohttp_client_timeout.py ├── demo_aiohttp_semaphore.py └── demo_request_session.py ├── assert_tutorial.py ├── assignment_expressions_tutorial.md ├── asyico_tutorial ├── README.md ├── demo10_asyncio.py ├── demo11_asyncio.py ├── demo1_async_1.py ├── demo1_async_2.py ├── demo1_sync.py ├── demo2_asyncio.py ├── demo3_asyncio.py ├── demo4_asyncio.py ├── demo5_asyncio.py ├── demo6_asyncio.py ├── demo7_asyncio.py ├── demo8_asyncio.py └── demo9_asyncio.py ├── attribute_obj.py ├── base64_tutorial.py ├── bcrypt_tutorial.py ├── binary_tree_traversal └── binary_tree_traversal.py ├── built-in-functions_tutorial.py ├── bytesio_tutorial.py ├── cachetools_tutorial.py ├── cap_theorem └── README.md ├── check_is_in_list.py ├── classmethod_tutorial.py ├── colorama_tutorial.py ├── commitizen_pre_commit_tutorial ├── .pre-commit-config.yaml └── README.md ├── compare_list_difference.py ├── concurrent_futures_tutorial ├── README.md ├── demo_ProcessPoolExecutor_map.py ├── demo_ProcessPoolExecutor_submit.py ├── demo_ThreadPoolExecutor_RaceConditions.py ├── demo_ThreadPoolExecutor_aviod_RaceConditions.py ├── demo_ThreadPoolExecutor_map.py └── demo_ThreadPoolExecutor_submit.py ├── configparser_tutorial ├── config.ini └── tutorial.py ├── context_manager_tutorial.py ├── convert_class_object_to_json.py ├── convert_json_to_class_object.py ├── copy_tutorial.py ├── counter_tutorial.py ├── data_structure └── linked_list │ └── Introduction │ ├── README.md │ ├── demo1.py │ ├── demo2.py │ └── demo3.py ├── dataclasses_tutorial.py ├── datetime_tutorial.py ├── decimal_tutorial.py ├── decorator_inspect.py ├── decorator_lib.py ├── decorator_tutorial.py ├── defaultdict_tutorial.py ├── dict.fromkeys_tutorial.py ├── dictionary_get.py ├── dictionary_update.py ├── dictionary_using_items.py ├── division_operators_tutorial.py ├── dj_database_url_tutorial ├── README.md └── tutorial │ ├── dj_database_url_tutorial │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py │ └── manage.py ├── eafp.py ├── enumerate_tutorial.py ├── escape_tutorial.py ├── faker_tutorial.py ├── fibonacci_numbers_tutorial ├── README.md ├── demo1.py ├── demo2.py ├── demo3.py ├── demo4.py └── demo5.py ├── filter.py ├── fnmatch_tutorial ├── README.md ├── demo1.txt ├── demo2.txt ├── demo3.txt ├── fnmatch_tutorial_1.py └── fnmatch_tutorial_2.py ├── format.py ├── freezegun_tutorial.py ├── function_default.py ├── functools_partial_tutorial.py ├── global_tutorial.py ├── globals_tutorial.py ├── graph ├── graph_iterative_dfs.py └── graph_recursive_dfs.py ├── groupby_tutorial.py ├── groupby_tutorial_find_consecutive_numbers.py ├── hashlib_tutorial ├── README.md └── detect_data.txt ├── hmac_sha256_tutorial.py ├── importlib_tutorial.py ├── interpreter └── README.md ├── is_integer_tutorial.py ├── isdigit.py ├── isinstance.py ├── itemgetter_tutorial.py ├── iter_another_trick_tutorial.py ├── iter_tutorial.py ├── iterator_in_tutorial.md ├── itertools_islice_tutorial.py ├── itertools_tee_tutorial.py ├── itertools_tutorial.py ├── join.py ├── json_tutorial.py ├── kwargs.py ├── lambda.py ├── list_tutorial.py ├── logging_tutorial.py ├── loop_if_else_break.py ├── map_tutorial.py ├── marshmallow_tutorial ├── README.md ├── demo.py ├── package_correct.json ├── package_error.json └── validating_package.py ├── match_case_tutorial.py ├── math_tutorial.py ├── methodcaller_tutorial.py ├── mock_tutorial ├── README.md ├── demo1.py ├── demo10.py ├── demo11.py ├── demo2.py ├── demo3.py ├── demo4.py ├── demo4_1.py ├── demo5.py ├── demo6.py ├── demo7.py ├── demo8.py ├── demo8_1.py ├── demo8_2.py ├── demo9.py ├── demo9_1.py ├── demo9_2.py └── my_user.py ├── namedtuple_tutorial.py ├── nested_loop_tutorial.py ├── operator_add_tutorial.py ├── operator_mul_tutorial.py ├── operator_or_xor_tutorial.py ├── pandas_tutorial ├── README.md ├── requirements.txt ├── tutorial_1 │ ├── README.md │ └── tutorial_1.py └── tutorial_2 │ ├── README.md │ └── tutorial_2.py ├── parse_dateutil.py ├── pathlib_tutorial.py ├── pickle_tutorial.py ├── pika_tutorial ├── README.md ├── docker-compose.yml ├── hello_world │ ├── consumer.py │ ├── consumer_batch.py │ ├── consumer_inactivity_timeout.py │ ├── mq_connection.py │ └── producer.py ├── pub_sub │ ├── consumer.py │ ├── mq_connection.py │ └── producer.py ├── routing │ ├── consumer_info_error.py │ ├── consumer_warning.py │ ├── mq_connection.py │ └── producer.py ├── rpc │ ├── mq_connection.py │ ├── rpc_client.py │ └── rpc_server.py ├── topic │ ├── consumer_all.py │ ├── consumer_info_error.py │ ├── consumer_warning.py │ ├── mq_connection.py │ └── producer.py └── work_queues │ ├── consumer.py │ ├── consumer2.py │ ├── mq_connection.py │ └── producer.py ├── pip-tools_tutorial ├── README.md ├── requirements.in └── requirements.txt ├── property_decorator.py ├── pycryptodome_tutorial ├── README.md ├── aes_tutorial.py ├── base64_str_key_to_sign.py ├── generator_public_private_key.py ├── rsa_encrypt_decrypted.py ├── rsa_segments_encrypt_decrypted.py └── sign_and_verify_sign.py ├── pydantic_tutorial └── README.md ├── pyenv_tutorial └── README.md ├── pyjwt_tutorial.py ├── pyotp_tutorial.md ├── pytest_tutorial ├── README.md ├── conftest.py ├── demo10_test.py ├── demo11_test.py ├── demo12_test.py ├── demo13_test.py ├── demo14_test.py ├── demo1_test.py ├── demo2_class_test.py ├── demo2_function_test.py ├── demo2_method_test.py ├── demo2_module_test.py ├── demo3_share_test.py ├── demo3_test.py ├── demo4_test.py ├── demo5_test.py ├── demo6_test.py ├── demo7_test.py ├── demo8_test.py ├── demo9_test.py └── pytest.ini ├── python-decouple-tutorial ├── README.md ├── settings.ini └── tutorial.py ├── python_circular_import ├── README.md ├── demo1 │ ├── a.py │ ├── b.py │ ├── c.py │ └── c_fix.py ├── demo2 │ ├── a2.py │ └── b2.py ├── demo3 │ ├── a3.py │ └── b3.py ├── demo4 │ ├── a4.py │ └── b4.py └── demo5 │ ├── a5.py │ └── b5.py ├── queue_tutorial.py ├── raise_an_exception_from_function_call.py ├── random_tutorial.py ├── range.py ├── re_tutorial.py ├── redis_tutorial ├── README.md ├── docker-compose.yml ├── redis_autocomplete.py ├── redis_base.py ├── redis_brpop_tutorial.py ├── redis_hash.py ├── redis_json.py ├── redis_list.py ├── redis_listen.py ├── redis_lock_unlock.py ├── redis_lpush_tutorial.py ├── redis_mbase.py ├── redis_msetnx.py ├── redis_object_class.py ├── redis_pickle.py ├── redis_pipeline.py ├── redis_pipeline_watch.py ├── redis_pub_sub.py ├── redis_pulish.py ├── redis_scan_iter.py ├── redis_set.py ├── redis_sorted_set.py ├── redis_stream.py └── redis_ttl.py ├── reduce.py ├── reduce_use_for_loop_tutorial_1.py ├── reduce_use_for_loop_tutorial_2.py ├── remove_trailing_zeros_tutorial.py ├── repr_tutorial.py ├── rjust_ljust_tutorial.py ├── set_tutorial.py ├── setdefault_tutorial.py ├── sort.py ├── sorted.py ├── staticmethod_tutorial.py ├── str_find_tutorial.py ├── str_startswith_tutorial.py ├── string_constants_tutorial.py ├── stringio_tutorial.py ├── strtobool_tutorial.py ├── sum_tutorial.py ├── suppress_tutorial.py ├── thread_process_tutorial ├── README.md ├── demo_process_join.py ├── demo_process_non_join.py ├── demo_threading_daemon.py ├── demo_threading_join.py ├── demo_threading_lock.py ├── demo_threading_non_daemon.py ├── demo_threading_non_join.py └── demo_threading_non_lock.py ├── translate_tutorial.py ├── try_except_tutorial.py ├── try_finally_tutorial.py ├── tuple_tutorial.py ├── type-hints-tutorial ├── Any_tutorial.py ├── Callable_tutorial.py ├── KeysView_tutorial.py ├── Protocol_tutorial.py ├── README.md ├── TYPE_CHECKING_tutorial │ ├── README.md │ ├── main.py │ ├── main_fix.py │ ├── module_a.py │ ├── module_a_fix.py │ ├── module_b.py │ └── module_b_fix.py ├── Tuple_tutorial.py ├── TypeVar_tutorial.py └── kwargs_args_tutorial.py ├── underscore_variable.py ├── unicodedata_tutorial.py ├── urllib_parse_quote_tutorial.py ├── use_unpacking.py ├── user_defined_exceptions_tutorial.py ├── using_a_mutable_default_value_as_an_argument.py ├── uv_tutorial └── README.md ├── vcr-tutorial └── README.md ├── weakref_tutorial.py ├── what_happens_when_you_type_an_URL_in_the_browser_and_press_enter └── README.md ├── what_is_classmethod_and_staticmethod ├── README.md ├── demo1.py └── demo2.py ├── what_is_f-string └── README.md ├── what_is_private_and_protected_attribute └── README.md ├── what_is_the_abstractmethod ├── README.md ├── demo1.py ├── demo1_fix.py ├── demo2.py ├── demo2_fix.py └── demo3.py ├── what_is_the_functools.lru_cache ├── README.md ├── clockdeco.py ├── demo1.py ├── demo2.py ├── demo3.py ├── demo4.py └── demo5.py ├── what_is_the_mixin ├── README.md ├── demo1.py ├── demo1_1.py ├── demo1_2.py ├── demo2.py └── demo2_1.py ├── what_is_the_name_main_in_python ├── README.md ├── demo1.py ├── demo2.py ├── demo3.py └── demo4.py ├── what_is_the_property ├── README.md ├── demo1.py ├── demo2.py ├── demo2_1.py └── demo3.py ├── what_is_the_python_decorator ├── README.md ├── demo1.py ├── demo2.py ├── demo3.py ├── demo4.py ├── demo4_1.py ├── demo4_2.py ├── demo5.py ├── demo6.py ├── demo7.py ├── demo7_1.py ├── demo8.py ├── demo8_1.py └── demo9.py ├── what_is_the_singledispatch ├── README.md ├── demo1.py └── demo2.py ├── what_is_the_singledispatchmethod ├── README.md ├── demo1.py ├── demo2.py ├── demo3.py └── demo4.py ├── with_as_tutorial.py ├── yield_from_tutorial.py ├── yield_tutorial.py ├── zip_tutorial.py └── zipfile_tutorial.py /Enum_tutorial.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, unique 2 | 3 | 4 | class Color(Enum): 5 | red = 1 6 | green = 2 7 | blue = 3 8 | 9 | # @unique # 不能重複定義 10 | # class ColorDuplicate(Enum): 11 | # red = 1 12 | # green = 2 13 | # blue = 2 14 | 15 | 16 | def example_1(): 17 | print('Color.red:', Color.red) 18 | print('repr(Color.red):', repr(Color.red)) 19 | print('Color(1):', Color(1)) 20 | member = Color.red 21 | print('member.name:', member.name) 22 | print('member.value:', member.value) 23 | 24 | 25 | def example_2(): 26 | animal = Enum('Animal', 'ant bee cat dog') # <1> 27 | # is equivalent to 28 | # >>> class Animal(Enum): 29 | # ... ant = 1 30 | # ... bee = 2 31 | # ... cat = 3 32 | # ... dog = 4 33 | print('animal:', animal) 34 | print('animal.ant:', animal.ant) 35 | print('animal.ant.value:', animal.ant.value) 36 | print('list(animal):', list(animal)) 37 | 38 | 39 | if __name__ == "__main__": 40 | example_1() 41 | # example_2() 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MappingProxyType_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. 2 | # https://docs.python.org/3/library/types.html#types.MappingProxyType 3 | 4 | #### 5 | # class types.MappingProxyType(mapping)¶ 6 | # Read-only proxy of a mapping. 7 | # It provides a dynamic view on the mapping’s entries, 8 | # which means that when the mapping changes, the view reflects these changes. 9 | ### 10 | 11 | from types import MappingProxyType 12 | 13 | d = {'a': 'A'} 14 | d_proxy = MappingProxyType(d) 15 | print(d_proxy) # mappingproxy({a: 'A'}) 16 | print(d_proxy['a']) # 'A' 17 | 18 | # d_proxy['b'] = 'B' 19 | # # Exception has occurred: TypeError 20 | # #'mappingproxy' object does not support item assignment 21 | 22 | d['b'] = 'B' 23 | print(d) # {'a': 'A', 'b': 'B'} 24 | print(d_proxy) # {'a': 'A', 'b': 'B'} 25 | print(d_proxy['b']) # B 26 | 27 | -------------------------------------------------------------------------------- /__call__tutorial.py: -------------------------------------------------------------------------------- 1 | class A: 2 | def __init__(self, data): 3 | self.__data = data 4 | 5 | def show(self): 6 | return self.__data 7 | 8 | # If a class defines a __call__ method, then its instances may be invoked as functions. 9 | def __call__(self): 10 | return self.show() 11 | 12 | 13 | if __name__ == "__main__": 14 | a = A('hello') 15 | print('a.show():', a.show()) 16 | print('a():', a()) 17 | # a.show() = a() 18 | print('callable(a):', callable(a)) 19 | -------------------------------------------------------------------------------- /__getattr__tutorial.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref 3 | https://docs.python.org/3/reference/datamodel.html#object.__getattr__ 4 | 5 | Called when the default attribute access fails with an AttributeError. 6 | 7 | Note that if the attribute is found through the normal mechanism, 8 | __getattr__() is not called. 9 | """ 10 | 11 | 12 | class A: 13 | def __init__(self, name: str): 14 | self.name = name 15 | 16 | def __getattribute__(self, item: str): 17 | return object.__getattribute__(self, item) 18 | 19 | def __getattr__(self, name: str) -> str: 20 | return name 21 | 22 | 23 | a = A("twtrubiks") 24 | print(a.aaa) # trigger __getattr__ 25 | print(getattr(a, "aaa")) # trigger __getattr__ 26 | 27 | print(a.name) # not trigger __getattr__ 28 | print(getattr(a, "name")) # not trigger __getattr__ 29 | -------------------------------------------------------------------------------- /__getitem__tutorial.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref 3 | https://docs.python.org/3/reference/datamodel.html#object.__getitem__ 4 | https://docs.python.org/3/reference/datamodel.html#object.__setitem__ 5 | """ 6 | 7 | 8 | class A: 9 | def __init__(self): 10 | self.my_dict = { 11 | "a": 1, 12 | "b": 2, 13 | } 14 | 15 | def __getitem__(self, key): 16 | return self.my_dict[key] 17 | 18 | def __setitem__(self, key, value): 19 | self.my_dict[key] = value 20 | 21 | 22 | a = A() 23 | print(a["a"]) 24 | print(a["b"]) 25 | a["c"] = 3 26 | print(a["c"]) 27 | -------------------------------------------------------------------------------- /__iter__tutorial.py: -------------------------------------------------------------------------------- 1 | class Product(object): 2 | def __init__(self): 3 | self.products = [ 4 | { 5 | 'id': 1, 6 | 'count': 1, 7 | 'price': 10 8 | }, 9 | { 10 | 'id': 2, 11 | 'count': 2, 12 | 'price': 20 13 | }, 14 | { 15 | 'id': 3, 16 | 'count': 3, 17 | 'price': 30 18 | }, 19 | { 20 | 'id': 4, 21 | 'count': 4, 22 | 'price': 40 23 | } 24 | ] 25 | 26 | def __iter__(self): 27 | for product in self.products: 28 | product['total'] = product['count'] * product['price'] 29 | yield product 30 | 31 | 32 | if __name__ == "__main__": 33 | p = Product() 34 | for result in p: 35 | print(result) 36 | -------------------------------------------------------------------------------- /__len__tutorial.py: -------------------------------------------------------------------------------- 1 | class Product(object): 2 | def __init__(self): 3 | self.items = [ 4 | { 5 | 'id': 1, 6 | 'value': 10 7 | }, 8 | { 9 | 'id': 2, 10 | 'value': 20 11 | }, 12 | { 13 | 'id': 3, 14 | 'value': 30 15 | }, 16 | { 17 | 'id': 4, 18 | 'value': 40 19 | } 20 | ] 21 | 22 | def __len__(self): 23 | return sum(item['value'] for item in self.items) 24 | 25 | 26 | if __name__ == "__main__": 27 | data = 'test' 28 | print('data.__str__(): {}'.format(data.__len__())) 29 | print('len(data): {}'.format(len(data))) 30 | product = Product() 31 | print('len(product): {}'.format(len(product))) 32 | -------------------------------------------------------------------------------- /__new__tutorial.py: -------------------------------------------------------------------------------- 1 | class A: 2 | def __new__(cls, *args, **kwargs): 3 | print("__new__") 4 | instance = super().__new__(cls, *args, **kwargs) 5 | return instance 6 | 7 | def __init__(self): 8 | print("__init__") 9 | 10 | 11 | class Singleton: 12 | _instance = None 13 | 14 | def __new__(cls, *args, **kwargs): 15 | if not cls._instance: 16 | cls._instance = super().__new__(cls, *args, **kwargs) 17 | return cls._instance 18 | 19 | def __init__(self): 20 | pass 21 | 22 | 23 | if __name__ == "__main__": 24 | a = A() 25 | # output 26 | # __new__ 27 | # __init__ 28 | 29 | s1 = Singleton() 30 | s2 = Singleton() 31 | print(id(s1) == id(s2)) 32 | -------------------------------------------------------------------------------- /__reduce__tutorial.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref. 3 | https://docs.python.org/3/library/pickle.html#object.__reduce__ 4 | """ 5 | 6 | import pickle 7 | import os 8 | 9 | class A: 10 | def __reduce__(self): 11 | return os.system, ("ls",) 12 | 13 | payload = pickle.dumps(A()) 14 | pickle.loads(payload) 15 | -------------------------------------------------------------------------------- /__str__tutorial.py: -------------------------------------------------------------------------------- 1 | class Person(object): 2 | def __init__(self, first, last, age): 3 | self.first = first 4 | self.last = last 5 | self.age = age 6 | 7 | def __str__(self): 8 | return '{first} {last} is {age} years old'.format(**self.__dict__) 9 | 10 | 11 | if __name__ == "__main__": 12 | data = 22 13 | print('data.__str__(): {}'.format(data.__str__())) 14 | print('type: {}'.format(type(data.__str__()))) 15 | person = Person('twt', 'rubiks', 20) 16 | print('person: {}'.format(person)) 17 | -------------------------------------------------------------------------------- /aiohttp_tutorial/demo_aiohttp.py: -------------------------------------------------------------------------------- 1 | 2 | import time 3 | import asyncio, aiohttp 4 | 5 | class WebCrawler: 6 | def __init__(self): 7 | pass 8 | 9 | async def fetch(self, session, url): 10 | async with session.get(url) as response: 11 | # https://docs.aiohttp.org/en/stable/client_reference.html 12 | html_body = await response.text() 13 | print(html_body) 14 | print(response.status) 15 | print(response.headers) 16 | print(await response.read()) 17 | # print(await response.json(encoding=None)) 18 | 19 | async def run(self): 20 | async with aiohttp.ClientSession() as session: 21 | url_link = "https://example.com/" 22 | tasks = [self.fetch(session, url_link) for _ in range(10)] 23 | await asyncio.gather(*tasks) 24 | 25 | if __name__ == "__main__": 26 | 27 | now = time.time() 28 | crawler = WebCrawler() 29 | asyncio.run(crawler.run()) 30 | print(time.time() - now) 31 | -------------------------------------------------------------------------------- /aiohttp_tutorial/demo_aiohttp_client_timeout.py: -------------------------------------------------------------------------------- 1 | 2 | import time 3 | import asyncio, aiohttp 4 | 5 | # ClientTimeout 6 | # https://docs.aiohttp.org/en/stable/client_quickstart.html#aiohttp-client-timeouts 7 | 8 | class WebCrawler: 9 | def __init__(self): 10 | pass 11 | 12 | async def fetch(self, session, url): 13 | try: 14 | async with session.get(url) as response: 15 | html_body = await response.text() 16 | except asyncio.TimeoutError as e: 17 | print('timeout') 18 | 19 | async def run(self): 20 | timeout = aiohttp.ClientTimeout(total=0.00001) 21 | async with aiohttp.ClientSession(timeout=timeout) as session: 22 | url_link = "https://example.com/" 23 | tasks = [self.fetch(session, url_link) for _ in range(10)] 24 | await asyncio.gather(*tasks) 25 | 26 | if __name__ == "__main__": 27 | 28 | now = time.time() 29 | crawler = WebCrawler() 30 | asyncio.run(crawler.run()) 31 | print(time.time() - now) 32 | -------------------------------------------------------------------------------- /aiohttp_tutorial/demo_aiohttp_semaphore.py: -------------------------------------------------------------------------------- 1 | 2 | import time 3 | import asyncio, aiohttp 4 | 5 | # https://docs.python.org/3/library/asyncio-sync.html#asyncio.Semaphore 6 | # https://stackoverflow.com/questions/55918048/asyncio-semaphore-runtimeerror-task-got-future-attached-to-a-different-loop 7 | 8 | class WebCrawler: 9 | def __init__(self): 10 | pass 11 | 12 | async def fetch(self, session, url, semaphore): 13 | async with semaphore: 14 | async with session.get(url) as response: 15 | html_body = await response.text() 16 | print(html_body) 17 | 18 | async def run(self): 19 | async with aiohttp.ClientSession() as session: 20 | semaphore = asyncio.Semaphore(2) 21 | url_link = "https://example.com/" 22 | tasks = [self.fetch(session, url_link, semaphore) for _ in range(10)] 23 | await asyncio.gather(*tasks) 24 | 25 | if __name__ == "__main__": 26 | 27 | now = time.time() 28 | crawler = WebCrawler() 29 | asyncio.run(crawler.run()) 30 | print(time.time() - now) 31 | -------------------------------------------------------------------------------- /aiohttp_tutorial/demo_request_session.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | # Using a session as a best practice 4 | # https://docs.aiohttp.org/en/stable/http_request_lifecycle.html#aiohttp-request-lifecycle 5 | 6 | with requests.Session() as session: 7 | response = session.get('http://python.org') 8 | print(response.text) 9 | -------------------------------------------------------------------------------- /assert_tutorial.py: -------------------------------------------------------------------------------- 1 | 2 | def ex1(): 3 | 4 | x = "hello" 5 | 6 | # returns True, then nothing happens 7 | assert x == "hello" 8 | 9 | # raise AssertionError 10 | assert x == "world" 11 | 12 | def ex2(): 13 | 14 | x = "hello" 15 | assert x == "world", "x should be 'hello'" 16 | 17 | if __name__ == "__main__": 18 | ex1() 19 | # ex2() 20 | 21 | -------------------------------------------------------------------------------- /asyico_tutorial/demo10_asyncio.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | 4 | 5 | async def a(): 6 | print("Suspending a") 7 | await asyncio.sleep(1) 8 | # raise Exception('error') 9 | 10 | 11 | async def b(): 12 | print("Suspending b") 13 | await asyncio.sleep(2) 14 | print("Resuming b") 15 | return "B" 16 | 17 | 18 | async def main(): 19 | done, pending = await asyncio.wait( 20 | [a(), b()], return_when=asyncio.tasks.ALL_COMPLETED 21 | ) 22 | print("done:", done) 23 | print("pending:", pending) 24 | 25 | 26 | start = time.time() 27 | asyncio.run(main()) 28 | print("TIME: ", time.time() - start) 29 | -------------------------------------------------------------------------------- /asyico_tutorial/demo11_asyncio.py: -------------------------------------------------------------------------------- 1 | # https://docs.python.org/3/library/asyncio-subprocess.html 2 | 3 | import asyncio 4 | import sys 5 | 6 | async def get_date(): 7 | code = 'import datetime; print(datetime.datetime.now())' 8 | 9 | # Create the subprocess; redirect the standard output 10 | # into a pipe. 11 | proc = await asyncio.create_subprocess_exec( 12 | sys.executable, '-c', code, 13 | stdout=asyncio.subprocess.PIPE) 14 | 15 | # Read one line of output. 16 | data = await proc.stdout.readline() 17 | line = data.decode('ascii').rstrip() 18 | 19 | # Wait for the subprocess exit. 20 | await proc.wait() 21 | return line 22 | 23 | async def main(): 24 | result = await asyncio.gather( 25 | get_date(), 26 | get_date(), 27 | get_date()) 28 | 29 | print(result) 30 | 31 | asyncio.run(main()) 32 | -------------------------------------------------------------------------------- /asyico_tutorial/demo1_async_1.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://docs.python.org/3/library/asyncio.html 3 | asyncio is often a perfect fit for IO-bound and high-level structured network code. 4 | """ 5 | 6 | import asyncio 7 | import time 8 | 9 | # def 前面加上 async 就會變成 coroutine function (有非同步的功能) 10 | async def something(num): 11 | print('第 {} 任務,第一步'.format(num)) 12 | # time.sleep is blocking call. 13 | # Hence, it cannot be awaited and we have to use asyncio.sleep 14 | # await 就是用來暫停或繼續的點, 其實它背後就是用 yield 實做的 15 | await asyncio.sleep(2) 16 | print('第 {} 任務,第二步'.format(num)) 17 | 18 | if __name__ == "__main__": 19 | start = time.time() 20 | tasks = [something(i) for i in range(5)] 21 | asyncio.run(asyncio.wait(tasks)) 22 | print('TIME: ', time.time() - start) 23 | 24 | -------------------------------------------------------------------------------- /asyico_tutorial/demo1_async_2.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://docs.python.org/3/library/asyncio.html 3 | asyncio is often a perfect fit for IO-bound and high-level structured network code. 4 | """ 5 | 6 | import asyncio 7 | import time 8 | 9 | # def 前面加上 async 就會變成 coroutine function (有非同步的功能) 10 | async def something(num): 11 | print('第 {} 任務,第一步'.format(num)) 12 | # time.sleep is blocking call. 13 | # Hence, it cannot be awaited and we have to use asyncio.sleep 14 | # await 就是用來暫停或繼續的點, 其實它背後就是用 yield 實做的 15 | await asyncio.sleep(2) 16 | print('第 {} 任務,第二步'.format(num)) 17 | 18 | async def main(): 19 | tasks = [something(i) for i in range(5)] 20 | await asyncio.wait(tasks) 21 | 22 | if __name__ == "__main__": 23 | start = time.time() 24 | asyncio.run(main()) 25 | print('TIME: ', time.time() - start) 26 | 27 | -------------------------------------------------------------------------------- /asyico_tutorial/demo1_sync.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | def something(num): 4 | print('第 {} 任務,第一步'.format(num)) 5 | time.sleep(2) 6 | print('第 {} 任務,第二步'.format(num)) 7 | 8 | if __name__ == "__main__": 9 | start = time.time() 10 | tasks = [something(i) for i in range(5)] 11 | print('TIME: ', time.time() - start) -------------------------------------------------------------------------------- /asyico_tutorial/demo2_asyncio.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | async def main(): 4 | print('hello') 5 | await asyncio.sleep(1) 6 | print('world') 7 | 8 | 9 | asyncio.run(main()) -------------------------------------------------------------------------------- /asyico_tutorial/demo3_asyncio.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | 4 | async def say_after(delay, what): 5 | await asyncio.sleep(delay) 6 | print(what) 7 | 8 | async def main(): 9 | print(f"started at {time.strftime('%X')}") 10 | 11 | await say_after(1, 'hello') 12 | await say_after(2, 'world') 13 | 14 | print(f"finished at {time.strftime('%X')}") 15 | 16 | start = time.time() 17 | asyncio.run(main()) 18 | print('TIME: ', time.time() - start) -------------------------------------------------------------------------------- /asyico_tutorial/demo4_asyncio.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | 4 | async def say_after(delay, what): 5 | await asyncio.sleep(delay) 6 | print(what) 7 | 8 | async def main(): 9 | task1 = asyncio.create_task( 10 | say_after(1, 'hello')) 11 | 12 | task2 = asyncio.create_task( 13 | say_after(2, 'world')) 14 | 15 | print(f"started at {time.strftime('%X')}") 16 | 17 | # Wait until both tasks are completed (should take 18 | # around 2 seconds.) 19 | await task1 20 | await task2 21 | 22 | print(f"finished at {time.strftime('%X')}") 23 | 24 | start = time.time() 25 | asyncio.run(main()) 26 | print('TIME: ', time.time() - start) -------------------------------------------------------------------------------- /asyico_tutorial/demo5_asyncio.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | async def nested(): 4 | return 42 5 | 6 | async def main(): 7 | # Nothing happens if we just call "nested()". 8 | # A coroutine object is created but not awaited, 9 | # so it *won't run at all*. 10 | nested() 11 | 12 | # Let's do it differently now and await it: 13 | print(await nested()) # will print "42". 14 | 15 | asyncio.run(main()) -------------------------------------------------------------------------------- /asyico_tutorial/demo6_asyncio.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | async def nested(): 4 | return 42 5 | 6 | async def main(): 7 | # Schedule nested() to run soon concurrently 8 | # with "main()". 9 | task = asyncio.create_task(nested()) 10 | 11 | # "task" can now be used to cancel "nested()", or 12 | # can simply be awaited to wait until it is complete: 13 | print(await task) 14 | 15 | 16 | asyncio.run(main()) -------------------------------------------------------------------------------- /asyico_tutorial/demo7_asyncio.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | async def nested(): 4 | return 42 5 | 6 | background_tasks = set() 7 | 8 | def task_cb(context): 9 | print("Task completion received...") 10 | print("Name of the task:%s"%context.get_name()) 11 | # print("Wrapped coroutine object:%s"%context.get_coro()) 12 | print("Task is done:%s"%context.done()) 13 | print("Task has been cancelled:%s"%context.cancelled()) 14 | print("Task result:%s"%context.result()) 15 | 16 | print(context) 17 | # To prevent keeping references to finished tasks forever, 18 | # make each task remove its own reference from the set after 19 | # completion: 20 | background_tasks.discard(context) 21 | 22 | async def main(): 23 | for _ in range(10): 24 | task = asyncio.create_task(nested()) 25 | 26 | # Add task to the set. This creates a strong reference. 27 | background_tasks.add(task) 28 | # https://docs.python.org/3/library/asyncio-future.html#asyncio.Future.add_done_callback 29 | task.add_done_callback(task_cb) 30 | 31 | asyncio.run(main()) -------------------------------------------------------------------------------- /asyico_tutorial/demo8_asyncio.py: -------------------------------------------------------------------------------- 1 | # https://docs.python.org/3/library/asyncio-task.html#asyncio.wait_for 2 | 3 | import asyncio 4 | 5 | async def eternity(): 6 | # Sleep for one hour 7 | await asyncio.sleep(3600) 8 | print('yay!') 9 | 10 | async def main(): 11 | # Wait for at most 1 second 12 | try: 13 | await asyncio.wait_for(eternity(), timeout=1) 14 | except asyncio.TimeoutError: 15 | print('timeout!') 16 | 17 | asyncio.run(main()) -------------------------------------------------------------------------------- /asyico_tutorial/demo9_asyncio.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import time 3 | 4 | async def something(num): 5 | print('第 {} 任務,第一步'.format(num)) 6 | await asyncio.sleep(2) 7 | print('第 {} 任務,第二步'.format(num)) 8 | return '第 {} 任務完成'.format(num) 9 | 10 | async def raise_error(): 11 | 1/0 12 | 13 | async def main(): 14 | tasks = [something(i) for i in range(5)] 15 | tasks1 = [raise_error() for _ in range(5)] 16 | 17 | # https://docs.python.org/3/library/asyncio-task.html#asyncio.gather 18 | results = await asyncio.gather(*tasks, *tasks1, return_exceptions=True) 19 | print(results) 20 | 21 | 22 | if __name__ == "__main__": 23 | 24 | start = time.time() 25 | asyncio.run(main()) 26 | print("TIME:", time.time() - start) -------------------------------------------------------------------------------- /attribute_obj.py: -------------------------------------------------------------------------------- 1 | class Person(object): 2 | name = 'twtrubiks' 3 | 4 | 5 | if __name__ == "__main__": 6 | p = Person() 7 | print('Before Set: {}'.format(p.name)) 8 | 9 | # The setattr() method sets the value of given attribute of an object. 10 | # setattr(object, name, value) 11 | setattr(p, 'name', 'rubiks') 12 | print('After Set: {}'.format(p.name)) 13 | 14 | # The getattr() method returns the value of the named attribute of an object 15 | # getattr(object, name[, default]) 16 | # default (Optional) - value that is returned when the named attribute is not found 17 | print('The age is: {}'.format(getattr(p, 'age', 'default_20'))) 18 | # print('The age is:'.format(p.age)) # error 19 | 20 | # creates a new attribute 21 | setattr(p, 'age', 18) 22 | print('After Set afe: {}'.format(getattr(p, 'age', 'default_20'))) 23 | 24 | # The hasattr() method returns true if an object has the given named attribute and false if it does not. 25 | # hasattr(object, name) 26 | print('Person has name?: {}'.format(hasattr(p, 'name'))) 27 | print('Person has salary?: {}'.format(hasattr(p, 'salary'))) 28 | -------------------------------------------------------------------------------- /base64_tutorial.py: -------------------------------------------------------------------------------- 1 | from base64 import b64encode, b64decode 2 | 3 | 4 | # encoded_data = b64encode(b'hello').decode() 5 | # or 6 | encoded_data = b64encode('hello'.encode("utf-8")).decode() 7 | print("encoded_data:", encoded_data) 8 | 9 | decoded_data = b64decode("aGVsbG8=") 10 | print("decoded_data:", decoded_data.decode()) 11 | 12 | -------------------------------------------------------------------------------- /bcrypt_tutorial.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://pypi.org/project/bcrypt/ 3 | 4 | pip install bcrypt 5 | 6 | 明碼保存進 db 很危險, 這邊使用 bcrypt 加密(hash)後再保存進去 db 7 | (Hash Value 不可逆) 8 | 9 | 10 | 和 hashlib 相比, bcrypt 是專門為了安全儲存密碼加密用的. 11 | """ 12 | 13 | import bcrypt 14 | 15 | def ex1(): 16 | print('加密 user password') 17 | user_input_pwd = 'mypassword' 18 | passwd = user_input_pwd.encode('utf-8') 19 | salt = bcrypt.gensalt(rounds=16) # rounds 越大越安全, 但加密時間越久 20 | hashed_pwd = bcrypt.hashpw(passwd, salt) 21 | print('hashed_pwd:', hashed_pwd) 22 | save_db_pwd = hashed_pwd.decode('utf-8') 23 | print('save db:', save_db_pwd) 24 | 25 | print('開始驗證') 26 | print('user input pwd:', user_input_pwd) 27 | if bcrypt.checkpw(user_input_pwd.encode('utf-8'), save_db_pwd.encode('utf-8')): 28 | print("match") 29 | else: 30 | print("does not match") 31 | 32 | 33 | if __name__ == "__main__": 34 | ex1() -------------------------------------------------------------------------------- /bytesio_tutorial.py: -------------------------------------------------------------------------------- 1 | # https://docs.python.org/3/library/io.html#binary-i-o 2 | 3 | # StringIO 只能是 str,如果要操作 bytes data 就要使用 BytesIO 4 | 5 | from io import BytesIO 6 | 7 | def tutorial_1(): 8 | # BytesIO 實作在內存 ( 記憶體 ram )中讀寫 bytes 9 | f = BytesIO() 10 | # 寫入的不是 str , 而是經過 utf-8 編碼的 bytes 11 | f.write('中文'.encode('utf-8')) 12 | print(f.getvalue()) 13 | f.close() # 釋放記憶體 14 | 15 | def tutorial_2(): 16 | f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87') 17 | result = f.read() 18 | print(result) 19 | print(result.decode('utf-8')) 20 | 21 | def main(): 22 | tutorial_1() 23 | # tutorial_2() 24 | 25 | if __name__ == "__main__": 26 | main() -------------------------------------------------------------------------------- /check_is_in_list.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | # check is target in list 3 | target = 'test' 4 | if target in ['test', 'yo', 'soso']: 5 | print('{} in list'.format(target)) 6 | else: 7 | print('{} not in list'.format(target)) 8 | -------------------------------------------------------------------------------- /colorama_tutorial.py: -------------------------------------------------------------------------------- 1 | # pip install colorama 2 | # https://pypi.org/project/colorama/ 3 | 4 | from colorama import Fore, Back, Style 5 | 6 | print(Fore.RED + 'some red text') 7 | print(Back.RED + 'some red text') 8 | print(Back.GREEN + 'and with a green background') -------------------------------------------------------------------------------- /commitizen_pre_commit_tutorial/.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/commitizen-tools/commitizen 3 | rev: v3.29.0 4 | hooks: 5 | - id: commitizen 6 | - id: commitizen-branch 7 | stages: [commit-msg] 8 | 9 | - repo: https://github.com/pre-commit/pre-commit-hooks 10 | rev: v4.6.0 11 | hooks: 12 | - id: check-yaml 13 | - id: end-of-file-fixer 14 | - id: trailing-whitespace 15 | 16 | - repo: https://github.com/python/black 17 | rev: 24.8.0 18 | hooks: 19 | - id: black 20 | 21 | - repo: https://github.com/pycqa/flake8 22 | rev: 7.1.1 23 | hooks: 24 | - id: flake8 25 | 26 | - repo: https://github.com/crate-ci/typos 27 | rev: v1.24.6 28 | hooks: 29 | - id: typos -------------------------------------------------------------------------------- /compare_list_difference.py: -------------------------------------------------------------------------------- 1 | # compare_list_difference 2 | 3 | if __name__ == "__main__": 4 | list_1 = [1, 2, 3, 4, 5] 5 | list_2 = [2, 0, 4, 6, 7] 6 | ''' 7 | # ex_1 list_1 - list_2 => {1, 3, 5} 8 | ''' 9 | ex_1 = set(list_1) - set(list_2) 10 | print('ex_1', ex_1) 11 | ''' 12 | # ex_2 list_1 - list_2 => { 0, 1, 3, 5, 6, 7 } 13 | ref. https://docs.python.org/3/library/stdtypes.html#frozenset.symmetric_difference 14 | ''' 15 | ex_2 = set(list_1).symmetric_difference(list_2) 16 | print('ex_2', ex_2) 17 | ''' 18 | # ex_3 list_1 and list_2 duplicate => {2, 4} 19 | ref. https://docs.python.org/3/library/stdtypes.html#frozenset.intersection 20 | ''' 21 | ex_3 = set(list_1).intersection(set(list_2)) 22 | print('ex_3', ex_3) 23 | -------------------------------------------------------------------------------- /concurrent_futures_tutorial/demo_ProcessPoolExecutor_map.py: -------------------------------------------------------------------------------- 1 | import time 2 | from concurrent.futures import ProcessPoolExecutor 3 | 4 | def calculate_time(func): 5 | def timeit_wrapper(*args, **kwargs): 6 | start_time = time.perf_counter_ns() 7 | result = func(*args, **kwargs) 8 | end_time = time.perf_counter_ns() 9 | total_time = end_time - start_time 10 | print('total_time: {} ms'.format(total_time // 1000000)) 11 | return result 12 | return timeit_wrapper 13 | 14 | def fib(n): 15 | if n < 2: 16 | return n 17 | return fib(n - 1) + fib(n - 2) 18 | 19 | @calculate_time 20 | def main(): 21 | with ProcessPoolExecutor() as executor: 22 | for result in executor.map(fib, [10, 11, 12, 13] * 100, chunksize=1): 23 | print(result) 24 | 25 | main() 26 | -------------------------------------------------------------------------------- /concurrent_futures_tutorial/demo_ProcessPoolExecutor_submit.py: -------------------------------------------------------------------------------- 1 | import time 2 | from concurrent.futures import ProcessPoolExecutor 3 | import subprocess 4 | 5 | def calculate_time(func): 6 | def timeit_wrapper(*args, **kwargs): 7 | start_time = time.perf_counter() 8 | result = func(*args, **kwargs) 9 | end_time = time.perf_counter() 10 | total_time = end_time - start_time 11 | print('total_time: {} seconds'.format(total_time)) 12 | return result 13 | return timeit_wrapper 14 | 15 | def task(id): 16 | print('start {}'.format(id)) 17 | subprocess.run(["date", "+%c"]) 18 | time.sleep(1) 19 | return 'end {}'.format(id) 20 | 21 | @calculate_time 22 | def main(): 23 | with ProcessPoolExecutor(max_workers=1) as executor: 24 | future1 = executor.submit(task, 1) 25 | future2 = executor.submit(task, 2) 26 | future3 = executor.submit(task, 3) 27 | future4 = executor.submit(task, 4) 28 | 29 | print(future1.result()) 30 | print(future2.result()) 31 | print(future3.result()) 32 | print(future4.result()) 33 | 34 | main() 35 | -------------------------------------------------------------------------------- /concurrent_futures_tutorial/demo_ThreadPoolExecutor_RaceConditions.py: -------------------------------------------------------------------------------- 1 | import time 2 | from concurrent.futures import ThreadPoolExecutor 3 | 4 | class A: 5 | def __init__(self): 6 | self.value = 0 7 | 8 | def update(self): 9 | print("Update Started") 10 | time.sleep(2) 11 | tmp = self.value + 1 12 | print("Updating Value") 13 | self.value = tmp 14 | print("Updating Finished") 15 | 16 | for i in range(10): 17 | # 如果輸出 1 , 就是 RaceConditions 18 | db = A() 19 | with ThreadPoolExecutor(max_workers=5) as executor: 20 | updates = [executor.submit(db.update) for _ in range(2)] 21 | 22 | if db.value != 2: 23 | print('Race Conditions') 24 | 25 | print(db.value) -------------------------------------------------------------------------------- /concurrent_futures_tutorial/demo_ThreadPoolExecutor_aviod_RaceConditions.py: -------------------------------------------------------------------------------- 1 | import time 2 | from concurrent.futures import ThreadPoolExecutor 3 | import threading 4 | 5 | LOCK = threading.Lock() 6 | 7 | class A: 8 | def __init__(self): 9 | self.value = 0 10 | 11 | def update(self): 12 | print("Update Started") 13 | time.sleep(2) # thread gets switched 14 | with LOCK: 15 | tmp = self.value + 1 16 | print("Updating Value") 17 | self.value = tmp 18 | print("Updating Finished") 19 | 20 | for i in range(10): 21 | db = A() 22 | with ThreadPoolExecutor(max_workers=5) as executor: 23 | updates = [executor.submit(db.update) for _ in range(2)] 24 | 25 | if db.value != 2: 26 | print('Race Conditions') 27 | 28 | print(db.value) -------------------------------------------------------------------------------- /concurrent_futures_tutorial/demo_ThreadPoolExecutor_map.py: -------------------------------------------------------------------------------- 1 | import time 2 | from concurrent.futures import ThreadPoolExecutor 3 | 4 | def calculate_time(func): 5 | def timeit_wrapper(*args, **kwargs): 6 | start_time = time.perf_counter() 7 | result = func(*args, **kwargs) 8 | end_time = time.perf_counter() 9 | total_time = end_time - start_time 10 | print('total_time: {} seconds'.format(total_time)) 11 | return result 12 | return timeit_wrapper 13 | 14 | def task(id): 15 | print('start {}'.format(id)) 16 | time.sleep(1) 17 | return 'end {}'.format(id) 18 | 19 | @calculate_time 20 | def main(): 21 | with ThreadPoolExecutor(max_workers=2) as executor: 22 | for result in executor.map(task, [1, 2, 3, 4]): 23 | print(result) 24 | 25 | main() 26 | -------------------------------------------------------------------------------- /concurrent_futures_tutorial/demo_ThreadPoolExecutor_submit.py: -------------------------------------------------------------------------------- 1 | import time 2 | from concurrent.futures import ThreadPoolExecutor 3 | 4 | def calculate_time(func): 5 | def timeit_wrapper(*args, **kwargs): 6 | start_time = time.perf_counter() 7 | result = func(*args, **kwargs) 8 | end_time = time.perf_counter() 9 | total_time = end_time - start_time 10 | print('total_time: {} seconds'.format(total_time)) 11 | return result 12 | return timeit_wrapper 13 | 14 | def task(id): 15 | print('start {}'.format(id)) 16 | time.sleep(1) 17 | return 'end {}'.format(id) 18 | 19 | @calculate_time 20 | def main(): 21 | with ThreadPoolExecutor(max_workers=1) as executor: 22 | future1 = executor.submit(task, 1) 23 | future2 = executor.submit(task, 2) 24 | future3 = executor.submit(task, 3) 25 | future4 = executor.submit(task, 4) 26 | 27 | print(future1.result()) 28 | print(future2.result()) 29 | print(future3.result()) 30 | print(future4.result()) 31 | 32 | main() 33 | -------------------------------------------------------------------------------- /configparser_tutorial/config.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | ServerAliveInterval = 45 3 | Compression = Yes 4 | CompressionLevel = 9 5 | 6 | [bitbucket.org] 7 | User = twtrubiks 8 | 9 | [topsecret.server.com] 10 | Port = 50022 11 | ForwardX11 = no -------------------------------------------------------------------------------- /configparser_tutorial/tutorial.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | 3 | # ref. https://docs.python.org/3/library/configparser.html 4 | config = configparser.ConfigParser() 5 | config.read("config.ini") 6 | 7 | print(config['DEFAULT']['Compression']) 8 | 9 | # Note also that keys in sections are case-insensitive and stored in lowercase 10 | print(config['DEFAULT']['ServerAliveInterval']) 11 | print(config['DEFAULT']['serveraliveinterval']) 12 | 13 | print(config['bitbucket.org']['User']) 14 | -------------------------------------------------------------------------------- /context_manager_tutorial.py: -------------------------------------------------------------------------------- 1 | import time 2 | from contextlib import contextmanager 3 | 4 | 5 | @contextmanager 6 | def my_context(): 7 | # do things in enter ( __enter__ ) 8 | yield 9 | # do things post ( __exit__ ) 10 | 11 | 12 | @contextmanager 13 | def tag(name): 14 | print('<{}>'.format(name)) 15 | yield 'HIHI~' 16 | print(''.format(name)) 17 | 18 | 19 | @contextmanager 20 | def elapsed_time(name=''): 21 | start_time = time.time() 22 | yield 23 | end_time = time.time() - start_time 24 | print(name, '{:.2f}'.format(end_time)) 25 | 26 | 27 | @contextmanager 28 | def try_catch(): 29 | try: 30 | yield 'okok' 31 | except Exception as e: 32 | print("e=%s" % str(e)) 33 | finally: 34 | print('stop') 35 | 36 | 37 | if __name__ == '__main__': 38 | # tutorial_1 39 | with tag('h1') as data: 40 | print('hello') 41 | print(data) 42 | 43 | # tutorial_2 44 | # with tag('h1'), tag('p'): 45 | # print('hello') 46 | 47 | # tutorial_3 48 | # with elapsed_time('block'): 49 | # time.sleep(2) 50 | 51 | # tutorial_4 52 | # with try_catch() as data: 53 | # print(data) 54 | # source = 1/0 55 | 56 | -------------------------------------------------------------------------------- /convert_class_object_to_json.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | class Stock: 5 | def __init__(self, num, date): 6 | self.num = num 7 | self.date = date 8 | self.push_date = ["5/3"] 9 | 10 | 11 | # create object 12 | stock = Stock("2222", "2/3") 13 | 14 | # convert to JSON string 15 | json_str = json.dumps(stock.__dict__) 16 | 17 | print(json_str) 18 | -------------------------------------------------------------------------------- /convert_json_to_class_object.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | 4 | class User: 5 | def __init__(self, name): 6 | self.name = name 7 | 8 | 9 | class Stock: 10 | def __init__(self, num, date, user): 11 | self.num = num 12 | self.date = date 13 | self.user = user 14 | 15 | 16 | # create object 17 | user = User("twtrubiks") 18 | stock = Stock("2222", "2/3", user) 19 | 20 | # convert to JSON string 21 | json_str = json.dumps(stock, default=lambda o: o.__dict__) 22 | print(json_str) 23 | 24 | json_data = json.loads(json_str) 25 | stock_obj = Stock(**json_data) 26 | print(stock_obj) 27 | -------------------------------------------------------------------------------- /copy_tutorial.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | if __name__ == "__main__": 4 | ''' 5 | ref. https://docs.python.org/3.6/library/copy.html 6 | 7 | ''' 8 | origin_list = [1, 2, [3, 4]] 9 | copy1 = copy.copy(origin_list) # shallow copy 10 | copy2 = copy.deepcopy(origin_list) # deep (recursive) copy 11 | print(copy1 == copy2) 12 | print(copy1 is copy2) 13 | origin_list[2][0] = "yoyo" 14 | print('origin_list:', origin_list) 15 | print('copy1:', copy1) 16 | print('copy2:', copy2) 17 | -------------------------------------------------------------------------------- /counter_tutorial.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | 4 | def ex1(): 5 | c = Counter(['eggs', 'ham', 'eggs']) 6 | print('c[bacon]:', c['bacon']) 7 | print('c[eggs]:', c['eggs']) 8 | print('c:', c) 9 | 10 | 11 | def ex2(): 12 | cnt = Counter() 13 | for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']: 14 | cnt[word] += 1 15 | print(cnt) 16 | 17 | 18 | def method_elements(): 19 | c = Counter(a=4, b=2, c=0, d=-2) 20 | show = sorted(c.elements()) 21 | print(show) 22 | print('c.values():', c.values()) 23 | print('sum:', sum(c.values())) 24 | 25 | 26 | def method_most_common(): 27 | show = Counter('abracadabra').most_common(3) 28 | print(show) 29 | 30 | 31 | def patterns(): 32 | c = Counter(a=2, b=-4, c=0) 33 | print('+c:', +c) 34 | print('-c:', -c) 35 | # +c # remove zero and negative counts 36 | 37 | 38 | def method_subtract(): 39 | c = Counter(a=4, b=2, c=0, d=-2) 40 | d = Counter(a=1, b=2, c=3, d=4) 41 | c.subtract(d) 42 | print('c:', c) 43 | 44 | 45 | if __name__ == "__main__": 46 | ex1() 47 | ex2() 48 | method_elements() 49 | method_most_common() 50 | patterns() 51 | method_subtract() 52 | -------------------------------------------------------------------------------- /data_structure/linked_list/Introduction/demo1.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | class ListNode: 3 | def __init__(self, val): 4 | self.val = val 5 | self.next = None # the pointer 6 | 7 | 8 | node1 = ListNode(2) 9 | node2 = ListNode(5) 10 | node3 = ListNode(7) 11 | 12 | node1.next = node2 # 2->5 13 | node2.next = node3 # 5->7 14 | 15 | # the entire linked list : 2->5->7 16 | -------------------------------------------------------------------------------- /data_structure/linked_list/Introduction/demo2.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | class ListNode: 3 | def __init__(self, val): 4 | self.val = val 5 | self.next = None # the pointer 6 | 7 | 8 | node1 = ListNode(2) 9 | node2 = ListNode(5) 10 | node3 = ListNode(7) 11 | 12 | node1.next = node2 # 2->5 13 | node2.next = node3 # 5->7 14 | 15 | 16 | # the entire linked list : 2->5->7 17 | 18 | 19 | while node1: 20 | print(node1.val) 21 | node1 = node1.next 22 | -------------------------------------------------------------------------------- /data_structure/linked_list/Introduction/demo3.py: -------------------------------------------------------------------------------- 1 | # Definition for singly-linked list. 2 | class ListNode: 3 | def __init__(self, val): 4 | self.val = val 5 | self.next = None # the pointer 6 | 7 | 8 | node1 = ListNode(2) 9 | node2 = ListNode(5) 10 | node3 = ListNode(7) 11 | 12 | node1.next = node2 # 2->5 13 | node2.next = node3 # 5->7 14 | 15 | 16 | def traversing_recursive(lists): 17 | if not lists: 18 | return 19 | print(lists.val) 20 | traversing_recursive(lists.next) 21 | print(lists.val) 22 | 23 | 24 | traversing_recursive(node1) 25 | -------------------------------------------------------------------------------- /decorator_inspect.py: -------------------------------------------------------------------------------- 1 | 2 | import inspect 3 | 4 | def autovacuum(method): 5 | assert method.__name__.startswith('_'), "%s: autovacuum methods must be private" % method.__name__ 6 | method._autovacuum = True 7 | return method 8 | 9 | class A: 10 | @autovacuum 11 | def _gc_file_store_A(self): 12 | print('run _gc_file_store_A') 13 | 14 | class B: 15 | # @autovacuum 16 | def _gc_file_store_B(self): 17 | print('run _gc_file_store_B') 18 | 19 | def is_autovacuum(func): 20 | """ Return whether ``func`` is an autovacuum method. """ 21 | return callable(func) and getattr(func, '_autovacuum', False) 22 | 23 | class AutoVacuum: 24 | 25 | my_data = [A(), B()] 26 | 27 | def _run_vacuum_cleaner(self): 28 | """ 29 | Perform a complete database cleanup by safely calling every 30 | ``@api.autovacuum`` decorated method. 31 | """ 32 | for model in self.my_data: 33 | cls = type(model) 34 | for attr, func in inspect.getmembers(cls, is_autovacuum): 35 | print('work') 36 | func(model) 37 | print('attr:', attr) 38 | print('func:', func) 39 | 40 | AutoVacuum()._run_vacuum_cleaner() -------------------------------------------------------------------------------- /decorator_lib.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | from decorator import decorator 3 | 4 | # decorator (https://github.com/micheles/decorator) 5 | # pip3 install decorator 6 | 7 | @decorator 8 | def func_log_use_lib(func, *args, **kw): 9 | print('call', func.__name__) 10 | result = func(*args, **kw) 11 | print('end', func.__name__) 12 | return result 13 | 14 | # 原生 decorator 15 | def func_log(func): 16 | @wraps(func) 17 | def wrapped(): 18 | print('call', func.__name__) 19 | func() 20 | print('end', func.__name__) 21 | 22 | return wrapped 23 | 24 | 25 | @func_log 26 | def hello_log(): 27 | print('hello') 28 | 29 | @func_log_use_lib 30 | def hello_log_use_lib(): 31 | print('hello') 32 | 33 | if __name__ == '__main__': 34 | hello_log() 35 | hello_log_use_lib() 36 | -------------------------------------------------------------------------------- /defaultdict_tutorial.py: -------------------------------------------------------------------------------- 1 | # defaultdict means that if a key is not found in the dictionary, 2 | # then instead of a KeyError being thrown, a new entry is created. 3 | # The type of this new entry is given by the argument of defaultdict. 4 | 5 | from collections import defaultdict 6 | 7 | 8 | def ex1(): 9 | # For the first example, default items are created using int(), which will return the integer object 0. 10 | int_dict = defaultdict(int) 11 | print('int_dict[3]', int_dict[3]) # print int(), thus 0 12 | # For the second example, default items are created using list(), which returns a new empty list object. 13 | list_dict = defaultdict(list) 14 | print('list_dict[test]', list_dict['ok']) # print list(), thus [] 15 | # default 16 | dic_list = defaultdict(lambda: 'test') 17 | dic_list['name'] = 'twtrubiks' 18 | print('dic_list[name]', dic_list['name']) 19 | print('dic_list[sex]', dic_list['sex']) 20 | 21 | 22 | def ex2_letter_frequency(sentence): 23 | frequencies = defaultdict(int) 24 | for letter in sentence: 25 | frequencies[letter] += 1 26 | return frequencies 27 | 28 | 29 | if __name__ == "__main__": 30 | ex1() 31 | print(ex2_letter_frequency('sentence')) 32 | -------------------------------------------------------------------------------- /dict.fromkeys_tutorial.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | ''' 3 | dictionary.fromkeys(sequence[, value]) 4 | ''' 5 | seq = ('name', 'age', 'sex') 6 | 7 | dict_1 = dict.fromkeys(seq) 8 | print('dict_1', dict_1) 9 | dict_2 = dict.fromkeys(seq, 10) 10 | print('dict_2', dict_2) 11 | -------------------------------------------------------------------------------- /dictionary_get.py: -------------------------------------------------------------------------------- 1 | # dict.get(key, default=None) 2 | 3 | def example_1(): 4 | # tuple 可以當作 dict 的 key 5 | my_dict_1 = {(1, 2): 5, (3, 4): 6, (5, 6): 7} 6 | print(my_dict_1[(1, 2)]) 7 | 8 | # equal 9 | my_dict_2 = {1: {2: 5}} 10 | print(my_dict_2[1][2]) 11 | 12 | if __name__ == "__main__": 13 | dict_data = {'Name': 'twtrubiks', 'Age': 18} 14 | 15 | # dict common use 16 | print('dict["Name"] : {}'.format(dict_data['Name'])) 17 | 18 | # if key does not exist in dict --> error 19 | # print('dict["Name"] : {}'.format(dict_['height'])) # error 20 | 21 | # if key does not exist in dict --> use dict.get(key, default=None) 22 | print('dict["Name"] : {}'.format(dict_data.get('height', 'default height'))) 23 | 24 | # dict.pop 25 | print('dict_data: {}'.format(dict_data)) 26 | pop_data = dict_data.pop('Name', None) 27 | print('pop_data: {} from dict_data'.format(pop_data)) 28 | print('dict_data: {}'.format(dict_data)) 29 | 30 | numbers = [1, 2, 3] 31 | my_dict = {number: number * 2 for number in numbers} 32 | print(my_dict) # {1: 2, 2: 4, 3: 6} 33 | example_1() -------------------------------------------------------------------------------- /dictionary_update.py: -------------------------------------------------------------------------------- 1 | # dict.update([other]) 2 | 3 | if __name__ == "__main__": 4 | ''' 5 | The update() method adds element(s) to the dictionary if the key is not in the dictionary. 6 | If the key is in the dictionary, it updates the key with the new value. 7 | 8 | If update() is called without passing parameters, the dictionary remains unchanged. 9 | ''' 10 | 11 | # If the key is in the dictionary, it updates the key with the new value. 12 | dict_data = {'Name': 'twtrubiks', 'Age': 18} 13 | dict_data_update = {'Age': 20} 14 | dict_data.update(dict_data_update) 15 | print('dict_data :', dict_data) 16 | 17 | # if the key is not in the dictionary, adds element(s) to the dictionary 18 | dict_data_2 = {'Name': 'twtrubiks', 'Age': 18} 19 | dict_data_2.update({"color": "blue"}) 20 | print('dict_data_2 :', dict_data_2) 21 | dict_data_2.clear() # clear dict data 22 | print('dict_data_2 :', dict_data_2) 23 | -------------------------------------------------------------------------------- /dictionary_using_items.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | 3 | # common way 4 | # dictory = {"first_name": "Alfred", "last_name": "Hitchcock"} 5 | # 6 | # for key in dictory: 7 | # print("{} = {}".format(key, dictory[key])) 8 | 9 | # preferred way using items() 10 | dictionary = {"first_name": "twt", "last_name": "rubiks"} 11 | print(list(dictionary.items()) ) 12 | for key, val in dictionary.items(): 13 | print("{} = {}".format(key, val)) 14 | -------------------------------------------------------------------------------- /division_operators_tutorial.py: -------------------------------------------------------------------------------- 1 | # division operators 2 | # python3 3 | 4 | print('5/2:', 5/2) 5 | print('5//2:', 5//2) 6 | 7 | 8 | print('5/3:', 5/3) 9 | print('5//3:', 5//3) 10 | 11 | 12 | print('5/5:', 5/5) 13 | print('5//5:', 5//5) -------------------------------------------------------------------------------- /dj_database_url_tutorial/README.md: -------------------------------------------------------------------------------- 1 | # dj-database-url-tutorial 2 | 3 | 簡單介紹一個套件, 名稱為 [dj-database-url](https://github.com/kennethreitz/dj-database-url), 4 | 5 | 主要功能:**簡化 django db 連線字串設定**。 6 | 7 | 詳細的大家可以自行前往閱讀,這邊會筆記一些重點, 8 | 9 | 安裝套件 10 | 11 | > pip install dj-database-url 12 | 13 | 使用方法很簡單,可參考 tutorial/dj_database_url_tutorial/[settings.py](https://github.com/twtrubiks/python-notes/blob/master/dj_database_url_tutorial/tutorial/dj_database_url_tutorial/settings.py) 14 | 15 | ( [tutorial](https://github.com/twtrubiks/python-notes/tree/master/dj_database_url_tutorial/tutorial) 是一個很簡單的 django 專案 ) 16 | 17 | ```python 18 | # DATABASES = { 19 | # 'default': { 20 | # 'ENGINE': 'django.db.backends.sqlite3', 21 | # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 22 | # } 23 | # } 24 | 25 | import dj_database_url 26 | 27 | DATABASES = { 28 | 'default': dj_database_url.config(default='sqlite:///{}'.format(os.path.join(BASE_DIR, 'db.sqlite3'))) 29 | } 30 | ``` 31 | 32 | 註解的部份是原來的寫法,其他資料庫的連接方式請參考 [dj-database-url](https://github.com/kennethreitz/dj-database-url)。 33 | 34 | ## 執行環境 35 | 36 | * Python 3.4.3 -------------------------------------------------------------------------------- /dj_database_url_tutorial/tutorial/dj_database_url_tutorial/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twtrubiks/python-notes/3f814d4a7711490bdf37ebed941aae75abf2d9b0/dj_database_url_tutorial/tutorial/dj_database_url_tutorial/__init__.py -------------------------------------------------------------------------------- /dj_database_url_tutorial/tutorial/dj_database_url_tutorial/urls.py: -------------------------------------------------------------------------------- 1 | """dj_database_url_tutorial URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | url(r'^admin/', admin.site.urls), 21 | ] 22 | -------------------------------------------------------------------------------- /dj_database_url_tutorial/tutorial/dj_database_url_tutorial/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for dj_database_url_tutorial project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/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", "dj_database_url_tutorial.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /dj_database_url_tutorial/tutorial/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", "dj_database_url_tutorial.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /eafp.py: -------------------------------------------------------------------------------- 1 | # LBYL: Look Before You Leap 2 | # EAFP: Easier to Ask for Forgiveness than Permission -> python 3 | 4 | import os 5 | 6 | if __name__ == "__main__": 7 | 8 | # violates EAFP coding style 9 | if os.path.exists("file.txt"): 10 | os.unlink("file.txt") 11 | 12 | # correspond EAFP coding style 13 | try: 14 | os.unlink("file.txt") 15 | # raised when file does not exist 16 | except OSError: 17 | pass 18 | -------------------------------------------------------------------------------- /enumerate_tutorial.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | # The enumerate() method adds counter to an iterable and returns it (the enumerate object). 3 | # enumerate(iterable, start=0) 4 | number_list = ['a', 'b', 'c', 'd', 'e'] 5 | for index, value in enumerate(number_list, start=1): 6 | print('index: {} value: {}'.format(index, value)) 7 | -------------------------------------------------------------------------------- /escape_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3/library/html.html 2 | import html.parser 3 | 4 | if __name__ == "__main__": 5 | test = '123>ss 3 else None 3 | 4 | 5 | if __name__ == "__main__": 6 | # the filter() method filters the given iterable with the help of 7 | # a function that tests each element in the iterable to be true or not. 8 | # filter(function, iterable) 9 | seq = [1, 2, 3, 4, 5, 6, 7, 8, 9] 10 | result = filter(fn, seq) 11 | print('result: {}'.format(result)) 12 | 13 | # lambda often used in like filter(), map() and reduce(). 14 | items = filter(lambda x: x > 3, seq) 15 | print('result_lambda: {}'.format(items)) 16 | 17 | # filter object (ref. map.py Compare the difference) 18 | data = [ 19 | {'key': 'a', 'value': 1}, 20 | {'key': 'b', 'value': 2}, 21 | {'key': 'c', 'value': 3}, 22 | {'key': 'd', 'value': 4}, 23 | {'key': 'e', 'value': 4}, 24 | ] 25 | data_items = filter(lambda x: x['value'] >= 3, data) 26 | print('data_items: {}'.format(data_items)) 27 | -------------------------------------------------------------------------------- /fnmatch_tutorial/README.md: -------------------------------------------------------------------------------- 1 | ## fnmatch 2 | 3 | `fnmatch.fnmatch` 4 | 5 | [fnmatch_tutorial_1.py](fnmatch_tutorial_1.py) 6 | 7 | `fnmatch.filter` 8 | 9 | [fnmatch_tutorial_2.py](fnmatch_tutorial_2.py) -------------------------------------------------------------------------------- /fnmatch_tutorial/demo1.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twtrubiks/python-notes/3f814d4a7711490bdf37ebed941aae75abf2d9b0/fnmatch_tutorial/demo1.txt -------------------------------------------------------------------------------- /fnmatch_tutorial/demo2.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twtrubiks/python-notes/3f814d4a7711490bdf37ebed941aae75abf2d9b0/fnmatch_tutorial/demo2.txt -------------------------------------------------------------------------------- /fnmatch_tutorial/demo3.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twtrubiks/python-notes/3f814d4a7711490bdf37ebed941aae75abf2d9b0/fnmatch_tutorial/demo3.txt -------------------------------------------------------------------------------- /fnmatch_tutorial/fnmatch_tutorial_1.py: -------------------------------------------------------------------------------- 1 | import fnmatch 2 | import os 3 | 4 | pattern = 'demo*.txt' 5 | print('Pattern :', pattern) 6 | 7 | 8 | files = os.listdir('.') 9 | for name in files: 10 | print(name, fnmatch.fnmatch(name, pattern)) 11 | -------------------------------------------------------------------------------- /fnmatch_tutorial/fnmatch_tutorial_2.py: -------------------------------------------------------------------------------- 1 | import fnmatch 2 | import os 3 | 4 | pattern = 'demo*.txt' 5 | print('Pattern :', pattern) 6 | files = os.listdir('.') 7 | matches = fnmatch.filter(files, pattern) 8 | # equal [n for n in names if fnmatch(n, pattern)] 9 | print('Matches', matches) 10 | -------------------------------------------------------------------------------- /function_default.py: -------------------------------------------------------------------------------- 1 | # REF. 2 | # http://blog.thedigitalcatonline.com/blog/2015/02/11/default-arguments-in-python/#.WPg_61OGPwc 3 | 4 | 5 | def get_first(iterable, default=None): 6 | if iterable: 7 | for item in iterable: 8 | return item 9 | return default 10 | 11 | 12 | def get_test(iterable, default='yo'): 13 | return '{} {}'.format(iterable, default) 14 | 15 | 16 | if __name__ == "__main__": 17 | print(get_test('t1')) 18 | print(get_test('t1', 't2')) 19 | -------------------------------------------------------------------------------- /functools_partial_tutorial.py: -------------------------------------------------------------------------------- 1 | from functools import partial 2 | 3 | from operator import mul 4 | 5 | def link_string(x, y): 6 | print('{}_{}'.format(x, y)) 7 | 8 | def example_1(): 9 | result = partial(link_string, y='data') 10 | result('test_1') 11 | result('test_2') 12 | 13 | def example_1_2(): 14 | # x = 'data' 15 | result = partial(link_string, 'data') 16 | result('test_1') 17 | result('test_2') 18 | 19 | def example_2(): 20 | ten_times = partial(mul, 10) 21 | print(ten_times(8)) 22 | print(ten_times(10)) 23 | print(list(map(ten_times, range(1, 5)))) 24 | 25 | if __name__ == "__main__": 26 | example_1() 27 | # example_1_2() 28 | # example_2() 29 | 30 | 31 | -------------------------------------------------------------------------------- /global_tutorial.py: -------------------------------------------------------------------------------- 1 | 2 | def example_1(): 3 | global content 4 | content = 'hello world' 5 | print('print: ' + content) 6 | 7 | # content= '' 8 | example_1() 9 | print(content) 10 | -------------------------------------------------------------------------------- /globals_tutorial.py: -------------------------------------------------------------------------------- 1 | # Return the dictionary containing the current scope's global variables. 2 | 3 | print(globals()) 4 | 5 | class A: 6 | pass 7 | 8 | x = 1 9 | 10 | print(globals()) 11 | print(globals()["x"]) 12 | print(globals()["A"]) 13 | -------------------------------------------------------------------------------- /graph/graph_iterative_dfs.py: -------------------------------------------------------------------------------- 1 | """ 2 | A 3 | / | \ 4 | D C B 5 | / / \ \ 6 | H G F E 7 | \ \ 8 | J I 9 | 10 | """ 11 | 12 | graph = { 13 | "A": ["D", "C", "B"], 14 | "B": ["E"], 15 | "C": ["G", "F"], 16 | "D": ["H"], 17 | "E": ["I"], 18 | "F": ["J"], 19 | } 20 | 21 | # 深度優先搜尋法 Depth-first Search (DFS) - iterative 22 | # ans: A B E I C F J G D H 23 | 24 | 25 | def dfs_iterative(graph, source): 26 | 27 | if source is None or source not in graph: 28 | return "Invalid input" 29 | 30 | path = [] 31 | stack = [source] 32 | 33 | while stack: 34 | s = stack.pop() 35 | 36 | if s not in path: 37 | path.append(s) 38 | 39 | if s not in graph: 40 | # leaf node 41 | continue 42 | 43 | for neighbor in graph[s]: 44 | stack.append(neighbor) 45 | 46 | return " ".join(path) 47 | 48 | 49 | print(dfs_iterative(graph, "A")) 50 | -------------------------------------------------------------------------------- /graph/graph_recursive_dfs.py: -------------------------------------------------------------------------------- 1 | """ 2 | A 3 | / | \ 4 | B C D 5 | / / \ \ 6 | E F G H 7 | / / 8 | I J 9 | 10 | """ 11 | 12 | graph = { 13 | "A": ["B", "C", "D"], 14 | "B": ["E"], 15 | "C": ["F", "G"], 16 | "D": ["H"], 17 | "E": ["I"], 18 | "F": ["J"], 19 | } 20 | 21 | # 深度優先搜尋法 Depth-first Search (DFS) - recursive 22 | # ans: ['A', 'B', 'E', 'I', 'C', 'F', 'J', 'G', 'D', 'H'] 23 | 24 | 25 | def recursive_dfs(graph, source, path=[]): 26 | 27 | if source not in path: 28 | path.append(source) 29 | 30 | if source not in graph: 31 | # leaf node, backtrack 32 | return path 33 | 34 | for neighbour in graph[source]: 35 | path = recursive_dfs(graph, neighbour, path) 36 | 37 | return path 38 | 39 | 40 | print(" ".join(recursive_dfs(graph, "A"))) 41 | -------------------------------------------------------------------------------- /groupby_tutorial.py: -------------------------------------------------------------------------------- 1 | from itertools import groupby 2 | 3 | ''' 4 | ref. https://docs.python.org/3.6/library/itertools.html#itertools.groupby 5 | 6 | itertools.groupby(iterable, key=None) 7 | 8 | ''' 9 | if __name__ == "__main__": 10 | 11 | things = [("apple", "bear"), 12 | ("cherry", "bear"), 13 | ("banana", "duck"), 14 | ("cherry", "bear"), 15 | ("banana", "cactus"), 16 | ("cherry", "bear"), 17 | ("cherry", "bear"), 18 | ("apple", "speed boat"), 19 | ("apple", "school bus"), ] 20 | 21 | # Generally, the iterable needs to already be sorted on the same key function. important!! 22 | things = sorted(things, key=lambda x: x[0]) 23 | 24 | for key, group in groupby(things, lambda x: x[0]): 25 | print('key', key) 26 | print('group', list(group)) 27 | print('==================') 28 | -------------------------------------------------------------------------------- /groupby_tutorial_find_consecutive_numbers.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3.0/library/itertools.html#examples 2 | from itertools import groupby 3 | from operator import itemgetter 4 | 5 | ''' 6 | seqs=[1,6,7,8,10,11] 7 | index value (index-value) 8 | 0 1 -1 9 | 1 6 -5 10 | 2 7 -5 11 | 3 8 -5 12 | 4 10 -6 13 | 5 11 -6 14 | 15 | [6,7,8] [10,11] 16 | ''' 17 | 18 | data = [1, 6, 7, 8, 10, 11] 19 | 20 | for key, group in groupby(enumerate(data), lambda x: x[0] - x[1]): 21 | g = list(map(itemgetter(1), group)) # method_1 22 | # g = list(map(lambda x: x[1], group)) # method_2 23 | print('consecutive numbers', g) 24 | -------------------------------------------------------------------------------- /hashlib_tutorial/detect_data.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 -------------------------------------------------------------------------------- /hmac_sha256_tutorial.py: -------------------------------------------------------------------------------- 1 | """ 2 | 可以使用以下的網站確認 3 | https://www.freeformatter.com/hmac-generator.html 4 | """ 5 | 6 | import hashlib 7 | import hmac 8 | 9 | wait_to_sign_str = "hello world twtrubiks" 10 | my_key = "aaa-bbb-ccc-ddd-token" 11 | 12 | # HMAC-SHA256 簽章 13 | hmac_sha256 = hmac.new( 14 | my_key.encode("utf-8"), wait_to_sign_str.encode("utf-8"), hashlib.sha256 15 | ) 16 | 17 | print(hmac_sha256.hexdigest()) -------------------------------------------------------------------------------- /importlib_tutorial.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://docs.python.org/3/library/importlib.html 3 | """ 4 | 5 | import importlib 6 | 7 | time = importlib.import_module('time') 8 | print(time.time()) -------------------------------------------------------------------------------- /is_integer_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3.6/library/stdtypes.html#float.is_integer 2 | 3 | import unittest 4 | 5 | ''' 6 | float.is_integer() 7 | Return True if the float is an integer 8 | ''' 9 | 10 | 11 | def check_is_integer(number): 12 | result = float(number).is_integer() 13 | return result 14 | 15 | 16 | class TestCase(unittest.TestCase): 17 | def test_case_1(self): 18 | result = check_is_integer(-2.00) 19 | self.assertTrue(result) 20 | 21 | def test_case_2(self): 22 | result = check_is_integer(12.00000) 23 | self.assertTrue(result) 24 | 25 | def test_case_3(self): 26 | result = check_is_integer(-3.1) 27 | self.assertFalse(result) 28 | 29 | def test_case_4(self): 30 | result = check_is_integer(1.100) 31 | self.assertFalse(result) 32 | 33 | 34 | if __name__ == '__main__': 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /isdigit.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | # The isdigit() method returns True if all characters in a string are digits. If not, it returns False. 3 | # True if all characters in the string are digits. 4 | # False if at least one character is not a digit. 5 | s = "28212" 6 | print(s.isdigit()) 7 | 8 | # contains alphabets and spaces 9 | s = "Mo3 nicaG el l22er" 10 | print(s.isdigit()) 11 | -------------------------------------------------------------------------------- /isinstance.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | # The isinstance() function checks if the object (first argument) 3 | # is an instance or subclass of classinfo class (second argument). 4 | 5 | # isinstance(object, classinfo) 6 | # object - object to be checked 7 | # classinfo - class, type, or tuple of classes and types 8 | 9 | 10 | class Foo(object): 11 | a = 5 12 | 13 | 14 | fooInstance = Foo() 15 | 16 | print('instance of Foo? {}'.format(isinstance(fooInstance, Foo))) 17 | 18 | numbers = [1, 2, 3] 19 | 20 | is_list = isinstance(numbers, list) 21 | print('instance of list? {}'.format(is_list)) 22 | 23 | is_dic = isinstance(numbers, dict) 24 | print('instance of dict? {}'.format(is_dic)) 25 | 26 | is_dic_or_list = isinstance(numbers, (dict, list)) 27 | print('instance of dict or list? {}'.format(is_dic_or_list)) 28 | 29 | is_int = isinstance(numbers, int) 30 | print('instance of int? {}'.format(is_int)) 31 | -------------------------------------------------------------------------------- /itemgetter_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3/library/operator.html#operator.itemgetter 2 | 3 | from operator import itemgetter 4 | 5 | # Basic tutorial 6 | seqs = [1, 2, 3, 4] 7 | x = itemgetter(1) 8 | print('x:', x) 9 | value = x(seqs) 10 | print('value == x(seqs) == seqs[1]:', value) 11 | xs = itemgetter(1, 3) 12 | value2 = xs(seqs) 13 | print('value2:', value2) 14 | 15 | # Example of using itemgetter() to retrieve specific fields from a tuple record 16 | inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)] 17 | getcount = itemgetter(1) 18 | print('list(map(getcount, inventory)):', list(map(getcount, inventory))) 19 | print('sorted(inventory, key=getcount):', sorted(inventory, key=getcount)) 20 | -------------------------------------------------------------------------------- /iter_another_trick_tutorial.py: -------------------------------------------------------------------------------- 1 | # Note that the iter function here returns a callable_iterator . 2 | 3 | # The for loop in the example may run for a very long time, 4 | # but it will never display 1(sentinel) 5 | # raise StopIteration instead of yielding the sentinel. 6 | 7 | # iter(func, sentinel) 8 | 9 | from random import randint 10 | 11 | def ex(): 12 | return randint(1, 6) 13 | 14 | def example_1(): 15 | # ex must be a callable 16 | ex_iter = iter(ex, 1) 17 | print(ex_iter) # 18 | for e in ex_iter: 19 | print(e) 20 | 21 | # This snippet reads lines from a file until 22 | # a blank line is found or the end of file is reached 23 | 24 | # def example_2(self, parameter_list): 25 | # with open('mydata.txt') as fp: 26 | # for line in iter(fp.readline, ''): 27 | # process_line(line) 28 | 29 | if __name__ == "__main__": 30 | example_1() 31 | -------------------------------------------------------------------------------- /itertools_islice_tutorial.py: -------------------------------------------------------------------------------- 1 | # https://docs.python.org/3.7/library/itertools.html#itertools.islice 2 | from itertools import islice 3 | 4 | ''' 5 | itertools.islice(iterable, start, stop[, step]) 6 | 7 | Make an iterator that returns selected elements from the iterable. 8 | If start is non-zero, then elements from the iterable are skipped until 9 | start is reached. Afterward, elements are returned consecutively unless 10 | step is set higher than one which results in items being skipped. 11 | If stop is None, then iteration continues until the iterator is exhausted, 12 | if at all; otherwise, it stops at the specified position. 13 | ''' 14 | if __name__ == '__main__': 15 | # islice('ABCDEFG', 2) --> A B 16 | # islice('ABCDEFG', 2, 4) --> C D 17 | # islice('ABCDEFG', 2, None) --> C D E F G 18 | # islice('ABCDEFG', 0, None, 2) --> A C E G 19 | 20 | print(tuple(islice('ABCDEFG', 2))) # --> A B 21 | print(list(islice('ABCDEFG', 2, 4))) # --> C D 22 | -------------------------------------------------------------------------------- /itertools_tee_tutorial.py: -------------------------------------------------------------------------------- 1 | # https://docs.python.org/3.7/library/itertools.html#itertools.tee 2 | from itertools import tee 3 | 4 | ''' 5 | itertools.tee(iterable, n=2) 6 | Return n independent iterators from a single iterable. 7 | ''' 8 | if __name__ == '__main__': 9 | print(tee([1, 2, 3, 4])) # (, ) 10 | iter1, iter2 = tee([1, 2, 3, 4]) 11 | print(next(iter1)) 12 | print(next(iter1)) 13 | print(next(iter2)) 14 | print(list(iter1)) 15 | print(list(iter2)) 16 | -------------------------------------------------------------------------------- /join.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | # The join() is a string method which returns a string concatenated with the elements of an iterable. 3 | numList = ['1', '2', '3', '4'] 4 | seperator = ', ' 5 | print(seperator.join(numList)) 6 | 7 | num_int = [1, 2, 3, 4] 8 | # print(seperator.join(num_int)) # error 9 | print(seperator.join(str(x) for x in num_int)) 10 | 11 | numTuple = ('1', '2', '3', '4') 12 | print(seperator.join(numTuple)) 13 | 14 | seq = {'Python', 'Java', 'Ruby'} 15 | s = '->->' 16 | print(s.join(seq)) 17 | -------------------------------------------------------------------------------- /json_tutorial.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | if __name__ == "__main__": 4 | load_data = ''' 5 | { 6 | "maps": [ 7 | { 8 | "id": "blabla", 9 | "iscategorical": "0" 10 | }, 11 | { 12 | "id": "blabla", 13 | "iscategorical": "0" 14 | } 15 | ], 16 | "masks": { 17 | "id": "twtrubiks" 18 | }, 19 | "om_points": "value", 20 | "parameters": { 21 | "id": "valore" 22 | } 23 | } 24 | ''' 25 | data = json.loads(load_data) 26 | print('data[maps]: {}'.format(data['maps'])) 27 | print('data[masks][id]: {}'.format(data['masks']['id'])) 28 | 29 | data_dump = json.dumps(data) 30 | print('json.dumps:', data_dump) 31 | 32 | # 排除空格 33 | print(json.dumps(data, separators=(",", ":"))) 34 | 35 | ascii_data = {"name": "你好", "age": 10} 36 | # 将 ensure_ascii 设置为 False,以保留非 ASCII 字符 37 | print(json.dumps(ascii_data, ensure_ascii=False)) 38 | print(json.dumps(ascii_data, ensure_ascii=True)) # dafault True -------------------------------------------------------------------------------- /kwargs.py: -------------------------------------------------------------------------------- 1 | # You would use *args when you're not sure how many arguments might be passed to 2 | # your function, i.e. it allows you pass an arbitrary number of arguments to your function 3 | 4 | 5 | def everything(*args): 6 | for count, thing in enumerate(args): 7 | print('{0}. {1}'.format(count, thing)) 8 | 9 | 10 | # **kwargs allows you to handle named arguments that you have not defined in advance 11 | def table_things(**kwargs): 12 | print('apple: {}'.format(kwargs.get('apple', 'default'))) 13 | for name, value in kwargs.items(): 14 | print('{0} = {1}'.format(name, value)) 15 | 16 | 17 | def print_three_things(a, b, c): 18 | print('a = {0}, b = {1}, c = {2}'.format(a, b, c)) 19 | 20 | 21 | if __name__ == "__main__": 22 | everything('apple', 'banana', 'cabbage') 23 | table_things(apple='fruit', cabbage='vegetable') 24 | my_list = ['aardvark', 'baboon', 'cat'] 25 | print_three_things(*my_list) 26 | 27 | my_dict = { 28 | "c": 33, 29 | "b": 22, 30 | } 31 | # 可以不用按照順序, 會自動 mapping 32 | print_three_things(a=11, **my_dict) 33 | # equal 34 | # print_three_things(11, **my_dict) 35 | -------------------------------------------------------------------------------- /lambda.py: -------------------------------------------------------------------------------- 1 | def show_max(m, n): 2 | return m if m > n else n 3 | 4 | 5 | if __name__ == "__main__": 6 | # anonymous functions 7 | # often used in like filter(), map() and reduce(). ref. filter.py map.py 8 | 9 | # common def 10 | print('show_max:{}'.format(show_max(100, 5))) # show 100 (common def) 11 | 12 | # lambda 13 | show_lambda = lambda m, n: m if m > n else n # but PEP-8 recommend use def 14 | print('show_lambda:{}'.format(show_lambda(100, 5))) # show 100 (lambda) 15 | -------------------------------------------------------------------------------- /list_tutorial.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | data_list = ['a', 'e', 'i', 'o', 'i', 'u'] 3 | 4 | # element 'i' is searched 5 | index = data_list.index('i') 6 | 7 | # index is printed 8 | print('The index of e: {}'.format(index)) 9 | 10 | # list remove 11 | del data_list[0] 12 | print('data_list:', data_list) 13 | data_list.remove('e') 14 | print('data_list:', data_list) 15 | 16 | # apply 17 | target_sort = ['2', '1', '3', '8', '0'] 18 | oringin = ['0', '1', '2', '3', '8'] 19 | result = sorted(oringin, key=lambda x: target_sort.index(x)) 20 | print(result) 21 | 22 | # reverse - method 1 23 | demo_list = [5, 4, 3, 2, 1] 24 | demo_list.reverse() 25 | print('demo_list', demo_list) 26 | # reverse - method 2 27 | demo_list_2 = [5, 4, 3, 2, 1] 28 | print('demo_list_2[::-1]', demo_list_2[::-1]) 29 | -------------------------------------------------------------------------------- /loop_if_else_break.py: -------------------------------------------------------------------------------- 1 | def contains_magic_number(list1, magic_number): 2 | for i in list1: 3 | if i == magic_number: 4 | print("This list contains the magic number") 5 | # if not add break , will run more meaningless loop 6 | break 7 | else: 8 | print("This list does NOT contain the magic number") 9 | 10 | 11 | if __name__ == "__main__": 12 | contains_magic_number(range(10), 3) 13 | -------------------------------------------------------------------------------- /map_tutorial.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | # The map() function applies a given function to each item of an iterable (list, tuple etc.) 3 | # and returns a list of the results. 4 | 5 | # tutorial_1 6 | numbers = (1, 2, 3, 4) 7 | # lambda often used in like filter(), map() and reduce(). 8 | result = map(lambda x: x * x, numbers) 9 | print('result: {}'.format(result)) 10 | 11 | # filter object (ref. filter.py Compare the difference) 12 | data = [ 13 | {'key': 'a', 'value': 1}, 14 | {'key': 'b', 'value': 2}, 15 | {'key': 'c', 'value': 3}, 16 | {'key': 'd', 'value': 4}, 17 | {'key': 'e', 'value': 4}, 18 | ] 19 | 20 | data_items = map(lambda x: x['value'], data) 21 | print('data_items: {}'.format(data_items)) 22 | print('data_items_distinct: {}'.format(set(data_items))) 23 | 24 | # tutorial_2 25 | str_num = '1,2,3,4,5,6,7,8,9,10,11' 26 | int_seqs = list(map(int, str_num.split(','))) # python3 27 | # int_seqs = map(int, str_num.split(',')) # python2 28 | print(isinstance(int_seqs, list)) 29 | for seq in int_seqs: 30 | print(isinstance(seq, int)) 31 | print(seq) 32 | 33 | # tutorial_3 34 | pattern = 'abcidkeujaddcsjb' 35 | print(list(map(pattern.find, pattern))) 36 | 37 | -------------------------------------------------------------------------------- /marshmallow_tutorial/README.md: -------------------------------------------------------------------------------- 1 | ## marshmallow 2 | 3 | 文件 [https://marshmallow.readthedocs.io/en/stable/](https://marshmallow.readthedocs.io/en/stable/) 4 | 5 | 6 | 安裝套件 7 | 8 | ```python 9 | pip install -U marshmallow 10 | ``` 11 | 12 | - 反序列化 (Loading) 13 | 14 | ```txt 15 | Deserialize input data to app-level objects. 16 | The reverse of the dump method is load, 17 | which validates and deserializes an input dictionary to an application-level data structure 18 | ``` 19 | 20 | - 序列化 (Dumping) obj -> dict 21 | 22 | ```txt 23 | Serialize app-level objects to primitive Python types. 24 | The serialized objects can then be rendered to standard formats 25 | such as JSON for use in an HTTP API. 26 | ``` 27 | 28 | 範例 [demo.py](https://github.com/twtrubiks/python-notes/blob/master/marshmallow_tutorial/demo.py) 29 | 30 | ```python 31 | python3 demo.py 32 | ``` 33 | 34 | 讀取 json 並且驗證資料 [validating_package.py](https://github.com/twtrubiks/python-notes/blob/master/marshmallow_tutorial/validating_package.py) 35 | 36 | [package_correct.json](package_correct.json) 37 | 38 | [package_error.json](package_error.json) 39 | 40 | ```python 41 | python3 validating_package.py 42 | ``` 43 | 44 | 更多例子 [https://marshmallow.readthedocs.io/en/stable/examples.html](https://marshmallow.readthedocs.io/en/stable/examples.html) 45 | -------------------------------------------------------------------------------- /marshmallow_tutorial/package_correct.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dunderscore", 3 | "version": "1.2.3", 4 | "description": "The Pythonic JavaScript toolkit", 5 | "devDependencies": { 6 | "pest": "^23.4.1" 7 | }, 8 | "main": "index.js", 9 | "scripts": { 10 | "test": "pest" 11 | }, 12 | "users": { 13 | "name": "alan", 14 | "email": "test@gmail.com" 15 | }, 16 | "license": "MIT" 17 | 18 | } 19 | -------------------------------------------------------------------------------- /marshmallow_tutorial/package_error.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dunderscore", 3 | "version": "INVALID", 4 | "homepage": "INVALID", 5 | "description": "The Pythonic JavaScript toolkit", 6 | "users": { 7 | "name": "alan", 8 | "email": "test123" 9 | }, 10 | "license": "MIT" 11 | 12 | } 13 | -------------------------------------------------------------------------------- /math_tutorial.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | if __name__ == "__main__": 5 | ''' 6 | https://docs.python.org/3/library/math.html 7 | ''' 8 | 9 | # 無條件進位到整數 10 | print(math.ceil(2.00001)) 11 | 12 | # 無條件捨去到整數 13 | print(math.floor(2.99999)) 14 | 15 | # 無條件進位到小數點第2位 16 | print(math.ceil(2.55 * 10) / 10) 17 | 18 | # 無條件進位到小數點第2位 19 | print(math.ceil(2.54 * 10) / 10) -------------------------------------------------------------------------------- /methodcaller_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. 2 | # https://docs.python.org/3/library/operator.html#operator.methodcaller 3 | 4 | from operator import methodcaller 5 | 6 | def example_1(): 7 | s = 'a b c d e' 8 | upcase = methodcaller('upper') 9 | print(upcase(s)) 10 | 11 | # Equivalent 12 | print(s.upper()) 13 | 14 | 15 | class A: 16 | 17 | def fun_2(self, data_1, data_2): 18 | print('{} + {}'.format(data_1, data_2)) 19 | 20 | def example_3(self): 21 | fun_3_case = methodcaller('fun_2', 'data_3_1', 'data_3_2') 22 | fun_3_case(self) 23 | 24 | def example_2(): 25 | a_obj = A() 26 | fun_2_case = methodcaller('fun_2', 'data_1', 'data_2') 27 | fun_2_case(a_obj) 28 | 29 | # Equivalent 30 | a_obj.fun_2('data_1', 'data_2') 31 | 32 | def example_3(): 33 | a3_obj = A() 34 | a3_obj.example_3() 35 | 36 | if __name__ == "__main__": 37 | example_1() 38 | # example_2() 39 | # example_3() -------------------------------------------------------------------------------- /mock_tutorial/demo1.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from unittest.mock import Mock 3 | 4 | print(datetime.datetime.today()) 5 | 6 | # start mock 7 | mock_date = datetime.datetime(year=2021, month=10, day=10) 8 | datetime = Mock() 9 | 10 | # mock .today() 11 | datetime.datetime.today.return_value = mock_date 12 | print(datetime.datetime.today()) -------------------------------------------------------------------------------- /mock_tutorial/demo10.py: -------------------------------------------------------------------------------- 1 | import my_user 2 | from unittest.mock import create_autospec 3 | 4 | user = create_autospec(my_user) 5 | print( 6 | user.get_today() 7 | ) 8 | 9 | print( 10 | user.get_users() 11 | ) 12 | 13 | 14 | # AttributeError: Mock object has no attribute 'not_this_func' 15 | # user.not_this_func() 16 | -------------------------------------------------------------------------------- /mock_tutorial/demo11.py: -------------------------------------------------------------------------------- 1 | import my_user 2 | from unittest.mock import patch 3 | 4 | with patch('__main__.my_user', autospec=True) as user: 5 | print( 6 | user.get_today() 7 | ) 8 | print( 9 | user.get_users() 10 | ) 11 | 12 | # AttributeError: Mock object has no attribute 'not_this_func' 13 | # user.not_this_func() 14 | -------------------------------------------------------------------------------- /mock_tutorial/demo2.py: -------------------------------------------------------------------------------- 1 | from requests.exceptions import HTTPError 2 | from unittest.mock import Mock 3 | 4 | requests = Mock() 5 | 6 | def get_users(): 7 | r = requests.get('http://demo/api/users') 8 | if r.status_code == 200: 9 | return r.json() 10 | return None 11 | 12 | if __name__ == '__main__': 13 | requests.get.side_effect = HTTPError 14 | try: 15 | get_users() 16 | except HTTPError: 17 | print('HTTPError') 18 | 19 | # Assert that the mock was called exactly once. 20 | requests.get.assert_called_once() 21 | 22 | 23 | # try: 24 | # get_users() 25 | # except HTTPError: 26 | # print('HTTPError') 27 | 28 | # # AssertionError: Expected 'get' to have been called once. Called 2 times 29 | # requests.get.assert_called_once() -------------------------------------------------------------------------------- /mock_tutorial/demo4.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import unittest 3 | from unittest.mock import Mock 4 | from requests.exceptions import HTTPError 5 | 6 | requests = Mock() 7 | 8 | def get_users(): 9 | r = requests.get('http://demo/api/users') 10 | if r.status_code == 200: 11 | return r.json() 12 | return None 13 | 14 | class TestUsers(unittest.TestCase): 15 | 16 | def test_get_users_retry(self): 17 | response_mock = Mock() 18 | response_mock.status_code = 200 19 | response_mock.json.return_value = { 20 | 'id': 1, 21 | 'user': 'twtrubiks', 22 | } 23 | requests.get.side_effect = [response_mock, HTTPError] 24 | user = get_users() 25 | assert user['id'] == 1 26 | assert user['user'] == 'twtrubiks' 27 | 28 | with self.assertRaises(HTTPError): 29 | get_users() 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /mock_tutorial/demo4_1.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import Mock 2 | 3 | 4 | mock = Mock() 5 | values = {'a': 1, 'b': 2, 'c': 3} 6 | def side_effect(arg): 7 | return values[arg] 8 | 9 | mock.side_effect = side_effect 10 | print( 11 | mock('a'), mock('b'), mock('c') 12 | ) 13 | # (1, 2, 3) 14 | 15 | 16 | mock_1 = Mock() 17 | mock_1.side_effect = [5, 4, 3, 2, 1] 18 | print( 19 | mock_1(), mock_1(), mock_1() 20 | ) 21 | # (5, 4, 3) -------------------------------------------------------------------------------- /mock_tutorial/demo5.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | from requests.exceptions import HTTPError 4 | from my_user import get_users 5 | 6 | 7 | class TestUsers(unittest.TestCase): 8 | 9 | # method_1 10 | @patch('my_user.requests') 11 | def test_get_users(self, mock_request): 12 | mock_request.get.side_effect = HTTPError 13 | with self.assertRaises(HTTPError): 14 | get_users() 15 | 16 | # method_2 17 | # @patch('my_user.requests', **{'get.side_effect': HTTPError}) 18 | # def test_get_users(self, mock_request): 19 | # with self.assertRaises(HTTPError): 20 | # get_users() 21 | 22 | if __name__ == '__main__': 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /mock_tutorial/demo6.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | from requests.exceptions import HTTPError 4 | from my_user import get_users 5 | 6 | 7 | class TestUsers(unittest.TestCase): 8 | 9 | # method_1 10 | def test_get_users(self): 11 | with patch('my_user.requests') as mock_requests: 12 | mock_requests.get.side_effect = HTTPError 13 | with self.assertRaises(HTTPError): 14 | get_users() 15 | 16 | # method_2 17 | # def test_get_users(self): 18 | # with patch('my_user.requests', **{'get.side_effect': HTTPError}) as mock_requests: 19 | # with self.assertRaises(HTTPError): 20 | # get_users() 21 | 22 | if __name__ == '__main__': 23 | unittest.main() 24 | 25 | -------------------------------------------------------------------------------- /mock_tutorial/demo7.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | from requests.exceptions import HTTPError 4 | from my_user import get_users, requests 5 | 6 | class TestUsers(unittest.TestCase): 7 | 8 | @patch.object(requests, 'get', side_effect=HTTPError) 9 | def test_get_users(self, mock_requests): 10 | with self.assertRaises(HTTPError): 11 | get_users() 12 | 13 | if __name__ == '__main__': 14 | unittest.main() 15 | 16 | -------------------------------------------------------------------------------- /mock_tutorial/demo8.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import patch 2 | import my_user 3 | import datetime 4 | 5 | mock_date = datetime.datetime(year=2021, month=10, day=10) 6 | 7 | # 比較好的寫法 8 | with patch('my_user.get_today', return_value = mock_date): 9 | # mock 成功 10 | print( 11 | my_user.get_today() 12 | ) -------------------------------------------------------------------------------- /mock_tutorial/demo8_1.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import patch 2 | from my_user import get_today 3 | import my_user 4 | import datetime 5 | 6 | mock_date = datetime.datetime(year=2021, month=10, day=10) 7 | 8 | with patch('my_user.get_today', return_value = mock_date): 9 | # mock 失敗 10 | print( 11 | get_today() 12 | ) -------------------------------------------------------------------------------- /mock_tutorial/demo8_2.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import patch 2 | from my_user import get_today 3 | import datetime 4 | 5 | mock_date = datetime.datetime(year=2021, month=10, day=10) 6 | 7 | with patch('__main__.get_today', return_value = mock_date): 8 | # mock 成功 9 | print( 10 | get_today() 11 | ) -------------------------------------------------------------------------------- /mock_tutorial/demo9.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import Mock 2 | 3 | user = Mock(spec=['fun1', 'fun2']) 4 | 5 | print( 6 | user.fun1() 7 | ) 8 | 9 | # AttributeError: Mock object has no attribute 'not_this_func' 10 | # user.not_this_func() 11 | -------------------------------------------------------------------------------- /mock_tutorial/demo9_1.py: -------------------------------------------------------------------------------- 1 | import my_user 2 | from unittest.mock import Mock 3 | 4 | user = Mock(spec=my_user) 5 | print( 6 | user.get_today() 7 | ) 8 | 9 | print( 10 | user.get_users() 11 | ) 12 | 13 | # AttributeError: Mock object has no attribute 'not_this_func' 14 | # user.not_this_func() 15 | 16 | user.attr_a = 123 17 | print(user.attr_a) 18 | 19 | -------------------------------------------------------------------------------- /mock_tutorial/demo9_2.py: -------------------------------------------------------------------------------- 1 | import my_user 2 | from unittest.mock import Mock 3 | 4 | user = Mock(spec_set=my_user) 5 | print( 6 | user.get_today() 7 | ) 8 | 9 | print( 10 | user.get_users() 11 | ) 12 | 13 | # AttributeError: Mock object has no attribute 'attr_a' 14 | # user.attr_a = 123 -------------------------------------------------------------------------------- /mock_tutorial/my_user.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import datetime 3 | 4 | def get_users(): 5 | r = requests.get('http://demo/api/users') 6 | print(r.status_code) 7 | if r.status_code == 200: 8 | return r.json() 9 | return None 10 | 11 | def get_today(): 12 | return datetime.datetime.today() 13 | -------------------------------------------------------------------------------- /nested_loop_tutorial.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | ''' 3 | common write method 4 | ''' 5 | results = [] 6 | for i in range(10): 7 | for j in range(i): 8 | results.append((i, j)) 9 | print('results', results) 10 | 11 | ''' 12 | better write method 1 13 | ''' 14 | 15 | results = [(i, j) 16 | for i in range(10) 17 | for j in range(i)] 18 | print('results', results) 19 | -------------------------------------------------------------------------------- /operator_add_tutorial.py: -------------------------------------------------------------------------------- 1 | from operator import add 2 | 3 | ''' 4 | operator.add(a, b) 5 | Return a + b 6 | ''' 7 | # example_1 8 | a, b = 1, 2 9 | print(add(a, b)) 10 | 11 | # example_2 12 | print(list(map(add, [1, 2, 3], [4, 5, 6]))) 13 | -------------------------------------------------------------------------------- /operator_mul_tutorial.py: -------------------------------------------------------------------------------- 1 | from operator import mul 2 | 3 | ''' 4 | operator.mul(a, b) 5 | Return a * b 6 | ''' 7 | # example_1 8 | a, b = 2, 5 9 | print(mul(a, b)) 10 | 11 | # example_2 12 | print(list(map(mul, [1, 2, 3], [4, 5, 6]))) 13 | -------------------------------------------------------------------------------- /operator_or_xor_tutorial.py: -------------------------------------------------------------------------------- 1 | # https://docs.python.org/zh-tw/3/library/operator.html 2 | 3 | print('a | b or_(a, b)') 4 | print('0 | 0 ->', 0 | 0) 5 | print('1 | 1 ->', 1 | 1) 6 | print('0 | 1 ->', 0 | 1) 7 | print('1 | 0 ->', 1 | 0) 8 | 9 | # 當兩數值相同時為False,而數值不同時為 True 10 | print('a ^ b xor(a, b)') 11 | print('0 ^ 0 ->', 0 ^ 0) 12 | print('1 ^ 1 ->', 1 ^ 1) 13 | print('0 ^ 1 ->', 0 ^ 1) 14 | print('1 ^ 0 ->', 1 ^ 0) -------------------------------------------------------------------------------- /pandas_tutorial/README.md: -------------------------------------------------------------------------------- 1 | # pandas_tutorial 2 | 3 | [pandas](https://pandas.pydata.org/) 真的非常的強大,這邊會記錄以及介紹一些我有用過的方法, 4 | 5 | * [pandas_tutorial_1](https://github.com/twtrubiks/python-notes/tree/master/pandas_tutorial/tutorial_1) - 透過 `pivot_table` 完成表格 6 | 7 | * [pandas_tutorial_2](https://github.com/twtrubiks/python-notes/tree/master/pandas_tutorial/tutorial_2) - 透過 pandas 把玩 `inner join` `outer join` `left join` `right join` 8 | 9 | 10 | ## 其他筆記 11 | 12 | [pandas.date_range](https://pandas.pydata.org/docs/reference/api/pandas.date_range.html) 13 | 14 | ```python 15 | import pandas as pd 16 | from datetime import date 17 | 18 | >>> start_date = date(2022, 3, 1) 19 | >>> end_date = date(2022, 3, 8) 20 | >>> pd.date_range(start_date, end_date).date 21 | array([datetime.date(2022, 3, 1), datetime.date(2022, 3, 2), 22 | datetime.date(2022, 3, 3), datetime.date(2022, 3, 4), 23 | datetime.date(2022, 3, 5), datetime.date(2022, 3, 6), 24 | datetime.date(2022, 3, 7), datetime.date(2022, 3, 8)], dtype=object) 25 | ``` 26 | 27 | ## Reference 28 | 29 | * [pandas](https://pandas.pydata.org/) 30 | -------------------------------------------------------------------------------- /pandas_tutorial/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.14.2 2 | pandas==0.22.0 -------------------------------------------------------------------------------- /pandas_tutorial/tutorial_1/tutorial_1.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | 4 | if __name__ == "__main__": 5 | df = pd.DataFrame( 6 | { 7 | 'color': ['red', 'blue', 'red', 'blue', 'red', 'blue', 'red', 'blue', 'yellow', 'blue'], 8 | 'name': ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c'], 9 | } 10 | ) 11 | print(df) 12 | 13 | df_size = df.groupby(['name', 'color']).size().reset_index(name='total') 14 | print(df_size) 15 | 16 | pd_pivot_table = pd.pivot_table(df_size, index=['name'], columns=['color'], 17 | aggfunc=[np.sum], fill_value=0, margins=True) 18 | print(pd_pivot_table) 19 | print(pd_pivot_table['sum']['total']) 20 | 21 | list_1 = [list(pd_pivot_table['sum']['total'].reset_index())] 22 | print(list_1) 23 | list_2 = pd_pivot_table['sum']['total'].to_records() 24 | print(list_2) 25 | list_2 = [list(p) for p in list_2] 26 | print(list_2) 27 | print(list_1 + list_2) 28 | -------------------------------------------------------------------------------- /pandas_tutorial/tutorial_2/README.md: -------------------------------------------------------------------------------- 1 | # pandas_tutorial_2 2 | 3 | * [Youtube Tutorial Part2 - pandas tutorial ( join )](https://youtu.be/TLp9bM2AzTQ) 4 | 5 | 這個範例主要是要和大家介紹, 6 | 7 | 用 pandas 也可以玩像是 database 中的 `inner join` `outer join` `left join` `right join`, 8 | 9 | 大家可以直接執行程式碼( 或看影片教學 ),這樣會比較了解 :smile: 10 | 11 | ```python 12 | df_1 = pd.DataFrame( 13 | { 14 | 'id': [1, 2, 3], 15 | 'key': ['a', 'b', 'c'], 16 | } 17 | ) 18 | print('=== df_1 ===') 19 | print(df_1) 20 | 21 | df_2 = pd.DataFrame( 22 | { 23 | 'key': ['b', 'c', 'd'], 24 | 'value': ['b_value', 'c_value', 'd_value'], 25 | } 26 | ) 27 | print('=== df_2 ===') 28 | print(df_2) 29 | 30 | # inner join 31 | pd_inner_join = pd.merge(df_1, df_2, how='inner', on='key', sort=True) 32 | print('=== inner_join ===') 33 | print(pd_inner_join) 34 | 35 | # left join 36 | pd_left_join = pd.merge(df_1, df_2, how='left', on='key', sort=True) 37 | print('=== left_join ===') 38 | print(pd_left_join) 39 | 40 | # right join 41 | pd_right_join = pd.merge(df_1, df_2, how='right', on='key', sort=True) 42 | print('=== right_join ===') 43 | print(pd_right_join) 44 | 45 | # outer join 46 | pd_outer_join = pd.merge(df_1, df_2, how='outer', sort=True) 47 | print('=== outer_join ===') 48 | print(pd_outer_join) 49 | ``` 50 | -------------------------------------------------------------------------------- /parse_dateutil.py: -------------------------------------------------------------------------------- 1 | from dateutil.parser import parse 2 | from dateutil.relativedelta import relativedelta 3 | from datetime import datetime 4 | 5 | if __name__ == "__main__": 6 | ''' 7 | ref. http://dateutil.readthedocs.io/en/stable/parser.html 8 | ''' 9 | print(parse('2017/4 /4 4:00:00 PM ')) 10 | print(parse('2017/4 -4 16:00:00 ')) 11 | 12 | ''' 13 | ref. https://dateutil.readthedocs.io/en/stable/relativedelta.html 14 | ''' 15 | now = datetime.now() 16 | now_plus_1_month = now + relativedelta(months=+1) 17 | now_minus_1_month = now + relativedelta(months=-1) 18 | print('now', now) 19 | print('now_plus_1_month', now_plus_1_month) 20 | print('now_minus_1_month', now_minus_1_month) 21 | -------------------------------------------------------------------------------- /pika_tutorial/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | services: 3 | 4 | rabbitmq: 5 | image: rabbitmq:management 6 | environment: 7 | RABBITMQ_DEFAULT_USER: admin 8 | RABBITMQ_DEFAULT_PASS: admin 9 | # RABBITMQ_DEFAULT_VHOST: my_vhost 10 | ports: 11 | - "5672:5672" 12 | - "15672:15672" 13 | -------------------------------------------------------------------------------- /pika_tutorial/hello_world/consumer.py: -------------------------------------------------------------------------------- 1 | from mq_connection import connection, channel 2 | 3 | channel.queue_declare(queue="hello") 4 | 5 | 6 | def callback(ch, method, properties, body): 7 | print(" [x] Received %r" % body) 8 | 9 | 10 | channel.basic_consume(queue="hello", auto_ack=True, on_message_callback=callback) 11 | 12 | print(" [*] Waiting for messages. To exit press CTRL+C") 13 | channel.start_consuming() 14 | -------------------------------------------------------------------------------- /pika_tutorial/hello_world/consumer_batch.py: -------------------------------------------------------------------------------- 1 | from mq_connection import connection, channel 2 | import time 3 | import random 4 | 5 | channel.queue_declare(queue="hello") 6 | 7 | collection_batch_size = 2 8 | collection = [] 9 | 10 | 11 | def batch_run(tasks): 12 | 13 | print("tasks length:", len(tasks)) 14 | print(tasks, "\n") 15 | 16 | rand_num = random.randint(0, 2) 17 | 18 | if rand_num: 19 | print(tasks, "\n") 20 | time.sleep(1) 21 | return True 22 | else: 23 | print("failed.", "\n") 24 | time.sleep(1) 25 | return False 26 | 27 | 28 | def batch_callback(ch, method, properties, body): 29 | 30 | print(f" [*] Received: {body}") 31 | 32 | collection.append(body) 33 | if len(collection) % collection_batch_size == 0: 34 | result = batch_run(collection) 35 | if result: 36 | ch.basic_ack(delivery_tag=method.delivery_tag, multiple=True) 37 | else: 38 | ch.basic_nack(delivery_tag=method.delivery_tag, multiple=True) 39 | collection.clear() 40 | 41 | 42 | channel.basic_consume(queue="hello", on_message_callback=batch_callback) 43 | 44 | 45 | channel.start_consuming() 46 | -------------------------------------------------------------------------------- /pika_tutorial/hello_world/consumer_inactivity_timeout.py: -------------------------------------------------------------------------------- 1 | from mq_connection import connection, channel 2 | import time 3 | 4 | channel.queue_declare(queue="hello") 5 | 6 | 7 | def callback(ch, method, properties, body): 8 | print(" [x] Received %r" % body) 9 | 10 | 11 | for method, properties, body in channel.consume( 12 | queue="hello", inactivity_timeout=3, auto_ack=True 13 | ): 14 | print(f" [x] Received {body}") 15 | 16 | if method == None and properties == None and body == None: 17 | break 18 | 19 | connection.close() 20 | -------------------------------------------------------------------------------- /pika_tutorial/hello_world/mq_connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref 3 | https://www.rabbitmq.com/tutorials/tutorial-one-python.html 4 | 5 | The simplest thing that does something 6 | """ 7 | 8 | import pika 9 | 10 | 11 | RABBITMQ_HOST = "localhost" 12 | RABBITMQ_PORT = "5672" 13 | RABBITMQ_USER = "admin" 14 | RABBITMQ_PASS = "admin" 15 | 16 | credentials = pika.PlainCredentials(RABBITMQ_USER, RABBITMQ_PASS) 17 | parameters = pika.ConnectionParameters( 18 | host=RABBITMQ_HOST, port=RABBITMQ_PORT, credentials=credentials 19 | ) 20 | connection = pika.BlockingConnection(parameters) 21 | channel = connection.channel() 22 | -------------------------------------------------------------------------------- /pika_tutorial/hello_world/producer.py: -------------------------------------------------------------------------------- 1 | from mq_connection import connection, channel 2 | 3 | channel.queue_declare(queue="hello") 4 | channel.basic_publish(exchange="", routing_key="hello", body="Hello World!") 5 | print(" [x] Sent 'Hello World!'") 6 | connection.close() 7 | -------------------------------------------------------------------------------- /pika_tutorial/pub_sub/consumer.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | from mq_connection import connection, channel 4 | 5 | channel.exchange_declare(exchange="logs", exchange_type="fanout") 6 | 7 | result = channel.queue_declare(queue="", exclusive=True) 8 | queue_name = result.method.queue 9 | channel.queue_bind(exchange="logs", queue=queue_name) 10 | 11 | 12 | def callback(ch, method, properties, body): 13 | print(" [x] Received %r" % body) 14 | 15 | 16 | channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True) 17 | 18 | channel.start_consuming() 19 | 20 | connection.close() 21 | -------------------------------------------------------------------------------- /pika_tutorial/pub_sub/mq_connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref 3 | https://www.rabbitmq.com/tutorials/tutorial-three-python.html 4 | 5 | Publish/Subscribe 6 | 7 | Sending messages to many consumers at once 8 | """ 9 | 10 | import pika 11 | 12 | 13 | RABBITMQ_HOST = "localhost" 14 | RABBITMQ_PORT = "5672" 15 | RABBITMQ_USER = "admin" 16 | RABBITMQ_PASS = "admin" 17 | 18 | credentials = pika.PlainCredentials(RABBITMQ_USER, RABBITMQ_PASS) 19 | parameters = pika.ConnectionParameters( 20 | host=RABBITMQ_HOST, port=RABBITMQ_PORT, credentials=credentials 21 | ) 22 | connection = pika.BlockingConnection(parameters) 23 | channel = connection.channel() 24 | -------------------------------------------------------------------------------- /pika_tutorial/pub_sub/producer.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | from mq_connection import connection, channel 4 | 5 | channel.exchange_declare(exchange="logs", exchange_type="fanout") 6 | 7 | for i in range(10): 8 | channel.basic_publish( 9 | exchange="logs", 10 | routing_key="", 11 | body=f"Hello World! {i}", 12 | ) 13 | time.sleep(1) 14 | 15 | connection.close() 16 | -------------------------------------------------------------------------------- /pika_tutorial/routing/consumer_info_error.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | from mq_connection import connection, channel 4 | 5 | channel.exchange_declare(exchange="direct_logs", exchange_type="direct") 6 | 7 | result = channel.queue_declare(queue="", exclusive=True) 8 | queue_name = result.method.queue 9 | severities = ("info", "error") 10 | 11 | for severity in severities: 12 | channel.queue_bind(exchange="direct_logs", queue=queue_name, routing_key=severity) 13 | 14 | 15 | def callback(ch, method, properties, body): 16 | print(" [x] Received %r" % body) 17 | 18 | 19 | channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True) 20 | 21 | channel.start_consuming() 22 | 23 | connection.close() 24 | -------------------------------------------------------------------------------- /pika_tutorial/routing/consumer_warning.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | from mq_connection import connection, channel 4 | 5 | channel.exchange_declare(exchange="direct_logs", exchange_type="direct") 6 | 7 | result = channel.queue_declare(queue="", exclusive=True) 8 | queue_name = result.method.queue 9 | severities = ("warning",) 10 | 11 | for severity in severities: 12 | channel.queue_bind(exchange="direct_logs", queue=queue_name, routing_key=severity) 13 | 14 | 15 | def callback(ch, method, properties, body): 16 | print(" [x] Received %r" % body) 17 | 18 | 19 | channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True) 20 | 21 | channel.start_consuming() 22 | 23 | connection.close() 24 | -------------------------------------------------------------------------------- /pika_tutorial/routing/mq_connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref 3 | https://www.rabbitmq.com/tutorials/tutorial-four-python.html 4 | 5 | Routing 6 | 7 | Receiving messages selectively 8 | """ 9 | 10 | import pika 11 | 12 | 13 | RABBITMQ_HOST = "localhost" 14 | RABBITMQ_PORT = "5672" 15 | RABBITMQ_USER = "admin" 16 | RABBITMQ_PASS = "admin" 17 | 18 | credentials = pika.PlainCredentials(RABBITMQ_USER, RABBITMQ_PASS) 19 | parameters = pika.ConnectionParameters( 20 | host=RABBITMQ_HOST, port=RABBITMQ_PORT, credentials=credentials 21 | ) 22 | connection = pika.BlockingConnection(parameters) 23 | channel = connection.channel() 24 | -------------------------------------------------------------------------------- /pika_tutorial/routing/producer.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | import random 4 | from mq_connection import connection, channel 5 | 6 | channel.exchange_declare(exchange="direct_logs", exchange_type="direct") 7 | 8 | severity = ("info", "warning", "error") 9 | for i in range(10): 10 | log_type = random.choices(severity)[0] 11 | channel.basic_publish( 12 | exchange="direct_logs", 13 | routing_key=log_type, 14 | body=f"Hello World! {i} {log_type}", 15 | ) 16 | time.sleep(1) 17 | 18 | connection.close() 19 | -------------------------------------------------------------------------------- /pika_tutorial/rpc/mq_connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref 3 | https://www.rabbitmq.com/tutorials/tutorial-six-python.html 4 | 5 | RPC 6 | 7 | Remote procedure call (RPC) 8 | Request/reply pattern 9 | """ 10 | 11 | import pika 12 | 13 | 14 | RABBITMQ_HOST = "localhost" 15 | RABBITMQ_PORT = "5672" 16 | RABBITMQ_USER = "admin" 17 | RABBITMQ_PASS = "admin" 18 | 19 | credentials = pika.PlainCredentials(RABBITMQ_USER, RABBITMQ_PASS) 20 | parameters = pika.ConnectionParameters( 21 | host=RABBITMQ_HOST, port=RABBITMQ_PORT, credentials=credentials 22 | ) 23 | connection = pika.BlockingConnection(parameters) 24 | channel = connection.channel() 25 | -------------------------------------------------------------------------------- /pika_tutorial/rpc/rpc_server.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | import random 4 | from mq_connection import connection, channel 5 | 6 | channel.queue_declare(queue="rpc_queue") 7 | 8 | 9 | def fib(n): 10 | time.sleep(n) 11 | return n 12 | 13 | 14 | def on_request(ch, method, props, body): 15 | n = int(body) 16 | 17 | print(" [.] fib(%s)" % n) 18 | response = fib(n) 19 | 20 | ch.basic_publish( 21 | exchange="", 22 | routing_key=props.reply_to, 23 | properties=pika.BasicProperties(correlation_id=props.correlation_id), 24 | body=str(response), 25 | ) 26 | ch.basic_ack(delivery_tag=method.delivery_tag) 27 | 28 | 29 | channel.basic_qos(prefetch_count=1) 30 | channel.basic_consume(queue="rpc_queue", on_message_callback=on_request) 31 | 32 | print(" [x] Awaiting RPC requests") 33 | channel.start_consuming() 34 | connection.close() 35 | -------------------------------------------------------------------------------- /pika_tutorial/topic/consumer_all.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | from mq_connection import connection, channel 4 | 5 | channel.exchange_declare(exchange="topic_logs", exchange_type="topic") 6 | 7 | result = channel.queue_declare(queue="", exclusive=True) 8 | queue_name = result.method.queue 9 | severities = ("#",) 10 | 11 | for severity in severities: 12 | channel.queue_bind(exchange="topic_logs", queue=queue_name, routing_key=severity) 13 | 14 | 15 | def callback(ch, method, properties, body): 16 | print(" [x] Received %r" % body) 17 | 18 | 19 | channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True) 20 | 21 | channel.start_consuming() 22 | 23 | connection.close() 24 | -------------------------------------------------------------------------------- /pika_tutorial/topic/consumer_info_error.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | from mq_connection import connection, channel 4 | 5 | channel.exchange_declare(exchange="topic_logs", exchange_type="topic") 6 | 7 | result = channel.queue_declare(queue="", exclusive=True) 8 | queue_name = result.method.queue 9 | severities = ("*.info", "*.error") 10 | 11 | for severity in severities: 12 | channel.queue_bind(exchange="topic_logs", queue=queue_name, routing_key=severity) 13 | 14 | 15 | def callback(ch, method, properties, body): 16 | print(" [x] Received %r" % body) 17 | 18 | 19 | channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True) 20 | 21 | channel.start_consuming() 22 | 23 | connection.close() 24 | -------------------------------------------------------------------------------- /pika_tutorial/topic/consumer_warning.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | from mq_connection import connection, channel 4 | 5 | channel.exchange_declare(exchange="topic_logs", exchange_type="topic") 6 | 7 | result = channel.queue_declare(queue="", exclusive=True) 8 | queue_name = result.method.queue 9 | severities = ("*.warning",) 10 | 11 | for severity in severities: 12 | channel.queue_bind(exchange="topic_logs", queue=queue_name, routing_key=severity) 13 | 14 | 15 | def callback(ch, method, properties, body): 16 | print(" [x] Received %r" % body) 17 | 18 | 19 | channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True) 20 | 21 | channel.start_consuming() 22 | 23 | connection.close() 24 | -------------------------------------------------------------------------------- /pika_tutorial/topic/mq_connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref 3 | https://www.rabbitmq.com/tutorials/tutorial-five-python.html 4 | 5 | Topics 6 | 7 | Receiving messages based on a pattern (topics) 8 | """ 9 | 10 | import pika 11 | 12 | 13 | RABBITMQ_HOST = "localhost" 14 | RABBITMQ_PORT = "5672" 15 | RABBITMQ_USER = "admin" 16 | RABBITMQ_PASS = "admin" 17 | 18 | credentials = pika.PlainCredentials(RABBITMQ_USER, RABBITMQ_PASS) 19 | parameters = pika.ConnectionParameters( 20 | host=RABBITMQ_HOST, port=RABBITMQ_PORT, credentials=credentials 21 | ) 22 | connection = pika.BlockingConnection(parameters) 23 | channel = connection.channel() 24 | -------------------------------------------------------------------------------- /pika_tutorial/topic/producer.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | import random 4 | from mq_connection import connection, channel 5 | 6 | channel.exchange_declare(exchange="topic_logs", exchange_type="topic") 7 | 8 | severity = ( 9 | "1.info", 10 | "2.warning", 11 | "3.error", 12 | "4.info", 13 | "5.warning", 14 | "6.error", 15 | "error.7", 16 | ) 17 | 18 | for routing_key in severity: 19 | channel.basic_publish( 20 | exchange="topic_logs", 21 | routing_key=routing_key, 22 | body=f"Hello World! {routing_key}", 23 | ) 24 | time.sleep(1) 25 | 26 | connection.close() 27 | -------------------------------------------------------------------------------- /pika_tutorial/work_queues/consumer.py: -------------------------------------------------------------------------------- 1 | from mq_connection import connection, channel 2 | import time 3 | 4 | channel.queue_declare(queue="task_queue", durable=True) 5 | 6 | 7 | def callback(ch, method, properties, body): 8 | print(" [x] Received %r" % body) 9 | time.sleep(2) 10 | ch.basic_ack(delivery_tag=method.delivery_tag) 11 | 12 | 13 | # two dispatching 14 | # Round-robin dispatching 15 | channel.basic_qos(prefetch_count=1) # -> Fair dispatch 16 | 17 | channel.basic_consume( 18 | queue="task_queue", 19 | # auto_ack=True, # Message acknowledgment 20 | on_message_callback=callback, 21 | ) 22 | 23 | print(" [*] Waiting for messages. To exit press CTRL+C") 24 | channel.start_consuming() 25 | -------------------------------------------------------------------------------- /pika_tutorial/work_queues/consumer2.py: -------------------------------------------------------------------------------- 1 | from mq_connection import connection, channel 2 | 3 | channel.queue_declare(queue="task_queue", durable=True) 4 | 5 | 6 | def callback(ch, method, properties, body): 7 | print(" [x] Received %r" % body) 8 | ch.basic_ack(delivery_tag=method.delivery_tag) 9 | 10 | # two dispatching 11 | # Round-robin dispatching 12 | channel.basic_qos(prefetch_count=1) # -> Fair dispatch 13 | 14 | channel.basic_consume( 15 | queue="task_queue", 16 | # auto_ack=True, # Message acknowledgment 17 | on_message_callback=callback, 18 | ) 19 | 20 | print(" [*] Waiting for messages. To exit press CTRL+C") 21 | channel.start_consuming() 22 | -------------------------------------------------------------------------------- /pika_tutorial/work_queues/mq_connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref 3 | https://www.rabbitmq.com/tutorials/tutorial-two-python.html 4 | 5 | Work queues 6 | 7 | Distributing tasks among workers (the competing consumers pattern) 8 | """ 9 | 10 | import pika 11 | 12 | 13 | RABBITMQ_HOST = "localhost" 14 | RABBITMQ_PORT = "5672" 15 | RABBITMQ_USER = "admin" 16 | RABBITMQ_PASS = "admin" 17 | 18 | credentials = pika.PlainCredentials(RABBITMQ_USER, RABBITMQ_PASS) 19 | parameters = pika.ConnectionParameters( 20 | host=RABBITMQ_HOST, port=RABBITMQ_PORT, credentials=credentials 21 | ) 22 | connection = pika.BlockingConnection(parameters) 23 | channel = connection.channel() 24 | -------------------------------------------------------------------------------- /pika_tutorial/work_queues/producer.py: -------------------------------------------------------------------------------- 1 | import time 2 | import pika 3 | from mq_connection import connection, channel 4 | 5 | channel.queue_declare(queue="task_queue", durable=True) 6 | 7 | for i in range(30): 8 | channel.basic_publish( 9 | exchange="", 10 | routing_key="task_queue", 11 | body=f"Hello World! {i}", 12 | properties=pika.BasicProperties( 13 | delivery_mode=pika.spec.PERSISTENT_DELIVERY_MODE 14 | ), 15 | ) 16 | print(" [x] Sent 'Hello World!'") 17 | time.sleep(0.1) 18 | connection.close() 19 | -------------------------------------------------------------------------------- /pip-tools_tutorial/requirements.in: -------------------------------------------------------------------------------- 1 | django 2 | redis -------------------------------------------------------------------------------- /pip-tools_tutorial/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.10 3 | # by the following command: 4 | # 5 | # pip-compile 6 | # 7 | asgiref==3.8.1 8 | # via django 9 | async-timeout==4.0.3 10 | # via redis 11 | django==5.0.4 12 | # via -r requirements.in 13 | redis==5.0.3 14 | # via -r requirements.in 15 | sqlparse==0.5.0 16 | # via django 17 | typing-extensions==4.11.0 18 | # via asgiref 19 | -------------------------------------------------------------------------------- /property_decorator.py: -------------------------------------------------------------------------------- 1 | class Square(object): 2 | def __init__(self, length): 3 | self._length = length 4 | 5 | @property 6 | def length(self): 7 | return self._length 8 | 9 | @length.setter 10 | def length(self, value): 11 | self._length = value 12 | 13 | @length.deleter 14 | def length(self): 15 | del self._length 16 | 17 | 18 | if __name__ == "__main__": 19 | r = Square(5) 20 | print('length', r.length) # automatically calls getter 21 | r.length = 6 # automatically calls setter 22 | print('length', r.length) 23 | del r.length 24 | # print('length', r.length) # -> AttributeError: 'Square' object has no attribute '_length' 25 | -------------------------------------------------------------------------------- /pycryptodome_tutorial/README.md: -------------------------------------------------------------------------------- 1 | # pycryptodome 2 | 3 | RSA 非對稱加密, 會有兩把密鑰. 速度比較慢. 4 | 5 | 注意, RSA 簽名 和 RSA 加密 概念是不一樣的. 6 | 7 | 加密: 公鑰加密, 私鑰解密 8 | 9 | 簽名: 私鑰簽名, 公鑰驗簽 10 | 11 | RSA 簽名 : 私鑰簽名, 公鑰驗簽 12 | 13 | 如果使用相同的 key 簽名 相同的字串, 每次結果都是**相同的**. 14 | 15 | ```python 16 | # 產生 公鑰 私鑰 ( PEM or DER ) 17 | python3 generator_public_private_key.py 18 | 19 | # 測試 私鑰簽名, 公鑰驗簽 20 | python3 sign_and_verify_sign.py 21 | 22 | # base64 編碼的 public key 和 private_key 23 | # 需要先進行 b64decode 24 | python3 base64_str_key_to_sign.py 25 | ``` 26 | 27 | RSA加解密 公鑰加密, 私鑰解密 28 | 29 | 如果使用相同的 key 加密 相同的字串, 每次結果都是**不相同的**. 30 | 31 | ```python 32 | # RSA 加解密, 有最大加密長度限制 33 | python3 rsa_encrypt_decrypted.py 34 | 35 | # RSA 分段加解密 36 | python3 rsa_segments_encrypt_decrypted.py 37 | ``` 38 | 39 | AES CBC 加解密 40 | 41 | AES 對稱加密, 一把密鑰進行加密和解密. 速度比較快. 42 | 43 | ```python 44 | python3 aes_tutorial 45 | ``` -------------------------------------------------------------------------------- /pycryptodome_tutorial/aes_tutorial.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://pypi.org/project/pycryptodome/ 3 | 4 | pip install pycryptodome 5 | 6 | ref 7 | https://pycryptodome.readthedocs.io/en/latest/src/cipher/classic.html#cbc-mode 8 | """ 9 | 10 | from Crypto.Cipher import AES 11 | from Crypto.Util.Padding import pad, unpad 12 | 13 | 14 | def aes_encrypt(plaintext, key, iv): 15 | # AES.block_size -> 16 16 | encoded_padded = pad(plaintext.encode(), AES.block_size) 17 | cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8')) 18 | encoded = cipher.encrypt(encoded_padded) 19 | print(encoded) 20 | return encoded 21 | 22 | def aes_decrypt(plaintext, key, iv): 23 | # AES.block_size -> 16 24 | decrypt_cipher = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8')) 25 | decrypted = decrypt_cipher.decrypt(plaintext) 26 | decoded = unpad(decrypted, AES.block_size) 27 | print(decoded)# 必須為16位 28 | return decoded 29 | 30 | 31 | plaintext = "hello world" 32 | key = "key23X8Ib9LM8w16" # 必須為16位 33 | iv = "iva23X8Ib9LM8w16" # 必須為16位 34 | 35 | encode_data = aes_encrypt(plaintext, key, iv) 36 | decoded_data = aes_decrypt(encode_data, key, iv) 37 | -------------------------------------------------------------------------------- /pycryptodome_tutorial/generator_public_private_key.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://pypi.org/project/pycryptodome/ 3 | 4 | pip install pycryptodome 5 | 6 | 產生 7 | public key 公鑰 8 | private key 私鑰 9 | """ 10 | 11 | from Crypto import Random 12 | from Crypto.PublicKey import RSA 13 | 14 | random_generator = Random.new().read 15 | rsa = RSA.generate(2048, random_generator) 16 | 17 | def generate_pem_key(): 18 | # 產生 PEM 格式 19 | # PEM 使用 Base64 編碼 20 | private_key = rsa.export_key() 21 | with open('private_key.pem', 'wb') as f: 22 | f.write(private_key) 23 | 24 | public_key = rsa.publickey().export_key() 25 | with open('public_key.pem', 'wb') as f: 26 | f.write(public_key) 27 | 28 | def generate_der_key(): 29 | # 產生 DER 格式 30 | # DER 使用的是 二進位格式資料 (Binary encoding) 31 | private_key = rsa.export_key(format="DER") 32 | with open('private_key.der', 'wb') as f: 33 | f.write(private_key) 34 | 35 | public_key = rsa.publickey().export_key(format="DER") 36 | with open('public_key.der', 'wb') as f: 37 | f.write(public_key) 38 | 39 | generate_pem_key() 40 | # generate_der_key() -------------------------------------------------------------------------------- /pycryptodome_tutorial/rsa_encrypt_decrypted.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://pypi.org/project/pycryptodome/ 3 | 4 | pip install pycryptodome 5 | 6 | RSA 加解密 公鑰加密, 私鑰解密 7 | """ 8 | 9 | 10 | from Crypto.PublicKey import RSA 11 | from Crypto.Cipher import PKCS1_OAEP 12 | from base64 import b64encode, b64decode 13 | 14 | 15 | key = RSA.generate(2048) 16 | 17 | public_key = key.publickey() 18 | private_key = key 19 | 20 | cipher = PKCS1_OAEP.new(public_key) 21 | decipher = PKCS1_OAEP.new(private_key) 22 | 23 | def encrypted(plaintext): 24 | # 公鑰加密 25 | ciphertext = cipher.encrypt(plaintext.encode('utf-8')) 26 | encrypted_msg = b64encode(ciphertext).decode('utf-8') 27 | print("Encrypted message:", encrypted_msg) 28 | return encrypted_msg 29 | 30 | def decrypted(encrypted_msg): 31 | # 私鑰解密 32 | ciphertext = b64decode(encrypted_msg.encode('utf-8')) 33 | decrypted_message = decipher.decrypt(ciphertext) 34 | print("Decrypted message:", decrypted_message.decode('utf-8')) 35 | return decrypted_message.decode('utf-8') 36 | 37 | 38 | plaintext = "Hello, World" 39 | encrypted_msg = encrypted(plaintext) 40 | decrypted(encrypted_msg) 41 | -------------------------------------------------------------------------------- /pycryptodome_tutorial/sign_and_verify_sign.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://pypi.org/project/pycryptodome/ 3 | 4 | pip install pycryptodome 5 | 私鑰簽名, 公鑰驗簽 6 | 7 | sign (簽名) 用 private key 私鑰 8 | verify_sign (驗證簽名) 用 public key 公鑰 9 | """ 10 | 11 | 12 | from Crypto.PublicKey import RSA 13 | from Crypto.Signature import PKCS1_v1_5 14 | from Crypto.Hash import SHA256 15 | from base64 import b64encode, b64decode 16 | 17 | 18 | def verify_sign(public_key_loc, signature, data): 19 | 20 | with open(public_key_loc, 'rb') as f: 21 | pub_key = RSA.import_key(f.read()) 22 | 23 | digest = SHA256.new(data) 24 | verifier = PKCS1_v1_5.new(pub_key) 25 | if verifier.verify(digest, b64decode(signature)): 26 | return True 27 | return False 28 | 29 | 30 | def sign(private_key_loc, message: str) -> str: 31 | with open(private_key_loc, 'rb') as f: 32 | priv_key = RSA.import_key(f.read()) 33 | 34 | h = SHA256.new(message) 35 | signer = PKCS1_v1_5.new(priv_key) 36 | signature = signer.sign(h) 37 | return b64encode(signature).decode() 38 | 39 | 40 | msg = "22222" 41 | msg = msg.encode("utf-8") 42 | 43 | # msg = b"22222" 44 | 45 | signed_str = sign('private_key.pem', msg) 46 | print("簽名:", signed_str) 47 | 48 | result = verify_sign('public_key.pem', signed_str, msg) 49 | print("驗證結果:", result) 50 | -------------------------------------------------------------------------------- /pyotp_tutorial.md: -------------------------------------------------------------------------------- 1 | ## pyopt 教學 2 | 3 | 實作 two-factor (2FA) or multi-factor (MFA) authentication methods 4 | 5 | 安裝指令 6 | 7 | ```cmd 8 | pip install pyotp 9 | ``` 10 | 11 | 官方文件可參考 [pyotp](https://pypi.org/project/pyotp/) 12 | 13 | 這邊需要知道一次事情,OTP 產生的密碼是用時間和演算法完成的, 和網路沒關係, 14 | 15 | 所以有時候在使用的時候要注意 server 的時間有沒有跑掉, 不然會不準. 16 | 17 | 先產生一組 key 18 | 19 | ```python 20 | import pyotp 21 | import time 22 | my_key = pyotp.random_base32() 23 | print(my_key) 24 | ``` 25 | 26 | 接著產生 QRCODE 27 | 28 | ```python 29 | qrcode_uri = pyotp.totp.TOTP(my_key).provisioning_uri(\ 30 | name='Test@test.com', issuer_name='TEST App') 31 | print(qrcode_uri) 32 | 33 | # otpauth://totp/TEST%20App:Test%40test.com?secret=7VOXCMNJYHKWZEPU5RSCBDT3VHBDHKAI&issuer=TEST%20App 34 | ``` 35 | 36 | 注意, 這組字串也相當你的 key 不要亂丟給別人. 37 | 38 | 你會得到一串字串, 請把這串字串用任何工具轉成 QECODE (選擇 文字) 39 | 40 | 接著安裝 FreeOTP App or Google Authenticator, 41 | 42 | 然後掃秒 QECODE, 就會成功加入 43 | 44 | 基本上, 這邊印出的數字, 會和手機一模一樣 45 | 46 | ```python 47 | totp = pyotp.TOTP(my_key) 48 | print(totp.now()) 49 | ``` 50 | 51 | 如果你想樣驗證是否現在的 code 是有效的, 可以這樣用 52 | 53 | ```python 54 | print(totp.verify('587597')) 55 | ``` 56 | 57 | 看完上面的例子, 要注意一些事情, 首先, 每個帳號應該要有自己獨立的secret key, 58 | 59 | 每個 key 都用於單獨產生 一次性密碼 OTP, 這樣才能確保獨立性以及安全性. 60 | 61 | 因為假如多個帳號共用相同的 key, 這樣只要一個帳號的 key 外洩, 就全部完蛋了. 62 | 63 | -------------------------------------------------------------------------------- /pytest_tutorial/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture() 5 | def hello(): 6 | print("hello world") 7 | return 66 8 | -------------------------------------------------------------------------------- /pytest_tutorial/demo10_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture(scope="function", params=[[3, 1, 4], [99, 2, 101], [1, 1, 2]]) 5 | def data(request): 6 | yield request.param 7 | 8 | 9 | class Test_Demo10: 10 | def test_case1(self): 11 | print("run test_case1") 12 | assert 2 + 2 == 4 13 | 14 | def test_case2(self): 15 | print("run test_case2") 16 | assert 1 + 12 == 13 17 | 18 | def test_case3(self): 19 | print("run test_case3") 20 | assert 199 + 1 == 200 21 | 22 | def test_case4(self, data): 23 | print("run test_case4") 24 | assert data[0] + data[1] == data[2] 25 | 26 | 27 | if __name__ == "__main__": 28 | pytest.main() 29 | -------------------------------------------------------------------------------- /pytest_tutorial/demo11_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.mark.parametrize( 5 | "input", 6 | ( 7 | (1, 1, 2), 8 | (2, 2, 4), 9 | (3, 3, 6), 10 | ), 11 | ) 12 | class Test_Demo11: 13 | def test_case1(self, input): 14 | print("run test_case1") 15 | print(input) 16 | assert input[0] + input[1] == input[2] 17 | 18 | 19 | if __name__ == "__main__": 20 | pytest.main() 21 | -------------------------------------------------------------------------------- /pytest_tutorial/demo12_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def test_zero_division(): 5 | with pytest.raises(ZeroDivisionError) as excinfo: 6 | 1 / 0 7 | 8 | assert excinfo.type == ZeroDivisionError 9 | assert "division by zero" in str(excinfo.value) 10 | 11 | 12 | if __name__ == "__main__": 13 | pytest.main() 14 | -------------------------------------------------------------------------------- /pytest_tutorial/demo13_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.mark.xfail(raises=ZeroDivisionError) 5 | def test_f(): 6 | 1 / 0 7 | 8 | 9 | @pytest.mark.skip(reason="pass.....") 10 | def test_s(): 11 | 1 / 0 12 | 13 | 14 | if __name__ == "__main__": 15 | pytest.main() 16 | -------------------------------------------------------------------------------- /pytest_tutorial/demo14_test.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | import pytest 4 | 5 | # pytest.ini 6 | 7 | # @pytest.mark.name_of_the_mark decorator will trigger an error. 8 | # @pytest.mark.slwo 9 | @pytest.mark.slow 10 | def test_super_slow_test(): 11 | sleep(2) 12 | 13 | 14 | def test_a(): 15 | assert 1 == 1 16 | 17 | 18 | if __name__ == "__main__": 19 | pytest.main() 20 | -------------------------------------------------------------------------------- /pytest_tutorial/demo1_test.py: -------------------------------------------------------------------------------- 1 | def func(x): 2 | return x + 2 3 | 4 | 5 | def test_answer(): 6 | assert func(3) == 5 7 | -------------------------------------------------------------------------------- /pytest_tutorial/demo2_class_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | class TestDemo2: 5 | def setup_class(self): 6 | print("setup...") 7 | 8 | def teardown_class(self): 9 | print("teardown...") 10 | 11 | def test_case1(self): 12 | print("run test_case1") 13 | assert 2 + 2 == 4 14 | 15 | def test_case2(self): 16 | print("run test_case2") 17 | assert 1 + 12 == 13 18 | 19 | def test_case3(self): 20 | print("run test_case3") 21 | assert 199 + 1 == 200 22 | -------------------------------------------------------------------------------- /pytest_tutorial/demo2_function_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def setup_function(): 5 | print("setup...") 6 | 7 | 8 | def teardown_function(): 9 | print("teardown...") 10 | 11 | 12 | def test_case1(): 13 | print("run test_case1") 14 | assert 2 + 2 == 4 15 | 16 | 17 | def test_case2(): 18 | print("run test_case2") 19 | assert 1 + 12 == 13 20 | 21 | 22 | def test_case3(): 23 | print("run test_case3") 24 | assert 199 + 1 == 200 25 | -------------------------------------------------------------------------------- /pytest_tutorial/demo2_method_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | class TestDemo2: 5 | 6 | # def setup_method(self): 7 | # print("setup...") 8 | 9 | # def teardown_method(self): 10 | # print("teardown...") 11 | 12 | # euqal 13 | 14 | def setup(self): 15 | print("setup...") 16 | 17 | def teardown(self): 18 | print("teardown...") 19 | 20 | def test_case1(self): 21 | print("run test_case1") 22 | assert 2 + 2 == 4 23 | 24 | def test_case2(self): 25 | print("run test_case2") 26 | assert 1 + 12 == 13 27 | 28 | def test_case3(self): 29 | print("run test_case3") 30 | assert 199 + 1 == 200 31 | -------------------------------------------------------------------------------- /pytest_tutorial/demo2_module_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def setup_module(): 5 | print("setup...") 6 | 7 | 8 | def teardown_module(): 9 | print("teardown...") 10 | 11 | 12 | class TestDemo2: 13 | def test_case1(self): 14 | print("run test_case1") 15 | assert 2 + 2 == 4 16 | 17 | def test_case2(self): 18 | print("run test_case2") 19 | assert 1 + 12 == 13 20 | 21 | def test_case3(self): 22 | print("run test_case3") 23 | assert 199 + 1 == 200 24 | -------------------------------------------------------------------------------- /pytest_tutorial/demo3_share_test.py: -------------------------------------------------------------------------------- 1 | # test conftest.py 2 | import pytest 3 | 4 | 5 | class Test_Demo3: 6 | def test_case1(self): 7 | print("run test_case1") 8 | assert 2 + 2 == 4 9 | 10 | def test_case2(self, hello): 11 | print("run test_case2") 12 | print(hello) 13 | assert 1 + 12 == 13 14 | 15 | def test_case3(self): 16 | print("run test_case3") 17 | assert 199 + 1 == 200 18 | 19 | 20 | if __name__ == "__main__": 21 | pytest.main() 22 | -------------------------------------------------------------------------------- /pytest_tutorial/demo3_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture 5 | def hello(): 6 | print("hello world") 7 | return 66 8 | 9 | 10 | class Test_Demo3: 11 | def test_case1(self): 12 | print("run test_case1") 13 | assert 2 + 2 == 4 14 | 15 | def test_case2(self, hello): 16 | print("run test_case2") 17 | print(hello) 18 | assert 1 + 12 == 13 19 | 20 | def test_case3(self): 21 | print("run test_case3") 22 | assert 199 + 1 == 200 23 | 24 | 25 | if __name__ == "__main__": 26 | pytest.main() 27 | -------------------------------------------------------------------------------- /pytest_tutorial/demo4_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture 5 | def hello(): 6 | print("start hello world") 7 | yield 66 8 | print("end hello world") 9 | 10 | 11 | class Test_Demo4: 12 | def test_case1(self): 13 | print("run test_case1") 14 | assert 2 + 2 == 4 15 | 16 | def test_case2(self, hello): 17 | print("run test_case2") 18 | print(hello) 19 | assert 1 + 12 == 13 20 | 21 | def test_case3(self): 22 | print("run test_case3") 23 | assert 199 + 1 == 200 24 | 25 | 26 | if __name__ == "__main__": 27 | pytest.main() 28 | -------------------------------------------------------------------------------- /pytest_tutorial/demo5_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture 5 | def hello(request): 6 | print("start hello world") 7 | 8 | def demo_finalizer(): 9 | print("end hello world") 10 | 11 | request.addfinalizer(demo_finalizer) 12 | return 66 13 | 14 | 15 | class Test_Demo5: 16 | def test_case1(self): 17 | print("run test_case1") 18 | assert 2 + 2 == 4 19 | 20 | def test_case2(self, hello): 21 | print("run test_case2") 22 | print(hello) 23 | assert 1 + 12 == 13 24 | 25 | def test_case3(self): 26 | print("run test_case3") 27 | assert 199 + 1 == 200 28 | 29 | 30 | if __name__ == "__main__": 31 | pytest.main() 32 | -------------------------------------------------------------------------------- /pytest_tutorial/demo6_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture(scope="function") 5 | def hello(): 6 | print("hello world") 7 | return 66 8 | 9 | 10 | class Test_Demo6: 11 | def test_case1(self, hello): 12 | print("run test_case1") 13 | print(hello) 14 | assert 2 + 2 == 4 15 | 16 | def test_case2(self, hello): 17 | print("run test_case2") 18 | print(hello) 19 | assert 1 + 12 == 13 20 | 21 | def test_case3(self, hello): 22 | print("run test_case3") 23 | print(hello) 24 | assert 199 + 1 == 200 25 | 26 | 27 | if __name__ == "__main__": 28 | pytest.main() 29 | -------------------------------------------------------------------------------- /pytest_tutorial/demo7_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture(scope="class") 5 | def hello1(): 6 | print("hello world") 7 | 8 | 9 | class Test_Demo7: 10 | def test_case1(self, hello1): 11 | print("run test_case1") 12 | assert 2 + 2 == 4 13 | 14 | def test_case2(self, hello1): 15 | print("run test_case2") 16 | assert 1 + 12 == 13 17 | 18 | def test_case3(self, hello1): 19 | print("run test_case3") 20 | assert 199 + 1 == 200 21 | 22 | 23 | if __name__ == "__main__": 24 | pytest.main() 25 | -------------------------------------------------------------------------------- /pytest_tutorial/demo8_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture(autouse=True) 5 | def hello(): 6 | print("hello world") 7 | 8 | 9 | class Test_Demo8: 10 | def test_case1(self): 11 | print("run test_case1") 12 | assert 2 + 2 == 4 13 | 14 | def test_case2(self): 15 | print("run test_case2") 16 | assert 1 + 12 == 13 17 | 18 | def test_case3(self): 19 | print("run test_case3") 20 | assert 199 + 1 == 200 21 | 22 | 23 | if __name__ == "__main__": 24 | pytest.main() 25 | -------------------------------------------------------------------------------- /pytest_tutorial/demo9_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture 5 | def hello(): 6 | print("hello world") 7 | 8 | 9 | @pytest.mark.usefixtures("hello") 10 | class Test_Demo9: 11 | def test_case1( 12 | self, 13 | ): 14 | print("run test_case1") 15 | assert 2 + 2 == 4 16 | 17 | def test_case2(self): 18 | print("run test_case2") 19 | assert 1 + 12 == 13 20 | 21 | def test_case3(self): 22 | print("run test_case3") 23 | assert 199 + 1 == 200 24 | 25 | 26 | if __name__ == "__main__": 27 | pytest.main() 28 | -------------------------------------------------------------------------------- /pytest_tutorial/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | markers = 3 | slow: marks tests as slow (deselect with '-m "not slow"') 4 | serial -------------------------------------------------------------------------------- /python-decouple-tutorial/settings.ini: -------------------------------------------------------------------------------- 1 | [settings] 2 | DEBUG=True 3 | PATH=/temp -------------------------------------------------------------------------------- /python-decouple-tutorial/tutorial.py: -------------------------------------------------------------------------------- 1 | from decouple import config 2 | 3 | if __name__ == "__main__": 4 | DEBUG = config('DEBUG', default=False, cast=bool) 5 | print('DEBUG', DEBUG) 6 | ''' 7 | environment variables have precedence over config files. 8 | os.environ['PATH'] = '/my_path' 9 | ''' 10 | PATH = config('PATH', cast=str) 11 | print('PATH', PATH) 12 | -------------------------------------------------------------------------------- /python_circular_import/demo1/a.py: -------------------------------------------------------------------------------- 1 | def hello(): 2 | print('hello in a.py') -------------------------------------------------------------------------------- /python_circular_import/demo1/b.py: -------------------------------------------------------------------------------- 1 | def hello(): 2 | print('hello in b.py') -------------------------------------------------------------------------------- /python_circular_import/demo1/c.py: -------------------------------------------------------------------------------- 1 | from demo1.a import hello 2 | from demo1.b import hello 3 | 4 | if __name__ == '__main__': 5 | hello() -------------------------------------------------------------------------------- /python_circular_import/demo1/c_fix.py: -------------------------------------------------------------------------------- 1 | import demo1.a 2 | import demo1.b 3 | 4 | if __name__ == '__main__': 5 | demo1.a.hello() 6 | demo1.b.hello() 7 | -------------------------------------------------------------------------------- /python_circular_import/demo2/a2.py: -------------------------------------------------------------------------------- 1 | from demo2.b2 import hello 2 | 3 | 4 | def world(): 5 | print('world in a2') 6 | 7 | 8 | def show(): 9 | print('show in a2') 10 | hello() 11 | 12 | 13 | if __name__ == '__main__': 14 | show() 15 | -------------------------------------------------------------------------------- /python_circular_import/demo2/b2.py: -------------------------------------------------------------------------------- 1 | from demo2.a2 import world 2 | 3 | 4 | def hello(): 5 | print('hello in b2') 6 | 7 | 8 | def show(): 9 | print('show in b2') 10 | world() 11 | 12 | 13 | if __name__ == '__main__': 14 | show() 15 | -------------------------------------------------------------------------------- /python_circular_import/demo3/a3.py: -------------------------------------------------------------------------------- 1 | import demo3.b3 2 | 3 | 4 | def world(): 5 | print('world in a3') 6 | 7 | 8 | def show(): 9 | print('show in a3') 10 | demo3.b3.hello() 11 | 12 | 13 | if __name__ == '__main__': 14 | show() 15 | -------------------------------------------------------------------------------- /python_circular_import/demo3/b3.py: -------------------------------------------------------------------------------- 1 | import demo3.a3 2 | 3 | 4 | def hello(): 5 | print('hello in b3') 6 | 7 | 8 | def show(): 9 | print('show in b3') 10 | demo3.a3.world() 11 | 12 | 13 | if __name__ == '__main__': 14 | show() 15 | -------------------------------------------------------------------------------- /python_circular_import/demo4/a4.py: -------------------------------------------------------------------------------- 1 | def world(): 2 | print('world in a4') 3 | 4 | 5 | def show(): 6 | from demo4.b4 import hello 7 | print('show in a4') 8 | hello() 9 | 10 | 11 | if __name__ == '__main__': 12 | show() 13 | -------------------------------------------------------------------------------- /python_circular_import/demo4/b4.py: -------------------------------------------------------------------------------- 1 | def hello(): 2 | print('hello in b4') 3 | 4 | 5 | def show(): 6 | from demo4.a4 import world 7 | print('show in b4') 8 | world() 9 | 10 | 11 | if __name__ == '__main__': 12 | show() 13 | -------------------------------------------------------------------------------- /python_circular_import/demo5/a5.py: -------------------------------------------------------------------------------- 1 | def world(): 2 | print('world in a5') 3 | 4 | 5 | from demo5.b5 import hello 6 | 7 | 8 | def show(): 9 | print('show in a5') 10 | hello() 11 | 12 | 13 | if __name__ == '__main__': 14 | show() 15 | -------------------------------------------------------------------------------- /python_circular_import/demo5/b5.py: -------------------------------------------------------------------------------- 1 | def hello(): 2 | print('hello in b5') 3 | 4 | 5 | from demo5.a5 import world 6 | 7 | 8 | def show(): 9 | print('show in b5') 10 | world() 11 | 12 | 13 | if __name__ == '__main__': 14 | show() 15 | -------------------------------------------------------------------------------- /random_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3/library/random.html 2 | 3 | from random import choice, sample 4 | 5 | if __name__ == "__main__": 6 | num_seqs = range(20) 7 | print("num_seqs", list(num_seqs)) 8 | print("choice(num_seqs)", choice(num_seqs)) 9 | print("choice(num_seqs)", choice(num_seqs)) 10 | 11 | print(sample(num_seqs, 3)) 12 | print(sample(num_seqs, 3)) 13 | print(sample(num_seqs, 5)) 14 | print(sample(num_seqs, 5)) 15 | -------------------------------------------------------------------------------- /range.py: -------------------------------------------------------------------------------- 1 | # range 2 | 3 | # ref. https://docs.python.org/3.0/whatsnew/3.0.html#views-and-iterators-instead-of-lists 4 | # python3 no longer exists xrange 5 | # range() now behaves like xrange() used to behave, except it works with values of arbitrary size. 6 | 7 | import time 8 | 9 | if __name__ == "__main__": 10 | # range 11 | print('range(5)', range(5)) 12 | print('list(range(5))', list(range(5))) 13 | 14 | # range 15 | tStart = time.time() 16 | for i in range(10000000): 17 | pass 18 | tEnd = time.time() 19 | print('range time:', tEnd - tStart) 20 | -------------------------------------------------------------------------------- /redis_tutorial/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | 3 | services: 4 | tmp-cache: 5 | image: redis 6 | container_name: tmp-redis 7 | restart: always 8 | ports: 9 | - '6379:6379' 10 | volumes: 11 | - cache-tmp:/data 12 | volumes: 13 | cache-tmp: 14 | driver: local -------------------------------------------------------------------------------- /redis_tutorial/redis_base.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | # r = redis.Redis(host='localhost', port=6379, decode_responses=True) 4 | # redis-cli --raw 5 | r = redis.Redis(host="localhost", port=6379, db=0) 6 | r.set("foo", "bar") 7 | print(r.get("foo")) 8 | print(r.exists("foo")) 9 | print(r.exists("foo1")) 10 | print(r.strlen("foo")) # value len 11 | print(r.delete("foo1")) 12 | 13 | # setnx = "SET if Not eXists" 14 | print(r.setnx("foo2", "3")) # -> True 15 | print(r.get("foo2")) # -> 3 16 | print(r.setnx("foo", "3")) # -> False 17 | print(r.get("foo2")) # -> bar 18 | 19 | r.incr("users") 20 | print(r.get("users")) 21 | r.incrby("users", 2) 22 | print(r.get("users")) 23 | r.decrby("users", 2) 24 | print(r.get("users")) 25 | -------------------------------------------------------------------------------- /redis_tutorial/redis_brpop_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref 2 | # https://redis.io/commands/blpop/ 3 | # b -> block 4 | 5 | import time 6 | import redis 7 | 8 | redis_client = redis.Redis(host="localhost", port=6379, db=0) 9 | 10 | while 1: 11 | time.sleep(0.5) 12 | print(redis_client.brpop("mq"), timeout=0) 13 | -------------------------------------------------------------------------------- /redis_tutorial/redis_json.py: -------------------------------------------------------------------------------- 1 | import redis 2 | import json 3 | 4 | redis_client = redis.Redis(host="localhost", port=6379) 5 | 6 | my_dict = [ 7 | {"type": "a1", "value": "v1"}, 8 | {"type": "a2", "value": "v2"}, 9 | {"type": "a3", "value": "v3"}, 10 | ] 11 | 12 | json_my_dict = json.dumps(my_dict) 13 | redis_client.set("myjson", json_my_dict) 14 | 15 | data = json.loads(redis_client.get("myjson")) 16 | print(data) 17 | -------------------------------------------------------------------------------- /redis_tutorial/redis_list.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | client = redis.Redis(host="localhost", port=6379, db=0) 4 | 5 | client.rpush("mylist", "a") 6 | client.rpush("mylist", "b") 7 | client.rpush("mylist", "c") 8 | client.rpush("mylist", "d") 9 | client.rpush("mylist", "e") 10 | client.rpush("mylist", "f", "g") 11 | 12 | print(client.lindex("mylist", 6)) 13 | print(client.lrange("mylist", 2, 5)) 14 | 15 | """ 16 | redis-cli 17 | 18 | 127.0.0.1:6379> LRANGE "mylist" 0 100 19 | 1) "a" 20 | 2) "b" 21 | 3) "c" 22 | 4) "d" 23 | 5) "e" 24 | 6) "f" 25 | 7) "g" 26 | """ 27 | 28 | while client.llen("mylist") != 0: 29 | print(client.rpop("mylist")) 30 | -------------------------------------------------------------------------------- /redis_tutorial/redis_listen.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | client = redis.Redis(host="localhost", port=6379) 4 | 5 | p = client.pubsub() 6 | p.subscribe("room") 7 | for message in p.listen(): 8 | print(message.get("data")) 9 | -------------------------------------------------------------------------------- /redis_tutorial/redis_lock_unlock.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | redis_client = redis.Redis(host="localhost", port=6379, db=0, decode_responses=True) 4 | 5 | # redis-cl -> SET lock_key secret NX PX 10000 6 | # NX – Only set the key if it does not already exist. 7 | # PX milliseconds – Set the specified expire time, in milliseconds. 8 | my_key = "my-lock-key" 9 | print(redis_client.set(my_key, "secret", nx=True, px=10000)) 10 | 11 | if redis_client.get(my_key) == "secret": 12 | print("unlock") 13 | redis_client.delete(my_key) 14 | else: 15 | print("not unlock") 16 | -------------------------------------------------------------------------------- /redis_tutorial/redis_lpush_tutorial.py: -------------------------------------------------------------------------------- 1 | import time 2 | import redis 3 | 4 | redis_client = redis.Redis(host="localhost", port=6379, db=0) 5 | 6 | count = 0 7 | while 1: 8 | time.sleep(0.3) 9 | count += 1 10 | redis_client.lpush("mq", count) 11 | -------------------------------------------------------------------------------- /redis_tutorial/redis_mbase.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | r = redis.Redis(host="localhost", port=6379, db=0) 4 | 5 | # Atomic operations can be used when all keys are mapped to the same slot 6 | r.mset({"boo1": "bar1", "boo2": "bar2"}) 7 | print(r.mget("boo1", "boo2")) 8 | -------------------------------------------------------------------------------- /redis_tutorial/redis_msetnx.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | r = redis.Redis(host="localhost", port=6379, db=0) 4 | 5 | """ 6 | https://redis.io/commands/msetnx/ 7 | 8 | Sets the given keys to their respective values. 9 | MSETNX will not perform any operation at all even 10 | if just a single key already exists. 11 | 12 | MSETNX is atomic, so all given keys are set at once. 13 | It is not possible for clients to see that some of the keys were updated 14 | while others are unchanged. 15 | """ 16 | 17 | print(r.msetnx({"a1": "2"})) 18 | print(r.get("a1")) 19 | 20 | print(r.msetnx({"a1": "1", "a2": "2"})) 21 | print(r.get("a1")) 22 | print(r.get("a2")) 23 | -------------------------------------------------------------------------------- /redis_tutorial/redis_pickle.py: -------------------------------------------------------------------------------- 1 | import redis 2 | import pickle 3 | 4 | # user pickle -> decode_responses=False 5 | redis_client = redis.Redis(host="localhost", port=6379, decode_responses=False) 6 | 7 | 8 | class Stock: 9 | def __init__(self, num, date): 10 | self.num = num 11 | self.date = date 12 | 13 | 14 | def set_pickled(): 15 | s_obj = Stock("xxxx", "10/02") 16 | pickled_object = pickle.dumps(s_obj) 17 | redis_client.set("test_pickle", pickled_object) 18 | 19 | 20 | def get_pickled(): 21 | data = pickle.loads(redis_client.get("test_pickle")) 22 | print(data) 23 | 24 | 25 | set_pickled() 26 | get_pickled() 27 | -------------------------------------------------------------------------------- /redis_tutorial/redis_pipeline.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | client = redis.Redis(host="localhost", port=6379) 4 | pipeline = client.pipeline() 5 | 6 | pipeline.set("key1", "value1") 7 | pipeline.set("key2", "value2") 8 | 9 | print(pipeline.execute()) 10 | 11 | print(pipeline.set("foo1", "bar1").sadd("faz1", "baz1").incr("auto_number").execute()) 12 | -------------------------------------------------------------------------------- /redis_tutorial/redis_pipeline_watch.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | client = redis.Redis(host="localhost", port=6379) 4 | 5 | with client.pipeline() as pipe: 6 | while True: 7 | try: 8 | pipe.watch("OUR-SEQUENCE-KEY") 9 | current_value = pipe.get("OUR-SEQUENCE-KEY") 10 | pipe.multi() 11 | next_value = int(current_value) + 1 12 | pipe.set("OUR-SEQUENCE-KEY", next_value) 13 | pipe.execute() 14 | break 15 | except: 16 | print("except") 17 | continue 18 | finally: 19 | pipe.reset() 20 | 21 | """ 22 | ref. https://github.com/redis/redis-py#pipelines 23 | 24 | run python3 redis_pipeline_watch.py -> start watch 25 | 26 | redis-cli 27 | 127.0.0.1:6379> set OUR-SEQUENCE-KEY 0 28 | OK 29 | 30 | python3 redis_pipeline_watch.py -> done 31 | 32 | 127.0.0.1:6379> get OUR-SEQUENCE-KEY 33 | "1" 34 | """ 35 | -------------------------------------------------------------------------------- /redis_tutorial/redis_pub_sub.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | client = redis.Redis(host="localhost", port=6379) 4 | 5 | 6 | def example_1(): 7 | pubsub = client.pubsub() 8 | pubsub.subscribe("channel-1") 9 | 10 | # use pattern subscribe 11 | pubsub.psubscribe("channel-*") 12 | 13 | print(pubsub.get_message()) 14 | print(pubsub.get_message()) 15 | 16 | print(client.publish("channel-1", "value-1")) 17 | print(pubsub.get_message()) 18 | print(pubsub.get_message()) 19 | 20 | print("unsubscribe") 21 | pubsub.unsubscribe("my") 22 | pubsub.punsubscribe("my-*") 23 | print(pubsub.get_message()) 24 | print(pubsub.get_message()) 25 | pubsub.close() 26 | 27 | 28 | def my_handler(message): 29 | print("MY HANDLER: ", message["data"]) 30 | 31 | 32 | def example_2(): 33 | pubsub = client.pubsub(ignore_subscribe_messages=False) 34 | pubsub.subscribe(**{"my-channel": my_handler}) 35 | print(pubsub.get_message()) 36 | client.publish("my-channel", "awesome data") 37 | pubsub.get_message() 38 | pubsub.get_message() 39 | pubsub.close() 40 | 41 | 42 | # 可搭配 redis-cli MONITOR 觀察 43 | 44 | example_1() 45 | # example_2() 46 | -------------------------------------------------------------------------------- /redis_tutorial/redis_pulish.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | client = redis.Redis(host="localhost", port=6379) 4 | client.publish("room", "hello") 5 | -------------------------------------------------------------------------------- /redis_tutorial/redis_scan_iter.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | client = redis.Redis(host="localhost", port=6379) 4 | client.set("foo", "bar") 5 | client.set("foo1", "bar1") 6 | client.set("foo2", "bar2") 7 | client.set("fo2o2", "bar2") 8 | 9 | for key in client.scan_iter("foo*"): 10 | print(client.get(key)) 11 | -------------------------------------------------------------------------------- /redis_tutorial/redis_set.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | client = redis.Redis(host="localhost", port=6379, db=0) 4 | client.sadd("test-set", 1, 1, 2, 2, 4, 3) 5 | 6 | print(client.smembers("test-set")) 7 | 8 | client.sadd("test-set", 3, 5) 9 | print(client.smembers("test-set")) 10 | print(client.scard("test-set")) 11 | 12 | # remove 13 | client.srem("test-set", 3) 14 | print(client.smembers("test-set")) 15 | print(client.scard("test-set")) 16 | 17 | # if 2 in test-set 18 | print(client.sismember("test-set", 2)) 19 | # if 3 in test-set 20 | print(client.sismember("test-set", 3)) 21 | 22 | # random pop (remove from set) 23 | print(client.spop("test-set")) 24 | print(client.smembers("test-set")) 25 | # random picked (not remove from set) 26 | print(client.srandmember("test-set"), 2) 27 | print(client.smembers("test-set")) 28 | 29 | client.sadd("user:1", 1, 2, 3, 4) 30 | client.sadd("user:2", 3, 4) 31 | 32 | # 共同擁有的 33 | print(client.sinter("user:1", "user:2")) 34 | # 第一個集合和其他集合的差異 35 | print(client.sdiff("user:1", "user:2")) 36 | -------------------------------------------------------------------------------- /redis_tutorial/redis_ttl.py: -------------------------------------------------------------------------------- 1 | import redis 2 | import time 3 | 4 | client = redis.Redis(host="localhost", port=6379, db=0) 5 | client.set("test", "123", ex=3) 6 | print(client.ttl("test")) 7 | time.sleep(1) 8 | print(client.get("test")) 9 | print(client.ttl("test")) 10 | time.sleep(3) 11 | print(client.get("test")) 12 | -------------------------------------------------------------------------------- /reduce.py: -------------------------------------------------------------------------------- 1 | # Reduce is a really useful function for performing some computation on a list 2 | # and returning the result. For example, if you wanted to compute the product of a list of integers. 3 | 4 | 5 | if __name__ == "__main__": 6 | f = lambda a, b: a if (a > b) else b # but PEP-8 recommend use def 7 | f_result = reduce(f, [47, 11, 42, 102, 13]) 8 | print(f_result) # 102 The largest number will is returnd from f_result 9 | total = reduce(lambda x, y: x + y, range(1, 4)) 10 | print(total) # 1+2+3 = 6 11 | -------------------------------------------------------------------------------- /reduce_use_for_loop_tutorial_1.py: -------------------------------------------------------------------------------- 1 | def number_add(num): 2 | return num + 1 3 | 4 | if __name__ == "__main__": 5 | ''' 6 | common write method 7 | ''' 8 | item_list = [0, 1, 2, 3] 9 | result = [] 10 | for item in item_list: 11 | new_item = number_add(item) 12 | result.append(new_item) 13 | print('result', result) 14 | 15 | ''' 16 | better write method 1 17 | ''' 18 | result = [number_add(item) for item in item_list] 19 | print('result', result) 20 | 21 | ''' 22 | better write method 2 23 | ''' 24 | # result2 = map(int, str_num.split(',')) # python2 25 | result = list(map(lambda x: number_add(x), item_list)) 26 | print('result', result) 27 | 28 | # tuple 29 | result = tuple(map(lambda x: number_add(x), item_list)) 30 | print('result tuple', result) 31 | -------------------------------------------------------------------------------- /reduce_use_for_loop_tutorial_2.py: -------------------------------------------------------------------------------- 1 | def process_item(item_new): 2 | item_new += 1 3 | result_new = item_new * item_new 4 | return result_new 5 | 6 | 7 | if __name__ == "__main__": 8 | ''' 9 | common write method 10 | ''' 11 | results = [] 12 | item_list = [0, 1, 2, 3, 4] 13 | for item in item_list: 14 | item += 1 15 | result = item * item 16 | results.append(result) 17 | print('results', results) 18 | 19 | ''' 20 | better write method 1 21 | ''' 22 | results = [process_item(item) for item in item_list] 23 | print('results', results) 24 | -------------------------------------------------------------------------------- /remove_trailing_zeros_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3.6/library/decimal.html 2 | 3 | import decimal 4 | import unittest 5 | 6 | 7 | # ref. `to_integral` identical to the `to_integral_value` 8 | # Round to the nearest integer 9 | 10 | # ref. `normalize(x)` Reduces x to its simplest form. 11 | 12 | 13 | def remove_trailing_zeros(**kwargs): 14 | number = kwargs.get('number') 15 | number = decimal.Decimal(str(number)) 16 | 17 | if number == number.to_integral_value(): 18 | result = number.to_integral_value() 19 | else: 20 | result = number.normalize() 21 | return result 22 | 23 | 24 | class TestCase(unittest.TestCase): 25 | def test_case_1(self): 26 | result = remove_trailing_zeros(number=0.00) 27 | self.assertEqual(result, decimal.Decimal('0')) 28 | 29 | def test_case_2(self): 30 | result = remove_trailing_zeros(number=3.02) 31 | self.assertEqual(result, decimal.Decimal('3.02')) 32 | 33 | def test_case_3(self): 34 | result = remove_trailing_zeros(number=1.10) 35 | self.assertEqual(result, decimal.Decimal('1.1')) 36 | 37 | def test_case_4(self): 38 | result = remove_trailing_zeros(number=1.00) 39 | self.assertEqual(result, decimal.Decimal('1')) 40 | 41 | 42 | if __name__ == "__main__": 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /repr_tutorial.py: -------------------------------------------------------------------------------- 1 | # repr 2 | # Return a string representing the object as the developer wants to see it. 3 | 4 | # str 5 | # Return a string representing the object as the user wants to see it. 6 | 7 | class A: 8 | 9 | def __init__(self, x, y): 10 | self._x = x 11 | self._y = y 12 | 13 | def __str__(self): 14 | return '{} {}'.format(self._x, self._y) 15 | 16 | def __repr__(self): 17 | class_name = type(self).__name__ 18 | return '{}({})'.format(class_name, self) 19 | 20 | a = A(1, 2) 21 | print('str(a)', str(a)) 22 | print('repr(a)', repr(a)) 23 | -------------------------------------------------------------------------------- /rjust_ljust_tutorial.py: -------------------------------------------------------------------------------- 1 | ''' 2 | https://docs.python.org/3/library/stdtypes.html#str.rjust 3 | https://docs.python.org/3/library/stdtypes.html#str.ljust 4 | ''' 5 | 6 | my_str = 'hello' 7 | print(my_str.rjust(10, '0')) 8 | 9 | print(my_str.ljust(12, '7')) 10 | -------------------------------------------------------------------------------- /set_tutorial.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | ''' 3 | ref. https://docs.python.org/3/tutorial/datastructures.html#sets 4 | A set is an unordered collection with no duplicate elements 5 | ''' 6 | # set_seqs = {'a', 'b'} # set 7 | # dict_seqs = {} # dict 8 | set_seqs = set() 9 | set_seqs.add('test1') 10 | set_seqs.add('test2') 11 | print('set_seqs:', set_seqs) 12 | set_seqs.add('test1') 13 | print('set_seqs:', set_seqs) 14 | 15 | ''' 16 | remove(elem) 17 | Remove element elem from the set. Raises KeyError if elem is not contained in the set. 18 | ''' 19 | set_seqs.remove('test1') 20 | print('set_seqs:', set_seqs) 21 | # set_seqs.remove('test1') ## Raises KeyError 22 | 23 | ''' 24 | discard(elem) 25 | Remove element elem from the set if it is present. 26 | ''' 27 | set_seqs.discard('test1') 28 | print('set_seqs:', set_seqs) 29 | 30 | set_1 = {"a", "b", "c", "d"} 31 | set_2 = {"d", "e", "f", "g"} 32 | print("All: {}".format(set_1.union(set_2))) 33 | print("Both: {}".format(set_1.intersection(set_2))) 34 | print("Either but not both: {}".format( 35 | set_1.symmetric_difference(set_2))) 36 | -------------------------------------------------------------------------------- /setdefault_tutorial.py: -------------------------------------------------------------------------------- 1 | # The method setdefault() is similar to get(), 2 | # but will set dict[key]=default if key is not already in dict. 3 | 4 | # dict.setdefault(key, default=None) 5 | 6 | # setdefault does it all with a single lookup. 7 | 8 | def ex1(): 9 | dict_data = {'Name': 'twtrubiks', 'Age': 18} 10 | print('Name: {}'.format(dict_data.setdefault('Name', None))) 11 | print('Sex: {}'.format(dict_data.setdefault('Sex', None))) 12 | print('dict_data: {}'.format(dict_data)) 13 | print('Likes: {}'.format(dict_data.setdefault('Likes', []))) 14 | print('dict_data: {}'.format(dict_data)) 15 | 16 | 17 | def ex2_letter_frequency(sentence): 18 | frequencies = {} 19 | for letter in sentence: 20 | frequency = frequencies.setdefault(letter, 0) 21 | frequencies[letter] = frequency + 1 22 | return frequencies 23 | 24 | # equal ex2_letter_frequency 25 | def ex2_1_letter_frequency(sentence): 26 | frequencies = {} 27 | for letter in sentence: 28 | if letter in frequencies: 29 | frequencies[letter] += 1 30 | else: 31 | frequencies[letter] = 1 32 | return frequencies 33 | 34 | if __name__ == "__main__": 35 | ex1() 36 | # print(ex2_letter_frequency('sentence')) 37 | # print(ex2_1_letter_frequency('sentence')) 38 | -------------------------------------------------------------------------------- /str_find_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3/library/stdtypes.html#str.find 2 | 3 | # str.find(sub[, start[, end]]) 4 | 5 | if __name__ == "__main__": 6 | data = 'hello 123 456 789' 7 | target = "456" 8 | print('data.find(target)', data.find(target)) 9 | 10 | # Return -1 if it is not found. 11 | print('data.find(target, 11)', data.find(target, 11)) 12 | -------------------------------------------------------------------------------- /str_startswith_tutorial.py: -------------------------------------------------------------------------------- 1 | def str_startswith(): 2 | text = 'abcd' 3 | if text.startswith('ab'): 4 | print('yes') 5 | 6 | 7 | def str_endswith(): 8 | text = 'abcd' 9 | if text.endswith('cd'): 10 | print('yes') 11 | 12 | 13 | if __name__ == "__main__": 14 | str_startswith() 15 | str_endswith() 16 | -------------------------------------------------------------------------------- /string_constants_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3/library/string.html 2 | 3 | from string import ascii_letters, ascii_lowercase, ascii_uppercase, digits 4 | 5 | if __name__ == "__main__": 6 | print("ascii_letters:", ascii_letters) 7 | print("ascii_lowercase:", ascii_lowercase) 8 | print("ascii_uppercase:", ascii_uppercase) 9 | print("digits:", digits) 10 | -------------------------------------------------------------------------------- /stringio_tutorial.py: -------------------------------------------------------------------------------- 1 | # https://docs.python.org/3/library/io.html#io.StringIO 2 | 3 | # 讀寫文件不一定是文件, 也可以是存在內存 ( 記憶體 ram ) 4 | # StringIO 就是在 Ram 中讀寫 str 5 | 6 | from io import StringIO 7 | 8 | def tutorial_1(): 9 | f = StringIO() 10 | f.write('hello') 11 | f.write(' ') 12 | f.write('world!') 13 | print(f.getvalue()) 14 | 15 | # Close object and discard memory buffer 16 | f.close() # 釋放記憶體 17 | # print(f.getvalue()) # .getvalue() will now raise an exception. 18 | 19 | def tutorial_2(): 20 | # 讀取 StringIO 21 | f = StringIO('Hello!\nHi!\nGoodbye!') 22 | while True: 23 | s = f.readline() 24 | if s == '': 25 | break 26 | print(s.strip()) 27 | 28 | 29 | def main(): 30 | tutorial_1() 31 | # tutorial_2() 32 | 33 | if __name__ == "__main__": 34 | main() -------------------------------------------------------------------------------- /strtobool_tutorial.py: -------------------------------------------------------------------------------- 1 | from distutils.util import strtobool 2 | 3 | if __name__ == "__main__": 4 | # Convert String to Boolean 5 | """ 6 | Convert a string representation of truth to true (1) or false (0). 7 | True values are 'y', 'yes', 't', 'true', 'on', and '1'; 8 | false valuesare 'n', 'no', 'f', 'false', 'off', and '0'. 9 | Raises ValueError if 'val' is anything else. 10 | """ 11 | # print(bool('true')) # -->error 12 | # print(bool('True')) # -->error 13 | # print(bool('false')) # -->error 14 | # print(bool('False')) # -->error 15 | # print(bool('0')) # -->error 16 | 17 | print(strtobool('true')) 18 | print(strtobool('True')) 19 | print(strtobool('False')) 20 | print(strtobool('on')) 21 | print(strtobool('n')) 22 | print(strtobool('y')) 23 | print(strtobool('0')) 24 | print(strtobool('1')) 25 | -------------------------------------------------------------------------------- /sum_tutorial.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | if __name__ == "__main__": 4 | ''' 5 | sum(iterable[, start]) 6 | ref. https://docs.python.org/3/library/functions.html#sum 7 | ''' 8 | number = [1, 2, 3, 4] 9 | print('sum(number):', sum(number)) 10 | print('sum(number) + 2:', sum(number, 2)) 11 | 12 | ''' 13 | math.fsum(iterable) 14 | ref. https://docs.python.org/3/library/math.html#math.fsum 15 | ''' 16 | f_number = [0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01] 17 | print('sum(f_number):', sum(f_number)) 18 | # Avoids loss of precision by tracking multiple intermediate partial sums 19 | print('math.fsum(f_number):', math.fsum(f_number)) 20 | 21 | seq_obj = [ 22 | { 23 | "count": 1 24 | }, 25 | { 26 | "count": 2 27 | }, 28 | { 29 | "count": 3 30 | }, 31 | { 32 | "count": 4 33 | }, 34 | ] 35 | total = sum(o.get('count') for o in seq_obj) 36 | print('total:', total) 37 | -------------------------------------------------------------------------------- /suppress_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. 2 | # https://docs.python.org/3/library/contextlib.html#contextlib.suppress 3 | 4 | # ignore specific errors 5 | from contextlib import suppress 6 | 7 | def ex1(): 8 | 9 | with suppress(TypeError): 10 | t = '1' / 0 11 | 12 | # Equivalent 13 | 14 | # try: 15 | # t = '1' / 0 16 | # except TypeError: 17 | # pass 18 | 19 | def ex2(): 20 | 21 | with suppress(TypeError, ZeroDivisionError): 22 | t = 1 / 0 23 | 24 | # Equivalent 25 | 26 | # try: 27 | # t = 1 / 0 28 | # except (TypeError,ZeroDivisionError): 29 | # pass 30 | 31 | # try: 32 | # t = 1 / 0 33 | # except TypeError: 34 | # pass 35 | # except ZeroDivisionError: 36 | # pass 37 | 38 | if __name__ == "__main__": 39 | ex1() 40 | # ex2() 41 | 42 | -------------------------------------------------------------------------------- /thread_process_tutorial/demo_process_join.py: -------------------------------------------------------------------------------- 1 | import multiprocessing as mp 2 | import time 3 | 4 | 5 | def main(url, num): 6 | print('開始執行', url) 7 | time.sleep(2) 8 | print('結束', num) 9 | 10 | 11 | url_list1 = ['www.yahoo.com.tw, www.google.com'] 12 | url_list2 = ['www.yahoo.com.tw, www.google.com'] 13 | url_list3 = ['www.yahoo.com.tw, www.google.com'] 14 | 15 | # 定義線程 16 | p_list = [] 17 | p1 = mp.Process(target=main, args=(url_list1, 1)) 18 | p_list.append(p1) 19 | 20 | p2 = mp.Process(target=main, args=(url_list2, 2)) 21 | p_list.append(p2) 22 | 23 | p3 = mp.Process(target=main, args=(url_list3, 3)) 24 | p_list.append(p3) 25 | 26 | # 開始工作 27 | for p in p_list: 28 | p.start() 29 | 30 | # 調整多程順序 31 | for p in p_list: 32 | # 有加入 join, 會等待輸出結果才會往下執行. 33 | p.join() 34 | 35 | print('main process quit') -------------------------------------------------------------------------------- /thread_process_tutorial/demo_process_non_join.py: -------------------------------------------------------------------------------- 1 | import multiprocessing as mp 2 | import time 3 | 4 | 5 | def main(url, num): 6 | print('開始執行', url) 7 | time.sleep(2) 8 | print('結束', num) 9 | 10 | 11 | url_list1 = ['www.yahoo.com.tw, www.google.com'] 12 | url_list2 = ['www.yahoo.com.tw, www.google.com'] 13 | url_list3 = ['www.yahoo.com.tw, www.google.com'] 14 | 15 | # 定義線程 16 | p_list = [] 17 | p1 = mp.Process(target=main, args=(url_list1, 1)) 18 | p_list.append(p1) 19 | 20 | p2 = mp.Process(target=main, args=(url_list2, 2)) 21 | p_list.append(p2) 22 | 23 | p3 = mp.Process(target=main, args=(url_list3, 3)) 24 | p_list.append(p3) 25 | 26 | # 開始工作 27 | for p in p_list: 28 | p.start() 29 | 30 | print('main process quit') -------------------------------------------------------------------------------- /thread_process_tutorial/demo_threading_daemon.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | 4 | def main(): 5 | while 1: 6 | print('執行中...') 7 | time.sleep(1) 8 | 9 | print("daemon Thread") 10 | t1 = threading.Thread(target=main, daemon=True) 11 | t1.start() 12 | print("isDaemon:", t1.isDaemon()) 13 | 14 | time.sleep(5) 15 | print('main thread quit') 16 | -------------------------------------------------------------------------------- /thread_process_tutorial/demo_threading_join.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | 4 | def main(num): 5 | print('開始執行', num) 6 | time.sleep(2) 7 | print('結束', num) 8 | 9 | t_list = [] 10 | 11 | t1 = threading.Thread(target=main, args=(1,)) 12 | t_list.append(t1) 13 | t2 = threading.Thread(target=main, args=(2,)) 14 | t_list.append(t2) 15 | t3 = threading.Thread(target=main, args=(3,)) 16 | t_list.append(t3) 17 | 18 | for t in t_list: 19 | t.start() 20 | 21 | for t in t_list: 22 | # 有加入 join, 會等待輸出結果才會往下執行. 23 | t.join() 24 | 25 | print('main thread quit') 26 | 27 | """ 28 | 開始執行 1 29 | 開始執行 2 30 | 開始執行 3 31 | 結束 1 32 | 結束 3 33 | 結束 2 34 | main thread quit 35 | """ -------------------------------------------------------------------------------- /thread_process_tutorial/demo_threading_lock.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | def thread_first_job(): 4 | global a, lock 5 | lock.acquire() 6 | 7 | for _ in range(3): 8 | a += 1 9 | print("This is the first thread ", a) 10 | 11 | lock.release() 12 | 13 | 14 | def thread_second_job(): 15 | global a, lock 16 | lock.acquire() 17 | 18 | for _ in range(3): 19 | a -= 1 20 | print("This is the second thread ", a) 21 | 22 | lock.release() 23 | 24 | a = 0 25 | lock = threading.Lock() 26 | first_thread = threading.Thread(target = thread_first_job) 27 | second_thread = threading.Thread(target = thread_second_job) 28 | first_thread.start() 29 | second_thread.start() 30 | first_thread.join() 31 | second_thread.join() -------------------------------------------------------------------------------- /thread_process_tutorial/demo_threading_non_daemon.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | 4 | def main(): 5 | while 1: 6 | print('執行中...') 7 | time.sleep(1) 8 | 9 | print("non-daemon Thread") 10 | t1 = threading.Thread(target=main) 11 | t1.start() 12 | print("isDaemon:", t1.isDaemon()) 13 | 14 | time.sleep(5) 15 | print('main thread quit') 16 | -------------------------------------------------------------------------------- /thread_process_tutorial/demo_threading_non_join.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | 4 | def main(num): 5 | print('開始執行', num) 6 | time.sleep(2) 7 | print('結束', num) 8 | 9 | t_list = [] 10 | 11 | t1 = threading.Thread(target=main, args=(1,)) 12 | t_list.append(t1) 13 | t2 = threading.Thread(target=main, args=(2,)) 14 | t_list.append(t2) 15 | t3 = threading.Thread(target=main, args=(3,)) 16 | t_list.append(t3) 17 | 18 | for t in t_list: 19 | t.start() 20 | 21 | print('main thread quit') 22 | 23 | """ 24 | 開始執行 1 25 | 開始執行 2 26 | 開始執行 3 27 | main thread quit 28 | 結束 3 29 | 結束 1 30 | 結束 2 31 | """ -------------------------------------------------------------------------------- /thread_process_tutorial/demo_threading_non_lock.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | a = 0 4 | 5 | def thread_first_job(): 6 | global a 7 | for _ in range(3): 8 | a += 1 9 | print("This is the first thread ", a) 10 | 11 | 12 | def thread_second_job(): 13 | global a 14 | for _ in range(3): 15 | a -= 1 16 | print("This is the second thread ", a) 17 | 18 | 19 | first_thread = threading.Thread(target = thread_first_job) 20 | second_thread = threading.Thread(target = thread_second_job) 21 | first_thread.start() 22 | second_thread.start() 23 | first_thread.join() 24 | second_thread.join() -------------------------------------------------------------------------------- /translate_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3/library/stdtypes.html 2 | 3 | if __name__ == "__main__": 4 | ''' 5 | str.translate(table[, deletechars]); 6 | ''' 7 | # tutorial_1 8 | intab_1 = "abc" 9 | outtab_1 = "def" 10 | # make translation table 11 | trantab_1 = str.maketrans(intab_1, outtab_1) 12 | value_1 = "aabbcc" 13 | print('tutorial_1:', value_1.translate(trantab_1)) 14 | 15 | # tutorial_2 16 | intab_2 = "abc" 17 | outtab_2 = "def" 18 | # make translation table and remove "2" this character 19 | trantab_2 = str.maketrans(intab_2, outtab_2, "2") 20 | value_2 = "2aabb123cc2" 21 | print('tutorial_2:', value_2.translate(trantab_2)) 22 | -------------------------------------------------------------------------------- /try_except_tutorial.py: -------------------------------------------------------------------------------- 1 | 2 | def call_indexerror(): 3 | raise IndexError 4 | 5 | def call_my(): 6 | print('hello') 7 | 8 | def example_bad(): 9 | try: 10 | call_indexerror() 11 | call_my() 12 | except IndexError: 13 | print('IndexError') 14 | 15 | def example_good_1(): 16 | try: 17 | call_indexerror() 18 | except IndexError: 19 | print('IndexError') 20 | else: 21 | # only execute if no exceptions are raised in the try block. 22 | call_my() 23 | 24 | def example_good_2(): 25 | try: 26 | print('pass') 27 | except IndexError: 28 | print('IndexError') 29 | else: 30 | # only execute if no exceptions are raised in the try block. 31 | call_my() 32 | 33 | if __name__ == "__main__": 34 | # example_bad() 35 | example_good_1() 36 | # example_good_2() -------------------------------------------------------------------------------- /tuple_tutorial.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | my_tuple = (1, 2, 3) 3 | print('my_tuple:', my_tuple) 4 | a, b, c = my_tuple 5 | print('a', a) 6 | print('b', b) 7 | print('c', c) 8 | 9 | print('my_tuple[0]:', my_tuple[0]) 10 | print('my_tuple[1]:', my_tuple[1]) 11 | print('my_tuple[1:3]:', my_tuple[1:3]) 12 | 13 | # my_tuple[0] = 1 # error , tuple read only 14 | -------------------------------------------------------------------------------- /type-hints-tutorial/Any_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref 2 | # https://docs.python.org/3/library/typing.html#typing.Any 3 | 4 | from typing import Any 5 | 6 | 7 | class A: 8 | def action(self, data: Any) -> None: 9 | print(data) 10 | 11 | 12 | a = A() 13 | a.action("test") 14 | a.action(123) 15 | a.action([1, 3, 4]) 16 | -------------------------------------------------------------------------------- /type-hints-tutorial/Callable_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref 2 | # https://docs.python.org/3.8/library/typing.html#typing.Callable 3 | # Callable[..., ReturnType] 4 | # A plain Callable is equivalent to Callable[..., Any] 5 | 6 | from typing import Callable 7 | 8 | 9 | class Dog: 10 | def action(self) -> None: 11 | print("dog dog") 12 | 13 | 14 | class Pet: 15 | def __init__(self, animal: Callable) -> None: 16 | self.animal = animal 17 | 18 | def show(self) -> None: 19 | self.animal() 20 | 21 | 22 | dog = Dog() 23 | pet = Pet(dog.action) 24 | pet.show() 25 | -------------------------------------------------------------------------------- /type-hints-tutorial/KeysView_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref 2 | # https://docs.python.org/3/library/typing.html#typing.KeysView 3 | 4 | from typing import KeysView 5 | 6 | 7 | class Data: 8 | 9 | products = { 10 | "milk": {"price": 1.50, "quantity": 10}, 11 | "eggs": {"price": 0.20, "quantity": 100}, 12 | "cheese": {"price": 2.00, "quantity": 10}, 13 | } 14 | 15 | def product_list(self) -> KeysView[str]: 16 | return self.products.keys() 17 | 18 | 19 | products = { 20 | "milk": {"price": 1.50, "quantity": 10}, 21 | "eggs": {"price": 0.20, "quantity": 100}, 22 | "cheese": {"price": 2.00, "quantity": 10}, 23 | } 24 | 25 | print(products.keys()) 26 | -------------------------------------------------------------------------------- /type-hints-tutorial/Protocol_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref 2 | # https://docs.python.org/3.8/library/typing.html#typing.Protocol 3 | # static duck-typing 4 | 5 | from typing import Protocol 6 | 7 | 8 | class Proto(Protocol): 9 | def meth(self) -> int: 10 | ... 11 | 12 | 13 | class A: 14 | def meth(self) -> int: 15 | return 10 16 | 17 | 18 | class B: 19 | def meth(self) -> int: 20 | return 0 21 | 22 | 23 | def func(duck: Proto) -> int: 24 | return duck.meth() 25 | 26 | 27 | print(func(A())) 28 | print(func(B())) 29 | -------------------------------------------------------------------------------- /type-hints-tutorial/TYPE_CHECKING_tutorial/main.py: -------------------------------------------------------------------------------- 1 | from module_a import ClassA 2 | from module_b import ClassB 3 | 4 | a = ClassA(None) 5 | b = ClassB(a) 6 | b.use_a() -------------------------------------------------------------------------------- /type-hints-tutorial/TYPE_CHECKING_tutorial/main_fix.py: -------------------------------------------------------------------------------- 1 | from module_a_fix import ClassA 2 | from module_b_fix import ClassB 3 | 4 | a = ClassA(None) 5 | b = ClassB(a) 6 | b.use_a() -------------------------------------------------------------------------------- /type-hints-tutorial/TYPE_CHECKING_tutorial/module_a.py: -------------------------------------------------------------------------------- 1 | from module_b import ClassB 2 | 3 | class ClassA: 4 | def __init__(self, b: ClassB) -> None: 5 | self.b = b 6 | 7 | def use_b(self) -> None: 8 | print("Using ClassB from ClassA") 9 | -------------------------------------------------------------------------------- /type-hints-tutorial/TYPE_CHECKING_tutorial/module_a_fix.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING 2 | 3 | if TYPE_CHECKING: 4 | from module_b_fix import ClassB 5 | 6 | class ClassA: 7 | def __init__(self, b: "ClassB") -> None: 8 | self.b = b 9 | 10 | def use_b(self) -> None: 11 | print("Using ClassB from ClassA") -------------------------------------------------------------------------------- /type-hints-tutorial/TYPE_CHECKING_tutorial/module_b.py: -------------------------------------------------------------------------------- 1 | from module_a import ClassA 2 | 3 | class ClassB: 4 | def __init__(self, a: ClassA) -> None: 5 | self.a = a 6 | 7 | def use_a(self) -> None: 8 | print("Using ClassA from ClassB") -------------------------------------------------------------------------------- /type-hints-tutorial/TYPE_CHECKING_tutorial/module_b_fix.py: -------------------------------------------------------------------------------- 1 | from typing import TYPE_CHECKING 2 | 3 | if TYPE_CHECKING: 4 | from module_a_fix import ClassA 5 | 6 | class ClassB: 7 | def __init__(self, a: "ClassA") -> None: 8 | self.a = a 9 | 10 | def use_a(self) -> None: 11 | print("Using ClassA from ClassB") -------------------------------------------------------------------------------- /type-hints-tutorial/Tuple_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref 2 | # https://docs.python.org/3/library/typing.html#typing.Tuple 3 | 4 | from typing import Tuple 5 | 6 | # "..." To specify a variable-length tuple 7 | 8 | def show(data : Tuple[int, ...]) -> None: 9 | print(data) 10 | 11 | show((1,2,3,)) 12 | show((1,2,)) -------------------------------------------------------------------------------- /type-hints-tutorial/TypeVar_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref 2 | # https://docs.python.org/3.8/library/typing.html#typing.TypeVar 3 | 4 | from typing import TypeVar 5 | 6 | T = TypeVar("T") # Can be anything 7 | 8 | 9 | class Dog: 10 | pass 11 | 12 | 13 | class Cat: 14 | pass 15 | 16 | 17 | class Pet: 18 | def __init__(self, animal: T) -> None: 19 | pass 20 | 21 | 22 | dog = Dog() 23 | cat = Cat() 24 | pet_cat = Pet(cat) 25 | pet_dog = Pet(dog) 26 | -------------------------------------------------------------------------------- /type-hints-tutorial/kwargs_args_tutorial.py: -------------------------------------------------------------------------------- 1 | def variable(*args: int, **kwargs: str) -> None: 2 | pass 3 | 4 | 5 | variable(1, 2, 3, a="1", b="2") 6 | -------------------------------------------------------------------------------- /underscore_variable.py: -------------------------------------------------------------------------------- 1 | from calendar import monthrange 2 | 3 | 4 | def data(): 5 | return 'n1', 'n2' 6 | 7 | 8 | if __name__ == "__main__": 9 | # _ is a traditional name for don't care 10 | _, show = data() 11 | print('show : {}'.format(show)) 12 | 13 | # monthrange(year, month) 14 | # Returns weekday of first day of the month and number of days in month, for the specified year and month. 15 | _, num_days = monthrange(2017, 4) 16 | print('num_days : {}'.format(num_days)) 17 | -------------------------------------------------------------------------------- /unicodedata_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3.6/library/unicodedata.html 2 | import unicodedata 3 | 4 | 5 | def remove_control_characters(s): 6 | return "".join(ch for ch in s if unicodedata.category(ch)[0] != "C") 7 | 8 | 9 | if __name__ == "__main__": 10 | a = unicodedata.category('A') # 'L'etter, 'u'ppercase 11 | print('a:', a) 12 | b = unicodedata.category('\r') # carriage return Cc : control character 13 | print('b:', b) 14 | c = unicodedata.category('\t') # tab Cc : control character 15 | print('c:', c) 16 | d = unicodedata.category('\v') # vertical tabulation. Cc : control character 17 | print('d:', d) 18 | demo = "\tA\rB\v" 19 | print('demo:', demo) 20 | print('remove_control:', remove_control_characters(demo)) 21 | -------------------------------------------------------------------------------- /urllib_parse_quote_tutorial.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://docs.python.org/3/library/urllib.parse.html 3 | """ 4 | 5 | from urllib.parse import quote, unquote 6 | 7 | # = becomes %3D 8 | # + becomes %2B 9 | # Original string with special characters 10 | signature = "test/def+123=4666" 11 | 12 | # URL encode the string 13 | encoded_signature = quote(signature) 14 | 15 | print("Original Signature:", signature) 16 | print("URL Encoded Signature:", encoded_signature) 17 | 18 | print("Restore Original Signature:", unquote(signature)) 19 | -------------------------------------------------------------------------------- /user_defined_exceptions_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3/tutorial/errors.html 2 | 3 | # a common practice is to create a base class for exceptions defined by that module, 4 | # and subclass that to create specific exception classes for different error conditions 5 | 6 | class Error(Exception): 7 | """Base class for exceptions in this module.""" 8 | pass 9 | 10 | class InputError(Error): 11 | """Exception raised for errors in the input. 12 | 13 | Attributes: 14 | expression -- input expression in which the error occurred 15 | message -- explanation of the error 16 | """ 17 | 18 | def __init__(self, expression, message): 19 | self.expression = expression 20 | self.message = message 21 | 22 | if __name__ == "__main__": 23 | try: 24 | raise InputError(expression= 'expression', message= 'This is InputError') 25 | except InputError as e: 26 | print('e.expression:', e.expression) 27 | print('e.message:', e.message) 28 | -------------------------------------------------------------------------------- /uv_tutorial/README.md: -------------------------------------------------------------------------------- 1 | # uv 教學 2 | 3 | 官方文件 [uv](https://docs.astral.sh/uv/) 4 | 5 | 這個安裝套件真的非常快, 如果你一次安裝很多套件, 你就能了解他有多快. 6 | 7 | 安裝方法, 8 | 9 | ```cmd 10 | curl -LsSf https://astral.sh/uv/install.sh | sh 11 | ``` 12 | 13 | 或是你也可以用 `pip3 install uv` 安裝. 14 | 15 | 使用方法, 16 | 17 | uv 支援 pip 安裝界面, [The pip interface](https://docs.astral.sh/uv/pip/#the-pip-interface) 18 | 19 | ```python 20 | uv pip install ruff 21 | ``` 22 | 23 | 如果要安裝 requirements.txt 一樣加上 uv 而已 24 | 25 | ```python 26 | uv pip install -r requirements.txt 27 | ``` 28 | 29 | [Using tools](https://docs.astral.sh/uv/guides/tools/) 30 | 31 | uvx 是一個工具, 它可以在不安裝套件的情況下(安裝在暫存區), 就使用這個套件做一些簡單的測試. 32 | 33 | ```cmd 34 | uvx pycowsay hello from uv 35 | ``` 36 | 37 | uv 非常多功能, 也可以建立 venv, 38 | 39 | 但我自己主要是使用 [pyenv 教學](https://github.com/twtrubiks/python-notes/tree/master/pyenv_tutorial), 所以這邊就不再介紹, 有興趣的可以再到官網研究. -------------------------------------------------------------------------------- /vcr-tutorial/README.md: -------------------------------------------------------------------------------- 1 | # vcrpy 介紹教學 - 輕鬆把 request 錄下來 2 | 3 | * [Youtube Tutorial - vcrpy 介紹教學 - 輕鬆把 request 錄下來](https://youtu.be/LrAxl5vfXJ4) 4 | 5 | 建議搭配影片服用 :smile: 6 | 7 | ## 說明 8 | 9 | 常常在串接 api 的時候, 有時候對方的 api 很慢, 每測試一次就要等一下 :sweat: 10 | 11 | 雖然我們可以直接把 response 的內容複製下來, 貼到文字檔的文件, 然後 12 | 13 | 再去讀那個文件檔, 這可能是一種方法, 但有沒有更好的方法呢 :question: 14 | 15 | 當然有, 就是今天要介紹的 `vcrpy` :smile: 16 | 17 | 官方文件可參考 [https://vcrpy.readthedocs.io/en/latest/installation.html](https://vcrpy.readthedocs.io/en/latest/installation.html) 18 | 19 | 安裝方法 ( python 版本至少要 `Python 3.5+`) 20 | 21 | ```cmd 22 | pip install vcrpy 23 | ``` 24 | 25 | 使用方法也很簡單 26 | 27 | ```python 28 | import vcr 29 | import requests 30 | 31 | @vcr.use_cassette('fixtures/vcr_cassettes/demo.yaml') 32 | # @vcr.use_cassette() 33 | def demo(): 34 | response = requests.get('http://127.0.0.1:8000/api/image/test') 35 | data = response.json() 36 | print(data['id'], data['Url']) 37 | 38 | demo() 39 | ``` 40 | 41 | 第一次執行的時候, 會真的發出去 `request`, 並且會把資訊全部都錄下來, 42 | 43 | 並且保存在你所指定的路徑(也可以讓系統自動產生). 44 | 45 | 當你第二次執行時, 它會檢查是否有對應的 vcr_cassettes, 如果有的話, 46 | 47 | 就會直接讀取你錄下來的檔案(不會真的發出去 `request`). 48 | 49 | 但假如今天同一隻 api, 相同參數, server 端回應不同的資料給你, 這時候 50 | 51 | 你就只能刪掉錄下來的 vcr_cassettes, 重新錄一次即可. 52 | 53 | 這個 `vcrpy` 很方便, 推薦大家有空看看他的文件, 它也可以整合你的測試. -------------------------------------------------------------------------------- /what_is_classmethod_and_staticmethod/demo1.py: -------------------------------------------------------------------------------- 1 | class Dates: 2 | def __init__(self, date): 3 | self._date = date 4 | 5 | def get_date(self): 6 | return self._date 7 | 8 | @staticmethod 9 | def to_dash_date(date): 10 | return date.replace("/", "-") 11 | 12 | 13 | def main(): 14 | date = Dates("2018-10-10") # <1> 15 | print('date.get_date():', date.get_date()) # <2> 16 | date_from_birthday = "2018/12/12" 17 | date_with_dash = Dates.to_dash_date(date_from_birthday) # <3> 18 | print('date_with_dash:', date_with_dash) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /what_is_classmethod_and_staticmethod/demo2.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | 4 | # Create simple factory method using class method 5 | class Person: 6 | def __init__(self, name, age): 7 | self._name = name 8 | self._age = age 9 | 10 | @classmethod 11 | def from_birth_year(cls, name, birth_year): 12 | print('cls:', cls) 13 | return cls(name, date.today().year - birth_year) 14 | 15 | def display(self): 16 | print(self._name + "'s age is: " + str(self._age)) 17 | 18 | 19 | def main(): 20 | person = Person('twtrubiks', 18) 21 | person.display() 22 | 23 | person1 = Person.from_birth_year('John', 1985) 24 | person1.display() 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /what_is_the_abstractmethod/demo1.py: -------------------------------------------------------------------------------- 1 | class A: 2 | 3 | def action1(self): 4 | raise NotImplemented 5 | 6 | def action2(self): 7 | raise NotImplemented 8 | 9 | class B(A): 10 | pass 11 | 12 | b = B() 13 | 14 | # 沒有使用 abstractmethod 不一定要實作 action1, action2 15 | b.action1() 16 | # raise NotImplemented 17 | -------------------------------------------------------------------------------- /what_is_the_abstractmethod/demo1_fix.py: -------------------------------------------------------------------------------- 1 | class A: 2 | 3 | def action1(self): 4 | raise NotImplemented 5 | 6 | def action2(self): 7 | raise NotImplemented 8 | 9 | class B(A): 10 | def action1(self): 11 | print('hello action1') 12 | 13 | def action2(self): 14 | pass 15 | 16 | b = B() 17 | 18 | # 沒有使用 abstractmethod 不一定要實作 action1, action2 19 | b.action1() 20 | b.action2() 21 | 22 | -------------------------------------------------------------------------------- /what_is_the_abstractmethod/demo2.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | 4 | # class A(metaclass=abc.ABCMeta): 5 | class A(abc.ABC): 6 | 7 | @abc.abstractmethod 8 | def action1(self): 9 | pass 10 | 11 | @abc.abstractmethod 12 | def action2(self): 13 | pass 14 | 15 | class B(A): 16 | pass 17 | 18 | # 有使用 abstractmethod 一定要實作 action1, action2 19 | b = B() 20 | # TypeError: Can't instantiate abstract class B with abstract methods action1, action2 21 | -------------------------------------------------------------------------------- /what_is_the_abstractmethod/demo2_fix.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | 4 | # class A(metaclass=abc.ABCMeta): 5 | class A(abc.ABC): 6 | 7 | @abc.abstractmethod 8 | def action1(self): 9 | pass 10 | 11 | @abc.abstractmethod 12 | def action2(self): 13 | pass 14 | 15 | class B(A): 16 | def action1(self): 17 | print('hello action1') 18 | 19 | def action2(self): 20 | pass 21 | 22 | # 有使用 abstractmethod 一定要實作 action1, action2 23 | b = B() 24 | b.action1() 25 | b.action2() 26 | -------------------------------------------------------------------------------- /what_is_the_abstractmethod/demo3.py: -------------------------------------------------------------------------------- 1 | import abc 2 | 3 | 4 | # class A(metaclass=abc.ABCMeta): 5 | class A(abc.ABC): 6 | 7 | # abc.abstractmethod 請放在最內層 8 | @staticmethod 9 | @abc.abstractmethod 10 | def action1(x, y): 11 | pass 12 | 13 | # abc.abstractmethod 請放在最內層 14 | @classmethod 15 | @abc.abstractmethod 16 | def action2(cls, x, y): 17 | pass 18 | 19 | @abc.abstractmethod 20 | def display(self): 21 | pass 22 | 23 | class B(A): 24 | 25 | @staticmethod 26 | def action1(x, y): 27 | print('hello action1') 28 | print('x', x) 29 | print('y', y) 30 | 31 | @classmethod 32 | def action2(cls, x, y): 33 | print('hello action2', cls) 34 | print('x', x) 35 | print('y', y) 36 | return cls() 37 | 38 | def display(self): 39 | print('hello display') 40 | 41 | 42 | B.action1('x1', 'y1') 43 | B.action2('x2', 'y2').display() 44 | -------------------------------------------------------------------------------- /what_is_the_functools.lru_cache/clockdeco.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | def clock(func): 5 | def clocked(*args): 6 | t0 = time.time() 7 | result = func(*args) 8 | elapsed = time.time() - t0 9 | name = func.__name__ 10 | arg_str = ', '.join(repr(arg) for arg in args) 11 | print('[%0.8fs] %s(%s) -> %r' % (elapsed, name, arg_str, result)) 12 | return result 13 | 14 | return clocked 15 | -------------------------------------------------------------------------------- /what_is_the_functools.lru_cache/demo1.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | 4 | @functools.lru_cache() 5 | def job(n): 6 | print('run very long.....') 7 | return n + 10000 8 | 9 | 10 | if __name__ == '__main__': 11 | print(job(2)) 12 | print(job(2)) 13 | -------------------------------------------------------------------------------- /what_is_the_functools.lru_cache/demo2.py: -------------------------------------------------------------------------------- 1 | from clockdeco import clock 2 | 3 | 4 | @clock 5 | def fib(n): 6 | if n < 2: 7 | return n 8 | return fib(n - 1) + fib(n - 2) 9 | 10 | 11 | if __name__ == '__main__': 12 | print([fib(n) for n in range(16)]) 13 | -------------------------------------------------------------------------------- /what_is_the_functools.lru_cache/demo3.py: -------------------------------------------------------------------------------- 1 | from clockdeco import clock 2 | import functools 3 | 4 | 5 | @functools.lru_cache() 6 | @clock 7 | def fib(n): 8 | if n < 2: 9 | return n 10 | return fib(n - 1) + fib(n - 2) 11 | 12 | 13 | if __name__ == '__main__': 14 | print([fib(n) for n in range(16)]) 15 | -------------------------------------------------------------------------------- /what_is_the_functools.lru_cache/demo4.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | 4 | @functools.lru_cache(maxsize=2, typed=False) 5 | def job(n): 6 | print('run very long.....') 7 | return n + 10000 8 | 9 | 10 | if __name__ == '__main__': 11 | print(job(2)) 12 | print(job(3)) 13 | print(job(2)) 14 | print(job(4)) 15 | print(job(3)) 16 | -------------------------------------------------------------------------------- /what_is_the_functools.lru_cache/demo5.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | 4 | @functools.lru_cache(maxsize=128, typed=False) 5 | def job(n): 6 | # print(n.__hash__()) 7 | print('run very long.....') 8 | return n + 10000 9 | 10 | 11 | if __name__ == '__main__': 12 | print(job([1,2,3])) 13 | # print(job(1.0)) 14 | -------------------------------------------------------------------------------- /what_is_the_mixin/demo1.py: -------------------------------------------------------------------------------- 1 | class A: 2 | def __init__(self, x1, x2): 3 | self.x1 = x1 4 | self.x2 = x2 5 | 6 | if __name__ == '__main__': 7 | a = A('x1', 'y1') 8 | print(a) 9 | 10 | -------------------------------------------------------------------------------- /what_is_the_mixin/demo1_1.py: -------------------------------------------------------------------------------- 1 | 2 | class StrMixin: 3 | def __str__(self): 4 | return '{}_{}'.format(self.x1, self.x2) 5 | 6 | class A(StrMixin): 7 | def __init__(self, x1, x2): 8 | self.x1 = x1 9 | self.x2 = x2 10 | 11 | if __name__ == '__main__': 12 | a = A('x1', 'y1') 13 | print(a) 14 | 15 | -------------------------------------------------------------------------------- /what_is_the_mixin/demo1_2.py: -------------------------------------------------------------------------------- 1 | 2 | class HelloMixin: 3 | def display(self): 4 | print('hello') 5 | 6 | class StrMixin: 7 | def __str__(self): 8 | return '{}_{}'.format(self.x1, self.x2) 9 | 10 | class A(StrMixin, HelloMixin): 11 | def __init__(self, x1, x2): 12 | self.x1 = x1 13 | self.x2 = x2 14 | 15 | if __name__ == '__main__': 16 | a = A('x1', 'y1') 17 | print(a) 18 | a.display() 19 | 20 | -------------------------------------------------------------------------------- /what_is_the_mixin/demo2.py: -------------------------------------------------------------------------------- 1 | 2 | class HelloMixin: 3 | def display(self): 4 | print('HelloMixin hello') 5 | 6 | class A(HelloMixin): 7 | pass 8 | 9 | if __name__ == '__main__': 10 | a = A() 11 | a.display() 12 | 13 | -------------------------------------------------------------------------------- /what_is_the_mixin/demo2_1.py: -------------------------------------------------------------------------------- 1 | 2 | class HelloMixin: 3 | def display(self): 4 | print('HelloMixin hello') 5 | 6 | class SuperHelloMixin: 7 | def display(self): 8 | print('SuperHello hello') 9 | 10 | class A(SuperHelloMixin, HelloMixin): 11 | pass 12 | 13 | if __name__ == '__main__': 14 | a = A() 15 | a.display() 16 | 17 | -------------------------------------------------------------------------------- /what_is_the_name_main_in_python/demo1.py: -------------------------------------------------------------------------------- 1 | def a1_func(): 2 | print('hello a1_func') 3 | 4 | 5 | print('demo1.py is called') 6 | a1_func() 7 | -------------------------------------------------------------------------------- /what_is_the_name_main_in_python/demo2.py: -------------------------------------------------------------------------------- 1 | from demo1 import a1_func 2 | 3 | print('demo2.py is called') 4 | a1_func() 5 | 6 | -------------------------------------------------------------------------------- /what_is_the_name_main_in_python/demo3.py: -------------------------------------------------------------------------------- 1 | def a1_func(): 2 | print('hello a1_func') 3 | 4 | 5 | if __name__ == '__main__': 6 | print('demo3.py is called') 7 | a1_func() 8 | -------------------------------------------------------------------------------- /what_is_the_name_main_in_python/demo4.py: -------------------------------------------------------------------------------- 1 | from demo3 import a1_func 2 | 3 | print('demo4.py is called') 4 | a1_func() 5 | -------------------------------------------------------------------------------- /what_is_the_property/demo1.py: -------------------------------------------------------------------------------- 1 | class A: 2 | def __init__(self, content): 3 | self._content = content 4 | 5 | def get_content(self): 6 | if not hasattr(self, '_content'): 7 | return "content not exists" 8 | return self._content 9 | 10 | def set_content(self, value): 11 | self._content = value 12 | 13 | def delete_content(self): 14 | del self._content 15 | 16 | 17 | if __name__ == "__main__": 18 | a = A('hello') 19 | print('content:', a.get_content()) # get content 20 | a.set_content('world') # set content 21 | print('content:', a.get_content()) 22 | a.delete_content() # delete content 23 | print('content:', a.get_content()) # content not exists 24 | -------------------------------------------------------------------------------- /what_is_the_property/demo2.py: -------------------------------------------------------------------------------- 1 | class A: 2 | def __init__(self, content): 3 | self._content = content 4 | 5 | @property 6 | def content(self): 7 | if not hasattr(self, '_content'): 8 | return "content not exists" 9 | return self._content 10 | 11 | @content.setter 12 | def content(self, value): 13 | self._content = value 14 | 15 | @content.deleter 16 | def content(self): 17 | del self._content 18 | 19 | 20 | if __name__ == "__main__": 21 | a = A('hello') 22 | print('content:', a.content) # automatically calls getter 23 | a.content = 'world' # automatically calls setter 24 | print('content:', a.content) 25 | del a.content # automatically calls deleter 26 | print('content:', a.content) # content not exists 27 | -------------------------------------------------------------------------------- /what_is_the_property/demo2_1.py: -------------------------------------------------------------------------------- 1 | class A: 2 | def __init__(self, content): 3 | self._content = content 4 | 5 | def get_content(self): 6 | if not hasattr(self, '_content'): 7 | return "content not exists" 8 | return self._content 9 | 10 | def set_content(self, value): 11 | self._content = value 12 | 13 | def del_content(self): 14 | del self._content 15 | 16 | # property(fget=None, fset=None, fdel=None, doc=None) 17 | content = property(get_content, set_content, del_content, 'my content property') 18 | 19 | 20 | if __name__ == "__main__": 21 | a = A('hello') 22 | print('content:', a.content) # automatically calls getter 23 | a.content = 'world' # automatically calls setter 24 | print('content:', a.content) 25 | del a.content # automatically calls deleter 26 | print('content:', a.content) # content not exists 27 | -------------------------------------------------------------------------------- /what_is_the_property/demo3.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | 4 | class A: 5 | def __init__(self, content): 6 | self._content = content 7 | 8 | @property 9 | def time(self): 10 | return datetime.datetime.now() 11 | 12 | 13 | if __name__ == "__main__": 14 | a = A('hello') 15 | print('a.time:', a.time) 16 | # a.time = datetime.time(12, 20) # AttributeError: can't set attribute 17 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo1.py: -------------------------------------------------------------------------------- 1 | def f1(): 2 | print("f1") 3 | 4 | 5 | def register(func): 6 | func() 7 | 8 | 9 | register(f1) 10 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo2.py: -------------------------------------------------------------------------------- 1 | def my_logging(func): 2 | print('logging - {} is running'.format(func.__name__)) 3 | func() 4 | 5 | 6 | def f1(): 7 | print("f1") 8 | 9 | 10 | my_logging(f1) 11 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo3.py: -------------------------------------------------------------------------------- 1 | def my_logging(func): 2 | def wrapper(): 3 | print('logging - {} is running'.format(func.__name__)) 4 | func() # run func() Equivalent run f1() 5 | 6 | return wrapper 7 | 8 | 9 | def f1(): 10 | print("f1") 11 | 12 | 13 | f1 = my_logging(f1) # Equivalent -> f1 = wrapper 14 | f1() # Equivalent -> f1() = wrapper() 15 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo4.py: -------------------------------------------------------------------------------- 1 | def my_logging(func): 2 | def wrapper(): 3 | print('logging - {} is running'.format(func.__name__)) 4 | func() # run func() Equivalent run f1() 5 | 6 | return wrapper 7 | 8 | 9 | @my_logging 10 | def f1(): 11 | print("f1") 12 | 13 | 14 | f1() 15 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo4_1.py: -------------------------------------------------------------------------------- 1 | def my_logging(func): 2 | def wrapper(): 3 | print('logging - {} is running'.format(func.__name__)) 4 | func() # run func() Equivalent run f1() 5 | 6 | return wrapper 7 | 8 | 9 | def bold(func): 10 | def wrapper(): 11 | print("") 12 | func() 13 | print("") 14 | 15 | return wrapper 16 | 17 | 18 | def italic(func): 19 | def wrapper(): 20 | print("") 21 | func() 22 | print("") 23 | 24 | return wrapper 25 | 26 | 27 | @my_logging 28 | @bold 29 | @italic 30 | def f1(): 31 | print("f1") 32 | 33 | 34 | f1() 35 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo4_2.py: -------------------------------------------------------------------------------- 1 | def my_logging(func): 2 | def wrapper(): 3 | print('logging - {} is running'.format(func.__name__)) 4 | func() # run func() Equivalent run f1() 5 | 6 | return wrapper 7 | 8 | 9 | def bold(func): 10 | def wrapper(): 11 | print("") 12 | func() 13 | print("") 14 | 15 | return wrapper 16 | 17 | 18 | def italic(func): 19 | def wrapper(): 20 | print("") 21 | func() 22 | print("") 23 | 24 | return wrapper 25 | 26 | 27 | def f1(): 28 | print("f1") 29 | 30 | 31 | f1 = my_logging(bold(italic(f1))) 32 | f1() 33 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo5.py: -------------------------------------------------------------------------------- 1 | def my_logging(func): 2 | def wrapper(*args, **kwargs): 3 | print('logging - {} is running'.format(func.__name__)) 4 | func(*args, **kwargs) 5 | 6 | return wrapper 7 | 8 | 9 | @my_logging 10 | def f1(*args, **kwargs): 11 | print("f1") 12 | 13 | for thing in args: 14 | print('hello {}'.format(thing)) 15 | 16 | for name, value in kwargs.items(): 17 | print('{0} = {1}'.format(name, value)) 18 | 19 | 20 | f1('twtrubiks', apple='fruit', cabbage='vegetable') 21 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo6.py: -------------------------------------------------------------------------------- 1 | def my_logging(level): 2 | def decorator(func): 3 | def wrapper(*args, **kwargs): 4 | if level == "1": 5 | print('level {} logging - {} is running'.format(level, func.__name__)) 6 | elif level == "2": 7 | print('level {} logging - {} is running'.format(level, func.__name__)) 8 | 9 | func(*args, **kwargs) 10 | 11 | return wrapper 12 | 13 | return decorator 14 | 15 | 16 | @my_logging(level="1") 17 | def f1(*args, **kwargs): 18 | print("f1") 19 | 20 | for thing in args: 21 | print('hello {}'.format(thing)) 22 | 23 | for name, value in kwargs.items(): 24 | print('{0} = {1}'.format(name, value)) 25 | 26 | 27 | f1('twtrubiks', apple='fruit', cabbage='vegetable') 28 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo7.py: -------------------------------------------------------------------------------- 1 | def my_logging(func): 2 | def wrapper(*args, **kwargs): 3 | """my wrapper""" 4 | print('logging - {} is running'.format(func.__name__)) 5 | func(*args, **kwargs) 6 | 7 | return wrapper 8 | 9 | 10 | @my_logging 11 | def f1(*args, **kwargs): 12 | """f1 function""" 13 | print("f1") 14 | 15 | for thing in args: 16 | print('hello {}'.format(thing)) 17 | 18 | for name, value in kwargs.items(): 19 | print('{0} = {1}'.format(name, value)) 20 | 21 | 22 | f1('twtrubiks', apple='fruit', cabbage='vegetable') 23 | print('f1.__name__', f1.__name__) # output -> 'wrapper' 24 | print('f1.__doc__', f1.__doc__) # output -> 'my wrapper' 25 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo7_1.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | 4 | def my_logging(func): 5 | @wraps(func) 6 | def wrapper(*args, **kwargs): 7 | """my wrapper""" 8 | print('logging - {} is running'.format(func.__name__)) 9 | func(*args, **kwargs) 10 | 11 | return wrapper 12 | 13 | 14 | @my_logging 15 | def f1(*args, **kwargs): 16 | """f1 function""" 17 | print("f1") 18 | 19 | for thing in args: 20 | print('hello {}'.format(thing)) 21 | 22 | for name, value in kwargs.items(): 23 | print('{0} = {1}'.format(name, value)) 24 | 25 | 26 | f1('twtrubiks', apple='fruit', cabbage='vegetable') 27 | print('f1.__name__', f1.__name__) # output -> 'f1' 28 | print('f1.__doc__', f1.__doc__) # output -> 'f1 function' 29 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo8.py: -------------------------------------------------------------------------------- 1 | class MyDecorator: 2 | def __init__(self, func): 3 | self.__func = func 4 | 5 | def __call__(self, *args, **kwargs): 6 | print('do something before calling function {}'.format(self.__func.__name__)) 7 | self.__func(*args, **kwargs) 8 | print('do something after calling function {}'.format(self.__func.__name__)) 9 | 10 | 11 | @MyDecorator 12 | def f1(*args, **kwargs): 13 | print('f1') 14 | for thing in args: 15 | print('hello {}'.format(thing)) 16 | 17 | for name, value in kwargs.items(): 18 | print('{0} = {1}'.format(name, value)) 19 | 20 | 21 | f1('twtrubiks', apple='fruit', cabbage='vegetable') 22 | 23 | # @MyDecorator Equivalent 24 | # f1 = MyDecorator(f1) 25 | # f1('twtrubiks', apple='fruit', cabbage='vegetable') -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo8_1.py: -------------------------------------------------------------------------------- 1 | class MyDecorator: 2 | def __init__(self, param): 3 | self.__param = param 4 | 5 | def __call__(self, func): 6 | def wrapper(*args, **kwargs): 7 | print('do something before calling function {}'.format(func.__name__)) 8 | print('self.__param', self.__param) 9 | func(*args, **kwargs) 10 | print('do something after calling function {}'.format(func.__name__)) 11 | 12 | return wrapper 13 | 14 | 15 | @MyDecorator('level') 16 | def f1(*args, **kwargs): 17 | print('f1') 18 | for thing in args: 19 | print('hello {}'.format(thing)) 20 | 21 | for name, value in kwargs.items(): 22 | print('{0} = {1}'.format(name, value)) 23 | 24 | 25 | f1('twtrubiks', apple='fruit', cabbage='vegetable') 26 | -------------------------------------------------------------------------------- /what_is_the_python_decorator/demo9.py: -------------------------------------------------------------------------------- 1 | registry = dict() 2 | 3 | 4 | def route(rule): 5 | def decorator(f): 6 | registry[rule] = f 7 | return f 8 | 9 | return decorator 10 | 11 | 12 | @route('/') 13 | def index(): 14 | print('hello') 15 | return 'hello' 16 | 17 | 18 | index() 19 | print('registry:', registry) 20 | -------------------------------------------------------------------------------- /what_is_the_singledispatch/demo1.py: -------------------------------------------------------------------------------- 1 | def fun(arg): 2 | if not arg: 3 | print("Nothing.") 4 | return 5 | if isinstance(arg, int) or isinstance(arg, float): 6 | print('hello int or float,', type(arg)) 7 | elif isinstance(arg, list): 8 | print('hello list') 9 | for i, elem in enumerate(arg): 10 | print(i, elem) 11 | else: 12 | print('my type:', type(arg)) 13 | 14 | 15 | if __name__ == '__main__': 16 | fun("Hello, world.") 17 | fun(123) 18 | fun(123.3) 19 | fun([1, 2, 3]) 20 | fun({'a': 2}) 21 | fun(None) 22 | -------------------------------------------------------------------------------- /what_is_the_singledispatch/demo2.py: -------------------------------------------------------------------------------- 1 | from functools import singledispatch 2 | 3 | 4 | @singledispatch 5 | def fun(arg): 6 | print('my type:', type(arg)) 7 | 8 | 9 | @fun.register(int) 10 | @fun.register(float) 11 | def _(arg): 12 | print('hello int or float,', type(arg)) 13 | 14 | 15 | @fun.register(list) 16 | def _(arg): 17 | print('hello list') 18 | for i, elem in enumerate(arg): 19 | print(i, elem) 20 | 21 | 22 | @fun.register(type(None)) 23 | def nothing(_): 24 | print("Nothing.") 25 | 26 | 27 | if __name__ == '__main__': 28 | fun("Hello, world.") 29 | # fun(123) 30 | # fun(123.3) 31 | # fun([1, 2, 3]) 32 | # fun({'a': 2}) 33 | # fun(None) 34 | -------------------------------------------------------------------------------- /what_is_the_singledispatchmethod/demo1.py: -------------------------------------------------------------------------------- 1 | from functools import singledispatch 2 | 3 | class A: 4 | 5 | @singledispatch 6 | def fun(self, arg): 7 | print('my type:', type(arg)) 8 | 9 | 10 | @fun.register(int) 11 | @fun.register(float) 12 | def _(self, arg): 13 | print('hello int or float,', type(arg)) 14 | 15 | 16 | @fun.register(list) 17 | def _(self, arg): 18 | print('hello list') 19 | for i, elem in enumerate(arg): 20 | print(i, elem) 21 | 22 | 23 | @fun.register(type(None)) 24 | def nothing(self, _): 25 | print("Nothing.") 26 | 27 | 28 | if __name__ == '__main__': 29 | a = A() 30 | a.fun(123) 31 | # 正確應該要輸出 hello int or float, 32 | # 但這邊卻輸入 my type: 33 | # 代表 singledispatch 沒有生效 -------------------------------------------------------------------------------- /what_is_the_singledispatchmethod/demo2.py: -------------------------------------------------------------------------------- 1 | """ 2 | ref: 3 | https://docs.python.org/3.12/library/functools.html#functools.singledispatchmethod 4 | 5 | the dispatch happens on the type of the first non-self or non-cls argument: 6 | 7 | 所以如果使用 class 必須使用 singledispatchmethod, singledispatch 在 class 中沒作用 8 | """ 9 | 10 | from functools import singledispatchmethod 11 | 12 | class A: 13 | 14 | @singledispatchmethod 15 | def fun(self, arg): 16 | print('my type:', type(arg)) 17 | 18 | 19 | @fun.register(int) 20 | @fun.register(float) 21 | def _(self, arg): 22 | print('hello int or float,', type(arg)) 23 | 24 | 25 | @fun.register(list) 26 | def _(self, arg): 27 | print('hello list') 28 | for i, elem in enumerate(arg): 29 | print(i, elem) 30 | 31 | 32 | @fun.register(type(None)) 33 | def nothing(self, _): 34 | print("Nothing.") 35 | 36 | 37 | if __name__ == '__main__': 38 | a = A() 39 | a.fun(123) # 有正確輸出 hello int or float, 40 | -------------------------------------------------------------------------------- /what_is_the_singledispatchmethod/demo3.py: -------------------------------------------------------------------------------- 1 | from functools import singledispatchmethod 2 | 3 | class DATA1: 4 | def show(self): 5 | print("DATA1") 6 | 7 | class DATA2: 8 | def show(self): 9 | print("DATA2") 10 | 11 | class A: 12 | 13 | @singledispatchmethod 14 | def fun(self, arg): 15 | raise NotImplementedError() 16 | 17 | 18 | @fun.register(DATA1) 19 | def _(self, arg): 20 | arg.show() 21 | 22 | 23 | @fun.register(DATA2) 24 | def _(self, arg): 25 | arg.show() 26 | 27 | 28 | @fun.register(type(None)) 29 | def nothing(self, _): 30 | print("Nothing.") 31 | 32 | if __name__ == '__main__': 33 | 34 | data1 = DATA1() 35 | data2 = DATA2() 36 | a = A() 37 | a.fun(data1) # DATA1 38 | a.fun(data2) # DATA2 39 | a.fun(None) # Nothing. -------------------------------------------------------------------------------- /what_is_the_singledispatchmethod/demo4.py: -------------------------------------------------------------------------------- 1 | from functools import singledispatchmethod 2 | 3 | class DATA1: 4 | def show(self): 5 | print("DATA1") 6 | 7 | class DATA2: 8 | def show(self): 9 | print("DATA2") 10 | 11 | class A: 12 | 13 | @singledispatchmethod 14 | def fun(self, arg): 15 | raise NotImplementedError() 16 | 17 | 18 | @fun.register 19 | def _(self, arg: DATA1): 20 | arg.show() 21 | 22 | 23 | @fun.register 24 | def _(self, arg: DATA2): 25 | arg.show() 26 | 27 | 28 | @fun.register 29 | def nothing(self, _: None): 30 | print("Nothing.") 31 | 32 | if __name__ == '__main__': 33 | data1 = DATA1() 34 | data2 = DATA2() 35 | a = A() 36 | a.fun(data1) # DATA1 37 | a.fun(data2) # DATA2 38 | a.fun(None) # Nothing. 39 | -------------------------------------------------------------------------------- /with_as_tutorial.py: -------------------------------------------------------------------------------- 1 | 2 | class Demo_1: 3 | 4 | def __enter__(self): 5 | print('__enter__') 6 | return 'hello enter' 7 | 8 | def __exit__(self, exc_type, exc_value, traceback): 9 | print('__exit__') 10 | if exc_type is ZeroDivisionError: 11 | print('Please DO NOT divide by zero!') 12 | return None 13 | 14 | class Demo_2: 15 | 16 | def __enter__(self): 17 | print('__enter__') 18 | return 'hello enter' 19 | 20 | def __exit__(self, exc_type, exc_value, traceback): 21 | print('__exit__') 22 | if exc_type is ZeroDivisionError: 23 | print('Please DO NOT divide by zero!') 24 | return True 25 | 26 | def example_1(): 27 | with Demo_1() as data: 28 | print('data:', data) 29 | 1/0 30 | print('example_1') 31 | 32 | def example_better(): 33 | with Demo_2() as data: 34 | print('data:', data) 35 | 1/0 36 | print('example_1') 37 | 38 | if __name__ == '__main__': 39 | # example_1() 40 | example_better() -------------------------------------------------------------------------------- /yield_from_tutorial.py: -------------------------------------------------------------------------------- 1 | # Using yield from allows us to avoid having to deal with unexpected exceptions, 2 | # let us focus on the implementation of business code. 3 | 4 | 5 | def demo(n): 6 | i = 0 7 | while i < n: 8 | yield i 9 | i += 1 10 | 11 | 12 | def test_yield_from(n): 13 | print("test_yield_from start") 14 | yield from demo(n) 15 | # 相當於下面 16 | # for item in demo(n): 17 | # yield item 18 | print("test_yield_from end") 19 | 20 | 21 | def example_1(): 22 | for i in test_yield_from(3): 23 | print(i) 24 | 25 | 26 | def return_yield(): 27 | yield from ( 28 | i 29 | for i in range(5) 30 | ) 31 | 32 | 33 | def example_2(): 34 | result = return_yield() 35 | print(next(result)) 36 | print(next(result)) 37 | 38 | 39 | def chain_old(*iterables): 40 | for it in iterables: 41 | for i in it: 42 | yield i 43 | 44 | 45 | def chain(*iterables): 46 | for it in iterables: 47 | yield from it 48 | 49 | 50 | def example_3(): 51 | s = 'ABC' 52 | t = tuple(range(3)) 53 | show = list(chain(s, t)) 54 | print(show) 55 | 56 | 57 | if __name__ == "__main__": 58 | example_1() 59 | example_2() 60 | example_3() 61 | -------------------------------------------------------------------------------- /zip_tutorial.py: -------------------------------------------------------------------------------- 1 | # The zip() function take iterables (can be zero or more), 2 | # makes iterator that aggregates elements based on the iterables passed, and returns an iterator of tuples. 3 | 4 | # zip(*iterables) 5 | 6 | if __name__ == "__main__": 7 | # tutorial 1 8 | numbers = [1, 2, 3] 9 | letters = ["A", "B", "C"] 10 | numbers_3 = ["a", "b", "c"] 11 | 12 | for numbers_value, letters_value in zip(numbers, letters): 13 | print(numbers_value, letters_value) 14 | 15 | for numbers_value, letters_value, v3 in zip(numbers, letters, numbers_3): 16 | print(numbers_value, letters_value, v3) 17 | 18 | # tutorial 2 19 | numberList = [1, 2, 3] 20 | strList = ['one', 'two', 'three'] 21 | result = zip(numberList, strList) 22 | resultSet = set(result) 23 | print(resultSet) 24 | 25 | # Unzipping the Value Using zip() 26 | numberList_org, strList_org = zip(*resultSet) 27 | print('numberList_org =', numberList_org) 28 | print('strList_org =', strList_org) 29 | -------------------------------------------------------------------------------- /zipfile_tutorial.py: -------------------------------------------------------------------------------- 1 | # ref. https://docs.python.org/3/library/zipfile.html 2 | import zipfile 3 | 4 | if __name__ == "__main__": 5 | with zipfile.ZipFile('spam.zip', 'w') as myzip: 6 | myzip.write('test.txt') 7 | --------------------------------------------------------------------------------