├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── .replit ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.de.md ├── README.es.md ├── README.hi.md ├── README.ko.md ├── README.md ├── README.zh_tw.md ├── codecov.yml ├── images └── ultimatepython.webp ├── pyproject.toml ├── requirements.txt ├── runner.py └── ultimatepython ├── __init__.py ├── advanced ├── __init__.py ├── async.py ├── benchmark.py ├── context_manager.py ├── data_format.py ├── date_time.py ├── decorator.py ├── file_handling.py ├── meta_class.py ├── mixin.py ├── mocking.py ├── mro.py ├── regex.py ├── thread.py └── weak_ref.py ├── classes ├── __init__.py ├── abstract_class.py ├── basic_class.py ├── encapsulation.py ├── exception_class.py ├── inheritance.py └── iterator_class.py ├── data_structures ├── __init__.py ├── comprehension.py ├── defaultdict.py ├── deque.py ├── dict.py ├── heap.py ├── list.py ├── namedtuple.py ├── set.py ├── string.py └── tuple.py └── syntax ├── __init__.py ├── bitwise.py ├── conditional.py ├── expression.py ├── function.py ├── loop.py └── variable.py /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | 9 | [*.{py,toml}] 10 | indent_size = 4 11 | indent_style = space 12 | 13 | [*.{xml,yaml,yml}] 14 | indent_size = 2 15 | indent_style = space 16 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: huangsam 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Please read the [contributing guidelines](https://github.com/huangsam/ultimate-python/blob/main/CONTRIBUTING.md) before submitting a pull request.* 2 | 3 | --- 4 | 5 | **Describe the change** 6 | A clear and concise description of what the change is. 7 | 8 | **Additional context** 9 | Add any other context or screenshots about the pull request here. 10 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | python-build: 14 | name: Python 3.13 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v4 20 | - name: Set up Python 3.13 21 | uses: actions/setup-python@v5 22 | with: 23 | python-version: '3.13' 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install -r requirements.txt 28 | - name: Lint with ruff 29 | run: | 30 | ruff check 31 | - name: Run tests and report with coverage 32 | run: | 33 | coverage run runner.py 34 | coverage report 35 | - name: Generate coverage.xml artifact 36 | run: | 37 | coverage xml -o ./coverage.xml 38 | - name: Upload coverage data to Codecov 39 | uses: codecov/codecov-action@v4 40 | with: 41 | files: ./coverage.xml 42 | token: ${{ secrets.CODECOV_TOKEN }} 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # System 2 | .DS_Store 3 | 4 | # IDE 5 | .idea/ 6 | .vscode/ 7 | 8 | # Python 9 | *.pyc 10 | .coverage 11 | coverage.json 12 | coverage.xml 13 | *.egg-info/ 14 | .ruff_cache/ 15 | __pycache__/ 16 | build/ 17 | htmlcov/ 18 | venv/ 19 | -------------------------------------------------------------------------------- /.replit: -------------------------------------------------------------------------------- 1 | language = "python3" 2 | run = "python runner.py" 3 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at samhuang91@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 🚀 Welcome to the Ultimate Python Study Guide! 📚 2 | 3 | 🎉 Thank you for considering contributing to this awesome project! 🎉 4 | 5 | But first, before you jump in, let's vibe with our [Code of Conduct](CODE_OF_CONDUCT.md). We want this space to be 🌈 inclusive, respectful, and nothing but fun! 6 | 7 | ## 🐍 What's This All About? 8 | 9 | Our Python Study Guide is your ticket to Python mastery! 🐍 This place is all about energy, excitement, and pure Python magic. 💫 10 | 11 | ## 📖 Let's Talk Documentation 12 | 13 | Our README is like the opening act at a concert. It's where the party starts, and we want it to be sensational! Here are the keys to this performance: 14 | 15 | - Translations? 🌍 Yes, they're right at the top for everyone to enjoy! 16 | - Python modules? 🤓 Oh, they've got a VIP seat in our Table of Contents (ToC). 17 | - External links? 🔗 They're all about HTTPS and that sweet `2xx` status. 18 | - Python documentation? For both newbies and wizards, it's all in here! 19 | - GitHub repositories? 🌟 We love stars! If it's got at least 1k stars, bring it on! 20 | - Practice resources? 🏋️‍♂️ We've got Python exercises to keep you in shape. 21 | 22 | ## 📚 Get into Python Modules 23 | 24 | Our Python modules are like mini-python-parties that you can host anywhere! They're packed with energy and make learning a blast! 🎉 25 | 26 | ### 🧩 The Setup 27 | 28 | Each Python module follows a rock-solid structure: 29 | 30 | ```python 31 | # The main event 🎉 32 | def main(): 33 | # Here's where the magic happens! 34 | assert 1 + 1 == 2 35 | assert True is not False 36 | 37 | # The show must go on 38 | if __name__ == "__main__": 39 | main() 40 | ``` 41 | 42 | If there's more Python goodness, it's up front before the main event! 43 | 44 | ### ✨ Style and Shine 45 | 46 | We've got style, oh baby! Check out the PEPs: 47 | 48 | - [PEP 8](https://www.python.org/dev/peps/pep-0008) - Our fashion bible! 49 | - [PEP 257](https://www.python.org/dev/peps/pep-0257) - Docstring Glamour! 50 | 51 | But there's more! We have our own style: 52 | 53 | - Imports are perfectly sorted with [isort](https://github.com/timothycrosley/isort). 54 | - Constants? They follow the `_UNDER_SCORE_FIRST` party rule. 55 | - Strings love double-quotes, but if there's a `"`, they'll use single quotes! 56 | - For dynamic strings, it's all about those fabulous f-strings! 🎤 57 | 58 | ### 📈 Code Coverage Stars 59 | 60 | We like to keep the energy high, and that means every module should have a whopping 80-100% code coverage! Our modules are like dance floors, and we don't want any empty spaces. That's because each module is a standalone lesson, and the `main` function is where the magic happens. 61 | 62 | ## 🌟 Your Contribution 63 | 64 | Your contributions are like the encore at a concert - they're a big deal! We appreciate your dedication to making this project even more amazing. Don't hesitate to reach out if you have any questions. Your contributions, no matter how small, are making a big difference in the Python learning world! 65 | 66 | So, get ready to rock and roll, Python style! 🤘🐍💥 67 | 68 | # 💥 Dive into the Python World 69 | 70 | Python is a versatile language used in web development, data analysis, artificial intelligence, and more. As a contributor, you're joining a vibrant community of learners and mentors. 71 | 72 | # 🧑‍💻 Learning Together 73 | 74 | Our project isn't just a repository; it's a collaborative learning experience. You can learn from the contributions of others and share your Python wisdom with the world. Together, we can unlock the true potential of this fantastic language. 75 | 76 | # 🚀 Opportunities Galore 77 | 78 | When you contribute to this project, you're not just improving it; you're also enhancing your own skills. You might discover new Python tricks, learn more about best practices, and even find inspiration for your own projects. 79 | 80 | # 🌍 Global Impact 81 | 82 | Python is a worldwide phenomenon, and your contributions will impact Python enthusiasts globally. Your work can help someone on the other side of the planet learn Python, kickstart their career, or solve a problem they've been struggling with. 83 | 84 | # 🙋‍♀️ Join a Supportive Community 85 | 86 | Our community is welcoming and supportive. If you have questions or need guidance, don't hesitate to ask. We're all here to help each other and grow together. 87 | 88 | # 📢 Your Voice Matters 89 | 90 | Your unique perspective is valuable. If you have ideas to make this guide even more engaging or fun, share them with us! We're open to creative and innovative suggestions. 91 | 92 | # 🤖 Evolving with Python 93 | 94 | Python is constantly evolving, and so is our guide. You can help keep it up-to-date, ensuring that learners always have access to the latest Python features and best practices. 95 | 96 | # 🎉 Your Contribution Matters 97 | 98 | Your contributions, whether they are big or small, are the building blocks of our project's success. Together, we're creating a resource that makes Python more accessible and exciting. 99 | 100 | # 🌟 Be a Python Star 101 | 102 | By contributing to this project, you're becoming a Python star, and you're helping others shine brightly too. Let's light up the Python world together! 103 | 104 | ## How to Contribute 105 | 106 | Ready to dive in? Here's how you can contribute: 107 | 108 | 1. **Fork the Repository**: Head to [https://github.com/huangsam/ultimate-python/](https://github.com/huangsam/ultimate-python/) and click the "Fork" button in the top right corner. 109 | 110 | 2. **Clone Your Fork**: After forking, you'll have your copy of the repository. Clone it to your local machine. 111 | 112 | 3. **Make Your Contributions**: Create or update Python modules, documentation, or anything that adds value to the project. 113 | 114 | 4. **Push Your Changes**: Once your work is ready, push your changes to your forked repository. 115 | 116 | 5. **Create a Pull Request**: Head back to the original repository (https://github.com/huangsam/ultimate-python/) and create a pull request. Describe your changes and let us know why they're awesome. 117 | 118 | We're excited to see what you bring to the table! Your contributions are making the Python world a better place. 119 | 120 | Please don't hesitate to reach out if you have any questions. Your contributions, no matter how small, are making a big difference! 🌟🐍💥 121 | 122 | ## Feel the Pythonic Energy - Contribute Now!🔥 123 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Samuel Huang 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 | -------------------------------------------------------------------------------- /README.de.md: -------------------------------------------------------------------------------- 1 | # Ultimativer Python-Lernführer 2 | 3 | [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) 4 | [![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) 5 | [![Quality Gate Status](https://img.shields.io/sonar/quality_gate/huangsam_ultimate-python?server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/dashboard?id=huangsam_ultimate-python) 6 | [![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) 7 | [![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) 8 | 9 | Der ultimative Python-Lernführer für Einsteiger und Profis gleichermaßen. 🐍 🐍 🐍 10 | 11 | ```python 12 | print("Ultimativer Python-Lernführer") 13 | ``` 14 | 15 | [English](README.md) | 16 | [한국어](README.ko.md) | 17 | [繁体中文](README.zh_tw.md) | 18 | [Español](README.es.md) | 19 | [Deutsch](README.de.md) | 20 | [हिन्दी](README.hi.md) 21 | 22 | Ultimate Python 23 | 24 | ## Motivation 25 | 26 | Ich habe dieses GitHub-Repository erstellt, um meine Erkenntnisse über [core Python](https://www.python.org/) 27 | in den letzten 5 Jahren als Hochschulabsolvent, Angestellter in 28 | großen Unternehmen und als Open-Source-Mitarbeiter von Repositories wie 29 | [Celery](https://github.com/celery/celery) und 30 | [Full Stack Python](https://github.com/mattmakai/fullstackpython.com) weiterzugeben. 31 | Ich freue mich darauf, dass noch mehr Menschen Python lernen und damit ihren Leidenschaften nachgehen. 🎓 32 | 33 | ## Ziele 34 | 35 | Dies sind die Hauptziele bei der Erstellung dieses Leitfadens: 36 | 37 | 🏆 **Als Ressource fungieren** für Python-Neulinge, die es vorziehen, praktisch zu lernen. 38 | Dieses Repository enthält eine Sammlung von eigenständigen Modulen, die in einer IDE 39 | wie [PyCharm](https://www.jetbrains.com/pycharm/) und im Browser wie 40 | [Replit](https://replit.com/languages/python3). Wleches wie ein einfaches Terminal 41 | mit den Beispielen funktioniert. Die meisten Zeilen haben sorgfältig ausgearbeitete Kommentare, die den Leser 42 | Schritt für Schritt durch das Programm führen. Die Benutzer werden ermutigt, den 43 | Quellcode überall zu ändern, solange die "Haupt"-Routinen nicht gelöscht werden und 44 | [run successfully](runner.py) nach jeder Änderung. 45 | 46 | 🏆 **Als reiner Leitfaden dienen** für diejenigen, die die wichtigsten Python-Konzepte wiederholen möchten. 47 | Wo nur [builtin libraries](https://docs.python.org/3/library/) genutzt werden, so dass 48 | diese Konzepte ohne den Overhead der bereichsspezifischen Konzepte vermittelt werden können. Als 49 | beliebte Open-Source-Bibliotheken und -Frameworks (d.h. `sqlalchemy`, `requests`, 50 | `pandas`) nicht installiert sind. Das Lesen des Quellcodes dieser Frameworks ist jedoch 51 | inspirierend und wird dringend empfohlen, wenn Sie ein echter Profi werden wollen. 52 | [Pythonista](https://www.urbandictionary.com/define.php?term=pythonista). 53 | 54 | ## Erste Schritte 55 | 56 | [![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) 57 | 58 | Klicken Sie auf das obige Abzeichen, um eine Arbeitsumgebung im Browser zu starten, ohne 59 | ohne dass Sie Git und Python auf Ihrem lokalen Rechner installiert haben müssen. Wenn diese Voraussetzungen 60 | bereits erfüllt sind, können Sie das Repository direkt klonen. 61 | 62 | Sobald das Repository zugänglich ist, können Sie mit den eigenständigen 63 | Modulen lernen. Um den größtmöglichen Nutzen aus jedem Modul zu ziehen, lesen Sie den Modulcode und führen Sie ihn aus. 64 | Es gibt zwei Möglichkeiten, die Module auszuführen: 65 | 66 | 1. Führen Sie ein einzelnes Modul aus: `python ultimatepython/syntax/variable.py` 67 | 2. Führen Sie alle Module aus: `python runner.py` 68 | 69 | ## Inhaltsübersicht 70 | 71 | 📚 = Externe Ressource, 72 | 🍰 = Thema für Anfänger, 73 | 🤯 = Fortgeschrittenes Thema 74 | 75 | 1. **Über Python** 76 | - Overview: [What is Python](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) 77 | - Design philosophy: [The Zen of Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) 78 | - Style guide: [Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) 79 | - Data model: [Data model](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) 80 | - Standard library: [The Python Standard Library](https://docs.python.org/3/library/) ( 📚, 🤯 ) 81 | - Built-in functions: [Built-in Functions](https://docs.python.org/3/library/functions.html) ( 📚 ) 82 | 2. **Syntax** 83 | - Variable: [Built-in literals](ultimatepython/syntax/variable.py) ( 🍰 ) 84 | - Expression: [Numeric operations](ultimatepython/syntax/expression.py) ( 🍰 ) 85 | - Bitwise: [Bitwise operators](ultimatepython/syntax/bitwise.py) ( 🍰 ), [One's/Two's Complement](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) 86 | - Conditional: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) 87 | - Loop: [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) 88 | - Function: [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) 89 | 3. **Daten-Strukturen** 90 | - List: [List operations](ultimatepython/data_structures/list.py) ( 🍰 ) 91 | - Tuple: [Tuple operations](ultimatepython/data_structures/tuple.py) 92 | - Set: [Set operations](ultimatepython/data_structures/set.py) 93 | - Dict: [Dictionary operations](ultimatepython/data_structures/dict.py) ( 🍰 ) 94 | - Comprehension: [list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) 95 | - String: [String operations](ultimatepython/data_structures/string.py) ( 🍰 ) 96 | - Deque: [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) 97 | - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) 98 | - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) 99 | - Time complexity: [cPython operations](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) 100 | 4. **Klassen** 101 | - Basic class: [Basic definition](ultimatepython/classes/basic_class.py) ( 🍰 ) 102 | - Inheritance: [Inheritance](ultimatepython/classes/inheritance.py) ( 🍰 ) 103 | - Abstract class: [Abstract definition](ultimatepython/classes/abstract_class.py) 104 | - Exception class: [Exception definition](ultimatepython/classes/exception_class.py) 105 | - Iterator class: [Iterator definition | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) 106 | - Encapsulation: [Encapsulation definition](ultimatepython/classes/encapsulation.py) 107 | 5. **Fortgeschrittene** 108 | - Decorator: [Decorator definition | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) 109 | - File Handling: [File Handling](ultimatepython/advanced/file_handling.py) ( 🤯 ) 110 | - Context manager: [Context managers](ultimatepython/advanced/context_manager.py) ( 🤯 ) 111 | - Method resolution order: [mro](ultimatepython/advanced/mro.py) ( 🤯 ) 112 | - Mixin: [Mixin definition](ultimatepython/advanced/mixin.py) ( 🤯 ) 113 | - Metaclass: [Metaclass definition](ultimatepython/advanced/meta_class.py) ( 🤯 ) 114 | - Thread: [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) 115 | - Asyncio: [async | await](ultimatepython/advanced/async.py) ( 🤯 ) 116 | - Weak reference: [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) 117 | - Benchmark: [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) 118 | - Mocking: [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) 119 | - Regular expression: [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) 120 | - Data format: [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) 121 | - Datetime: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) 122 | 123 | ## Zusätzliche Ressourcen 124 | 125 | 👔 = Interview-Ressource, 126 | 🧪 = Code-Beispiele, 127 | 🧠 = Projektideen 128 | 129 | ### GitHub repositories 130 | 131 | Lernen Sie weiter, indem Sie von anderen Quellen lesen. 132 | 133 | - [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔, 🧪 ) 134 | - [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔, 🧪 ) 135 | - [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) 136 | - [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) 137 | - [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) 138 | - [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) 139 | - [vinta/awesome-python](https://github.com/vinta/awesome-python) 140 | - [academic/awesome-datascience](https://github.com/academic/awesome-datascience) 141 | - [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) 142 | - [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) 143 | - [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) 144 | - [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) 145 | - [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) 146 | - [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) 147 | 148 | ### Interaktive Übungen 149 | 150 | Üben Sie weiter, damit Ihre Programmierkenntnisse nicht einrosten. 151 | 152 | - [codechef.com](https://www.codechef.com/) ( 👔 ) 153 | - [codeforces.com](https://codeforces.com/) 154 | - [codementor.io](https://www.codementor.io) ( 🧠 ) 155 | - [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) 156 | - [codewars.com](https://www.codewars.com/) 157 | - [exercism.io](https://exercism.io/) 158 | - [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) 159 | - [hackerearth.com](https://www.hackerearth.com/) 160 | - [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) 161 | - [kaggle.com](https://www.kaggle.com/) ( 🧠 ) 162 | - [leetcode.com](https://leetcode.com/) ( 👔 ) 163 | - [projecteuler.net](https://projecteuler.net/) 164 | - [replit.com](https://replit.com/) 165 | - [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) 166 | -------------------------------------------------------------------------------- /README.es.md: -------------------------------------------------------------------------------- 1 | # Guía de estudio "Python Definitivo" 2 | 3 | [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) 4 | [![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) 5 | [![Quality Gate Status](https://img.shields.io/sonar/quality_gate/huangsam_ultimate-python?server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/dashboard?id=huangsam_ultimate-python) 6 | [![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) 7 | [![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) 8 | 9 | Guía de estudio "Python Definitivo" para principiantes y profesionales. 🐍 🐍 🐍 10 | 11 | ```python 12 | print("Guía de estudio 'Python Definitivo'") 13 | ``` 14 | 15 | [English](README.md) | 16 | [한국어](README.ko.md) | 17 | [繁体中文](README.zh_tw.md) | 18 | [Español](README.es.md) | 19 | [Deutsch](README.de.md) | 20 | [हिन्दी](README.hi.md) 21 | 22 | Ultimate Python 23 | 24 | ## Motivación 25 | 26 | Creé este repositorio de GitHub para compartir lo que he aprendido sobre [Python](https://www.python.org/) 27 | durante más de 5 años usándolo como graduado de universidad, empleado en grandes empresas y como contribuidor 28 | de código abierto en repositorios como [Celery](https://github.com/celery/celery) y 29 | [Full Stack Python](https://github.com/mattmakai/fullstackpython.com). 30 | Espero ver a más personas aprendiendo Python y persiguiendo su pasión a través de él. 🎓 31 | 32 | ## Objetivos 33 | 34 | Estos son los objetivos principales de esta guía: 35 | 36 | 🏆 **Servir como un recurso** para principiantes de Python que prefieren aprender por su cuenta. 37 | Este repositorio enumera una colección de módulos independientes que pueden ser ejecutados en 38 | un IDE como [PyCharm](https://www.jetbrains.com/pycharm/) e incluso en el navegador, como 39 | [Repl.it](https://repl.it/languages/python3). Incluso una terminal antigua funcionará igual de bien 40 | con los ejemplos. La mayoría de las líneas de código tienen comentarios útiles que ayudan a guiar 41 | al lector para entender paso a paso el proceso que el programa está ejecutando. Se anima a los usuarios 42 | a que modifiquen el código fuente en cualquier parte siempre y cuando las rutinas principales (`main`) 43 | se eliminen y se [ejecuten con éxito](runner.py) tras cada cambio. 44 | 45 | 🏆 **Servir como una guía pura** para aquellos que quieren reforzar los conceptos base de 46 | Python. Se utilizan sólo las [librerías integradas](https://docs.python.org/3/library/) para que 47 | estos conceptos puedan adquirirse sin el esfuerzo de aprender conocimientos de dominios específicos. 48 | Por ello no se han instalado librerías y entornos de código abierto populares (como `sqlalchemy`, 49 | `requests`, `pandas`). No obstante, leer el código fuente de estos frameworks es inspirador y altamente 50 | recomendado si tu objetivo es convertirte en un verdadero 51 | [Pythonista](https://www.urbandictionary.com/define.php?term=pythonista). 52 | 53 | ## Empezando 54 | 55 | [![Run on Repl.it](https://repl.it/badge/github/huangsam/ultimate-python)](https://repl.it/github/huangsam/ultimate-python) 56 | 57 | Haz clic en la imagen de arriba para crear un ambiente de trabajo en el navegador sin necesidad 58 | de tener Git y Python instalados en tu ordenador local. Si estos requisitos ya se cumplen, 59 | puedes clonar el repositorio directamente. 60 | 61 | Una vez que el repositorio sea accesible, estás listo para aprender de los módulos independientes. 62 | Para aprender el máximo de cada módulo, lee el código del módulo y ejecútalo. 63 | Hay dos maneras de ejecutar los módulos: 64 | 65 | 1. Ejecuta un solo módulo: `python ultimatepython/syntax/variable.py` 66 | 2. Ejecuta todos los módulos: `python runner.py` 67 | 68 | ## Contenido 69 | 70 | 📚 = Recurso externo, 71 | 🍰 = Tema principiante, 72 | 🤯 = Tema avanzado 73 | 74 | 1. **Sobre Python** 75 | - Resumen: [¿Qué es Python?](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) 76 | - Filosofía de diseño: [El Zen de Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) 77 | - Guía de estilos: [Guía de estilos para código de Python](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) 78 | - Modelo de datos: [Modelo de datos](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) 79 | - Librería estándar: [La librería estándar de Python](https://docs.python.org/3/library/) ( 📚, 🤯 ) 80 | - Funciones integradas: [Funciones integradas](https://docs.python.org/3/library/functions.html) ( 📚 ) 81 | 2. **Sintaxis** 82 | - Variables: [Literales integrados](ultimatepython/syntax/variable.py) ( 🍰 ) 83 | - Expresiones: [Operaciones numéricas](ultimatepython/syntax/expression.py) ( 🍰 ) 84 | - Bit a bit: [Operadores bit a bit](ultimatepython/syntax/bitwise.py) ( 🍰 ), [Complemento a uno/dos](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) 85 | - Condicionales: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) 86 | - Iteraciones: [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) 87 | - Funciones: [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) 88 | 3. **Estructura de datos** 89 | - Lista: [Operaciones con listas](ultimatepython/data_structures/list.py) ( 🍰 ) 90 | - Tupla: [Operaciones con tuplas](ultimatepython/data_structures/tuple.py) 91 | - Set: [Operaciones con sets](ultimatepython/data_structures/set.py) 92 | - Diccionario: [Operaciones con dicts](ultimatepython/data_structures/dict.py) ( 🍰 ) 93 | - Comprensión: [list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) 94 | - Cadena: [Operaciones con strings](ultimatepython/data_structures/string.py) ( 🍰 ) 95 | - Deque: [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) 96 | - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) 97 | - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) 98 | - Complejidad de tiempo: [Operaciones de cPython](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) 99 | 4. **Clases** 100 | - Clase básica: [Definición de básica](ultimatepython/classes/basic_class.py) ( 🍰 ) 101 | - Herencia: [Herencia](ultimatepython/classes/inheritance.py) ( 🍰 ) 102 | - Clase abstracta: [Definición de abstracta](ultimatepython/classes/abstract_class.py) 103 | - Clase de excepción: [Definición de excepción](ultimatepython/classes/exception_class.py) 104 | - Clase iteradora: [Definición de iteradora | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) 105 | - Encapsulación: [Definición de encapsulación](ultimatepython/classes/encapsulation.py) 106 | 5. **Avanzado** 107 | - Decorador: [Definición de decorador | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) 108 | - Manejo de archivos: [Manejo de archivos](ultimatepython/advanced/file_handling.py) ( 🤯 ) 109 | - Gestor de contexto: [Gestores de contexto](ultimatepython/advanced/context_manager.py) ( 🤯 ) 110 | - Orden de resolución de método (MRO por sus siglas en inglés): [mro](ultimatepython/advanced/mro.py) ( 🤯 ) 111 | - Mixin: [Definición de Mixin](ultimatepython/advanced/mixin.py) ( 🤯 ) 112 | - Metaclase: [Definición de metaclase](ultimatepython/advanced/meta_class.py) ( 🤯 ) 113 | - Hilos: [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) 114 | - Asyncio: [async | await](ultimatepython/advanced/async.py) ( 🤯 ) 115 | - Referencias débiles: [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) 116 | - Referencia: [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) 117 | - Mocking: [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) 118 | - Expresiones regulares: [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) 119 | - Formatos de datos: [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) 120 | - Fecha y hora: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) 121 | 122 | ## Recursos adicionales 123 | 124 | 👔 = Recurso de entrevista, 125 | 🧪 = Ejemplos de código, 126 | 🧠 = Ideas para proyecto 127 | 128 | ### Repositorios de GitHub 129 | 130 | Sigue aprendiendo leyendo otros buenos recursos. 131 | 132 | - [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔, 🧪 ) 133 | - [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔, 🧪 ) 134 | - [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) 135 | - [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) 136 | - [karan/Projects](https://github.com/karan/Projects) (🧠 ) 137 | - [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) 138 | - [vinta/awesome-python](https://github.com/vinta/awesome-python) 139 | - [academic/awesome-datascience](https://github.com/academic/awesome-datascience) 140 | - [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) 141 | - [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) 142 | - [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) 143 | - [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) 144 | - [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) 145 | - [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) 146 | 147 | ### Práctica interactiva 148 | 149 | Continua practicando para que no se oxiden tus habilidades de programación. 150 | 151 | - [codechef.com](https://www.codechef.com/) ( 👔 ) 152 | - [codeforces.com](https://codeforces.com/) 153 | - [codementor.io](https://www.codementor.io) ( 🧠 ) 154 | - [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) 155 | - [codewars.com](https://www.codewars.com/) 156 | - [exercism.io](https://exercism.io/) 157 | - [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) 158 | - [hackerearth.com](https://www.hackerearth.com/) 159 | - [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) 160 | - [kaggle.com](https://www.kaggle.com/) ( 🧠 ) 161 | - [leetcode.com](https://leetcode.com/) ( 👔 ) 162 | - [projecteuler.net](https://projecteuler.net/) 163 | - [replit.com](https://replit.com/) 164 | - [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) 165 | -------------------------------------------------------------------------------- /README.hi.md: -------------------------------------------------------------------------------- 1 | # अल्टीमेट Python अध्ययन गाइड 2 | 3 | [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) 4 | [![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) 5 | [![Quality Gate Status](https://img.shields.io/sonar/quality_gate/huangsam_ultimate-python?server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/dashboard?id=huangsam_ultimate-python) 6 | [![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) 7 | [![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) 8 | 9 | नए और पेशेवर लोगों के लिए अल्टीमेट पायथन अध्ययन गाइड। 🐍 🐍 🐍 10 | 11 | ```python 12 | print("Ultimate Python study guide") 13 | ``` 14 | 15 | [English](README.md) | 16 | [한국어](README.ko.md) | 17 | [繁体中文](README.zh_tw.md) | 18 | [Español](README.es.md) | 19 | [Deutsch](README.de.md) | 20 | [हिन्दी](README.hi.md) 21 | 22 | Ultimate Python 23 | 24 | ## प्रेरणा 25 | 26 | मैंने यह गिटहब रिपोजिटरी [core Python](https://www.python.org/) के बारे में जो कुछ मैंने पिछले 5+ वर्षों में सीखा है, उसे साझा करने के लिए बनाई है। मैंने इसे एक कॉलेज ग्रेजुएट, बड़ी कंपनियों के कर्मचारी, और [Celery](https://github.com/celery/celery) और [Full Stack Python](https://github.com/mattmakai/fullstackpython.com) जैसी रिपोजिटरी के ओपन-सोर्स कंट्रीब्यूटर के रूप में उपयोग किया है। मैं यह देखने के लिए उत्सुक हूँ कि और लोग पायथन सीखें और इसके माध्यम से अपने जुनून को आगे बढ़ाएं। 🎓 27 | 28 | 29 | ## लक्ष्य 30 | 31 | इस गाइड को बनाने के मुख्य लक्ष्य निम्नलिखित हैं: 32 | 33 | 🏆 **संसाधन के रूप में सेवा देना** उन नए पायथन उपयोगकर्ताओं के लिए जो प्रैक्टिकल तरीके से सीखना पसंद करते हैं। इस रिपोजिटरी में स्वतंत्र मॉड्यूलों का एक संग्रह है, जिन्हें IDE जैसे [PyCharm](https://www.jetbrains.com/pycharm/) में या [Replit](https://replit.com/languages/python3) जैसे ब्राउज़र में चलाया जा सकता है। पुराने साधारण टर्मिनल में भी इन उदाहरणों को चलाया जा सकता है। अधिकतर लाइनों में बहुत ही अच्छे से लिखे गए comments होते हैं, जो पाठक को प्रोग्राम्स के प्रत्येक चरण के माध्यम से मार्गदर्शन करते हैं। उपयोगकर्ताओं को कोड में बदलाव करने के लिए प्रोत्साहित किया जाता है, बशर्ते कि `main` रूटीन को हटाया न जाए और हर परिवर्तन के बाद [सफलतापूर्वक चलाया जाए](runner.py)। 34 | 35 | 🏆 **शुद्ध गाइड के रूप में सेवा देना** उन लोगों के लिए जो मुख्य पायथन अवधारणाओं को फिर से समझना चाहते हैं। केवल [बिल्ट-इन लाइब्रेरीज़](https://docs.python.org/3/library/) का उपयोग किया गया है ताकि इन अवधारणाओं को बिना किसी विशेष डोमेन की अवधारणाओं के सरलता से समझाया जा सके। इसी कारण से लोकप्रिय ओपन-सोर्स लाइब्रेरीज़ और फ्रेमवर्क (जैसे `sqlalchemy`, `requests`, `pandas`) को इंस्टॉल नहीं किया गया है। हालांकि, इन फ्रेमवर्क्स के स्रोत कोड को पढ़ना प्रेरणादायक है और यदि आपका लक्ष्य एक सच्चे [Pythonista](https://www.urbandictionary.com/define.php?term=pythonista) बनने का है तो इसे ज़रूर पढ़ना चाहिए। 36 | 37 | 38 | ## शुरूआत 39 | 40 | [![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) 41 | 42 | ऊपर दिए गए बैज पर क्लिक करें ताकि आप ब्राउज़र में एक कार्यशील वातावरण शुरू कर सकें, इसके लिए आपके स्थानीय मशीन पर Git और पायथन की आवश्यकता नहीं होगी। यदि ये आवश्यकताएँ पहले से ही पूरी हो चुकी हैं, तो आप सीधे रिपोजिटरी को क्लोन कर सकते हैं। 43 | 44 | एक बार जब रिपोजिटरी उपलब्ध हो जाती है, तो आप स्वतंत्र मॉड्यूल से सीखने के लिए तैयार हैं। प्रत्येक मॉड्यूल का अधिकतम लाभ उठाने के लिए, मॉड्यूल का कोड पढ़ें और इसे चलाएं। मॉड्यूल चलाने के दो तरीके हैं: 45 | 46 | 1. एकल मॉड्यूल चलाएं: `python ultimatepython/syntax/variable.py` 47 | 2. सभी मॉड्यूल चलाएं: `python runner.py` 48 | 49 | ## विषय सूची 50 | 51 | 📚 = बाहरी स्रोत, 52 | 🍰 = शुरुआती विषय, 53 | 🤯 = उन्नत विषय 54 | 55 | 56 | 1. **पायथन के बारे में** 57 | - अवलोकन: [पायथन क्या है](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) 58 | - डिज़ाइन दर्शन: [पायथन का ज़ेन](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) 59 | - शैली मार्गदर्शिका: [पायथन कोड के लिए शैली मार्गदर्शिका](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) 60 | - डेटा मॉडल: [डेटा मॉडल](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) 61 | - मानक पुस्तकालय: [पायथन मानक पुस्तकालय](https://docs.python.org/3/library/) ( 📚, 🤯 ) 62 | - अंतर्निहित कार्य: [अंतर्निहित कार्य](https://docs.python.org/3/library/functions.html) ( 📚 ) 63 | 2. **सिंटेक्स** 64 | - वेरिएबल: [अंतर्निहित लिटरल](ultimatepython/syntax/variable.py) ( 🍰 ) 65 | - अभिव्यक्ति: [संख्यात्मक ऑपरेशन्स](ultimatepython/syntax/expression.py) ( 🍰 ) 66 | - बाइनरी: [बाइनरी ऑपरेटर](ultimatepython/syntax/bitwise.py) ( 🍰 ), [एक्स/टू का पूरक](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) 67 | - कंडीशनल: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) 68 | - लूप: [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) 69 | - फ़ंक्शन: [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) 70 | 3. **डेटा संरचनाएँ** 71 | - लिसट: [लिसट ऑपरेशन्स](ultimatepython/data_structures/list.py) ( 🍰 ) 72 | - ट्यूपल: [ट्यूपल ऑपरेशन्स](ultimatepython/data_structures/tuple.py) 73 | - सेट: [सेट ऑपरेशन्स](ultimatepython/data_structures/set.py) 74 | - डिक्ट: [डिक्शनरी ऑपरेशन्स](ultimatepython/data_structures/dict.py) ( 🍰 ) 75 | - संकलन: [लिसट | ट्यूपल | सेट | डिक्ट](ultimatepython/data_structures/comprehension.py) 76 | - स्ट्रिंग: [स्ट्रिंग ऑपरेशन्स](ultimatepython/data_structures/string.py) ( 🍰 ) 77 | - डेक: [डेक](ultimatepython/data_structures/deque.py) ( 🤯 ) 78 | - नामित ट्यूपल: [नामित ट्यूपल](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) 79 | - डिफ़ॉल्ट डिक्ट: [डिफ़ॉल्ट डिक्ट](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) 80 | - समय कोम्पलेक्सिटी: [cPython ऑपरेशन्स](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) 81 | 4. **क्लासेज़** 82 | - बेसिक क्लास: [बेसिक परिभाषा](ultimatepython/classes/basic_class.py) ( 🍰 ) 83 | - इन्हरिटैंस: [इन्हरिटैंस](ultimatepython/classes/inheritance.py) ( 🍰 ) 84 | - एैबस्टराक्ट क्लास: [एैबस्टराक्ट परिभाषा](ultimatepython/classes/abstract_class.py) 85 | - एक्सेपशन क्लास: [एक्सेपशन परिभाषा](ultimatepython/classes/exception_class.py) 86 | - इटरेटर क्लास: [इटरेटर परिभाषा | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) 87 | - ऐनकैपसुलेषन: [ऐनकैपसुलेषन परिभाषा](ultimatepython/classes/encapsulation.py) 88 | 5. **उन्नत** 89 | - डेकोरेटर: [डेकोरेटर परिभाषा | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) 90 | - फ़ाइल प्रबंधन: [फ़ाइल प्रबंधन](ultimatepython/advanced/file_handling.py) ( 🤯 ) 91 | - संदर्भ प्रबंधक: [संदर्भ प्रबंधक](ultimatepython/advanced/context_manager.py) ( 🤯 ) 92 | - मेथड रिज़ॉल्यूशन क्रम: [mro](ultimatepython/advanced/mro.py) ( 🤯 ) 93 | - मिक्सिन: [मिक्सिन परिभाषा](ultimatepython/advanced/mixin.py) ( 🤯 ) 94 | - मेटाक्लास: [मेटाक्लास परिभाषा](ultimatepython/advanced/meta_class.py) ( 🤯 ) 95 | - थ्रेड: [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) 96 | - एसिंको: [async | await](ultimatepython/advanced/async.py) ( 🤯 ) 97 | - वीक रेफरेंस: [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) 98 | - बेंचमार्क: [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) 99 | - मॉकिंग: [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) 100 | - नियमित अभिव्यक्ति: [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) 101 | - डेटा फ़ॉर्मेट: [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) 102 | - दिनांक और समय: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) 103 | 104 | 105 | ## अतिरिक्त संसाधन 106 | 107 | 👔 = इंटरव्यू संसाधन, 108 | 🧪 = कोड नमूने, 109 | 🧠 = प्रोजेक्ट विचार 110 | 111 | 112 | ### गिटहब रिपॉजिटरी 113 | 114 | अन्य उच्च मानक संसाधनों से पढ़कर सीखना जारी रखें। 115 | 116 | - [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔 , 🧪 ) 117 | - [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔 , 🧪 ) 118 | - [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) 119 | - [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) 120 | - [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) 121 | - [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) 122 | - [vinta/awesome-python](https://github.com/vinta/awesome-python) 123 | - [academic/awesome-datascience](https://github.com/academic/awesome-datascience) 124 | - [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) 125 | - [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) 126 | - [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) 127 | - [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) 128 | - [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) 129 | - [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) 130 | 131 | ### इंटरैक्टिव प्रैक्टिस 132 | 133 | अभ्यास करते रहें ताकि आपकी कोडिंग कौशल खराब न हों। 134 | 135 | - [codechef.com](https://www.codechef.com/) ( 👔 ) 136 | - [codeforces.com](https://codeforces.com/) 137 | - [codementor.io](https://www.codementor.io) ( 🧠 ) 138 | - [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) 139 | - [codewars.com](https://www.codewars.com/) 140 | - [exercism.io](https://exercism.io/) 141 | - [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) 142 | - [hackerearth.com](https://www.hackerearth.com/) 143 | - [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) 144 | - [kaggle.com](https://www.kaggle.com/) ( 🧠 ) 145 | - [leetcode.com](https://leetcode.com/) ( 👔 ) 146 | - [projecteuler.net](https://projecteuler.net/) 147 | - [replit.com](https://replit.com/) 148 | - [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) 149 | -------------------------------------------------------------------------------- /README.ko.md: -------------------------------------------------------------------------------- 1 | # Ultimate Python 학습 가이드 2 | 3 | [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) 4 | [![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) 5 | [![Quality Gate Status](https://img.shields.io/sonar/quality_gate/huangsam_ultimate-python?server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/dashboard?id=huangsam_ultimate-python) 6 | [![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) 7 | [![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) 8 | 9 | 초보자와 전문가 모두를 위한 최고의 Python 학습 가이드입니다. 🐍 🐍 🐍 10 | 11 | ```python 12 | print("Ultimate Python 학습 가이드") 13 | ``` 14 | 15 | [English](README.md) | 16 | [한국어](README.ko.md) | 17 | [繁体中文](README.zh_tw.md) | 18 | [Español](README.es.md) | 19 | [Deutsch](README.de.md) | 20 | [हिन्दी](README.hi.md) 21 | 22 | Ultimate Python 23 | 24 | ## 동기 25 | 26 | 이 GitHub 저장소는 대학 졸업 후, 대규모 회사에서 근무하면서 27 | 그리고 [Celery](https://github.com/celery/celery)와 [Full Stack Python](https://github.com/mattmakai/fullstackpython.com) 같은 오픈소스 프로젝트에 기여하면서 28 | 지난 5년 이상 동안 배운 [core Python](https://www.python.org/)에 대한 지식을 공유하기 위해 만들었습니다. 29 | 저는 더 많은 사람들이 Python을 배우고 자신의 열정을 추구하길 기대합니다. 🎓 30 | 31 | ## 목표 32 | 33 | 이 가이드를 만드는 주요 목표는 다음과 같습니다: 34 | 35 | 🏆 실습 학습을 선호하는 Python 초보자를 위한 **학습 자료를 제공합니다.** 36 | 이 저장소에는 [PyCharm](https://www.jetbrains.com/pycharm/)과 같은 IDE 및 [Replit](https://replit.com/languages/python3)와 같은 브라우저에서 실행할 수 있는 독립형 모듈 모음이 있습니다. 기본 터미널에서도 예제를 실행할 수 있습니다. 37 | 대부분의 코드 라인에 프로그램이 단계별로 어떤 작업을 하는지 안내하는 신중하게 작성된 주석이 있습니다. 38 | 사용자는 `main` 루틴을 삭제하지 않고, 각 변경 후에 [성공적으로 실행](runner.py)되는 한 소스 코드를 얼마든지 수정할 수 있습니다. 39 | 40 | 🏆 core Python 개념을 다시 복습하고 싶은 사람들을 위한 **순수 가이드를 제공합니다.** 41 | 여기서는 오직 [내장 라이브러리](https://docs.python.org/3/library/)만을 사용하여 이러한 개념을 도메인 특화된 개념의 오버헤드 없이 전달합니다. 42 | 따라서 유명한 오픈소스 라이브러리와 프레임워크(`sqlalchemy`, `requests`, `pandas` 등)는 설치되어 있지 않습니다. 43 | 그러나, 당신의 목표가 진정한 진정한 [Pythonista](https://www.urbandictionary.com/define.php?term=pythonista)이 되는 것 이라면 이러한 프레임워크의 소스 코드를 읽는 것은 매우 고무적이고 권장이 됩니다. 44 | 45 | ## 시작하기 46 | 47 | [![Run on Replit](https://repl.it/badge/github/huangsam/ultimate-python)](https://repl.it/github/huangsam/ultimate-python) 48 | 49 | 로컬 컴퓨터에 Git 및 Python을 설치하지 않고도 브라우저에서 작업 환경을 시작하려면 위의 배지를 클릭하세요. 이러한 50 | 요구 사항이 이미 충족된 경우, 저장소를 바로 clone해도 됩니다. 51 | 52 | 저장소에 접근할 수 있게 되면 단독 모듈에서 배울 준비가 된 것입니다. 각 모듈을 최대한 활용하려면 모듈 코드를 53 | 읽고 실행하십시오. 모듈을 실행하는 두 가지 방법이 있습니다: 54 | 55 | 1. 단일 모듈 실행 : `python ultimatepython/syntax/variable.py` 56 | 2. 전체 모듈 실행 : `python runner.py` 57 | 58 | ## 목차 59 | 60 | 📚 = 외부 리소스, 61 | 🍰 = 초급 주제, 62 | 🤯 = 고급 주제 63 | 64 | 1. **Python 정보** 65 | - 개요 : [Python이란 무엇인가](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) 66 | - 디자인 철학 : [The Zen of Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) 67 | - 스타일 가이드 : [Python 코드 스타일 가이드](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) 68 | - 데이터 모델 : [데이터 모델](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) 69 | - 표준 라이브러리 : [Python 표준 라이브러리](https://docs.python.org/3/library/) ( 📚, 🤯 ) 70 | - 내장 함수 : [내장 함수](https://docs.python.org/3/library/functions.html) ( 📚 ) 71 | 2. **통사론** 72 | - 변수 : [내장 리터럴](ultimatepython/syntax/variable.py) ( 🍰 ) 73 | - 표현식 : [숫자 연산](ultimatepython/syntax/expression.py) ( 🍰 ) 74 | - 비트 연산 : [비트 연산자](ultimatepython/syntax/bitwise.py) ( 🍰 ), [1의 보수/2의 보수](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) 75 | - 조건문 : [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) 76 | - 반복문 : [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) 77 | - 함수 : [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) 78 | 3. **데이터 구조** 79 | - 리스트 : [리스트 연산](ultimatepython/data_structures/list.py) ( 🍰 ) 80 | - 튜플 : [튜플 연산](ultimatepython/data_structures/tuple.py) 81 | - 세트 : [세트 연산](ultimatepython/data_structures/set.py) 82 | - 딕셔너리 : [딕셔너리 연산](ultimatepython/data_structures/dict.py) ( 🍰 ) 83 | - 컴프리헨션 : [리스트 | 튜플 | 세트 | 딕셔너리](ultimatepython/data_structures/comprehension.py) 84 | - 문자열 : [문자열 연산](ultimatepython/data_structures/string.py) ( 🍰 ) 85 | - 덱: [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) 86 | - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) 87 | - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) 88 | - 시간 복잡도 : [cPython 연산](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) 89 | 4. **클래스** 90 | - 기본 클래스 : [기본 정의](ultimatepython/classes/basic_class.py) ( 🍰 ) 91 | - 계승: [계승](ultimatepython/classes/inheritance.py) ( 🍰 ) 92 | - 추상 클래스 : [추상 정의](ultimatepython/classes/abstract_class.py) 93 | - 예외 클래스 : [예외 정의](ultimatepython/classes/exception_class.py) 94 | - 이터레이터 클래스 : [이터레이터 정의 | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) 95 | - 캡슐화: [캡슐화 정의](ultimatepython/classes/encapsulation.py) 96 | 5. **고급** 97 | - 데코레이터 : [데코레이터 정의 | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) 98 | - 파일 처리: [파일 처리](ultimatepython/advanced/file_handling.py) ( 🤯 ) 99 | - 컨텍스트 매니저 : [컨텍스트 매니저](ultimatepython/advanced/context_manager.py) ( 🤯 ) 100 | - 메서드 결정 순서 : [mro](ultimatepython/advanced/mro.py) ( 🤯 ) 101 | - 믹스인 : [믹스인 정의](ultimatepython/advanced/mixin.py) ( 🤯 ) 102 | - 메타클래스 : [메타클래스 정의](ultimatepython/advanced/meta_class.py) ( 🤯 ) 103 | - 스레드 : [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) 104 | - Asyncio : [async | await](ultimatepython/advanced/async.py) ( 🤯 ) 105 | - 약한 참조 : [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) 106 | - 벤치마크 : [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) 107 | - 모킹 : [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) 108 | - 정규식 : [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) 109 | - 데이터 포맷 : [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) 110 | - 날짜와 시간 : [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) 111 | 112 | ## 추가 자료 113 | 114 | 👔 = 인터뷰 자료, 115 | 🧪 = 코드 샘플, 116 | 🧠 = 프로젝트 아이디어 117 | 118 | ### GitHub 저장소 119 | 120 | 잘 알려진 다른 자료를 읽으면서 계속 배우세요. 121 | 122 | - [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔, 🧪 ) 123 | - [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔, 🧪 ) 124 | - [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) 125 | - [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) 126 | - [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) 127 | - [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) 128 | - [vinta/awesome-python](https://github.com/vinta/awesome-python) 129 | - [academic/awesome-datascience](https://github.com/academic/awesome-datascience) 130 | - [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) 131 | - [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) 132 | - [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) 133 | - [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) 134 | - [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) 135 | - [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) 136 | 137 | ### 대화형 연습 138 | 139 | 코딩 실력이 녹슬지 않기 위해 계속 연습하세요. 140 | 141 | - [codechef.com](https://www.codechef.com/) ( 👔 ) 142 | - [codeforces.com](https://codeforces.com/) 143 | - [codementor.io](https://www.codementor.io) ( 🧠 ) 144 | - [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) 145 | - [codewars.com](https://www.codewars.com/) 146 | - [exercism.io](https://exercism.io/) 147 | - [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) 148 | - [hackerearth.com](https://www.hackerearth.com/) 149 | - [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) 150 | - [kaggle.com](https://www.kaggle.com/) ( 🧠 ) 151 | - [leetcode.com](https://leetcode.com/) ( 👔 ) 152 | - [projecteuler.net](https://projecteuler.net/) 153 | - [replit.com](https://replit.com/) 154 | - [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ultimate Python study guide 2 | 3 | [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) 4 | [![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) 5 | [![Quality Gate Status](https://img.shields.io/sonar/quality_gate/huangsam_ultimate-python?server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/dashboard?id=huangsam_ultimate-python) 6 | [![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) 7 | [![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) 8 | 9 | Ultimate Python study guide for newcomers and professionals alike. 🐍 🐍 🐍 10 | 11 | ```python 12 | print("Ultimate Python study guide") 13 | ``` 14 | 15 | [English](README.md) | 16 | [한국어](README.ko.md) | 17 | [繁体中文](README.zh_tw.md) | 18 | [Español](README.es.md) | 19 | [Deutsch](README.de.md) | 20 | [हिन्दी](README.hi.md) 21 | 22 | Ultimate Python 23 | 24 | ## Motivation 25 | 26 | I created this GitHub repo to share what I've learned about [core Python](https://www.python.org/) 27 | over the past 5+ years of using it as a college graduate, an employee at 28 | large-scale companies and an open-source contributor of repositories like 29 | [Celery](https://github.com/celery/celery) and 30 | [Full Stack Python](https://github.com/mattmakai/fullstackpython.com). 31 | I look forward to seeing more people learn Python and pursue their passions 32 | through it. 🎓 33 | 34 | ## Goals 35 | 36 | Here are the primary goals of creating this guide: 37 | 38 | 🏆 **Serve as a resource** for Python newcomers who prefer to learn hands-on. 39 | This repository has a collection of standalone modules which can be run in an IDE 40 | like [PyCharm](https://www.jetbrains.com/pycharm/) and in the browser like 41 | [Replit](https://replit.com/languages/python3). Even a plain old terminal will work 42 | with the examples. Most lines have carefully crafted comments which guide a reader 43 | through what the programs are doing step-by-step. Users are encouraged to modify 44 | source code anywhere as long as the `main` routines are not deleted and 45 | [run successfully](runner.py) after each change. 46 | 47 | 🏆 **Serve as a pure guide** for those who want to revisit core Python concepts. 48 | Only [builtin libraries](https://docs.python.org/3/library/) are leveraged so that 49 | these concepts can be conveyed without the overhead of domain-specific concepts. As 50 | such, popular open-source libraries and frameworks (i.e. `sqlalchemy`, `requests`, 51 | `pandas`) are not installed. However, reading the source code in these frameworks is 52 | inspiring and highly encouraged if your goal is to become a true 53 | [Pythonista](https://www.urbandictionary.com/define.php?term=pythonista). 54 | 55 | ## Getting started 56 | 57 | [![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) 58 | 59 | Click the badge above to spin up a working environment in the browser without 60 | needing Git and Python installed on your local machine. If these requirements 61 | are already met, feel free to clone the repository directly. 62 | 63 | Once the repository is accessible, you are ready to learn from the standalone 64 | modules. To get the most out of each module, read the module code and run it. 65 | There are two ways of running the modules: 66 | 67 | 1. Run a single module: `python ultimatepython/syntax/variable.py` 68 | 2. Run all of the modules: `python runner.py` 69 | 70 | ## Table of contents 71 | 72 | 📚 = External resource, 73 | 🍰 = Beginner topic, 74 | 🤯 = Advanced topic 75 | 76 | 1. **About Python** 77 | - Overview: [What is Python](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) 78 | - Design philosophy: [The Zen of Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) 79 | - Style guide: [Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) 80 | - Data model: [Data model](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) 81 | - Standard library: [The Python Standard Library](https://docs.python.org/3/library/) ( 📚, 🤯 ) 82 | - Built-in functions: [Built-in Functions](https://docs.python.org/3/library/functions.html) ( 📚 ) 83 | 2. **Syntax** 84 | - Variable: [Built-in literals](ultimatepython/syntax/variable.py) ( 🍰 ) 85 | - Expression: [Numeric operations](ultimatepython/syntax/expression.py) ( 🍰 ) 86 | - Bitwise: [Bitwise operators](ultimatepython/syntax/bitwise.py) ( 🍰 ), [One's/Two's Complement](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) 87 | - Conditional: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) 88 | - Loop: [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) 89 | - Function: [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) 90 | 3. **Data Structures** 91 | - List: [List operations](ultimatepython/data_structures/list.py) ( 🍰 ) 92 | - Tuple: [Tuple operations](ultimatepython/data_structures/tuple.py) 93 | - Set: [Set operations](ultimatepython/data_structures/set.py) 94 | - Dict: [Dictionary operations](ultimatepython/data_structures/dict.py) ( 🍰 ) 95 | - Comprehension: [list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) 96 | - String: [String operations](ultimatepython/data_structures/string.py) ( 🍰 ) 97 | - Deque: [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) 98 | - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) 99 | - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) 100 | - Time complexity: [cPython operations](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) 101 | 4. **Classes** 102 | - Basic class: [Basic definition](ultimatepython/classes/basic_class.py) ( 🍰 ) 103 | - Inheritance: [Inheritance](ultimatepython/classes/inheritance.py) ( 🍰 ) 104 | - Abstract class: [Abstract definition](ultimatepython/classes/abstract_class.py) 105 | - Exception class: [Exception definition](ultimatepython/classes/exception_class.py) 106 | - Iterator class: [Iterator definition | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) 107 | - Encapsulation: [Encapsulation definition](ultimatepython/classes/encapsulation.py) 108 | 5. **Advanced** 109 | - Decorator: [Decorator definition | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) 110 | - File Handling: [File Handling](ultimatepython/advanced/file_handling.py) ( 🤯 ) 111 | - Context manager: [Context managers](ultimatepython/advanced/context_manager.py) ( 🤯 ) 112 | - Method resolution order: [mro](ultimatepython/advanced/mro.py) ( 🤯 ) 113 | - Mixin: [Mixin definition](ultimatepython/advanced/mixin.py) ( 🤯 ) 114 | - Metaclass: [Metaclass definition](ultimatepython/advanced/meta_class.py) ( 🤯 ) 115 | - Thread: [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) 116 | - Asyncio: [async | await](ultimatepython/advanced/async.py) ( 🤯 ) 117 | - Weak reference: [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) 118 | - Benchmark: [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) 119 | - Mocking: [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) 120 | - Regular expression: [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) 121 | - Data format: [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) 122 | - Datetime: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) 123 | 124 | ## Additional resources 125 | 126 | 👔 = Interview resource, 127 | 🧪 = Code samples, 128 | 🧠 = Project ideas 129 | 130 | ### GitHub repositories 131 | 132 | Keep learning by reading from other well-regarded resources. 133 | 134 | - [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔 , 🧪 ) 135 | - [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔 , 🧪 ) 136 | - [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) 137 | - [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) 138 | - [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) 139 | - [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) 140 | - [vinta/awesome-python](https://github.com/vinta/awesome-python) 141 | - [academic/awesome-datascience](https://github.com/academic/awesome-datascience) 142 | - [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) 143 | - [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) 144 | - [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) 145 | - [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) 146 | - [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) 147 | - [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) 148 | 149 | ### Interactive practice 150 | 151 | Keep practicing so that your coding skills don't get rusty. 152 | 153 | - [codechef.com](https://www.codechef.com/) ( 👔 ) 154 | - [codeforces.com](https://codeforces.com/) 155 | - [codementor.io](https://www.codementor.io) ( 🧠 ) 156 | - [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) 157 | - [codewars.com](https://www.codewars.com/) 158 | - [exercism.io](https://exercism.io/) 159 | - [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) 160 | - [hackerearth.com](https://www.hackerearth.com/) 161 | - [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) 162 | - [kaggle.com](https://www.kaggle.com/) ( 🧠 ) 163 | - [leetcode.com](https://leetcode.com/) ( 👔 ) 164 | - [projecteuler.net](https://projecteuler.net/) 165 | - [replit.com](https://replit.com/) 166 | - [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) 167 | -------------------------------------------------------------------------------- /README.zh_tw.md: -------------------------------------------------------------------------------- 1 | # Ultimate Python 學習大綱 2 | 3 | [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) 4 | [![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) 5 | [![Quality Gate Status](https://img.shields.io/sonar/quality_gate/huangsam_ultimate-python?server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/dashboard?id=huangsam_ultimate-python) 6 | [![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) 7 | [![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) 8 | 9 | Ultimate Python 學習大綱 - 適用於新手和專業人士。🐍 🐍 🐍 10 | 11 | ```python 12 | print("Ultimate Python 學習大綱") 13 | ``` 14 | 15 | [English](README.md) | 16 | [한국어](README.ko.md) | 17 | [繁体中文](README.zh_tw.md) | 18 | [Español](README.es.md) | 19 | [Deutsch](README.de.md) | 20 | [हिन्दी](README.hi.md) 21 | 22 | Ultimate Python 23 | 24 | ## 動力 25 | 26 | 我為了分享過去五年作為一個學生,大公司員工,以及開源(例如 Celery 和 Full Stack Python)貢獻者所習得的知識而創 27 | 建了這個代碼倉庫。我期待更多人能抱持熱忱並開始一段與Python的美好旅程。🎓 28 | 29 | ## 目標 30 | 31 | 這是創建本指南的主要目標: 32 | 33 | 🏆 **為喜歡動手學習的Python新手提供資源。** 本存儲庫集合了不同題目的獨立模組範例,而每個模組可以獨立在普通 34 | 終端機(Terminal),IDE(如PyCharm)或者瀏覽器(如Repl.it)中運行。範例中的註解都經過精心編寫,引導讀者逐步了解程 35 | 式流程。在不刪除主例程(main)並在修改後成功運行大前題下,我鼓勵讀者修改源代碼作練習。 36 | 37 | 🏆 **為想重溫Python核心概念的程式員提供指南。** 本存儲庫主要借助內置庫(builtin libraries)作重溫工具, 38 | 故不需額外安裝開源庫(如`sqlalchemy`,`requests`,`pandas`)。但是,如果您的目標是成為一個真正的Python 39 | 達人(Pythonista),那麼我會鼓勵您閱讀這些源代碼,而激發靈感。 40 | 41 | ## 學習之旅 42 | 43 | [![Run on Repl.it](https://repl.it/badge/github/huangsam/ultimate-python)](https://repl.it/github/huangsam/ultimate-python) 44 | 45 | 單擊上面的徽章就可在瀏覽器中啟動工作環境,而無需在電腦上額外安裝Git和Python。當你完成啟動,請複製這存儲庫。 46 | 當你可以開啟你所複製存儲庫後,您就準備好Python學習之旅!善用每個模組,請細讀註解並嘗試運行模組代碼。 47 | 48 | 有兩種運行模組的方式: 49 | 50 | 1. 運行單一模組:`python ultimatepython/syntax/variable.py` 51 | 2. 運行所有模組:`python runner.py` 52 | 53 | ## 目錄 54 | 55 | 📚 = 外部資源, 56 | 🍰 = 入門題目, 57 | 🤯 = 進階題目 58 | 59 | 1. **關於 Python** 60 | - 概述:[什麼是 Python](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) 61 | - 設計理念:[Python之格言](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) 62 | - 樣式指南:[Python代碼樣式指南](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) 63 | - 數據模型:[數據模型](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) 64 | - 標準庫:[Python標準庫](https://docs.python.org/3/library/) ( 📚, 🤯 ) 65 | - 內置函式:[內置函式](https://docs.python.org/3/library/functions.html) ( 📚 ) 66 | 2. **語法** 67 | - 變數:[內置值](ultimatepython/syntax/variable.py) ( 🍰 ) 68 | - 運算式:[數值運算](ultimatepython/syntax/expression.py) ( 🍰 ) 69 | - 按位: [中的位元運算符](ultimatepython/syntax/bitwise.py) ( 🍰 ), [一個的補語/補碼](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) 70 | - 條件運算式:[if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) 71 | - 迴圈:[for迴圈 | while迴圈](ultimatepython/syntax/loop.py) ( 🍰 ) 72 | - 定義函式:[def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) 73 | 3. **資料結構** 74 | - 列表:[列表操作](ultimatepython/data_structures/list.py) ( 🍰 ) 75 | - 元組:[元組操作](ultimatepython/data_structures/tuple.py) 76 | - 集合:[集合操作](ultimatepython/data_structures/set.py) 77 | - 字典:[字典操作](ultimatepython/data_structures/dict.py) ( 🍰 ) 78 | - 綜合:[list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) 79 | - 字串:[字串操作](ultimatepython/data_structures/string.py) ( 🍰 ) 80 | - 雙端隊列:[deque](ultimatepython/data_structures/deque.py) ( 🤯 ) 81 | - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) 82 | - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) 83 | - 時間複雜度:[cPython操作](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) 84 | 4. **類別** 85 | - 基本類別:[基本定義](ultimatepython/classes/basic_class.py) ( 🍰 ) 86 | - 抽象類別:[抽象定義](ultimatepython/classes/abstract_class.py) 87 | - 異常類別:[異常定義](ultimatepython/classes/exception_class.py) 88 | - 迭代類別:[迭代器定義](ultimatepython/classes/iterator_class.py) ( 🤯 ) 89 | - 封裝: [封裝定義](ultimatepython/classes/encapsulation.py) 90 | 5. **進階技巧** 91 | - 裝飾器:[Decorator definition | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) 92 | - 文件處理: [File Handling](ultimatepython/advanced/file_handling.py) ( 🤯 ) 93 | - 資源管理器:[Context managers](ultimatepython/advanced/context_manager.py) ( 🤯 ) 94 | - 方法解析順序:[mro](ultimatepython/advanced/mro.py) ( 🤯 ) 95 | - Mixin:[Mixin定義](ultimatepython/advanced/mixin.py) ( 🤯 ) 96 | - 元類:[Metaclass定義](ultimatepython/advanced/meta_class.py) ( 🤯 ) 97 | - 執行緒:[ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) 98 | - 異步:[async | await](ultimatepython/advanced/async.py) ( 🤯 ) 99 | - 弱引用:[weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) 100 | - 基準:[cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) 101 | - 模擬:[MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) 102 | - 正規表示式:[search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) 103 | - 數據格式:[json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) 104 | - 日期時間: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) 105 | 106 | ## 額外資源 107 | 108 | 👔 = 面試資源, 109 | 🧪 = 代碼範例, 110 | 🧠 = 項目構想 111 | 112 | ### GitHub儲存庫 113 | 114 | 通過閱讀其他備受尊重的資源來繼續學習。 115 | 116 | - [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔, 🧪 ) 117 | - [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔, 🧪 ) 118 | - [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) 119 | - [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) 120 | - [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) 121 | - [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) 122 | - [vinta/awesome-python](https://github.com/vinta/awesome-python) 123 | - [academic/awesome-datascience](https://github.com/academic/awesome-datascience) 124 | - [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) 125 | - [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) 126 | - [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) 127 | - [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) 128 | - [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) 129 | - [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) 130 | 131 | ### 互動練習 132 | 133 | 繼續練習才能使您的編碼技能不會生疏。 134 | 135 | - [DevProjects](https://www.codementor.io/projects/python) 136 | - [codechef.com](https://www.codechef.com/) ( 👔 ) 137 | - [codeforces.com](https://codeforces.com/) 138 | - [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) 139 | - [codewars.com](https://www.codewars.com/) 140 | - [exercism.io](https://exercism.io/) 141 | - [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) 142 | - [hackerearth.com](https://www.hackerearth.com/) 143 | - [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) 144 | - [kaggle.com](https://www.kaggle.com/) ( 🧠 ) 145 | - [leetcode.com](https://leetcode.com/) ( 👔 ) 146 | - [projecteuler.net](https://projecteuler.net/) 147 | - [replit.com](https://replit.com/) 148 | - [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) 149 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | # https://docs.codecov.com/docs/common-recipe-list 2 | # https://docs.codecov.com/docs/commit-status 3 | coverage: 4 | status: 5 | patch: 6 | default: 7 | target: 100% 8 | -------------------------------------------------------------------------------- /images/ultimatepython.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangsam/ultimate-python/26887e626b9509aa56f99da604399ed800405aaa/images/ultimatepython.webp -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.ruff] 2 | line-length = 160 3 | 4 | [tool.isort] 5 | multi_line_output = 3 6 | include_trailing_comma = true 7 | force_grid_wrap = 0 8 | use_parentheses = true 9 | ensure_newline_before_comments = true 10 | line_length = 160 11 | 12 | [tool.coverage.run] 13 | branch = true 14 | 15 | [tool.coverage.report] 16 | exclude_lines = [ 17 | "skip: (if|else)", 18 | "def __repr__", 19 | "raise NotImplementedError", 20 | "if __name__ == .__main__.:", 21 | "any\\(" 22 | ] 23 | fail_under = 80 24 | omit = [ 25 | "venv/**", 26 | "runner.py", 27 | "**/__init__.py" 28 | ] 29 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | coverage==7.8.2 2 | isort==6.0.1 3 | ruff==0.11.11 4 | -------------------------------------------------------------------------------- /runner.py: -------------------------------------------------------------------------------- 1 | from importlib import import_module 2 | from inspect import isfunction, signature 3 | from pkgutil import walk_packages 4 | 5 | from ultimatepython import __name__ as root_name 6 | from ultimatepython import __path__ as root_path 7 | 8 | # Module-level constants 9 | _STYLE_SUCCESS = "\033[92m" 10 | _STYLE_BOLD = "\033[1m" 11 | _STYLE_END = "\033[0m" 12 | _RUNNER_PROGRESS = "->" 13 | _RUNNER_MAIN = "main" 14 | 15 | 16 | def success_text(text): 17 | """Get success text.""" 18 | return f"{_STYLE_SUCCESS}{bold_text(text)}{_STYLE_END}" 19 | 20 | 21 | def bold_text(text): 22 | """Get bold text.""" 23 | return f"{_STYLE_BOLD}{text}{_STYLE_END}" 24 | 25 | 26 | def main(): 27 | print(bold_text(f"Start {root_name} runner")) 28 | 29 | for item in walk_packages(root_path, f"{root_name}."): 30 | mod = import_module(item.name) 31 | 32 | # Skip modules without a main object 33 | if not hasattr(mod, _RUNNER_MAIN): 34 | continue 35 | 36 | # By this point, there is a main object in the module 37 | mod_main = getattr(mod, _RUNNER_MAIN) 38 | 39 | # The main object is a function 40 | assert isfunction(mod_main) 41 | 42 | # The main function has zero parameters 43 | assert len(signature(mod_main).parameters) == 0 44 | 45 | # The main function should not throw any errors 46 | print(f"{_RUNNER_PROGRESS} Run {mod.__name__}:{_RUNNER_MAIN}", end="") 47 | mod_main() 48 | print(" [PASS]") 49 | 50 | print(success_text(f"Finish {root_name} runner")) 51 | 52 | 53 | if __name__ == "__main__": 54 | main() 55 | -------------------------------------------------------------------------------- /ultimatepython/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangsam/ultimate-python/26887e626b9509aa56f99da604399ed800405aaa/ultimatepython/__init__.py -------------------------------------------------------------------------------- /ultimatepython/advanced/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangsam/ultimate-python/26887e626b9509aa56f99da604399ed800405aaa/ultimatepython/advanced/__init__.py -------------------------------------------------------------------------------- /ultimatepython/advanced/async.py: -------------------------------------------------------------------------------- 1 | """ 2 | Concurrent programming with an event loop is a relatively new concept in 3 | Python 3.x. This module aims to highlight how it could be used in the 4 | context of a scheduler which runs a fire-and-forget operation for starting 5 | jobs. In the real world, it takes time for a scheduler to start a job (i.e. 6 | hit an API endpoint, ask the operating system for resources) so we assume 7 | that starting a job has some intrinsic delay. 8 | """ 9 | import asyncio 10 | from dataclasses import dataclass 11 | from datetime import datetime 12 | from uuid import uuid4 13 | 14 | # Module-level constants 15 | _DELAY_SMALL = 0.001 16 | _DELAY_LARGE = 3600 17 | 18 | 19 | @dataclass 20 | class JobRecord: 21 | """Job record with useful metadata.""" 22 | 23 | guid: str 24 | queued_at: datetime 25 | started_at: datetime 26 | 27 | 28 | def _is_valid_record(record): 29 | """Check whether job record is valid or not.""" 30 | return record.queued_at < record.started_at 31 | 32 | 33 | def _current_time(): 34 | """Return current time that is timezone-naive.""" 35 | return datetime.now() 36 | 37 | 38 | async def start_job(job_id, delay): 39 | """Start job ID after a certain amount of delay.""" 40 | queue_time = _current_time() 41 | await asyncio.sleep(delay) 42 | start_time = _current_time() 43 | return JobRecord(job_id, queue_time, start_time) 44 | 45 | 46 | async def schedule_jobs(): 47 | """Schedule jobs concurrently.""" 48 | # Start a job which also represents a coroutine 49 | single_job = start_job(uuid4().hex, _DELAY_SMALL) 50 | assert asyncio.iscoroutine(single_job) 51 | 52 | # Grab a job record from the coroutine 53 | single_record = await single_job 54 | assert _is_valid_record(single_record) 55 | 56 | # Task is a wrapped coroutine which also represents a future 57 | single_task = asyncio.create_task(start_job(uuid4().hex, _DELAY_LARGE)) 58 | assert asyncio.isfuture(single_task) 59 | 60 | # Futures are different from other coroutines since they can be cancelled 61 | single_task.cancel() 62 | task_failed = False 63 | try: 64 | await single_task 65 | except asyncio.exceptions.CancelledError: 66 | assert single_task.cancelled() 67 | task_failed = True 68 | assert task_failed is True 69 | 70 | # Gather coroutines for batch start 71 | batch_jobs = [start_job(uuid4().hex, _DELAY_SMALL) for _ in range(10)] 72 | batch_records = await asyncio.gather(*batch_jobs) 73 | 74 | # We get the same amount of records as we have coroutines 75 | assert len(batch_records) == len(batch_jobs) 76 | assert all(_is_valid_record(record) for record in batch_records) 77 | 78 | 79 | def main(): 80 | asyncio.run(schedule_jobs()) 81 | 82 | 83 | if __name__ == "__main__": 84 | main() 85 | -------------------------------------------------------------------------------- /ultimatepython/advanced/benchmark.py: -------------------------------------------------------------------------------- 1 | """ 2 | As programs increase in size, they have the risk of getting slow as new 3 | features are added and extra layers of complexity to the main features. 4 | Benchmarking is an approach that helps developers use profiling metrics 5 | and their code intuition to optimize programs further. This module uses 6 | cProfile to compare the performance of two functions with each other. 7 | """ 8 | import cProfile 9 | import io 10 | import pstats 11 | import time 12 | 13 | # Module-level constants 14 | _SLEEP_DURATION = 0.001 15 | 16 | 17 | def finish_slower(): 18 | """Finish slower by sleeping more.""" 19 | for _ in range(20): 20 | time.sleep(_SLEEP_DURATION) 21 | 22 | 23 | def finish_faster(): 24 | """Finish faster by sleeping less.""" 25 | for _ in range(10): 26 | time.sleep(_SLEEP_DURATION) 27 | 28 | 29 | def main(): 30 | # Create a profile instance 31 | profile = cProfile.Profile() 32 | 33 | profile.enable() 34 | 35 | for _ in range(2): 36 | finish_slower() 37 | finish_faster() 38 | 39 | profile.disable() 40 | 41 | # Sort statistics by cumulative time spent for each function call. 42 | # There are other ways to sort the stats by, but this is the most 43 | # common way of doing so. For more info, please consult Python docs: 44 | # https://docs.python.org/3/library/profile.html 45 | buffer = io.StringIO() 46 | ps = pstats.Stats(profile, stream=buffer).sort_stats("cumulative") 47 | 48 | # Notice how many times each function was called. In this case, the main 49 | # bottleneck for `finish_slower` and `finish_faster` is `time.sleep` 50 | # which occurred 60 times. By reading the code and the statistics, we 51 | # can infer that 40 occurrences came from `finish_slower` and 20 came 52 | # from `finish_faster`. It is clear why the latter function runs faster 53 | # in this case, but identifying insights like this are not simple in 54 | # large projects. Consider profiling in isolation when analyzing complex 55 | # classes and functions 56 | ps.print_stats() 57 | time_sleep_called = any("60" in line and "time.sleep" in line 58 | for line in buffer.getvalue().split("\n")) 59 | assert time_sleep_called is True 60 | 61 | 62 | if __name__ == "__main__": 63 | main() 64 | -------------------------------------------------------------------------------- /ultimatepython/advanced/context_manager.py: -------------------------------------------------------------------------------- 1 | """ 2 | Context managers are used to open and close resources as Python enters 3 | and exits a code block respectively. Some examples of the resources it 4 | can manage are files, database connections and sockets. In this module, 5 | we simulate how a context manager can handle open and close operations of 6 | a file-like object called StringIO. 7 | """ 8 | from contextlib import contextmanager 9 | from io import StringIO 10 | 11 | # Simple directory with file contents 12 | _FILESYSTEM = { 13 | "a.txt": "Hello World", 14 | "b.xml": "Hello World", 15 | "c.out": "10101010", 16 | } 17 | 18 | 19 | @contextmanager 20 | def file(filename): 21 | """File context manager. 22 | 23 | This is the function variant of the context manager. Context managers 24 | are useful for resources that need to be opened and closed such as 25 | files, database connections and sockets. 26 | """ 27 | io_buffer = StringIO(_FILESYSTEM[filename]) 28 | try: 29 | # Pass the buffer to the context block 30 | yield io_buffer 31 | finally: 32 | # Close the buffer unconditionally 33 | io_buffer.close() 34 | 35 | 36 | class FileHandler: 37 | """File handler context manager. 38 | 39 | This is the class variant of the context manager. Just like with 40 | iterators, it depends on context and preference that we design a 41 | class or simply write a function. 42 | """ 43 | 44 | def __init__(self, filename): 45 | self.io_buffer = StringIO(_FILESYSTEM[filename]) 46 | 47 | def __enter__(self): 48 | """Pass the buffer to the context block.""" 49 | return self.io_buffer 50 | 51 | def __exit__(self, *args): 52 | """Close the buffer unconditionally.""" 53 | self.io_buffer.close() 54 | 55 | 56 | def main(): 57 | # An example of a function-based context manager 58 | with file("a.txt") as txt_buffer: 59 | assert txt_buffer.read() == "Hello World" 60 | 61 | # An example of a class-based context manager 62 | with FileHandler("b.xml") as xml_buffer: 63 | assert xml_buffer.read() == "Hello World" 64 | 65 | # Examples of context manager failures 66 | for context_obj in (file, FileHandler): 67 | call_failed = False 68 | try: 69 | # Whenever any error happens in the context block, the buffer 70 | # in the context manager gets closed automatically and the 71 | # error gets raised to the outer block 72 | with context_obj("c.out"): 73 | raise RuntimeError("System crash. Abort!") 74 | except RuntimeError: 75 | call_failed = True 76 | assert call_failed is True 77 | 78 | 79 | if __name__ == "__main__": 80 | main() 81 | -------------------------------------------------------------------------------- /ultimatepython/advanced/data_format.py: -------------------------------------------------------------------------------- 1 | """ 2 | One of the reasons people use Python is that it simplifies parsing and 3 | converting data to serialized objects for further analysis. This module 4 | shows how to parse and process these data formats: JSON, XML and CSV. 5 | """ 6 | import json 7 | from csv import DictReader 8 | from dataclasses import dataclass, fields 9 | from io import StringIO 10 | from xml.etree import ElementTree as ETree 11 | 12 | # Data in JSON format. For more info on this format: 13 | # https://fileinfo.com/extension/json 14 | _JSON_DATA = """ 15 | [ 16 | { 17 | "author": "John", 18 | "title": "Summer", 19 | "body": "Summer time is hot" 20 | }, 21 | { 22 | "author": "Jane", 23 | "title": "Winter", 24 | "body": "Winter time is cold" 25 | } 26 | ] 27 | """ 28 | 29 | # Data in XML format. For more info on this format: 30 | # https://fileinfo.com/extension/xml 31 | _XML_DATA = """ 32 | 33 | 34 | John 35 | Summer 36 | Summer time is hot 37 | 38 | 39 | Jane 40 | Winter 41 | Winter time is cold 42 | 43 | 44 | """ 45 | 46 | # Data in CSV format. For more info on this format: 47 | # https://fileinfo.com/extension/csv 48 | _CSV_DATA = """ 49 | John,Summer,Summer time is hot 50 | Jane,Winter,Winter time is cold 51 | """ 52 | 53 | 54 | @dataclass 55 | class Note: 56 | """Note model. 57 | 58 | We notice that each data format has the notion of a record with fields 59 | associated with them. To streamline the creation and comparison of 60 | these records, we define an in-memory model of what it is. 61 | """ 62 | author: str 63 | title: str 64 | body: str 65 | 66 | @classmethod 67 | def from_data(cls, data): 68 | """Create note from dictionary data.""" 69 | return cls(**data) 70 | 71 | @classmethod 72 | def fields(cls): 73 | """Get field names to simplify parsing logic.""" 74 | return tuple(field.name for field in fields(cls)) 75 | 76 | 77 | def main(): 78 | # Let's use `json.load` to parse note data from a JSON file 79 | # https://docs.python.org/3/library/json.html 80 | json_content = json.load(StringIO(_JSON_DATA)) 81 | json_notes = [Note.from_data(data) for data in json_content] 82 | assert all(isinstance(note, Note) for note in json_notes) 83 | 84 | # Let's use `ElementTree.parse` to parse note data from a XML file 85 | # https://docs.python.org/3/library/xml.html 86 | tree = ETree.parse(StringIO(_XML_DATA)) 87 | xml_notes = [ 88 | Note.from_data({ 89 | field: note_el.findtext(field) 90 | for field in Note.fields() 91 | }) for note_el in tree.getroot() 92 | ] 93 | assert all(isinstance(note, Note) for note in xml_notes) 94 | 95 | # Let's use `csv.DictReader` to parse note data from a CSV file 96 | # https://docs.python.org/3/library/csv.html 97 | csv_reader = DictReader(StringIO(_CSV_DATA), fieldnames=Note.fields()) 98 | csv_notes = [Note.from_data(row) for row in csv_reader] 99 | assert all(isinstance(note, Note) for note in csv_notes) 100 | 101 | # All three formats have similar `Note` objects 102 | for json_note, xml_note, csv_note in zip(json_notes, xml_notes, csv_notes): 103 | assert json_note == xml_note == csv_note 104 | 105 | 106 | if __name__ == "__main__": 107 | main() 108 | -------------------------------------------------------------------------------- /ultimatepython/advanced/date_time.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `datetime` class is one of the core classes we encounter when tracking 3 | events at a given date and time. By default, creating an instance with 4 | `datetime.now` means that an offset-naive datetime object is produced in 5 | the host's local timezone. 6 | 7 | An offset-naive `datetime` object is useful for scripts that are run on a 8 | personal device. Once we use `datetime` objects for web applications that 9 | are deployed globally, it's important to know the offset that `datetime` 10 | objects are aligned to before processing them. For more on `datetime`: 11 | 12 | https://docs.python.org/3/library/datetime.html 13 | 14 | Backend developers address this by storing time fields with offsets aligned 15 | with the UTC (Coordinated Universal Time) timezone. As a result, time fields 16 | can be displayed in any timezone - at any moment. For more on UTC: 17 | 18 | https://en.wikipedia.org/wiki/Coordinated_Universal_Time 19 | 20 | In this module, we will show the difference between offset-naive and 21 | offset-aware `datetime` objects. We will also highlight the builtin 22 | UTC timezone and show how it can be used to make the default `datetime` 23 | object more powerful. 24 | """ 25 | from datetime import datetime, timezone 26 | 27 | 28 | def convert_dt_to_utc_epoch(dt): 29 | """Convert datetime to UTC epoch seconds. 30 | 31 | Note that the timestamp method assumes that an offset-naive 32 | datetime instance is in the local timezone and converts its 33 | offset to UTC before making it a floating point number. 34 | """ 35 | return dt.timestamp() 36 | 37 | 38 | def convert_utc_epoch_to_dt(epoch): 39 | """Convert UTC epoch seconds to datetime.""" 40 | return datetime.fromtimestamp(epoch, tz=timezone.utc) 41 | 42 | 43 | def convert_dt_timezone(dt, tz): 44 | """Convert datetime timezone.""" 45 | return dt.astimezone(tz=tz) 46 | 47 | 48 | def get_utc_now_as_dt(): 49 | """Get current UTC time as datetime.""" 50 | return datetime.now(tz=timezone.utc) 51 | 52 | 53 | def get_utc_now_as_epoch(): 54 | """Get current UTC time as epoch seconds.""" 55 | return convert_dt_to_utc_epoch(get_utc_now_as_dt()) 56 | 57 | 58 | def main(): 59 | # Create offset-naive datetime 60 | naive_dt = datetime.now() 61 | assert naive_dt.tzinfo is None 62 | 63 | # Change offset-naive datetime to epoch seconds 64 | naive_dt_epoch = convert_dt_to_utc_epoch(naive_dt) 65 | assert naive_dt_epoch > 0 66 | 67 | # Change epoch seconds to UTC datetime 68 | utc_dt = convert_utc_epoch_to_dt(naive_dt_epoch) 69 | assert utc_dt.tzinfo is timezone.utc 70 | assert convert_dt_to_utc_epoch(utc_dt) == naive_dt_epoch 71 | 72 | # We cannot compute differences between offset-naive and offset-aware 73 | # datetime objects 74 | calc_failed = False 75 | try: 76 | _ = utc_dt - naive_dt 77 | except TypeError: 78 | calc_failed = True 79 | assert calc_failed is True 80 | 81 | # But we can change the timezone of an offset-naive datetime object 82 | # first before running operations on them 83 | assert convert_dt_timezone(naive_dt, timezone.utc) == utc_dt 84 | 85 | # Create new UTC time as datetime 86 | utc_dt_new_one = get_utc_now_as_dt() 87 | assert utc_dt_new_one > utc_dt 88 | 89 | # Create another new UTC time as epoch seconds 90 | utc_epoch_new_two = get_utc_now_as_epoch() 91 | utc_epoch_new_one = convert_dt_to_utc_epoch(utc_dt_new_one) 92 | assert utc_epoch_new_two > utc_epoch_new_one > naive_dt_epoch 93 | utc_dt_new_two = convert_utc_epoch_to_dt(utc_epoch_new_two) 94 | assert utc_dt_new_two > utc_dt_new_one > utc_dt 95 | 96 | 97 | if __name__ == "__main__": 98 | main() 99 | -------------------------------------------------------------------------------- /ultimatepython/advanced/decorator.py: -------------------------------------------------------------------------------- 1 | """ 2 | Decorators add new functionality to a function or class at runtime. 3 | This module shows how a simple "encryption" function for one string can 4 | be decorated to work with a collection of strings. Note that the decorator 5 | handles nested collections with the use of recursion. 6 | """ 7 | from functools import wraps 8 | 9 | # Module-level constants 10 | _MASKING = "*" 11 | 12 | 13 | def run_with_stringy(fn): 14 | """Run a string function with a string or a collection of strings. 15 | 16 | We define a custom decorator that allows us to convert a function whose 17 | input is a single string into a function whose input can be a string 18 | or a collection of strings. 19 | 20 | A function decorator consists of the following: 21 | 22 | - An input function to run with 23 | - A wrapper function that uses the input function 24 | 25 | The `wrapper` does not need to accept the input function as a parameter 26 | because it can get that from its parent `run_with_any`. Also, the 27 | parameters that `wrapper` receives do NOT have to be the same as the 28 | ones that the input function `fn` needs to receive. However, it is highly 29 | recommended to have the parameter lists for `wrapper` and `fn` line up so 30 | that developers are less likely to get confused. 31 | 32 | The formal specification for function decorators is here: 33 | 34 | https://www.python.org/dev/peps/pep-0318/ 35 | 36 | The formal specification for class decorators is here: 37 | 38 | https://www.python.org/dev/peps/pep-3129/ 39 | """ 40 | 41 | @wraps(fn) 42 | def wrapper(obj): 43 | """Apply wrapped function to a string or a collection. 44 | 45 | This looks like a policy-based engine which runs a `return` statement 46 | if a particular set of rules is true. Otherwise, it aborts. This is 47 | an example of the Strategy design pattern. 48 | 49 | https://en.wikipedia.org/wiki/Strategy_pattern 50 | 51 | But instead of writing the logic using classes, we write the logic 52 | using a single function that encapsulates all possible rules. 53 | """ 54 | if isinstance(obj, str): 55 | return fn(obj) 56 | elif isinstance(obj, dict): 57 | return {key: wrapper(value) for key, value in obj.items()} 58 | elif isinstance(obj, (list, set, tuple)): 59 | sequence_kls = type(obj) 60 | return sequence_kls(wrapper(value) for value in obj) 61 | raise ValueError(f"Found an invalid item: {obj}") 62 | 63 | return wrapper 64 | 65 | 66 | @run_with_stringy 67 | def hide_content(content): 68 | """Hide half of the string content.""" 69 | start_point = len(content) // 2 70 | num_of_asterisks = len(content) // 2 + len(content) % 2 71 | return content[:start_point] + _MASKING * num_of_asterisks 72 | 73 | 74 | def _is_hidden(obj): 75 | """Check whether string or collection is hidden.""" 76 | if isinstance(obj, str): 77 | return _MASKING in obj 78 | elif isinstance(obj, dict): 79 | return all(_is_hidden(value) for value in obj.values()) 80 | return all(_is_hidden(value) for value in obj) 81 | 82 | 83 | def main(): 84 | # There is so much plain-text data out in the open 85 | insecure_data = [ 86 | {"username": "johndoe", "country": "USA"}, # User information 87 | ["123-456-7890", "123-456-7891"], # Social security numbers 88 | [("johndoe", "janedoe"), ("bobdoe", "marydoe")], # Couple names 89 | "secretLaunchCode123", # Secret launch code 90 | ] 91 | 92 | # Time to encrypt it all so that it can't be snatched away. This kind 93 | # of work is the stuff that might be done by a company for GDPR. For more 94 | # on that policy, check out the following Wikipedia page: 95 | # https://en.wikipedia.org/wiki/General_Data_Protection_Regulation 96 | secure_data = hide_content(insecure_data) 97 | 98 | # See what changed between the insecure data and the secure data 99 | for insecure_item, secure_item in zip(insecure_data, secure_data): 100 | assert insecure_item != secure_item 101 | assert not _is_hidden(insecure_item) 102 | assert _is_hidden(secure_item) 103 | 104 | # Throw an error on a collection with non-string objects 105 | input_failed = False 106 | try: 107 | hide_content([1]) 108 | except ValueError: 109 | input_failed = True 110 | assert input_failed is True 111 | 112 | 113 | if __name__ == "__main__": 114 | main() 115 | -------------------------------------------------------------------------------- /ultimatepython/advanced/file_handling.py: -------------------------------------------------------------------------------- 1 | """ 2 | File handling is a fundamental concept in Python that involves 3 | opening, reading, writing, and appending to files. This module 4 | demonstrates the basics of file handling in Python. 5 | 6 | Python provides various ways to work with files. We can use the 7 | builtin 'open' function to open files in different modes like 8 | reading ('r'), writing ('w'), and appending ('a'). 9 | """ 10 | import os 11 | 12 | _TARGET_FILE = "sample.txt" 13 | 14 | 15 | def read_file(filename): 16 | """Read content from existing file.""" 17 | with open(filename, "r") as file: 18 | content = file.read() 19 | return content 20 | 21 | 22 | def write_file(filename, content): 23 | """Write content to new file.""" 24 | with open(filename, "w") as file: 25 | file.write(content) 26 | return f"Content written to '{filename}'." 27 | 28 | 29 | def append_file(filename, content): 30 | """Append content to existing file.""" 31 | with open(filename, "a") as file: 32 | file.write(content) 33 | return f"Content appended to '{filename}'." 34 | 35 | 36 | def delete_file(filename): 37 | """Delete content of existing file.""" 38 | os.remove(filename) 39 | return f"'{filename}' has been deleted." 40 | 41 | 42 | def main(): 43 | result = write_file(_TARGET_FILE, "This is a test.") 44 | assert result == f"Content written to '{_TARGET_FILE}'." 45 | 46 | content = read_file(_TARGET_FILE) 47 | assert content == "This is a test." 48 | 49 | append_result = append_file(_TARGET_FILE, "\nThis is an appended line.") 50 | assert append_result == f"Content appended to '{_TARGET_FILE}'." 51 | 52 | content = read_file(_TARGET_FILE) 53 | assert content == "This is a test.\nThis is an appended line." 54 | 55 | delete_result = delete_file(_TARGET_FILE) 56 | assert delete_result == f"'{_TARGET_FILE}' has been deleted." 57 | 58 | 59 | if __name__ == "__main__": 60 | main() 61 | -------------------------------------------------------------------------------- /ultimatepython/advanced/meta_class.py: -------------------------------------------------------------------------------- 1 | """ 2 | Metaclass are used to modify a class as it is being created at runtime. 3 | This module shows how a metaclass can add database attributes and tables 4 | to "logic-free" model classes for the developer. 5 | """ 6 | from abc import ABC 7 | 8 | 9 | class ModelMeta(type): 10 | """Model metaclass. 11 | 12 | By studying how SQLAlchemy and Django ORM work under the hood, we can see 13 | a metaclass can add useful abstractions to class definitions at runtime. 14 | That being said, this metaclass is a toy example and does not reflect 15 | everything that happens in either framework. Check out the source code 16 | in SQLAlchemy and Django to see what actually happens: 17 | 18 | https://github.com/sqlalchemy/sqlalchemy 19 | https://github.com/django/django 20 | 21 | The main use cases for a metaclass are (A) to modify a class before 22 | it is visible to a developer and (B) to add a class to a dynamic registry 23 | for further automation. 24 | 25 | Do NOT use a metaclass if a task can be done more simply with class 26 | composition, class inheritance or functions. Simple code is the reason 27 | why Python is attractive for 99% of users. 28 | 29 | For more on metaclass mechanisms, visit the link below: 30 | 31 | https://realpython.com/python-metaclasses/ 32 | """ 33 | 34 | # Model table registry 35 | tables = {} 36 | 37 | def __new__(mcs, name, bases, attrs): 38 | """Factory for modifying the defined class at runtime. 39 | 40 | Here are the following steps that we take: 41 | 42 | 1. Get the defined model class 43 | 2. Add a model_name attribute to it 44 | 3. Add a model_fields attribute to it 45 | 4. Add a model_table attribute to it 46 | 5. Link its model_table to a registry of model tables 47 | 6. Return the modified model class 48 | """ 49 | kls = super().__new__(mcs, name, bases, attrs) 50 | 51 | # Abstract model does not have a `model_name` but a real model does. 52 | # We will leverage this fact later on this routine 53 | if attrs.get("__abstract__") is True: 54 | kls.model_name = None 55 | else: 56 | custom_name = attrs.get("__table_name__") 57 | default_name = kls.__name__.replace("Model", "").lower() 58 | kls.model_name = custom_name if custom_name else default_name 59 | 60 | # Ensure abstract and real models have fields so that 61 | # they can be inherited 62 | kls.model_fields = {} 63 | 64 | # Fill model fields from the parent classes (left-to-right) 65 | for base in bases: 66 | kls.model_fields.update(base.model_fields) 67 | 68 | # Fill model fields from itself 69 | kls.model_fields.update({ 70 | field_name: field_obj 71 | for field_name, field_obj in attrs.items() 72 | if isinstance(field_obj, BaseField) 73 | }) 74 | 75 | # Register a real table (a table with valid `model_name`) to 76 | # the metaclass `table` registry. After all the tables are 77 | # registered, the registry can be sent to a database adapter 78 | # which uses each table to create a properly defined schema 79 | # for the database of choice (i.e. PostgresSQL, MySQL) 80 | if kls.model_name: 81 | kls.model_table = ModelTable(kls.model_name, kls.model_fields) 82 | ModelMeta.tables[kls.model_name] = kls.model_table 83 | else: 84 | kls.model_table = None 85 | 86 | return kls 87 | 88 | @property 89 | def is_registered(cls): 90 | """Check if the model's name is valid and exists in the registry.""" 91 | return cls.model_name and cls.model_name in cls.tables 92 | 93 | 94 | class ModelTable: 95 | """Model table.""" 96 | 97 | def __init__(self, table_name, table_fields): 98 | self.table_name = table_name 99 | self.table_fields = table_fields 100 | 101 | 102 | class BaseField(ABC): 103 | """Base field.""" 104 | 105 | 106 | class CharField(BaseField): 107 | """Character field.""" 108 | 109 | 110 | class IntegerField(BaseField): 111 | """Integer field.""" 112 | 113 | 114 | class BaseModel(metaclass=ModelMeta): 115 | """Base model. 116 | 117 | Notice how `ModelMeta` is injected at the base class. The base class 118 | and its subclasses will be processed by the method `__new__` in the 119 | `ModelMeta` class before being created. 120 | 121 | In short, think of a metaclass as the creator of classes. This is 122 | very similar to how classes are the creator of instances. 123 | """ 124 | __abstract__ = True # This is NOT a real table 125 | row_id = IntegerField() 126 | 127 | 128 | class UserModel(BaseModel): 129 | """User model.""" 130 | __table_name__ = "user_rocks" # This is a custom table name 131 | username = CharField() 132 | password = CharField() 133 | age = CharField() 134 | sex = CharField() 135 | 136 | 137 | class AddressModel(BaseModel): 138 | """Address model.""" 139 | user_id = IntegerField() 140 | address = CharField() 141 | state = CharField() 142 | zip_code = CharField() 143 | 144 | 145 | def main(): 146 | # Real models are given a name at runtime with `ModelMeta` 147 | assert UserModel.model_name == "user_rocks" 148 | assert AddressModel.model_name == "address" 149 | 150 | # Real models are given fields at runtime with `ModelMeta` 151 | assert "row_id" in UserModel.model_fields 152 | assert "row_id" in AddressModel.model_fields 153 | assert "username" in UserModel.model_fields 154 | assert "address" in AddressModel.model_fields 155 | 156 | # Real models are registered at runtime with `ModelMeta` 157 | assert UserModel.is_registered 158 | assert AddressModel.is_registered 159 | 160 | # Real models have a `ModelTable` that can be used for DB setup 161 | assert isinstance(ModelMeta.tables[UserModel.model_name], ModelTable) 162 | assert isinstance(ModelMeta.tables[AddressModel.model_name], ModelTable) 163 | 164 | # Base model is given special treatment at runtime 165 | assert not BaseModel.is_registered 166 | assert BaseModel.model_name is None 167 | assert BaseModel.model_table is None 168 | 169 | # Every model is created by `ModelMeta` 170 | assert isinstance(BaseModel, ModelMeta) 171 | assert all(isinstance(model, ModelMeta) 172 | for model in BaseModel.__subclasses__()) 173 | 174 | # And `ModelMeta` is created by `type` 175 | assert isinstance(ModelMeta, type) 176 | 177 | # And `type` is created by `type` itself 178 | assert isinstance(type, type) 179 | 180 | # And everything in Python is an object! 181 | assert isinstance(BaseModel, object) 182 | assert isinstance(ModelMeta, object) 183 | assert isinstance(type, object) 184 | assert isinstance(object, object) 185 | 186 | 187 | if __name__ == "__main__": 188 | main() 189 | -------------------------------------------------------------------------------- /ultimatepython/advanced/mixin.py: -------------------------------------------------------------------------------- 1 | """ 2 | Mixins are a way to provide implementation details that simplify the work 3 | for a developer to conform to an opaque interface specification. In this 4 | module, we have one request handler interface and two request handler 5 | mixins to illustrate how mixins can make our lives easier when defining 6 | concrete classes. 7 | """ 8 | from abc import ABC, abstractmethod 9 | from dataclasses import dataclass 10 | 11 | 12 | @dataclass 13 | class Request: 14 | """Request data model. 15 | 16 | Assumes only GET requests for simplicity so there is no method 17 | attribute associated with this class. 18 | """ 19 | url: str 20 | user: str 21 | 22 | 23 | class RequestHandler(ABC): 24 | """Request handler interface. 25 | 26 | In the real world, a URL is expected to handle different kinds of HTTP 27 | methods. To support this, we would define a `View` class with a method 28 | that dispatches the request payload to the appropriate HTTP handler. 29 | Afterward, we would register the class to a URL router. Check out 30 | the source code in Django and Flask to see how that works: 31 | 32 | https://github.com/django/django 33 | https://github.com/pallets/flask 34 | """ 35 | 36 | @abstractmethod 37 | def handle(self, request): 38 | """Handle incoming request.""" 39 | raise NotImplementedError 40 | 41 | 42 | class TemplateHandlerMixin(RequestHandler): 43 | """Abstract template mixin for RequestHandler. 44 | 45 | This is a mixin because it's an abstract class that provides a 46 | concrete implementation of the `handle` method. In other words, it 47 | adds additional structure for implementing the `handle` routine. This 48 | class helps if downstream developers typically implement request 49 | handlers that retrieve template content. 50 | """ 51 | template_suffix = ".template" 52 | 53 | def handle(self, request): 54 | template_name = self.get_template_name(request.url) 55 | if not self.is_valid_template(template_name): 56 | return self.handle_invalid_template(request) 57 | return self.render_template(template_name) 58 | 59 | @abstractmethod 60 | def get_template_name(self, request_url): 61 | """Get template name.""" 62 | raise NotImplementedError 63 | 64 | def is_valid_template(self, template_name): 65 | """Check if template name is valid.""" 66 | return template_name.endswith(self.template_suffix) 67 | 68 | @staticmethod 69 | def handle_invalid_template(request): 70 | """Handle request for invalid template.""" 71 | return f"

Invalid entry for {request.url}

" 72 | 73 | @abstractmethod 74 | def render_template(self, template_name): 75 | """Render contents of specified template name.""" 76 | raise NotImplementedError 77 | 78 | 79 | class AuthHandlerMixin(RequestHandler): 80 | """Abstract auth mixin for RequestHandler. 81 | 82 | This is another mixin class where authentication helper methods are 83 | defined in this abstract class and must be implemented in concrete 84 | classes. Notice that the `handle` method is implemented and returns 85 | the output of the parent's `handle` method. This means that we can 86 | continue to chain mixin effects as long as this mixin is to the left 87 | of another mixin in a concrete class MRO. 88 | """ 89 | 90 | def handle(self, request): 91 | if not self.is_valid_user(request.user): 92 | return self.handle_invalid_user(request) 93 | return super().handle(request) 94 | 95 | @abstractmethod 96 | def is_valid_user(self, request_user): 97 | """Check if user is valid.""" 98 | raise NotImplementedError 99 | 100 | @staticmethod 101 | def handle_invalid_user(request): 102 | """Handle request for invalid user.""" 103 | return f"

Access denied for {request.url}

" 104 | 105 | 106 | class TemplateFolderHandler(TemplateHandlerMixin): 107 | """Concrete template handler. 108 | 109 | This concrete class implements the abstract methods of its parent 110 | mixin. By extension, it has implemented everything that is needed 111 | for the `handle` method. 112 | """ 113 | 114 | def __init__(self, template_dir): 115 | self.template_dir = template_dir 116 | 117 | def get_template_name(self, request_url): 118 | return request_url[1:] 119 | 120 | def is_valid_template(self, template_name): 121 | return (super().is_valid_template(template_name) 122 | and template_name in self.template_dir) 123 | 124 | def render_template(self, template_name): 125 | return self.template_dir[template_name] 126 | 127 | 128 | class AdminTemplateHandler(AuthHandlerMixin, TemplateFolderHandler): 129 | """Concrete auth and template handler. 130 | 131 | This concrete class gets the benefits of the previous concrete 132 | class but also gets authentication for free just by implementing 133 | the abstract method of the authentication mixin. 134 | """ 135 | 136 | def __init__(self, admin_users, template_dir): 137 | super().__init__(template_dir) 138 | self.admin_users = admin_users 139 | 140 | def is_valid_user(self, request_user): 141 | return request_user in self.admin_users 142 | 143 | 144 | def main(): 145 | # Handle requests with simple template handler 146 | simple_dir = {"welcome.template": "

Hello world

", 147 | "about.template": "

About me

"} 148 | simple_handler = TemplateFolderHandler(simple_dir) 149 | welcome_from_nobody = Request("/welcome.template", "nobody") 150 | about_from_nobody = Request("/about.template", "nobody") 151 | foo_from_nobody = Request("/foo.bar", "nobody") 152 | assert simple_handler.handle(welcome_from_nobody) == "

Hello world

" 153 | assert simple_handler.handle(about_from_nobody) == "

About me

" 154 | assert simple_handler.handle(foo_from_nobody) == "

Invalid entry for /foo.bar

" 155 | 156 | # Handle requests with admin template handler 157 | admin_users = {"john", "jane"} 158 | admin_dir = {"fqdn.template": "

server.example.com

", 159 | "salary.template": "

123456789.00

"} 160 | admin_handler = AdminTemplateHandler(admin_users, admin_dir) 161 | fqdn_from_john = Request("/fqdn.template", "john") 162 | salary_from_jane = Request("/salary.template", "jane") 163 | salary_from_nobody = Request("/salary.template", "nobody") 164 | foo_from_john = Request("/foo.bar", "john") 165 | assert admin_handler.handle(fqdn_from_john) == "

server.example.com

" 166 | assert admin_handler.handle(salary_from_jane) == "

123456789.00

" 167 | assert admin_handler.handle(salary_from_nobody) == "

Access denied for /salary.template

" 168 | assert admin_handler.handle(foo_from_john) == "

Invalid entry for /foo.bar

" 169 | 170 | 171 | if __name__ == "__main__": 172 | main() 173 | -------------------------------------------------------------------------------- /ultimatepython/advanced/mocking.py: -------------------------------------------------------------------------------- 1 | """ 2 | Mocking objects is a common strategy that developers use to test code that 3 | depends on an external system or external resources for it to work 4 | properly. This module shows how to use mocking to modify an application 5 | server so that it is easier to test. 6 | """ 7 | from collections import Counter 8 | from unittest.mock import MagicMock, PropertyMock, patch 9 | 10 | # Module-level constants 11 | _COUNTER = Counter(pid=1) 12 | _START_SUCCESS = "success" 13 | _START_FAILURE = "failure" 14 | _PROTOCOL_HTTP = "http" 15 | _PROTOCOL_HTTPS = "https" 16 | _FAKE_BASE_URL = f"{_PROTOCOL_HTTPS}://www.google.com:443" 17 | _FAKE_PID = 127 18 | 19 | 20 | class AppServer: 21 | """Application server. 22 | 23 | Normally we don't mock an application server because it is the runtime 24 | environment (AKA central nervous system) for business logic, database 25 | endpoints, network sockets and more. However, this server definition 26 | is lightweight, so it's okay to mock this. 27 | """ 28 | 29 | def __init__(self, host, port, proto): 30 | self._host = host 31 | self._port = port 32 | self._proto = proto 33 | self._pid = -1 34 | 35 | @property 36 | def endpoint(self): 37 | """Get application server endpoint URL.""" 38 | return f"{self._proto}://{self._host}:{self._port}" 39 | 40 | @property 41 | def pid(self): 42 | """Get application server process ID.""" 43 | return self._pid 44 | 45 | @property 46 | def started(self): 47 | """Check if application server is started.""" 48 | return self.pid > 0 49 | 50 | def start(self): 51 | """Start application server.""" 52 | if self.started: 53 | return _START_FAILURE 54 | self._pid = _COUNTER["pid"] 55 | _COUNTER["pid"] += 1 56 | return _START_SUCCESS 57 | 58 | 59 | class FakeServer(AppServer): 60 | """Subclass parent and fake some routines.""" 61 | 62 | @property 63 | def endpoint(self): 64 | """Mock output of endpoint URL.""" 65 | return _FAKE_BASE_URL 66 | 67 | @property 68 | def pid(self): 69 | """Mock output of process ID.""" 70 | return _FAKE_PID 71 | 72 | 73 | def main(): 74 | # This is the original class instance and it works as expected 75 | app_server = AppServer("localhost", 8000, _PROTOCOL_HTTP) 76 | assert app_server.endpoint == f"{_PROTOCOL_HTTP}://localhost:8000" 77 | assert app_server.start() == _START_SUCCESS 78 | assert app_server.started is True 79 | assert app_server.start() == _START_FAILURE 80 | 81 | # But sometimes we cannot test the finer details of a class because 82 | # its methods depend on the availability of external resources. This 83 | # is where mocking comes to the rescue. There are a couple approaches 84 | # that developers use when it comes to mocking 85 | 86 | # Approach 1: Use a `MagicMock` in place of a real class instance 87 | mock_server = MagicMock() 88 | assert isinstance(mock_server, MagicMock) 89 | assert isinstance(mock_server.start_server(), MagicMock) 90 | mock_server.start_server.assert_called() 91 | mock_server.endpoint.assert_not_called() 92 | 93 | # Approach 2: Patch a method in the original class 94 | with patch.object(AppServer, "endpoint", PropertyMock(return_value=_FAKE_BASE_URL)): 95 | patch_server = AppServer("localhost", 8080, _PROTOCOL_HTTP) 96 | assert isinstance(patch_server, AppServer) 97 | assert patch_server.endpoint == _FAKE_BASE_URL 98 | assert patch_server.started is False 99 | assert patch_server.start() == _START_SUCCESS 100 | 101 | # Approach 3: Create a new class that inherits the original class 102 | fake_server = FakeServer("localhost", 8080, _PROTOCOL_HTTP) 103 | assert isinstance(fake_server, AppServer) 104 | assert fake_server.endpoint == _FAKE_BASE_URL 105 | assert fake_server.started is True 106 | assert patch_server.start() == _START_FAILURE 107 | 108 | 109 | if __name__ == "__main__": 110 | main() 111 | -------------------------------------------------------------------------------- /ultimatepython/advanced/mro.py: -------------------------------------------------------------------------------- 1 | """ 2 | MRO stands for method resolution order, and it's used by class definitions 3 | to determine which method will be run by a class instance. This module 4 | shows how the MRO is useful for the classic diamond problem where classes 5 | B and C depend on class A, and class D depends on classes B and C. 6 | """ 7 | 8 | 9 | class BasePlayer: 10 | """Base player.""" 11 | 12 | def ping(self): 13 | return "ping" 14 | 15 | def pong(self): 16 | return "pong" 17 | 18 | 19 | class PongPlayer(BasePlayer): 20 | """Pong player.""" 21 | 22 | def pong(self): 23 | return "PONG" 24 | 25 | 26 | class NeutralPlayer(BasePlayer): 27 | """Neutral player.""" 28 | 29 | 30 | class ConfusedPlayer(PongPlayer, NeutralPlayer): 31 | """Confused player. 32 | 33 | This is what we call the diamond problem, where `BasePlayer` child classes 34 | are the same as `ConfusedPlayer` parent classes. Python has the MRO to 35 | determine which `ping` and `pong` methods are called via the `super()` 36 | call followed by the respective method. 37 | 38 | The `super()` call is usually used without any parameters, which 39 | means that we start the MRO process from the current class upwards. 40 | 41 | For more on the subject, please consult this link: 42 | 43 | https://www.python.org/download/releases/2.3/mro/ 44 | """ 45 | 46 | def ping(self): 47 | """Override `ping` method.""" 48 | return "pINg" 49 | 50 | def ping_pong(self): 51 | """Run `ping` and `pong` in different ways.""" 52 | return [ 53 | self.ping(), 54 | super().ping(), 55 | self.pong(), 56 | super().pong() 57 | ] 58 | 59 | 60 | class IndecisivePlayer(NeutralPlayer, PongPlayer): 61 | """Indecisive player. 62 | 63 | Notice that this class was created successfully without any conflicts 64 | even though the MRO of `ConfusedPlayer` is different. 65 | 66 | Notice that one of the `super()` calls uses additional parameters to 67 | start the MRO process from another class. This is generally discouraged 68 | as this bypasses the default method resolution process. 69 | """ 70 | 71 | def pong(self): 72 | """Override `pong` method.""" 73 | return "pONg" 74 | 75 | def ping_pong(self): 76 | """Run `ping` and `pong` in different ways.""" 77 | return [ 78 | self.ping(), 79 | super().ping(), 80 | self.pong(), 81 | super(PongPlayer, self).pong() # bypass MRO to `BasePlayer` 82 | ] 83 | 84 | 85 | def main(): 86 | # `ConfusedPlayer` methods are resolved from child to parent like this 87 | assert ConfusedPlayer.mro() == [ 88 | ConfusedPlayer, PongPlayer, NeutralPlayer, BasePlayer, object] 89 | 90 | # `IndecisivePlayer` methods are resolved from child to parent like this 91 | assert IndecisivePlayer.mro() == [ 92 | IndecisivePlayer, NeutralPlayer, PongPlayer, BasePlayer, object] 93 | 94 | # Show `ConfusedPlayer` method resolution in action 95 | assert ConfusedPlayer().ping_pong() == ["pINg", "ping", "PONG", "PONG"] 96 | 97 | # Show `IndecisivePlayer` method resolution in action 98 | assert IndecisivePlayer().ping_pong() == ["ping", "ping", "pONg", "pong"] 99 | 100 | class_creation_failed = False 101 | try: 102 | # Creating a new class `ConfusedPlayer` and `IndecisivePlayer` 103 | # results in a `TypeError` because both classes do not have 104 | # matching MRO outputs. This means that they cannot be reconciled 105 | # as one class. Hence, `MissingPlayer` will not be created 106 | type("MissingPlayer", (ConfusedPlayer, IndecisivePlayer), {}) 107 | except TypeError: 108 | class_creation_failed = True 109 | assert class_creation_failed is True 110 | 111 | 112 | if __name__ == "__main__": 113 | main() 114 | -------------------------------------------------------------------------------- /ultimatepython/advanced/regex.py: -------------------------------------------------------------------------------- 1 | """ 2 | Using regular expressions is a robust way to search for text. Implementing 3 | them is difficult but Python provides a package for us to use them easily. 4 | This module shows a few examples of how to use the `re` package to search 5 | predefined text snippets stored in module-level constants. 6 | """ 7 | import re 8 | 9 | # Module-level constants 10 | _TEXT_HELLO = "World Hello Hello" 11 | _TEXT_NAMES = "John, Jane" 12 | _TEXT_ABC123 = "abc123" 13 | _TEXT_BYE = "Bye for now" 14 | _TEXT_EMAILS = "My work email is kayode@dodo.ng while nerdthejohn@yahoo.com is personal" 15 | 16 | 17 | def main(): 18 | # Running `search` with "Hello" has a match for first Hello 19 | assert re.search(r"Hello", _TEXT_HELLO).start() == 6 20 | 21 | # Running `search` with "Hello$" has a match for last Hello 22 | assert re.search(r"Hello$", _TEXT_HELLO).start() == 12 23 | 24 | # Running `search` with "(Hello) (Hello)" has matches for Hello 25 | assert re.search(r"(Hello) (Hello)", _TEXT_HELLO).groups() == ("Hello", "Hello") 26 | 27 | # Running `findall` with "Hi \w+" has a list of strings 28 | assert re.findall(r"\w+", _TEXT_NAMES) == ["John", "Jane"] 29 | 30 | # Running `findall` with "[a-z]+@[a-z]+\.[a-z]+" has a list of email strings 31 | assert re.findall(r"[a-z]+@[a-z]+\.[a-z]+", _TEXT_EMAILS) == ["kayode@dodo.ng", "nerdthejohn@yahoo.com"] 32 | 33 | # Running `match` with "[123]+" has nothing 34 | assert re.match(r"[123]+", _TEXT_ABC123) is None 35 | 36 | # Running `match` with "[abc]+" has a match for abc 37 | assert re.match(r"[abc]+", _TEXT_ABC123).group(0) == "abc" 38 | 39 | # Running `fullmatch` with "[\w]+" has nothing 40 | assert re.fullmatch(r"[\w]+", _TEXT_BYE) is None 41 | 42 | # Running `fullmatch` with "[\w ]+" has a full match 43 | assert re.fullmatch(r"[\w ]+", _TEXT_BYE).group(0) == _TEXT_BYE 44 | 45 | # To learn more about regular expressions: 46 | # https://en.wikipedia.org/wiki/Regular_expression 47 | # https://github.com/ziishaned/learn-regex 48 | 49 | # To play around with regular expressions in the browser: 50 | # https://regex101.com 51 | 52 | 53 | if __name__ == "__main__": 54 | main() 55 | -------------------------------------------------------------------------------- /ultimatepython/advanced/thread.py: -------------------------------------------------------------------------------- 1 | """ 2 | Threaded programming is used by developers to improve the performance of 3 | an application. This module shows how a multiplication operation with 4 | some delay can be parallelized using `ThreadPoolExecutor`. 5 | 6 | A good grasp of threads is recommended, but not necessary, before 7 | reading the code below. 8 | 9 | Here are some resources to learn more about threads: 10 | 11 | https://realpython.com/intro-to-python-threading/ 12 | https://docs.python.org/3/library/threading.html 13 | 14 | Python threads are not suitable for CPU-heavy tasks in the CPython 15 | interpreter due to the GIL. To address this, we typically resort to 16 | forking processes or running C externally. 17 | 18 | Here are some resources to learn more about the GIL: 19 | 20 | https://realpython.com/python-gil/ 21 | https://wiki.python.org/moin/GlobalInterpreterLock 22 | """ 23 | import time 24 | from concurrent.futures import ThreadPoolExecutor, as_completed 25 | from datetime import datetime 26 | 27 | # Module-level constants 28 | _MULTIPLY_DELAY = 0.01 # delay is long enough for threads to be faster 29 | 30 | 31 | def multiply_by_two(item): 32 | """This multiplication has a small delay.""" 33 | time.sleep(_MULTIPLY_DELAY) 34 | return item * 2 35 | 36 | 37 | def run_thread_workers(work, data): 38 | """Run thread workers that invoke work on each data element. 39 | 40 | The inspiration for this function comes directly from an example 41 | in the Python 3.x documentation: 42 | 43 | https://docs.python.org/3/library/concurrent.futures.html 44 | """ 45 | results = set() 46 | 47 | # We can use a with statement to ensure workers are cleaned up promptly 48 | with ThreadPoolExecutor() as executor: 49 | # Note that results are returned out of order 50 | work_queue = (executor.submit(work, item) for item in data) 51 | for future in as_completed(work_queue): 52 | results.add(future.result()) 53 | 54 | return results 55 | 56 | 57 | def main(): 58 | original_data = {num for num in range(5)} 59 | expected_data = {(item * 2) for item in original_data} 60 | 61 | # Let's get the data using the simple approach 62 | simple_start = datetime.now() 63 | simple_data = {multiply_by_two(item) for item in original_data} 64 | simple_duration = datetime.now() - simple_start 65 | 66 | # The simple approach has the expected data 67 | assert simple_data == expected_data 68 | 69 | # Let's get the data using the threaded approach 70 | thread_start = datetime.now() 71 | thread_data = run_thread_workers(multiply_by_two, original_data) 72 | thread_duration = datetime.now() - thread_start 73 | 74 | # The threaded approach has the expected data 75 | assert thread_data == expected_data 76 | 77 | # The threaded approach is faster than the simple approach in this case 78 | # because a blocking I/O call like time.sleep forces the current thread 79 | # to yield its control over to a waiting thread to start running. That 80 | # means the threaded approach can run blocking operations in parallel. 81 | # The cost of creating threads is somewhat cheap which means we often 82 | # create more than one thread to speed up I/O-heavy workloads 83 | assert thread_duration < simple_duration 84 | 85 | 86 | if __name__ == "__main__": 87 | main() 88 | -------------------------------------------------------------------------------- /ultimatepython/advanced/weak_ref.py: -------------------------------------------------------------------------------- 1 | """ 2 | Weak references are a way to help the Python interpreter remove unused data 3 | more easily. This module shows how it can be used to keep a server registry 4 | up-to-date as it explicitly sets up and implicitly tears down servers as 5 | the program enters and leaves a function scope. 6 | """ 7 | import weakref 8 | from uuid import uuid4 9 | 10 | # Module-level constants 11 | _CLOUD_PROVIDER = "aws" 12 | _CLOUD_APPS = ["yelp", "pinterest", "uber", "twitter"] 13 | _CLOUD_APP_COMPONENTS = ("db", "web", "cache") 14 | 15 | 16 | class Server: 17 | """General server.""" 18 | 19 | @classmethod 20 | def create(cls, role, provider=_CLOUD_PROVIDER): 21 | """Create server with autogenerated SSID.""" 22 | return cls(uuid4().hex, role, provider) 23 | 24 | def __init__(self, ssid, role, provider): 25 | self.ssid = ssid 26 | self.role = role 27 | self.provider = provider 28 | 29 | 30 | class ServerRegistry: 31 | """Server registry with weak references.""" 32 | 33 | def __init__(self): 34 | self._servers = weakref.WeakSet() 35 | 36 | @property 37 | def servers(self): 38 | """Get set of added servers.""" 39 | return {s for s in self._servers} 40 | 41 | @property 42 | def server_count(self): 43 | """Get count of added servers.""" 44 | return len(self.servers) 45 | 46 | def add(self, server): 47 | """Add server to registry.""" 48 | self._servers.add(server) 49 | 50 | 51 | def setup_and_teardown_servers(registry): 52 | """Explicitly setup and implicitly teardown servers.""" 53 | app_servers = {} 54 | 55 | # Let's create all the servers and store them properly 56 | for app in _CLOUD_APPS: 57 | app_servers[app] = set() 58 | for component in _CLOUD_APP_COMPONENTS: 59 | server = Server.create(f"{app}_{component}") 60 | registry.add(server) 61 | app_servers[app].add(server) 62 | 63 | # All of these counts are equivalent. This is no surprise since our 64 | # for loop unconditionally creates a server for every permutation of 65 | # apps and components. The loop also adds each server to the registry 66 | # and dictionary unconditionally 67 | assert ( 68 | registry.server_count 69 | == len(_CLOUD_APPS) * len(_CLOUD_APP_COMPONENTS) 70 | == len([(app, server) 71 | for app, servers in app_servers.items() 72 | for server in servers]) 73 | ) 74 | 75 | # What's fascinating is that servers go away when we leave the 76 | # scope of this function. In this function, each server is created and 77 | # strongly referenced by the `app_servers` variable. When we leave this 78 | # function, the `app_servers` variable no longer exists which brings 79 | # the reference count for each server from 1 to 0. A reference count of 80 | # 0 for each server triggers the garbage collector to run the cleanup 81 | # process for all the servers in this function scope 82 | 83 | 84 | def main(): 85 | # Initialize a server registry 86 | registry = ServerRegistry() 87 | 88 | # Setup and teardown servers with the registry 89 | setup_and_teardown_servers(registry) 90 | 91 | # Notice that our registry does not remember the servers because 92 | # it uses weak references. Because there are no strong references 93 | # to the created servers in `setup_and_teardown_servers`, the 94 | # garbage collector cleans up the servers. This behavior is usually 95 | # desired if we want to keep our software memory-efficient 96 | assert registry.servers == set() 97 | assert registry.server_count == 0 98 | 99 | 100 | if __name__ == "__main__": 101 | main() 102 | -------------------------------------------------------------------------------- /ultimatepython/classes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangsam/ultimate-python/26887e626b9509aa56f99da604399ed800405aaa/ultimatepython/classes/__init__.py -------------------------------------------------------------------------------- /ultimatepython/classes/abstract_class.py: -------------------------------------------------------------------------------- 1 | """ 2 | Abstract class is an extension of a basic class. Like a basic class, an 3 | abstract class has methods and state. Unlike a basic class, it inherits 4 | the `ABC` class and has at least one `abstractmethod`. That means we 5 | cannot create an instance directly from its constructor. In this module, 6 | we will create an abstract class and two concrete classes. 7 | 8 | For more about abstract classes, click the link below: 9 | 10 | https://www.python.org/dev/peps/pep-3119/ 11 | """ 12 | from abc import ABC, abstractmethod 13 | 14 | 15 | class Employee(ABC): 16 | """Abstract definition of an employee. 17 | 18 | Any employee can work and relax. The way that one type of employee 19 | can work and relax is different from another type of employee. 20 | """ 21 | 22 | def __init__(self, name, title): 23 | self.name = name 24 | self.title = title 25 | 26 | def __str__(self): 27 | return self.name 28 | 29 | @abstractmethod 30 | def do_work(self): 31 | """Do something for work.""" 32 | raise NotImplementedError 33 | 34 | @abstractmethod 35 | def do_relax(self): 36 | """Do something to relax.""" 37 | raise NotImplementedError 38 | 39 | 40 | class Engineer(Employee): 41 | """Concrete definition of an engineer. 42 | 43 | The Engineer class is concrete because it implements every 44 | `abstractmethod` that was not implemented above. 45 | 46 | Notice that we leverage the parent's constructor when creating 47 | this object. We also define `do_refactor` for an engineer, which 48 | is something that a manager prefers not to do. 49 | """ 50 | 51 | def __init__(self, name, title, skill): 52 | super().__init__(name, title) 53 | self.skill = skill 54 | 55 | def do_work(self): 56 | return f"{self} is coding in {self.skill}" 57 | 58 | def do_relax(self): 59 | return f"{self} is watching YouTube" 60 | 61 | def do_refactor(self): 62 | """Do the hard work of refactoring code, unlike managers.""" 63 | return f"{self} is refactoring code" 64 | 65 | 66 | class Manager(Employee): 67 | """Concrete definition of a manager. 68 | 69 | The Manager class is concrete for the same reasons as the Engineer 70 | class is concrete. Notice that a manager has direct reports and 71 | has the responsibility of hiring people on the team, unlike an 72 | engineer. 73 | """ 74 | 75 | def __init__(self, name, title, direct_reports): 76 | super().__init__(name, title) 77 | self.direct_reports = direct_reports 78 | 79 | def do_work(self): 80 | return f"{self} is meeting up with {len(self.direct_reports)} reports" 81 | 82 | def do_relax(self): 83 | return f"{self} is taking a trip to the Bahamas" 84 | 85 | def do_hire(self): 86 | """Do the hard work of hiring employees, unlike engineers.""" 87 | return f"{self} is hiring employees" 88 | 89 | 90 | def main(): 91 | # Declare two engineers 92 | engineer_john = Engineer("John Doe", "Software Engineer", "Android") 93 | engineer_jane = Engineer("Jane Doe", "Software Engineer", "iOS") 94 | engineers = [engineer_john, engineer_jane] 95 | 96 | # These engineers are employees but not managers 97 | assert all(isinstance(engineer, Employee) for engineer in engineers) 98 | assert all(not isinstance(engineer, Manager) for engineer in engineers) 99 | 100 | # Engineers can work, relax and refactor 101 | assert engineer_john.do_work() == "John Doe is coding in Android" 102 | assert engineer_john.do_relax() == "John Doe is watching YouTube" 103 | assert engineer_john.do_refactor() == "John Doe is refactoring code" 104 | 105 | # Declare manager with engineers as direct reports 106 | manager_max = Manager("Max Doe", "Engineering Manager", engineers) 107 | 108 | # Managers are employees but not engineers 109 | assert isinstance(manager_max, Employee) 110 | assert not isinstance(manager_max, Engineer) 111 | 112 | # Managers can work, relax and hire 113 | assert manager_max.do_work() == "Max Doe is meeting up with 2 reports" 114 | assert manager_max.do_relax() == "Max Doe is taking a trip to the Bahamas" 115 | assert manager_max.do_hire() == "Max Doe is hiring employees" 116 | 117 | 118 | if __name__ == "__main__": 119 | main() 120 | -------------------------------------------------------------------------------- /ultimatepython/classes/basic_class.py: -------------------------------------------------------------------------------- 1 | """ 2 | A class is made up of methods and state. This allows code and data to be 3 | combined as one logical entity. This module defines a basic car class, 4 | creates a car instance and uses it for demonstration purposes. 5 | """ 6 | from inspect import isfunction, ismethod, signature 7 | 8 | 9 | class Car: 10 | """Basic definition of a car. 11 | 12 | We begin with a simple mental model of what a car is. That way, we 13 | can start exploring the core concepts that are associated with a 14 | class definition. 15 | """ 16 | 17 | def __init__(self, make, model, year, miles): 18 | """Constructor logic.""" 19 | self.make = make 20 | self.model = model 21 | self.year = year 22 | self.miles = miles 23 | 24 | def __repr__(self): 25 | """Formal representation for developers.""" 26 | return f"" 27 | 28 | def __str__(self): 29 | """Informal representation for users.""" 30 | return f"{self.make} {self.model} ({self.year})" 31 | 32 | def drive(self, rate_in_mph): 33 | """Drive car at a certain rate in MPH.""" 34 | return f"{self} is driving at {rate_in_mph} MPH" 35 | 36 | 37 | def main(): 38 | # Create a car with the provided class constructor 39 | car = Car("Bumble", "Bee", 2000, 200000.0) 40 | 41 | # Formal representation is good for debugging issues 42 | assert repr(car) == "" 43 | 44 | # Informal representation is good for user output 45 | assert str(car) == "Bumble Bee (2000)" 46 | 47 | # Call a method on the class constructor 48 | assert car.drive(75) == "Bumble Bee (2000) is driving at 75 MPH" 49 | 50 | # As a reminder: everything in Python is an object! And that applies 51 | # to classes in the most interesting way - because they're not only 52 | # subclasses of object - they are also instances of object. This 53 | # means that we can modify the `Car` class at runtime, just like any 54 | # other piece of data we define in Python 55 | assert issubclass(Car, object) and isinstance(Car, object) 56 | 57 | # To emphasize the idea that everything is an object, let's look at 58 | # the `drive` method in more detail 59 | driving = getattr(car, "drive") 60 | 61 | # The variable method is the same as the instance method 62 | assert driving == car.drive 63 | 64 | # The variable method is bound to the instance 65 | assert driving.__self__ == car 66 | 67 | # That is why `driving` is considered a method and not a function 68 | assert ismethod(driving) and not isfunction(driving) 69 | 70 | # And there is only one parameter for `driving` because `__self__` 71 | # binding is implicit 72 | driving_params = signature(driving).parameters 73 | assert len(driving_params) == 1 74 | assert "rate_in_mph" in driving_params 75 | 76 | 77 | if __name__ == "__main__": 78 | main() 79 | -------------------------------------------------------------------------------- /ultimatepython/classes/encapsulation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Encapsulation is a feature of OOP that allows you to hide the 3 | implementation details of a class from its users. 4 | Encapsulation allows us to limit the access of certain attributes 5 | within a class. This prevents users from directly accessing and modifying such 6 | attributes from outside the class. Instead, users must use methods to access and 7 | modify attributes. 8 | """ 9 | import secrets 10 | 11 | # Module-level constant 12 | _INVALID_AMOUNT_MESSAGE = "Invalid amount." 13 | _INSUFFICIENT_BALANCE_MESSAGE = "Insufficient balance." 14 | 15 | 16 | class BankAccount: 17 | def __init__(self, account_holder_name): 18 | """ 19 | In Python, a class attribute can be made private by prefixing it with two underscores. 20 | This makes it inaccessible to users outside the class. 21 | By default, class attributes are public. Therefore, they can be accessed and modified 22 | outside the class. 23 | 24 | Here, account_number and balance are private while account_holder_name is public. 25 | """ 26 | self.account_holder_name = account_holder_name 27 | """ 28 | The account number is generated automatically using the randbelow function from 29 | the random module when a new instance of the class is created. 30 | The balance is set to 0 by default. 31 | """ 32 | self.__account_number = secrets.randbelow(10**10) # generate a random account number of 10 digits. 33 | self.__balance = 0 34 | 35 | def deposit(self, balance): 36 | """ 37 | The deposit function is used to add new balance to the account. 38 | The provided balance is added to the existing balance. 39 | """ 40 | self.__balance += int(balance) 41 | 42 | def withdraw(self, balance): 43 | """ 44 | The withdrawal method is used to deduct the balance from the account. 45 | In case there is insufficient balance, or the input is invalid, 46 | a value error is raised. 47 | """ 48 | if balance <= 0: 49 | raise ValueError(_INVALID_AMOUNT_MESSAGE) 50 | if balance > self.__balance: 51 | raise ValueError(_INSUFFICIENT_BALANCE_MESSAGE) 52 | 53 | self.__balance -= balance 54 | 55 | def get_balance(self): 56 | """ 57 | This function returns the available balance in the account. 58 | """ 59 | return self.__balance 60 | 61 | def get_account_number(self): 62 | """ 63 | The account number is generated randomly when a new instance of the class is created. 64 | Since the attribute is also private, it cannot be accessed directly from outside the class. 65 | The get_account_number method allows you to access the account number outside the class. 66 | But since we do not define a setter method for this variable, we cannot modify it outside the class. 67 | Therefore, the account number generated while creating an object of the BankAccount class cannot be changed 68 | but can only be read using this function. 69 | """ 70 | return self.__account_number 71 | 72 | def __set_account_number(self, number): 73 | """ 74 | This is a private method. Similar to private variables, 75 | private methods also cannot be accessed outside the class. 76 | """ 77 | self.__account_number = number 78 | 79 | def remove_account_details(self): 80 | """ 81 | This method is used to reset the account details. 82 | Here, the __set_account_number function is private. 83 | This, it cannot be called from outside the class. 84 | However, the remove_account_details calls the function from 85 | inside the class and as it is a public method, it can be called from 86 | outside the class. 87 | """ 88 | self.__balance = 0 89 | self.__set_account_number(0) 90 | self.account_holder_name = "" 91 | 92 | 93 | def main(): 94 | # Account names constants. 95 | user1 = "John Doe" 96 | user2 = "Jane Doe" 97 | 98 | # Account instances. 99 | account1 = BankAccount(user1) 100 | account2 = BankAccount(user2) 101 | 102 | assert account1.account_holder_name == user1 103 | assert account2.account_holder_name == user2 104 | 105 | # Deposit amount and check if the balance is updated. 106 | account1.deposit(100) 107 | assert account1.get_balance() == 100 108 | 109 | # Withdraw amount and check if the balance is updated. 110 | account1.withdraw(50) 111 | assert account1.get_balance() == 50 112 | 113 | # validating invalid amounts. 114 | error_inputs = [-10, 0, 150] 115 | for input in error_inputs: 116 | try: 117 | account1.withdraw(input) 118 | except ValueError as e: 119 | assert str(e) in {_INSUFFICIENT_BALANCE_MESSAGE, _INVALID_AMOUNT_MESSAGE} 120 | 121 | # Remove account details and assert values. 122 | account1.remove_account_details() 123 | 124 | assert account1.get_balance() == 0 125 | assert account1.get_account_number() == 0 126 | assert account1.account_holder_name == "" 127 | 128 | 129 | if __name__ == "__main__": 130 | main() 131 | -------------------------------------------------------------------------------- /ultimatepython/classes/exception_class.py: -------------------------------------------------------------------------------- 1 | """ 2 | Exception classes are used to indicate that something has gone wrong with 3 | the program at runtime. Functions use the `raise` keyword, if an error is 4 | anticipated, and specify the exception class they intend to throw. This 5 | module defines a handful of custom exception classes and shows how they 6 | can be used in the context of a function. 7 | """ 8 | 9 | 10 | class CustomError(Exception): 11 | """Custom class of errors. 12 | 13 | This is a custom exception for any issues that arise in this module. 14 | One of the reasons why developers design a class like this is for 15 | consumption by downstream services and command-line tools. 16 | 17 | If we designed a standalone application with no downstream consumers, then 18 | it makes little sense to define a custom hierarchy of exceptions. In that 19 | case, we should use the existing hierarchy of builtin exception 20 | classes which are listed in the Python docs: 21 | 22 | https://docs.python.org/3/library/exceptions.html 23 | """ 24 | 25 | 26 | class DivisionError(CustomError): 27 | """Any division error that results from invalid input. 28 | 29 | This exception can be subclassed with the following exceptions if they 30 | happen enough across the codebase: 31 | 32 | - ZeroDivisorError 33 | - NegativeDividendError 34 | - NegativeDivisorError 35 | 36 | That being said, there's a point of diminishing returns when we design 37 | too many exceptions. It is better to design few exceptions that many 38 | developers handle than design many exceptions that few developers handle. 39 | """ 40 | 41 | 42 | def divide_positive_numbers(dividend, divisor): 43 | """Divide a positive number by another positive number. 44 | 45 | Writing a program in this style is considered defensive programming. 46 | For more on this programming style, check the Wikipedia link below: 47 | 48 | https://en.wikipedia.org/wiki/Defensive_programming 49 | """ 50 | if dividend <= 0: 51 | raise DivisionError(f"Non-positive dividend: {dividend}") 52 | elif divisor <= 0: 53 | raise DivisionError(f"Non-positive divisor: {divisor}") 54 | return dividend // divisor 55 | 56 | 57 | def main(): 58 | # Exception classes are no different from concrete classes in that 59 | # they all have inheritance baked in 60 | assert issubclass(DivisionError, CustomError) 61 | 62 | # Try a couple of inputs that are known to throw an error based on 63 | # the exceptions thrown in `divide_positive_numbers` 64 | for dividend, divisor in [(0, 1), (1, 0), (-1, 1), (1, -1)]: 65 | division_failed = False 66 | try: 67 | divide_positive_numbers(dividend, divisor) 68 | except DivisionError as e: 69 | division_failed = True 70 | assert str(e).startswith("Non-positive") 71 | assert division_failed is True 72 | 73 | # Now let's do it correctly to skip all the exceptions 74 | result = divide_positive_numbers(1, 1) 75 | assert result == 1 76 | 77 | 78 | if __name__ == "__main__": 79 | main() 80 | -------------------------------------------------------------------------------- /ultimatepython/classes/inheritance.py: -------------------------------------------------------------------------------- 1 | """ 2 | Inheritance is a way to reuse code and data from a parent class. This 3 | allows us to avoid repeating ourselves and to build upon existing 4 | functionality. This module defines a basic vehicle class, creates a car 5 | class that inherits from vehicle, then creates a truck class that 6 | inherits from car and use it for demonstration purposes. 7 | """ 8 | from inspect import isfunction, ismethod 9 | 10 | 11 | class Vehicle: 12 | """Basic definition of a vehicle. 13 | 14 | We begin with a simple mental model of what a vehicle is. It has 15 | a make, model, year, and miles. That way, we can start exploring 16 | the core concepts that are associated with a class definition. 17 | """ 18 | 19 | def __init__(self, make, model, year, miles): 20 | """Construct a vehicle with make, model, year, and miles.""" 21 | self.make = make 22 | self.model = model 23 | self.year = year 24 | self.miles = miles 25 | 26 | def __repr__(self): 27 | """Return the formal representation of a vehicle.""" 28 | return f"" 29 | 30 | def __str__(self): 31 | """Return the informal representation of a vehicle.""" 32 | return f"{self.make} {self.model} ({self.year})" 33 | 34 | def drive(self, rate_in_mph): 35 | """Drive a vehicle at a certain rate in MPH.""" 36 | return f"{self} is driving at {rate_in_mph} MPH" 37 | 38 | 39 | class Car(Vehicle): 40 | """Definition of a car. 41 | 42 | We inherit from the vehicle class to reuse the code and data that 43 | we have already defined. In addition, we add a new attribute called 44 | `wheels` to the car class. This is an example of extending the 45 | functionality of a parent class. In __init__, we call the parent 46 | constructor with the `super` function. This is a way to invoke the 47 | parent constructor without having to explicitly name the parent 48 | class. We also override the method `__repr__` to have a different 49 | output than the vehicle. 50 | """ 51 | 52 | def __init__(self, make, model, year, miles): 53 | """Construct a car with make, model, year, miles, and wheels.""" 54 | super().__init__(make, model, year, miles) 55 | self.wheels = 4 56 | 57 | def __repr__(self): 58 | """Return the formal representation of a car.""" 59 | return f"" 60 | 61 | 62 | class Truck(Vehicle): 63 | """Definition of a truck. 64 | 65 | We inherit from vehicle just like we did with the car class. In this case we 66 | will also override the method `drive` to have a different output than the 67 | car and the vehicle. 68 | """ 69 | 70 | def __init__(self, make, model, year, miles): 71 | """Construct a truck with make, model, year, miles, and wheels.""" 72 | super().__init__(make, model, year, miles) 73 | self.wheels = 6 74 | 75 | def __repr__(self): 76 | """Return the formal representation of a truck.""" 77 | return f"" 78 | 79 | def drive(self, rate_in_mph): 80 | """Drive a truck at a certain rate in MPH.""" 81 | return f"{self} is driving a truck at {rate_in_mph} MPH" 82 | 83 | 84 | def main(): 85 | # Create a vehicle with the provided class constructor 86 | vehicle = Vehicle("Mistery Machine", "Van", 1969, 100000.0) 87 | 88 | # Formal representation 89 | assert repr(vehicle) == "" 90 | 91 | # Informal representation 92 | assert str(vehicle) == "Mistery Machine Van (1969)" 93 | 94 | # Call a method on the class constructor 95 | assert vehicle.drive(50) == "Mistery Machine Van (1969) is driving at 50 MPH" 96 | 97 | # Check the type of the method drive 98 | assert ismethod(vehicle.drive) and not isfunction(vehicle.drive) 99 | 100 | # Now we create a car with the provided class constructor 101 | car = Car("DeLorean", "DMC-12", 1982, 220000.0) 102 | 103 | # The informal representation is similar to the vehicle 104 | assert str(car) == "DeLorean DMC-12 (1982)" 105 | 106 | # But the formal representation is different because we included 107 | # the wheels attribute 108 | assert repr(car) == "" 109 | 110 | # And we can check the type of the method drive like we did with 111 | # the vehicle 112 | assert ismethod(car.drive) and not isfunction(car.drive) 113 | 114 | # If we call the method drive, we can see that we did not 115 | # write any code for the car class, but we can still use it 116 | # because it is inherited from the vehicle class and the 117 | # behavior is the same as the vehicle 118 | assert car.drive(50) == "DeLorean DMC-12 (1982) is driving at 50 MPH" 119 | 120 | # Now we create a truck with the provided class constructor 121 | truck = Truck("Optimus Prime", "Truck", 1984, 1000000.0) 122 | 123 | # Like car and vehicle, the informal representation is similar 124 | assert str(truck) == "Optimus Prime Truck (1984)" 125 | 126 | # And the formal representation is different from the vehicle 127 | # because we included the wheels attribute 128 | assert repr(truck) == "" 129 | 130 | # And we can check the type of the method drive like we did with 131 | # the vehicle 132 | assert ismethod(truck.drive) and not isfunction(truck.drive) 133 | 134 | # For the last part, we can see that the method drive is different 135 | # for the truck 136 | assert truck.drive(50) == "Optimus Prime Truck (1984) is driving a truck at 50 MPH" 137 | 138 | 139 | if __name__ == "__main__": 140 | main() 141 | -------------------------------------------------------------------------------- /ultimatepython/classes/iterator_class.py: -------------------------------------------------------------------------------- 1 | """ 2 | Iterator classes implement the `__iter__` and `__next__` magic methods. 3 | This module defines an employee iterator class that iterates through each 4 | employee in a hierarchy one-by-one. This module also shows how a similar 5 | approach can be achieved with a generator function. 6 | """ 7 | 8 | # Module-level constants 9 | _ITERATION_MESSAGE = "Cyclic loop detected" 10 | 11 | 12 | class Employee: 13 | """Generic employee class. 14 | 15 | For this module, we're going to remove the inheritance hierarchy 16 | in `abstract_class` and make all employees have a `direct_reports` 17 | attribute. 18 | 19 | Notice that if we continue adding employees in the `direct_reports` 20 | attribute, those same employees have a `direct_reports` attribute 21 | as well. 22 | 23 | The tree-like structure of this class resembles the Composite design 24 | pattern, and it can be found on Wikipedia: 25 | 26 | https://en.wikipedia.org/wiki/Composite_pattern 27 | 28 | Design patterns are battle-tested ways of structuring code to handle 29 | common problems encountered while writing software in a team setting. 30 | Here's a Wikipedia link for more design patterns: 31 | 32 | https://en.wikipedia.org/wiki/Design_Patterns 33 | """ 34 | 35 | def __init__(self, name, title, direct_reports): 36 | self.name = name 37 | self.title = title 38 | self.direct_reports = direct_reports 39 | 40 | 41 | class IterationError(RuntimeError): 42 | """Any error that comes while iterating through objects. 43 | 44 | Notice that this class inherits from `RuntimeError`. That way dependent 45 | functions can handle this exception using either the package hierarchy 46 | or the native hierarchy. 47 | """ 48 | 49 | 50 | class EmployeeIterator: 51 | """Employee iterator. 52 | 53 | An iterator class is composed of three methods: 54 | 55 | - A constructor which defines data structures 56 | - An iterator returns the instance itself 57 | - A retriever which gets the next element 58 | 59 | We do this by providing what are called magic methods. Other people 60 | call them d-under methods because they have double-underscores. 61 | 62 | An iterator class resembles the Iterator design pattern, and it 63 | can be found on Wikipedia: 64 | 65 | https://en.wikipedia.org/wiki/Iterator_pattern 66 | """ 67 | 68 | def __init__(self, employee): 69 | """Constructor logic.""" 70 | self.employees_to_visit = [employee] 71 | self.employees_visited = set() 72 | 73 | def __iter__(self): 74 | """Iterator is self by convention.""" 75 | return self 76 | 77 | def __next__(self): 78 | """Return the next employee available. 79 | 80 | The logic may seem complex, but it's actually a common algorithm 81 | used in traversing a relationship graph. It is called depth-first 82 | search, and it can be found on Wikipedia: 83 | 84 | https://en.wikipedia.org/wiki/Depth-first_search 85 | """ 86 | if not self.employees_to_visit: 87 | raise StopIteration 88 | employee = self.employees_to_visit.pop() 89 | if employee.name in self.employees_visited: 90 | raise IterationError(_ITERATION_MESSAGE) 91 | self.employees_visited.add(employee.name) 92 | for report in employee.direct_reports: 93 | self.employees_to_visit.append(report) 94 | return employee 95 | 96 | 97 | def employee_generator(top_employee): 98 | """Employee generator. 99 | 100 | It is essentially the same logic as above except constructed as a 101 | generator function. Notice that the generator code is in a single 102 | place, whereas the iterator code is in multiple places. Also notice 103 | that we are using the `yield` keyword in the generator code. 104 | 105 | It is a matter of preference and context that we choose one approach 106 | over the other. If we want something simple, go with the generator. 107 | Otherwise, go with the iterator to fulfill more demanding requirements. 108 | In this case, examples of such requirements are tasks like encrypting 109 | the employee's username, running statistics on iterated employees or 110 | excluding the reports under a particular set of managers. 111 | 112 | For more on the subject of using a function versus a class, check 113 | out this post from Microsoft Developer Blogs: 114 | 115 | https://devblogs.microsoft.com/python/idiomatic-python-functions-versus-classes/ 116 | """ 117 | to_visit = [top_employee] 118 | visited = set() 119 | while len(to_visit) > 0: 120 | employee = to_visit.pop() 121 | if employee.name in visited: 122 | raise IterationError(_ITERATION_MESSAGE) 123 | visited.add(employee.name) 124 | for report in employee.direct_reports: 125 | to_visit.append(report) 126 | yield employee 127 | 128 | 129 | def main(): 130 | # Manager with two direct reports 131 | manager = Employee("Max Doe", "Engineering Manager", [ 132 | Employee("John Doe", "Software Engineer", []), 133 | Employee("Jane Doe", "Software Engineer", []) 134 | ]) 135 | 136 | # We should provide the same three employees in the same order regardless 137 | # of whether we use the iterator class or the generator function 138 | employees = [emp for emp in EmployeeIterator(manager)] 139 | assert employees == [emp for emp in employee_generator(manager)] 140 | assert len(employees) == 3 141 | 142 | # Make sure that the employees are who we expect them to be 143 | assert all(isinstance(emp, Employee) for emp in employees) 144 | 145 | # This is not a good day for this company 146 | hacker = Employee("Unknown", "Hacker", []) 147 | hacker.direct_reports.append(hacker) 148 | 149 | for iter_obj in (EmployeeIterator, employee_generator): 150 | call_failed = False 151 | try: 152 | list(iter_obj(hacker)) 153 | except IterationError as e: 154 | call_failed = True 155 | assert str(e) == _ITERATION_MESSAGE 156 | assert call_failed is True 157 | 158 | 159 | if __name__ == "__main__": 160 | main() 161 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangsam/ultimate-python/26887e626b9509aa56f99da604399ed800405aaa/ultimatepython/data_structures/__init__.py -------------------------------------------------------------------------------- /ultimatepython/data_structures/comprehension.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module shows one-liner comprehensions where we make lists, tuples, 3 | sets and dictionaries by looping through iterators. 4 | """ 5 | 6 | 7 | def main(): 8 | # One interesting fact about data structures is that we can build 9 | # them with comprehensions. Let's explain how the first one works: 10 | # we just want to create zeros so our expression is set to `0` 11 | # since no computing is required; because `0` is a constant value, 12 | # we can set the item that we compute with to `_`; and we want to 13 | # create five zeros, so we set the iterator as `range(5)` 14 | assert [0 for _ in range(5)] == [0] * 5 == [0, 0, 0, 0, 0] 15 | 16 | # For the next comprehension operations, let's see what we can do 17 | # with a list of 3-5 letter words 18 | words = ["cat", "mice", "horse", "bat"] 19 | 20 | # Tuple comprehension can find the length for each word 21 | tuple_comp = tuple(len(word) for word in words) 22 | assert tuple_comp == (3, 4, 5, 3) 23 | 24 | # Set comprehension can find the unique word lengths 25 | set_comp = {len(word) for word in words} 26 | assert len(set_comp) < len(words) 27 | assert set_comp == {3, 4, 5} 28 | 29 | # Dictionary comprehension can map each word to its length 30 | dict_comp = {word: len(word) for word in words} 31 | assert len(dict_comp) == len(words) 32 | assert dict_comp == {"cat": 3, 33 | "mice": 4, 34 | "horse": 5, 35 | "bat": 3} 36 | 37 | # Comprehensions can also be used with inline conditionals to 38 | # get filtered values from the original list. In this example, 39 | # we grab only odd numbers from the original list 40 | nums = [31, 13, 64, 12, 767, 84] 41 | odds = [_ for _ in nums if _ % 2 == 1] 42 | assert odds == [31, 13, 767] 43 | 44 | 45 | if __name__ == "__main__": 46 | main() 47 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/defaultdict.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module demonstrates the use of defaultdict, which is a dictionary that is 3 | possible to set up a default value in its creation. 4 | """ 5 | 6 | from collections import defaultdict 7 | 8 | # Module-level constants 9 | _GPA_MIN = 0.0 10 | _GPA_MAX = 4.0 11 | _EPS = 0.000001 12 | 13 | 14 | def main(): 15 | # Let's create a defaultdict with student keys and GPA values. The first 16 | # parameter is called default_factory, and it is the initialization value for 17 | # first use of a key. It can be a common type or a function 18 | student_gpa = defaultdict(float, [("john", 3.5), ("bob", 2.8), ("mary", 3.2)]) 19 | 20 | # There are three student records in this dictionary 21 | assert len(student_gpa) == 3 22 | 23 | # Each student has a name key and a GPA value 24 | assert len(student_gpa.keys()) == len(student_gpa.values()) 25 | 26 | # We can get the names in isolation. Note that in Python 3.7 and 27 | # above, dictionary entries are sorted in the order that they were 28 | # defined or inserted 29 | student_names = [] 30 | for student in student_gpa.keys(): 31 | student_names.append(student) 32 | assert student_names == ["john", "bob", "mary"] 33 | 34 | # We can get the GPA for a specific student 35 | assert abs(student_gpa["john"] < 3.5) < _EPS 36 | 37 | # And the defaultdict allow us to get the GPA of a student that is not in 38 | # the data structure yet, returning a default value for float that is 0.0 39 | assert student_gpa["jane"] == _GPA_MIN 40 | 41 | # And now there are four student records in this dictionary 42 | assert len(student_gpa) == 4 43 | 44 | # You can set the default value in default_factory attribute 45 | def set_default_to_gpa_max(): 46 | return _GPA_MAX 47 | 48 | student_gpa.default_factory = set_default_to_gpa_max 49 | 50 | assert student_gpa["rika"] == _GPA_MAX 51 | 52 | # And now there are five student records in this dictionary 53 | assert len(student_gpa) == 5 54 | 55 | 56 | if __name__ == "__main__": 57 | main() 58 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/deque.py: -------------------------------------------------------------------------------- 1 | """ 2 | A deque is similar to all the other sequential data structures but 3 | has some implementation details that are different from other sequences 4 | like a list. This module highlights those differences and shows how 5 | a deque can be used as a LIFO stack and a FIFO queue. 6 | """ 7 | from collections import deque 8 | 9 | 10 | def main(): 11 | # A list is identical to a vector where a new array is created when 12 | # there are too many elements in the old array, and the old array 13 | # elements are moved over to the new array one-by-one. The time 14 | # involved with growing a list increases linearly. A deque is 15 | # identical to a doubly linked list whose nodes have a left pointer 16 | # and a right pointer. In order to grow the linked list, a new node 17 | # is created and added to the left, or the right, of the linked list. 18 | # The time complexity involved with growing a deque is constant. 19 | # Check out the source code for a list and a deque here: 20 | # https://github.com/python/cpython/blob/3.8/Objects/listobject.c 21 | # https://github.com/python/cpython/blob/3.8/Modules/_collectionsmodule.c 22 | dq = deque() 23 | 24 | for i in range(1, 5): 25 | # Similar to adding a new node to the right of the linked list 26 | dq.append(i) 27 | 28 | # Similar to adding a new node to the left of the linked list 29 | dq.appendleft(i * 2) 30 | 31 | # A deque can be iterated over to build any data structure 32 | assert [el for el in dq] == [8, 6, 4, 2, 1, 2, 3, 4] 33 | assert tuple(el for el in dq) == (8, 6, 4, 2, 1, 2, 3, 4) 34 | assert {el for el in dq} == {8, 6, 4, 2, 1, 3} 35 | 36 | # A deque can be used as a stack 37 | # https://en.wikipedia.org/wiki/Stack_(abstract_data_type) 38 | assert dq.pop() == 4 39 | assert dq.pop() == 3 40 | 41 | # A deque can be used as a queue 42 | # https://en.wikipedia.org/wiki/Queue_(abstract_data_type) 43 | assert dq.popleft() == 8 44 | assert dq.popleft() == 6 45 | 46 | 47 | if __name__ == "__main__": 48 | main() 49 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/dict.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionaries are a mapping of keys to values. This module shows how to 3 | access, modify, remove and extend key-value pairs with this data 4 | structure. 5 | """ 6 | import math 7 | 8 | # Module-level constants 9 | _GPA_MIN = 0.0 10 | _GPA_MAX = 4.0 11 | 12 | 13 | def main(): 14 | # Let's create a dictionary with student keys and GPA values 15 | student_gpa = {"john": 3.5, 16 | "jane": _GPA_MAX, 17 | "bob": 2.8, 18 | "mary": 3.2} 19 | 20 | # There are four student records in this dictionary 21 | assert len(student_gpa) == 4 22 | 23 | # Each student has a name key and a GPA value 24 | assert len(student_gpa.keys()) == len(student_gpa.values()) 25 | 26 | # We can get the names in isolation. Note that in Python 3.7 and 27 | # above, dictionary entries are sorted in the order that they were 28 | # defined or inserted 29 | student_names = [] 30 | for student in student_gpa.keys(): 31 | student_names.append(student) 32 | assert student_names == ["john", "jane", "bob", "mary"] 33 | 34 | # We can check that `student_gpa` has the names that were stored 35 | # in `student_names` from the loop above 36 | for student in student_names: 37 | assert student in student_gpa 38 | 39 | # We can get the GPAs in isolation 40 | gpa_values = [] 41 | for gpa in student_gpa.values(): 42 | gpa_values.append(gpa) 43 | assert gpa_values == [3.5, _GPA_MAX, 2.8, 3.2] 44 | 45 | # We can get the GPA for a specific student 46 | assert math.isclose(student_gpa["john"], 3.5) 47 | 48 | # If the key does not always exist inside a dictionary, we 49 | # can check for its existence by using `in` 50 | assert "bob" in student_gpa 51 | assert "alice" not in student_gpa 52 | 53 | # If we want to retrieve a value that may not exist inside 54 | # the dictionary, we can use `get` which allows us to return a 55 | # default value in case the checked key is missing 56 | gpa_jane = student_gpa.get("jane", _GPA_MIN) 57 | assert gpa_jane == _GPA_MAX 58 | gpa_alice = student_gpa.get("alice", _GPA_MIN) 59 | assert gpa_alice == _GPA_MIN 60 | 61 | # We can update the GPA for a specific student 62 | student_gpa["john"] = _GPA_MAX 63 | 64 | # Or update the GPA for multiple students 65 | student_gpa.update(bob=_GPA_MIN, mary=_GPA_MIN) 66 | 67 | # We can access the student and GPA simultaneously 68 | gpa_binary = [] 69 | for student, gpa in student_gpa.items(): 70 | assert student_gpa[student] == gpa 71 | gpa_binary.append(gpa) 72 | assert gpa_binary == [_GPA_MAX, _GPA_MAX, _GPA_MIN, _GPA_MIN] 73 | 74 | # Let's remove all the students 75 | for student in student_names: 76 | student_gpa.pop(student) 77 | assert len(student_gpa) == 0 78 | 79 | # Let's add all the students back in 80 | for student, gpa in zip(student_names, gpa_binary): 81 | student_gpa[student] = gpa 82 | assert len(student_gpa) == len(student_names) 83 | 84 | 85 | if __name__ == "__main__": 86 | main() 87 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/heap.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | 4 | def main(): 5 | # Define the list of numbers 6 | nums = [3, 1, 4, 1, 5] 7 | 8 | # Creating a min-heap 9 | min_heap = [] 10 | for num in nums: 11 | heapq.heappush(min_heap, num) 12 | assert min_heap[0] == 1 # The root of the heap is the smallest element 13 | 14 | # Pop the smallest element 15 | smallest = heapq.heappop(min_heap) 16 | assert smallest == 1 17 | 18 | # Adding a new element 19 | heapq.heappush(min_heap, 5) 20 | assert min_heap[0] == 1 # The root remains the smallest element 21 | 22 | # Creating a max-heap 23 | max_heap = [] 24 | for num in nums: 25 | heapq.heappush(max_heap, -num) # Negate numbers for a max-heap 26 | assert -max_heap[0] == 5 # The root of the heap is the largest element 27 | 28 | # Pop the largest element 29 | largest = -heapq.heappop(max_heap) 30 | assert largest == 5 31 | 32 | # Converting a list to a heap in-place 33 | data = [3, 1, 4, 1, 5] 34 | heapq.heapify(data) 35 | assert data[0] == 1 # The root is the smallest element 36 | 37 | # Extending a heap 38 | more_data = [2, 6, 5] 39 | for item in more_data: 40 | heapq.heappush(data, item) 41 | assert data[0] == 1 # The root is still the smallest element 42 | 43 | # Using heap for sorting 44 | sorted_data = [heapq.heappop(data) for _ in range(len(data))] 45 | assert sorted_data == [1, 1, 2, 3, 4, 5, 5, 6] 46 | 47 | # Getting the n smallest or largest elements from a list 48 | n_smallest = heapq.nsmallest(3, nums) # Get the 3 smallest elements 49 | assert n_smallest == [1, 1, 3] 50 | 51 | n_largest = heapq.nlargest(3, nums) # Get the 3 largest elements 52 | assert n_largest == [5, 4, 3] 53 | 54 | # Merging multiple sorted lists into a single sorted list using a heap 55 | list1 = [1, 3, 5, 7] 56 | list2 = [2, 4, 6, 8] 57 | merged_list = list(heapq.merge(list1, list2)) 58 | assert merged_list == [1, 2, 3, 4, 5, 6, 7, 8] 59 | 60 | 61 | if __name__ == "__main__": 62 | main() 63 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/list.py: -------------------------------------------------------------------------------- 1 | """ 2 | Lists are a sequence of values that can be modified at runtime. This 3 | module shows how lists are created, iterated, accessed, extended 4 | and shortened. 5 | """ 6 | 7 | 8 | def main(): 9 | # This is a list of strings where 10 | # "a" is a string at index 0 and 11 | # "e" is a string at index 4 12 | letters = ["a", "b", "c", "d", "e"] 13 | assert letters[0] == "a" 14 | assert letters[4] == letters[-1] == "e" 15 | 16 | for letter in letters: 17 | # Each of the strings is one character 18 | assert len(letter) == 1 19 | 20 | # Each of the strings is a letter 21 | assert letter.isalpha() 22 | 23 | # We can get a subset of letters with range slices 24 | assert letters[1:] == ["b", "c", "d", "e"] 25 | assert letters[:-1] == ["a", "b", "c", "d"] 26 | assert letters[1:-2] == ["b", "c"] 27 | assert letters[0:3:2] == ["a", "c"] 28 | assert letters[::2] == ["a", "c", "e"] 29 | assert letters[::-2] == ["e", "c", "a"] 30 | assert letters[::-1] == ["e", "d", "c", "b", "a"] 31 | 32 | # This is a list of integers where 33 | # 1 is an integer at index 0 and 34 | # 5 is an integer at index 4 35 | numbers = [1, 2, 3, 4, 5] 36 | assert numbers[0] == 1 37 | assert numbers[4] == numbers[-1] == 5 38 | 39 | # Note that a list is ordered and mutable. If we want to reverse the order 40 | # of the `numbers` list, we can start at index 0 and end halfway. At each 41 | # step of the `for` loop, we swap a value from the first half of the list 42 | # with a value from the second half of the list 43 | for ix_front in range(len(numbers) // 2): 44 | ix_back = len(numbers) - ix_front - 1 45 | numbers[ix_front], numbers[ix_back] = numbers[ix_back], numbers[ix_front] 46 | 47 | # Let's check that `numbers` is in reverse order 48 | assert numbers == [5, 4, 3, 2, 1] 49 | 50 | # Suppose that we want to go back to the original order, we can use the 51 | # builtin `reverse` method in lists 52 | numbers.reverse() 53 | 54 | # Let's check that `numbers` is in the original order 55 | assert numbers == [1, 2, 3, 4, 5] 56 | 57 | # Print letters and numbers side-by-side using the `zip` function. Notice 58 | # that we pair the letter at index 0 with the number at index 0, and 59 | # do the same for the remaining indices. To see the indices and values 60 | # of a list at the same time, we can use `enumerate` to transform the 61 | # list of values into an iterator of index-value pairs 62 | for index, (letter, number) in enumerate(zip(letters, numbers)): 63 | assert letters[index] == letter 64 | assert numbers[index] == number 65 | 66 | # The `for` loop worked because the lengths of both lists are equal 67 | assert len(letters) == len(numbers) 68 | 69 | # Lists can be nested at arbitrary levels 70 | matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 71 | assert matrix[0][0] == 1 72 | assert matrix[0][1] == 2 73 | assert matrix[1][0] == 4 74 | assert matrix[1][1] == 5 75 | 76 | # This matrix just so happens to be a square so that the length of each 77 | # row is the same as the number of rows in the matrix 78 | for row in matrix: 79 | assert len(matrix) == len(row) 80 | 81 | # Notice that lists have variable length and can be modified to have 82 | # more elements. Lists can also be modified to have fewer elements 83 | lengthy = [] 84 | for i in range(5): 85 | lengthy.append(i) # add 0..4 to the back 86 | assert lengthy == [0, 1, 2, 3, 4] 87 | lengthy.pop() # pop out the 4 from the back 88 | assert lengthy == [0, 1, 2, 3] 89 | 90 | # Let's sort this list in ascending order 91 | numbers = [5, 4, 3, 2, 1] 92 | numbers.sort() 93 | assert numbers == [1, 2, 3, 4, 5] 94 | 95 | # Let's check if these lists are empty 96 | assert len(numbers) == 5 97 | empty_list = [] 98 | assert len(empty_list) == 0 99 | assert not empty_list 100 | assert len([None]) == 1 101 | 102 | 103 | if __name__ == "__main__": 104 | main() 105 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/namedtuple.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module demonstrates the use of named tuples, which are a data structure 3 | with named fields, similar to a class but lightweight and immutable. Named 4 | tuples are created using the namedtuple function from the collections module. 5 | """ 6 | from collections import namedtuple 7 | 8 | 9 | def main(): 10 | # Named Tuple Attributes: 11 | # - namedtuple: Callable from collections to define a named tuple 12 | # - Point: A named tuple type with fields "x" and "y" 13 | Point = namedtuple("Point", ["x", "y"]) 14 | 15 | # Named Tuple Fields: 16 | # - x and y: Fields of the named tuple Point representing coordinates 17 | # - point1 and point2: Instances of the Point named tuple 18 | point1 = Point(x=1, y=2) 19 | point2 = Point(x=3, y=4) 20 | assert isinstance(point1, Point) is True 21 | assert isinstance(point2, Point) is True 22 | 23 | # Named Tuple Operations: 24 | # - Accessing fields using dot notation 25 | # - Named tuples are immutable 26 | # - Named tuples support tuple operations 27 | # - Converting named tuples to dictionaries and vice versa 28 | # - Additional methods and attributes 29 | assert point1.x == 1 30 | assert point1.y == 2 31 | assert point2.x == 3 32 | assert point2.y == 4 33 | 34 | # Attempt to change the "x" field of point1 (raises an error) 35 | access_immutable_error = False 36 | try: 37 | point1.x = 5 38 | except AttributeError: 39 | access_immutable_error = True 40 | assert access_immutable_error is True 41 | 42 | # One can access Point data by indexes 43 | assert point1[0] + point2[0] == 4 44 | assert point1[0] + point2[1] == 5 45 | assert point1[1] + point2[0] == 5 46 | assert point1[1] + point2[1] == 6 47 | 48 | point_dict = point1._asdict() 49 | assert point_dict == {"x": 1, "y": 2} 50 | 51 | # It is possible to initialize a Point without explicit parameters 52 | point3 = Point(10, 20) 53 | assert point3.x == 10 54 | assert point3.y == 20 55 | assert Point._fields == ("x", "y") 56 | 57 | # It is also possible to create a new point out of an existing one 58 | point4 = point1._replace(x=5) 59 | assert point4.x == 5 60 | assert point4.y == 2 61 | 62 | # Note that point4 is not the same as point1 63 | assert id(point4) != id(point1) 64 | 65 | 66 | if __name__ == "__main__": 67 | main() 68 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/set.py: -------------------------------------------------------------------------------- 1 | """ 2 | Sets are an unordered collection of unique values that can be modified at 3 | runtime. This module shows how sets are created, iterated, accessed, 4 | extended and shortened. 5 | """ 6 | 7 | 8 | def main(): 9 | # Let's define one `set` for starters 10 | simple_set = {0, 1, 2} 11 | 12 | # A set is dynamic like a `list` and `tuple` 13 | simple_set.add(3) 14 | simple_set.remove(0) 15 | assert simple_set == {1, 2, 3} 16 | 17 | # Unlike a `list and `tuple`, it is not an ordered sequence as it 18 | # does not allow duplicates to be added 19 | for _ in range(5): 20 | simple_set.add(0) 21 | simple_set.add(4) 22 | assert simple_set == {0, 1, 2, 3, 4} 23 | 24 | # Use `pop` return any random element from a set 25 | random_element = simple_set.pop() 26 | assert random_element in {0, 1, 2, 3, 4} 27 | assert random_element not in simple_set 28 | 29 | # Now let's define two new `set` collections 30 | multiples_two = set() 31 | multiples_four = set() 32 | 33 | # Fill sensible values into the set using `add` 34 | for i in range(10): 35 | multiples_two.add(i * 2) 36 | multiples_four.add(i * 4) 37 | 38 | # As we can see, both sets have similarities and differences 39 | assert multiples_two == {0, 2, 4, 6, 8, 10, 12, 14, 16, 18} 40 | assert multiples_four == {0, 4, 8, 12, 16, 20, 24, 28, 32, 36} 41 | 42 | # We cannot decide in which order the numbers come out - so let's 43 | # look for fundamental truths instead, such as divisibility against 44 | # 2 and 4. We do this by checking whether the modulus of 2 and 4 45 | # yields 0 (i.e. no remainder from performing a division). We can 46 | # also use `&` to perform set intersection 47 | multiples_common = multiples_two.intersection(multiples_four) 48 | multiples_common_shorthand = multiples_two & multiples_four 49 | 50 | for number in multiples_common: 51 | assert number % 2 == 0 and number % 4 == 0 52 | 53 | for number in multiples_common_shorthand: 54 | assert number % 2 == 0 and number % 4 == 0 55 | 56 | # We can compute exclusive multiples. We can also use `-` to perform 57 | # set difference 58 | multiples_two_exclusive = multiples_two.difference(multiples_four) 59 | multiples_two_exclusive_shorthand = multiples_two - multiples_four 60 | multiples_four_exclusive = multiples_four.difference(multiples_two) 61 | assert len(multiples_two_exclusive) > 0 62 | assert len(multiples_four_exclusive) > 0 63 | assert len(multiples_two_exclusive_shorthand) > 0 64 | 65 | # Numbers in this bracket are greater than 2 * 9 and less than 4 * 10 66 | for number in multiples_four_exclusive: 67 | assert 18 < number < 40 68 | 69 | # By computing a set union against the two sets, we have all integers 70 | # in this program. We can also use `|` to perform set union 71 | multiples_all = multiples_two.union(multiples_four) 72 | multiples_all_shorthand = multiples_two | multiples_four 73 | 74 | # Check if set A is a subset of set B 75 | assert multiples_four_exclusive.issubset(multiples_four) 76 | assert multiples_four.issubset(multiples_all) 77 | 78 | # Check if set A is a subset and superset of itself 79 | assert multiples_all.issubset(multiples_all) 80 | assert multiples_all.issuperset(multiples_all) 81 | assert multiples_all_shorthand.issuperset(multiples_all_shorthand) 82 | 83 | # Check if set A is a superset of set B 84 | assert multiples_all.issuperset(multiples_two) 85 | assert multiples_two.issuperset(multiples_two_exclusive) 86 | 87 | 88 | if __name__ == "__main__": 89 | main() 90 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/string.py: -------------------------------------------------------------------------------- 1 | """ 2 | Strings are an ordered collection of unicode characters that cannot be 3 | modified at runtime. This module shows how strings are created, iterated, 4 | accessed and concatenated. 5 | """ 6 | 7 | # Module-level constants 8 | _DELIMITER = " | " 9 | 10 | 11 | def main(): 12 | # Strings are some of the most robust data structures around 13 | content = "Ultimate Python study guide" 14 | 15 | # We can compute the length of a string just like all other data structures 16 | assert len(content) > 0 17 | 18 | # We can use range slices to get substrings from a string 19 | assert content[:8] == "Ultimate" 20 | assert content[9:15] == "Python" 21 | assert content[::-1] == "ediug yduts nohtyP etamitlU" 22 | 23 | # Like tuples, we cannot change the data in a string. However, we can 24 | # create a new string from existing strings 25 | new_content = f"{content.upper()}{_DELIMITER}{content.lower()}" 26 | assert _DELIMITER in new_content 27 | 28 | # We can split one string into a list of strings 29 | split_content = new_content.split(_DELIMITER) 30 | assert isinstance(split_content, list) 31 | assert len(split_content) == 2 32 | assert all(isinstance(item, str) for item in split_content) 33 | 34 | # A two-element list can be decomposed as two variables 35 | upper_content, lower_content = split_content 36 | assert upper_content.isupper() and lower_content.islower() 37 | 38 | # Notice that the data in `upper_content` and `lower_content` exists 39 | # in the `new_content` variable as expected 40 | assert upper_content in new_content 41 | assert new_content.startswith(upper_content) 42 | assert lower_content in new_content 43 | assert new_content.endswith(lower_content) 44 | 45 | # Notice that `upper_content` and `lower_content` are smaller in length 46 | # than `new_content` and have the same length as the original `content` 47 | # they were derived from 48 | assert len(upper_content) < len(new_content) 49 | assert len(lower_content) < len(new_content) 50 | assert len(upper_content) == len(lower_content) == len(content) 51 | 52 | # We can also join `upper_content` and `lower_content` back into one 53 | # string with the same contents as `new_content`. The `join` method is 54 | # useful for joining an arbitrary amount of text items together 55 | joined_content = _DELIMITER.join(split_content) 56 | assert isinstance(joined_content, str) 57 | assert new_content == joined_content 58 | 59 | 60 | if __name__ == "__main__": 61 | main() 62 | -------------------------------------------------------------------------------- /ultimatepython/data_structures/tuple.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tuples are an ordered collection of values that cannot be modified at 3 | runtime. This module shows how tuples are created, iterated, accessed 4 | and combined. 5 | """ 6 | 7 | 8 | def main(): 9 | # This is a tuple of integers 10 | immutable = (1, 2, 3, 4) 11 | 12 | # It can be indexed like a list 13 | assert immutable[0] == 1 14 | assert immutable[-1] == 4 15 | 16 | # It can be sliced like a list 17 | assert immutable[1:3] == (2, 3) 18 | assert immutable[3:4] == (4,) 19 | assert immutable[1::2] == (2, 4) 20 | assert immutable[::-1] == (4, 3, 2, 1) 21 | 22 | # It can be iterated over like a list 23 | for ix, number in enumerate(immutable): 24 | assert immutable[ix] == number 25 | 26 | # But its contents cannot be changed. As an alternative, we can 27 | # create new tuples from existing tuples 28 | bigger_immutable = immutable + (5, 6) 29 | assert bigger_immutable == (1, 2, 3, 4, 5, 6) 30 | smaller_immutable = immutable[0:2] 31 | assert smaller_immutable == (1, 2) 32 | 33 | # We use tuples when the number of items is consistent. An example 34 | # where this can help is a 2D game with X and Y coordinates. Using a 35 | # tuple with two numbers can ensure that the number of coordinates 36 | # doesn't change to one, three, four, etc. 37 | moved_count = 0 38 | pos_x, pos_y = (0, 0) 39 | for i in range(1, 5, 2): 40 | moved_count += 1 41 | pos_x, pos_y = (pos_x + 10 * i, pos_y + 15 * i) 42 | assert moved_count == 2 43 | assert pos_x == 40 and pos_y == 60 44 | 45 | 46 | if __name__ == "__main__": 47 | main() 48 | -------------------------------------------------------------------------------- /ultimatepython/syntax/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huangsam/ultimate-python/26887e626b9509aa56f99da604399ed800405aaa/ultimatepython/syntax/__init__.py -------------------------------------------------------------------------------- /ultimatepython/syntax/bitwise.py: -------------------------------------------------------------------------------- 1 | """ 2 | Bitwise operators in Python allow you to manipulate individual bits of integers. 3 | This module demonstrates the use of bitwise operators and their behavior. 4 | """ 5 | 6 | 7 | def main(): 8 | # Define some integer values for demonstration 9 | a = 5 # Binary: 0101 10 | b = 3 # Binary: 0011 11 | 12 | # Bitwise AND (&) operator compares each bit of two integers and returns 1 13 | # if both bits are 1, otherwise returns 0 14 | result_and = a & b # Binary: 0001 (Decimal: 1) 15 | assert result_and == 1 16 | 17 | # Bitwise OR (|) operator compares each bit of two integers and returns 1 18 | # if at least one bit is 1, otherwise returns 0 19 | result_or = a | b # Binary: 0111 (Decimal: 7) 20 | assert result_or == 7 21 | 22 | # Bitwise XOR (^) operator compares each bit of two integers and returns 1 23 | # if the bits are different (one is 1 and the other is 0), otherwise returns 0 24 | result_xor = a ^ b # Binary: 0110 (Decimal: 6) 25 | assert result_xor == 6 26 | 27 | # Bitwise NOT (~) operator inverts all bits of an integer 28 | # It returns the one's complement of the integer 29 | result_not_a = ~a # Binary: 11111010 (Decimal: -6) 30 | assert result_not_a == -6 31 | 32 | # Bitwise left shift (<<) operator shifts the bits of an integer to the left by 33 | # a specified number of positions, filling with zeros 34 | result_left_shift = a << 2 # Binary: 010100 (Decimal: 20) 35 | assert result_left_shift == 20 36 | 37 | # Bitwise right shift (>>) operator shifts the bits of an integer to the right 38 | # by a specified number of positions, filling with zeros for positive numbers 39 | # and with ones for negative numbers 40 | result_right_shift = a >> 1 # Binary: 0010 (Decimal: 2) 41 | assert result_right_shift == 2 42 | 43 | 44 | if __name__ == "__main__": 45 | main() 46 | -------------------------------------------------------------------------------- /ultimatepython/syntax/conditional.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module shows how to use if blocks, if-else blocks and if-elif-else 3 | blocks to decide which lines of code to run (and skip). 4 | """ 5 | 6 | 7 | def main(): 8 | x = 1 9 | x_add_two = x + 2 10 | 11 | # This condition is obviously true 12 | ran_1 = False 13 | if x_add_two == 3: # skip: else 14 | ran_1 = True # run 15 | assert ran_1 is True 16 | 17 | # A negated condition can also be true 18 | ran_2 = False 19 | if not x_add_two == 1: # skip: else 20 | ran_2 = True # run 21 | assert ran_2 is True 22 | 23 | # There are `else` statements as well, which run if the initial condition 24 | # fails. Notice that one line gets skipped and this conditional does not 25 | # help us make a conclusion on the variable's true value 26 | if x_add_two == 1: 27 | ran_3 = False # skip: if 28 | else: 29 | ran_3 = True # run 30 | assert ran_3 is True 31 | 32 | # The `else` statement also runs once all other `if` and `elif` conditions 33 | # fail. Notice that multiple lines get skipped, and that all the 34 | # conditions could have been compressed to `x_add_two != 3` for 35 | # simplicity. In this case, less logic results in more clarity 36 | if x_add_two == 1: 37 | ran_4 = False # skip: if 38 | elif x_add_two == 2: 39 | ran_4 = False # skip: if 40 | elif x_add_two < 3 or x_add_two > 3: 41 | ran_4 = False # skip: if 42 | else: 43 | ran_4 = True # run 44 | assert ran_4 is True 45 | 46 | # Conditionals can also be written in one line using `if` and `else` 47 | # with the following form: A if condition else B. This can be used 48 | # for assignments as shown below 49 | ran_5 = False 50 | ran_5 = True if x_add_two == 3 else False 51 | assert ran_5 is True 52 | 53 | # Python is one of the few programming languages that allows chained 54 | # comparisons. This is useful for checking if a variable is within 55 | # a range of values. You can see that in this example, the expression 56 | # `0 < x_add_two < 2` is equivalent to `x_add_two > 0 and x_add_two < 2` 57 | ran_6 = False 58 | if 0 < x_add_two < 2: 59 | ran_6 = False # skip: if 60 | else: 61 | ran_6 = True # run 62 | assert ran_6 is True 63 | 64 | 65 | if __name__ == "__main__": 66 | main() 67 | -------------------------------------------------------------------------------- /ultimatepython/syntax/expression.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module shows how to create new integers by applying math expressions 3 | on existing integers. 4 | """ 5 | import math 6 | 7 | 8 | def main(): 9 | # This is a simple integer 10 | x = 1 11 | 12 | # Its value can be used as part of expressions 13 | assert x + 1 == 2 14 | 15 | # An expression can be chained indefinitely. This concept of chaining 16 | # expressions is powerful because it allows us to compose simple pieces 17 | # of code into larger pieces of code over time 18 | assert x * 2 * 2 * 2 == 8 19 | 20 | # Division is tricky because Python 3.x returns 0.5 of type `float` 21 | # whereas Python 2.x returns 0 of type `int`. If this line fails, it 22 | # is a sign that the wrong version of Python was used 23 | assert math.isclose(x / 2, 0.5) 24 | 25 | # If an integer division is desired, then an extra slash must be 26 | # added to the expression. In Python 2.x and Python 3.x, the behavior 27 | # is exactly the same 28 | assert x // 2 == 0 29 | 30 | # Powers of an integer can be leveraged too. If more features are 31 | # needed, then leverage the builtin `math` library or a third-party 32 | # library. Otherwise, we have to build our own math library 33 | assert x * 2 ** 3 == 8 34 | 35 | 36 | if __name__ == "__main__": 37 | main() 38 | -------------------------------------------------------------------------------- /ultimatepython/syntax/function.py: -------------------------------------------------------------------------------- 1 | """ 2 | Functions allow us to consolidate simple / complex code into a single 3 | block that can be invoked with specific parameters. This module defines 4 | a simple function and a composite function that uses the simple function 5 | in an interesting way. 6 | """ 7 | 8 | 9 | def add(x, y): 10 | """Add two objects together to produce a new object. 11 | 12 | Two differences between `add` and `main` are that: 13 | 14 | - It accepts input parameters 15 | - It returns a value 16 | """ 17 | return x + y 18 | 19 | 20 | def sum_until(fn, n): 21 | """Sum function results from 0 until n - 1. 22 | 23 | This expects a function to be provided as its first input and an integer 24 | as its second input. Like `add`, `sum_until` returns a value. 25 | 26 | The fact that a function can be passed into `sum_until` highlights a core 27 | concept that was mentioned before: everything in Python is an object, and 28 | that includes this docstring! 29 | """ 30 | total = 0 31 | for i in range(n): 32 | total += fn(i) 33 | return total 34 | 35 | 36 | def main(): 37 | # The `add` function can be used for numbers as expected 38 | add_result_int = add(1, 2) 39 | assert add_result_int == 3 40 | 41 | # The `add` function can be used for strings as well 42 | add_result_string = add("hello", " world") 43 | assert add_result_string == "hello world" 44 | 45 | # Run the input function multiple times. Notice that we make use of 46 | # `lambda` to create an anonymous function (i.e. a function without 47 | # a name) that accepts one input and does something with it. Anonymous 48 | # functions are powerful because they allow us to write functions 49 | # inline, unlike `add` and `sum_until` 50 | run_results = sum_until(lambda i: i * 100, 5) 51 | assert run_results == 1000, run_results 52 | 53 | # We can see the `sum_until` docstring by accessing the `__doc__` magic 54 | # attribute! Remember this - everything in Python is an object 55 | assert "includes this docstring!" in sum_until.__doc__ 56 | 57 | 58 | if __name__ == "__main__": 59 | main() 60 | -------------------------------------------------------------------------------- /ultimatepython/syntax/loop.py: -------------------------------------------------------------------------------- 1 | """ 2 | Loops are to expressions as multiplication is to addition. They help us 3 | run the same code many times until a certain condition is not met. This 4 | module shows how to use the for-loop and while-loop, and also shows how 5 | `continue` and `break` give us precise control over a loop's lifecycle. 6 | 7 | Note that for-else and while-else loops exist in Python, but they are 8 | not commonly used. Please visit this link for some examples: 9 | 10 | https://stackoverflow.com/a/59491247/9921431 11 | """ 12 | 13 | 14 | def main(): 15 | # This is a `for` loop that iterates on values 0..4 and adds each 16 | # value to `total`. It leverages the `range` iterator. Providing 17 | # a single integer implies that the start point is 0, the end point 18 | # is 5 and the increment step is 1 (going forward one step) 19 | total = 0 20 | for i in range(5): 21 | total += i 22 | 23 | # The answer is...10! 24 | assert total == 10 25 | 26 | # This is a `for` loop that iterates on values 5..1 and multiplies each 27 | # value to `fact`. The `range` iterator is used here more precisely by 28 | # setting the start point at 5, the end point at 0 and the increment 29 | # step at -1 (going backward one step) 30 | fact = 1 31 | for i in range(5, 0, -1): 32 | fact *= i 33 | 34 | # The answer is...120! 35 | assert fact == 120 36 | 37 | # This is a simple `while` loop, similar to a `for` loop except that the 38 | # counter is declared outside the loop and its state is explicitly 39 | # managed inside the loop. The loop will continue until the counter 40 | # exceeds 8 41 | i = 0 42 | while i < 8: 43 | i += 2 44 | 45 | # The `while` loop terminated at this value 46 | assert i == 8 47 | 48 | # This is a `while` loop that stops with `break` and its counter is 49 | # multiplied in the loop, showing that we can do anything to the 50 | # counter. Like the previous `while` loop, this one continues until 51 | # the counter exceeds 8 52 | i = 1 53 | break_hit = False 54 | continue_hit = False 55 | other_hit = False 56 | while True: 57 | i *= 2 58 | 59 | if i >= 8: 60 | # The `break` statement stops the current `while` loop. 61 | # If this `while` loop was nested in another loop, 62 | # this statement would not stop the parent loop 63 | break_hit = True 64 | break 65 | 66 | if i == 2: 67 | # The `continue` statement returns to the start of the 68 | # current `while` loop 69 | continue_hit = True 70 | continue 71 | 72 | # This statement runs when the counter equals 4 73 | other_hit = True 74 | 75 | # The `while` loop terminated at this value 76 | assert i == 8 77 | 78 | # The `while` loop hit the `break` and `continue` blocks 79 | assert break_hit is True 80 | assert continue_hit is True 81 | assert other_hit is True 82 | 83 | 84 | if __name__ == "__main__": 85 | main() 86 | -------------------------------------------------------------------------------- /ultimatepython/syntax/variable.py: -------------------------------------------------------------------------------- 1 | """ 2 | Variables allow us to store values in named records that can be used in 3 | a program. This module shows how to define variables and make assertions 4 | about the state of each defined variable. 5 | """ 6 | import math 7 | 8 | 9 | def main(): 10 | # Here are the main literal types to be aware of 11 | a = 1 12 | b = 2.0 13 | c = True 14 | d = "hello" 15 | 16 | # Notice that each type is a class. Each of the variables above refers 17 | # to an instance of the class it belongs to 18 | a_type = type(a) 19 | b_type = type(b) 20 | c_type = type(c) 21 | d_type = type(d) 22 | 23 | # Also, say hello to the `assert` keyword! This is a debugging aid that 24 | # we will use to validate the code as we progress through each `main` 25 | # function. These statements are used to validate the correctness of 26 | # the data and to reduce the amount of output sent to the screen 27 | assert a_type is int 28 | assert b_type is float 29 | assert c_type is bool 30 | assert d_type is str 31 | 32 | # Everything is an object in Python. That means instances are objects 33 | # and classes are objects as well 34 | assert isinstance(a, object) and isinstance(a_type, object) 35 | assert isinstance(b, object) and isinstance(b_type, object) 36 | assert isinstance(c, object) and isinstance(c_type, object) 37 | assert isinstance(d, object) and isinstance(d_type, object) 38 | 39 | # We can represent integer literals in Python using 4 bases: decimal, 40 | # hexadecimal, octal, and binary. Decimal literals do not require any 41 | # prefix while other bases require prefixes: 42 | # - `0x` for hexadecimal 43 | # - `0o` for octal 44 | # - `0b` for binary 45 | assert 100 == 0x64 == 0o144 == 0b1100100 46 | 47 | # We can use underscores (literal `_`) to separate digit groups in 48 | # integer literals 49 | assert 10_000 == 10000 50 | assert 0x01_0F_2C == 69_420 51 | assert math.isclose(3.456_290e-1, 0.3_456_290) 52 | 53 | # There is also a special literal called None. This literal is used to 54 | # point that a particular variable or object is not created 55 | e = None 56 | e_type = type(e) 57 | assert e_type is type(None) 58 | assert isinstance(e, object) and isinstance(e_type, object) 59 | 60 | 61 | if __name__ == "__main__": 62 | main() 63 | --------------------------------------------------------------------------------