diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..a65f7f45 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,27 @@ +version: 2.1 + +orbs: + python: circleci/python@0.3.2 + +jobs: + build-and-test: + executor: python/default + steps: + - checkout + - python/load-cache + - python/install-deps + - python/save-cache + - run: + command: flake8 + name: Lint + - run: + command: coverage run -m runner + name: Test + - run: + command: coverage report + name: Report + +workflows: + main: + jobs: + - build-and-test diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 3be246be..00000000 --- a/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true - -[*.{py,toml,md}] -indent_size = 4 -indent_style = space - -[*.{xml,yaml,yml}] -indent_size = 2 -indent_style = space diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 50d26646..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: huangsam diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index dd84ea78..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7d..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 38ab8116..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,9 +0,0 @@ -*Please read the [contributing guidelines](https://github.com/huangsam/ultimate-python/blob/main/CONTRIBUTING.md) before submitting a pull request.* - ---- - -**Describe the change** -A clear and concise description of what the change is. - -**Additional context** -Add any other context or screenshots about the pull request here. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 4a24b3ee..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: CI - -on: - push: - branches: [main] - pull_request: - branches: [main] - -permissions: - contents: read - -jobs: - python-build: - name: Python - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v5 - - name: Set up Python 3.14 - uses: actions/setup-python@v6 - with: - python-version: '3.14' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - - name: Lint with ruff - run: | - ruff check - - name: Type check with mypy - run: | - mypy ultimatepython - - name: Run tests and report with coverage - run: | - coverage run runner.py - coverage report - - name: Generate coverage.xml artifact - run: | - coverage xml -o ./coverage.xml - - name: Upload coverage data to Codecov - uses: codecov/codecov-action@v4 - with: - files: ./coverage.xml - token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index d64421e7..18804740 100644 --- a/.gitignore +++ b/.gitignore @@ -1,19 +1,10 @@ -# System -.DS_Store - -# IDE .idea/ -.vscode/ - -# Python +venv/ +__pycache__/ +*.egg-info/ +htmlcov/ *.pyc +.DS_Store .coverage -coverage.json coverage.xml -*.egg-info/ -.ruff_cache/ -__pycache__/ -build/ -htmlcov/ -venv/ -brainstorm/ +coverage.json diff --git a/.replit b/.replit deleted file mode 100644 index 66d6a7a4..00000000 --- a/.replit +++ /dev/null @@ -1,2 +0,0 @@ -language = "python3" -run = "python runner.py" diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index e4efa791..00000000 --- a/AGENTS.md +++ /dev/null @@ -1,58 +0,0 @@ -# Quick orientation for AI coding agents - -## Key facts an agent must know (short): - -- The runner: `runner.py` dynamically imports every module under `ultimatepython` and runs any callable named `main` with zero parameters. Keep `main()` functions parameterless, idempotent, and side-effect safe for CI. -- Single-file runs are supported: modules are runnable with `python ultimatepython//.py`. Most modules already include `if __name__ == "__main__": main()`. -- Examples use plain Python stdlib only. Avoid adding new third-party dependencies without updating `requirements.txt` and `pyproject.toml`. -- Assertions are used as the primary verification mechanism inside examples (not pytest tests). Preserve their intent and messages when editing. - -## Patterns and conventions to follow - -- main() contract: must be a function, accept zero parameters, and not raise exceptions when run. The runner asserts the function is callable and has zero parameters. Example: `ultimatepython/syntax/function.py` and `ultimatepython/classes/basic_class.py`. -- Module structure: brief module docstring, helper functions/classes, then `main()` demonstrating usage via asserts, and final `if __name__ == "__main__": main()`. -- Avoid long-running or destructive operations in examples. If a module interacts with the filesystem (e.g., `advanced/file_handling.py`), keep operations local to ephemeral files (module uses `_TARGET_FILE = "sample.txt"`), and clean up after running. -- Typing: some modules include simple type hints; prefer to keep existing style and minimal typing additions only. -- Formatting & linting: the repo uses `ruff` and `isort` settings in `pyproject.toml`. Try to keep line-length <= 160 and maintain import ordering consistent with isort defaults. - -## When creating or modifying modules - -- Preserve the didactic nature: keep explanatory comments and short, clear examples. -- If you add new modules, include them under the appropriate folder and follow the same pattern (module docstring, helpers, `main()`, `if __name__...`). The runner will pick them up automatically. -- If a change requires a new dependency, add it to `requirements.txt` and update `pyproject.toml` before proposing a PR. - -## Top-level README files - -- The top-level `README.md` is the primary project landing page: it explains the repo goals, running instructions, and links to example modules (it also shows badges for CI and coverage). When changing top-level documentation, keep the runner guidance intact (it points to `runner.py`) and preserve any badges and links. -- Translated files like `README.ko.md`, `README.zh_tw.md`, `README.es.md`, `README.de.md`, `README.fr.md`, and `README.hi.md` are language variants of the same content. If you update the English `README.md`, consider updating translations or add a brief note in the PR explaining why translations were not updated. - -## Developer workflows and useful commands - -- Run all examples locally (fast smoke): - -```bash -python runner.py -``` - -- Run a single example (recommended when editing): - -```bash -python ultimatepython/syntax/function.py -``` - -- Check formatting/linting (ruff/isort configured in `pyproject.toml`): run your local ruff/isort commands or CI. -- Coverage config exists in `pyproject.toml` (coverage fail_under=80). The examples use assertions; running `runner.py` is a good quick coverage smoke. - -## Integration points & CI notes - -- CI expects that running `runner.py` and executing each `main()` will succeed. Avoid adding code that requires network access, long sleeps, or interactive input. -- Do not introduce external services or config files; this repo intentionally uses only the Python standard library. - -## Files and locations of interest (examples to inspect) - -- `runner.py` — how modules are discovered and executed (pkgutil.walk_packages + `main` lookups). -- `ultimatepython/syntax/*.py` — simple, illustrative examples of the `main()` pattern. -- `ultimatepython/advanced/*` — more involved examples; watch for filesystem or concurrency code (e.g., `advanced/file_handling.py`, `advanced/async.py`). -- `pyproject.toml` — linting/format settings and coverage rules. - -If anything in these instructions is unclear or you want additional examples (CI commands, recommended local dev Docker container, or a tiny unit-test harness), tell me which areas to expand and I'll iterate. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index aaa87332..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,126 +0,0 @@ -# 🚀 Welcome to the Ultimate Python Study Guide! 📚 - -🎉 Thank you for considering contributing to this awesome project! 🎉 - -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! - -## 🐍 What's This All About? - -Our Python Study Guide is your ticket to Python mastery! 🐍 This place is all about energy, excitement, and pure Python magic. 💫 - -## 📖 Let's Talk Documentation - -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: - -- Translations? 🌍 Yes, they're right at the top for everyone to enjoy! -- Python modules? 🤓 Oh, they've got a VIP seat in our Table of Contents (ToC). -- External links? 🔗 They're all about HTTPS and that sweet `2xx` status. -- Python documentation? For both newbies and wizards, it's all in here! -- GitHub repositories? 🌟 We love stars! If it's got at least 1k stars, bring it on! -- Practice resources? 🏋️‍♂️ We've got Python exercises to keep you in shape. - -## 📚 Get into Python Modules - -Our Python modules are like mini-python-parties that you can host anywhere! They're packed with energy and make learning a blast! 🎉 - -### 🧩 The Setup - -Each Python module follows a rock-solid structure: - -```python -# The main event 🎉 -def main(): - # Here's where the magic happens! - assert 1 + 1 == 2 - assert True is not False - -# The show must go on -if __name__ == "__main__": - main() -``` - -If there's more Python goodness, it's up front before the main event! - -### ✨ Style and Shine - -We've got style, oh baby! Check out the PEPs: - -- [PEP 8](https://www.python.org/dev/peps/pep-0008) - Our fashion bible! -- [PEP 257](https://www.python.org/dev/peps/pep-0257) - Docstring Glamour! - -But there's more! We have our own style: - -- Imports are perfectly sorted with [isort](https://github.com/timothycrosley/isort). -- Constants? They follow the `_UNDER_SCORE_FIRST` party rule. -- Strings love double-quotes, but if there's a `"`, they'll use single quotes! -- For dynamic strings, it's all about those fabulous f-strings! 🎤 - -### 📈 Code Coverage Stars - -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. - -## 🌟 Your Contribution - -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! - -So, get ready to rock and roll, Python style! 🤘🐍💥 - -# 💥 Dive into the Python World - -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. - -# 🧑‍💻 Learning Together - -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. - -# 🚀 Opportunities Galore - -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. - -# 🌍 Global Impact - -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. - -# 🙋‍♀️ Join a Supportive Community - -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. - -# 📢 Your Voice Matters - -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. - -# 🤖 Evolving with Python - -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. - -# 🎉 Your Contribution Matters - -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. - -# 🌟 Be a Python Star - -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! - -## How to Contribute - -Ready to dive in? Here's how you can contribute: - -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. - -2. **Clone Your Fork**: After forking, you'll have your copy of the repository. Clone it to your local machine. - -3. **Make Your Contributions**: Create or update Python modules, documentation, or anything that adds value to the project. - -4. **Push Your Changes**: Once your work is ready, push your changes to your forked repository. - -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. - -We're excited to see what you bring to the table! Your contributions are making the Python world a better place. - -Please don't hesitate to reach out if you have any questions. Your contributions, no matter how small, are making a big difference! 🌟🐍💥 - -## 🌍 README translations - -Please update `README.md` (English) first - it's the source of truth. If you can, mirror important changes like link updates in the corresponding `README..md` files so translations stay current. If you can't, no worries — just add a short note in your PR listing which translation files need updates. Thanks - your help keeps the docs welcoming for everyone! 🙏 - -## Feel the Pythonic Energy - Contribute Now! 🔥 diff --git a/README.de.md b/README.de.md deleted file mode 100644 index 7ecfe09a..00000000 --- a/README.de.md +++ /dev/null @@ -1,191 +0,0 @@ -# Ultimativer Python-Lernführer - -[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) -[![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) -[![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) -[![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) -[![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) - -Der ultimative Python-Lernführer für Einsteiger und Profis gleichermaßen. 🐍 🐍 🐍 - -```python -print("Ultimativer Python-Lernführer") -``` - -[English](README.md) | -[한국어](README.ko.md) | -[繁体中文](README.zh_tw.md) | -[Español](README.es.md) | -[Deutsch](README.de.md) | -[Français](README.fr.md) | -[हिन्दी](README.hi.md) | -[Português - Brasil](README.pt_br.md) - -Ultimate Python - -## Motivation - -Ich habe dieses GitHub-Repository erstellt, um meine Erkenntnisse über [core Python](https://www.python.org/) -in den letzten 5 Jahren als Hochschulabsolvent, Angestellter in -großen Unternehmen und als Open-Source-Mitarbeiter von Repositories wie -[Celery](https://github.com/celery/celery) und -[Full Stack Python](https://github.com/mattmakai/fullstackpython.com) weiterzugeben. -Ich freue mich darauf, dass noch mehr Menschen Python lernen und damit ihren Leidenschaften nachgehen. 🎓 - -## Ziele - -Dies sind die Hauptziele bei der Erstellung dieses Leitfadens: - -🏆 **Als Ressource fungieren** für Python-Neulinge, die es vorziehen, praktisch zu lernen. -Dieses Repository enthält eine Sammlung von eigenständigen Modulen, die in einer IDE - wie [PyCharm](https://www.jetbrains.com/pycharm/) oder im Browser via - [Replit](https://replit.com/languages/python3) ausgeführt werden können. Ein Terminal funktioniert - ebenfalls gut für die Beispiele. Die meisten Zeilen enthalten sorgfälltig formulierte Kommentare, die den Leser - Schritt für Schritt durch die Abläufe führen. Benutzer werden ermutigt, den Quellcode zu ändern, - sofern die `main`-Routinen nicht entfernt werden und die Programme nach Änderungen weiterhin erfolgreich - ausgeführt werden (siehe `runner.py`). - -🏆 **Als reiner Leitfaden dienen** für diejenigen, die die wichtigsten Python-Konzepte wiederholen möchten. -Wo nur [builtin libraries](https://docs.python.org/3/library/) genutzt werden, so dass -diese Konzepte ohne den Overhead der bereichsspezifischen Konzepte vermittelt werden können. Als -beliebte Open-Source-Bibliotheken und -Frameworks (d.h. `sqlalchemy`, `requests`, -`pandas`) nicht installiert sind. Das Lesen des Quellcodes dieser Frameworks ist jedoch -inspirierend und wird dringend empfohlen, wenn Sie ein echter Profi werden wollen. -[Pythonista](https://www.urbandictionary.com/define.php?term=pythonista). - -## Erste Schritte - -[![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) - -Klicken Sie auf das obige Abzeichen, um eine Arbeitsumgebung im Browser zu starten, ohne -ohne dass Sie Git und Python auf Ihrem lokalen Rechner installiert haben müssen. Wenn diese Voraussetzungen -bereits erfüllt sind, können Sie das Repository direkt klonen. - -Sobald das Repository zugänglich ist, können Sie mit den eigenständigen -Modulen lernen. Um den größtmöglichen Nutzen aus jedem Modul zu ziehen, lesen Sie den Modulcode und führen Sie ihn aus. -Es gibt zwei Möglichkeiten, die Module auszuführen: - -1. Führen Sie ein einzelnes Modul aus: `python ultimatepython/syntax/variable.py` -2. Führen Sie alle Module aus: `python runner.py` - -## Inhaltsübersicht - -📚 = Externe Ressource, -🍰 = Thema für Anfänger, -🤯 = Fortgeschrittenes Thema - -1. **Über Python** - - Overview: [What is Python](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) - - Design philosophy: [The Zen of Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) - - Style guide: [Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) - - Data model: [Data model](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) - - Standard library: [The Python Standard Library](https://docs.python.org/3/library/) ( 📚, 🤯 ) - - Built-in functions: [Built-in Functions](https://docs.python.org/3/library/functions.html) ( 📚 ) -2. **Syntax** - - Variable: [Built-in literals](ultimatepython/syntax/variable.py) ( 🍰 ) - - Expression: [Numeric operations](ultimatepython/syntax/expression.py) ( 🍰 ) - - 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/) ( 📚 ) - - Conditional: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) - - Loop: [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) - - Function: [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) - - Walrus operator: [Assignment expressions :=](ultimatepython/syntax/walrus_operator.py) ( 🤯 ) - - Argument enforcement: [Positional-only / | Keyword-only *](ultimatepython/syntax/arg_enforcement.py) ( 🤯 ) -3. **Daten-Strukturen** - - List: [List operations](ultimatepython/data_structures/list.py) ( 🍰 ) - - Tuple: [Tuple operations](ultimatepython/data_structures/tuple.py) - - Set: [Set operations](ultimatepython/data_structures/set.py) - - Dict: [Dictionary operations](ultimatepython/data_structures/dict.py) ( 🍰 ) - - Dict union: [Dictionary merge | and |=](ultimatepython/data_structures/dict_union.py) ( 🤯 ) - - Comprehension: [list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) - - String: [String operations](ultimatepython/data_structures/string.py) ( 🍰 ) - - Deque: [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) - - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) - - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) - - Iterator-Tools: [Iterator-Tools](ultimatepython/data_structures/itertools.py) ( 🤯 ) - - Time complexity: [cPython operations](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) -4. **Klassen** - - Basic class: [Basic definition](ultimatepython/classes/basic_class.py) ( 🍰 ) - - Inheritance: [Inheritance](ultimatepython/classes/inheritance.py) ( 🍰 ) - - Abstract class: [Abstract definition](ultimatepython/classes/abstract_class.py) - - Exception class: [Exception definition](ultimatepython/classes/exception_class.py) - - Iterator class: [Iterator definition | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) - - Encapsulation: [Encapsulation definition](ultimatepython/classes/encapsulation.py) -5. **Fortgeschrittene** - - Decorator: [Decorator definition | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) - - File Handling: [File Handling](ultimatepython/advanced/file_handling.py) ( 🤯 ) - - Context manager: [Context managers](ultimatepython/advanced/context_manager.py) ( 🤯 ) - - Method resolution order: [mro](ultimatepython/advanced/mro.py) ( 🤯 ) - - Mixin: [Mixin definition](ultimatepython/advanced/mixin.py) ( 🤯 ) - - Metaclass: [Metaclass definition](ultimatepython/advanced/meta_class.py) ( 🤯 ) - - Thread: [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) - - Asyncio: [async | await](ultimatepython/advanced/async.py) ( 🤯 ) - - Weak reference: [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) - - Benchmark: [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) - - Mocking: [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) - - Regular expression: [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) - - Data format: [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) - - Datetime: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) - - Pattern Matching: [match | case](ultimatepython/advanced/pattern_matching.py) ( 🤯 ) - -## Zusätzliche Ressourcen - -👔 = Interview-Ressource, -🧪 = Code-Beispiele, -🧠 = Projektideen - -### GitHub repositories - -Lernen Sie weiter, indem Sie von anderen Quellen lesen. - -- [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔 , 🧪 ) -- [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔 , 🧪 ) -- [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) -- [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) -- [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) -- [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) -- [vinta/awesome-python](https://github.com/vinta/awesome-python) -- [academic/awesome-datascience](https://github.com/academic/awesome-datascience) -- [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) -- [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) -- [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) -- [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) -- [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) -- [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) -- [microsoft/ML-For-Beginners](https://github.com/microsoft/ML-For-Beginners) ( 🧪 ) -- [microsoft/Data-Science-For-Beginners](https://github.com/microsoft/Data-Science-For-Beginners) ( 🧪 ) -- [Avik-Jain/100-Days-Of-ML-Code](https://github.com/Avik-Jain/100-Days-Of-ML-Code) ( 🧪 ) - -### Projekte des Autors - -Projekte, die ich mit Python erstellt habe und die zeigen, was man nach dem Erlernen dieser Konzepte erstellen kann: - -- [huangsam/chowist](https://github.com/huangsam/chowist) ( 🧪 ) -- [huangsam/githooks](https://github.com/huangsam/githooks) ( 🧪 ) -- [huangsam/ragchain](https://github.com/huangsam/ragchain) ( 🧪 ) -- [huangsam/mailprune](https://github.com/huangsam/mailprune) ( 🧪 ) - -### Interaktive Übungen - -Üben Sie weiter, damit Ihre Programmierkenntnisse nicht einrosten. - -- [codechef.com](https://www.codechef.com/) ( 👔 ) -- [codeforces.com](https://codeforces.com/) -- [codementor.io](https://www.codementor.io) ( 🧠 ) -- [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) -- [codewars.com](https://www.codewars.com/) -- [exercism.io](https://exercism.io/) -- [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) -- [hackerearth.com](https://www.hackerearth.com/) -- [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) -- [kaggle.com](https://www.kaggle.com/) ( 🧠 ) -- [labex.io](https://labex.io/exercises/python)( 🧪 ) -- [leetcode.com](https://leetcode.com/) ( 👔 ) -- [projecteuler.net](https://projecteuler.net/) -- [replit.com](https://replit.com/) -- [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) -- [teclado.com](https://teclado.com/30-days-of-python/#prerequisites) ( 👔 ) -- [fullstakpython.org](https://fullstackpython.org/) ( 🧪 ) - -## Sternengucker der Zeit - -[![Stargazers over time](https://starchart.cc/huangsam/ultimate-python.svg?variant=adaptive)](https://starchart.cc/huangsam/ultimate-python) diff --git a/README.es.md b/README.es.md deleted file mode 100644 index 138ad36e..00000000 --- a/README.es.md +++ /dev/null @@ -1,189 +0,0 @@ -# Guía de estudio "Python Definitivo" - -[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) -[![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) -[![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) -[![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) -[![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) - -Guía de estudio "Python Definitivo" para principiantes y profesionales. 🐍 🐍 🐍 - -```python -print("Guía de estudio 'Python Definitivo'") -``` - -[English](README.md) | -[한국어](README.ko.md) | -[繁体中文](README.zh_tw.md) | -[Español](README.es.md) | -[Deutsch](README.de.md) | -[Français](README.fr.md) | -[हिन्दी](README.hi.md) | -[Português - Brasil](README.pt_br.md) - -Ultimate Python - -## Motivación - -Creé este repositorio de GitHub para compartir lo que he aprendido sobre [Python](https://www.python.org/) -durante más de 5 años usándolo como graduado de universidad, empleado en grandes empresas y como contribuidor -de código abierto en repositorios como [Celery](https://github.com/celery/celery) y -[Full Stack Python](https://github.com/mattmakai/fullstackpython.com). -Espero ver a más personas aprendiendo Python y persiguiendo su pasión a través de él. 🎓 - -## Objetivos - -Estos son los objetivos principales de esta guía: - -🏆 **Servir como un recurso** para principiantes de Python que prefieren aprender de forma práctica. -Este repositorio contiene una colección de módulos independientes que pueden ejecutarse en -un IDE como [PyCharm](https://www.jetbrains.com/pycharm/) y en el navegador, como -[Replit](https://replit.com/languages/python3). Incluso una terminal sencilla funcionará con los ejemplos. -La mayoría de las líneas de código tienen comentarios útiles que guían al lector paso a paso. -Se anima a los usuarios a modificar el código fuente en cualquier parte siempre y cuando las rutinas -principales (`main`) no se eliminen y los programas se ejecuten con éxito tras cada cambio (ver `runner.py`). - -🏆 **Servir como una guía pura** para aquellos que quieren reforzar los conceptos base de -Python. Se utilizan sólo las [librerías integradas](https://docs.python.org/3/library/) para que -estos conceptos puedan adquirirse sin el esfuerzo de aprender conocimientos de dominios específicos. -Por ello no se han instalado librerías y entornos de código abierto populares (como `sqlalchemy`, -`requests`, `pandas`). No obstante, leer el código fuente de estos frameworks es inspirador y altamente -recomendado si tu objetivo es convertirte en un verdadero -[Pythonista](https://www.urbandictionary.com/define.php?term=pythonista). - -## Empezando - -[![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) - -Haz clic en la imagen de arriba para crear un ambiente de trabajo en el navegador sin necesidad -de tener Git y Python instalados en tu ordenador local. Si estos requisitos ya se cumplen, -puedes clonar el repositorio directamente. - -Una vez que el repositorio sea accesible, estás listo para aprender de los módulos independientes. -Para aprender el máximo de cada módulo, lee el código del módulo y ejecútalo. -Hay dos maneras de ejecutar los módulos: - -1. Ejecuta un solo módulo: `python ultimatepython/syntax/variable.py` -2. Ejecuta todos los módulos: `python runner.py` - -## Contenido - -📚 = Recurso externo, -🍰 = Tema principiante, -🤯 = Tema avanzado - -1. **Sobre Python** - - Resumen: [¿Qué es Python?](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) - - Filosofía de diseño: [El Zen de Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) - - Guía de estilos: [Guía de estilos para código de Python](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) - - Modelo de datos: [Modelo de datos](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) - - Librería estándar: [La librería estándar de Python](https://docs.python.org/3/library/) ( 📚, 🤯 ) - - Funciones integradas: [Funciones integradas](https://docs.python.org/3/library/functions.html) ( 📚 ) -2. **Sintaxis** - - Variables: [Literales integrados](ultimatepython/syntax/variable.py) ( 🍰 ) - - Expresiones: [Operaciones numéricas](ultimatepython/syntax/expression.py) ( 🍰 ) - - 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/) ( 📚 ) - - Condicionales: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) - - Iteraciones: [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) - - Funciones: [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) - - Operador morsa: [Expresiones de asignación :=](ultimatepython/syntax/walrus_operator.py) ( 🤯 ) - - Aplicación de argumentos: [Solo posicional / | Solo palabra clave *](ultimatepython/syntax/arg_enforcement.py) ( 🤯 ) -3. **Estructura de datos** - - Lista: [Operaciones con listas](ultimatepython/data_structures/list.py) ( 🍰 ) - - Tupla: [Operaciones con tuplas](ultimatepython/data_structures/tuple.py) - - Set: [Operaciones con sets](ultimatepython/data_structures/set.py) - - Diccionario: [Operaciones con dicts](ultimatepython/data_structures/dict.py) ( 🍰 ) - - Unión de diccionarios: [Fusión de diccionarios | y |=](ultimatepython/data_structures/dict_union.py) ( 🤯 ) - - Comprensión: [list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) - - Cadena: [Operaciones con strings](ultimatepython/data_structures/string.py) ( 🍰 ) - - Deque: [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) - - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) - - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) - - Herramientas de iteradores: [Herramientas de iteradores](ultimatepython/data_structures/itertools.py) ( 🤯 ) - - Complejidad de tiempo: [Operaciones de cPython](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) -4. **Clases** - - Clase básica: [Definición de básica](ultimatepython/classes/basic_class.py) ( 🍰 ) - - Herencia: [Herencia](ultimatepython/classes/inheritance.py) ( 🍰 ) - - Clase abstracta: [Definición de abstracta](ultimatepython/classes/abstract_class.py) - - Clase de excepción: [Definición de excepción](ultimatepython/classes/exception_class.py) - - Clase iteradora: [Definición de iteradora | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) - - Encapsulación: [Definición de encapsulación](ultimatepython/classes/encapsulation.py) -5. **Avanzado** - - Decorador: [Definición de decorador | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) - - Manejo de archivos: [Manejo de archivos](ultimatepython/advanced/file_handling.py) ( 🤯 ) - - Gestor de contexto: [Gestores de contexto](ultimatepython/advanced/context_manager.py) ( 🤯 ) - - Orden de resolución de método (MRO por sus siglas en inglés): [mro](ultimatepython/advanced/mro.py) ( 🤯 ) - - Mixin: [Definición de Mixin](ultimatepython/advanced/mixin.py) ( 🤯 ) - - Metaclase: [Definición de metaclase](ultimatepython/advanced/meta_class.py) ( 🤯 ) - - Hilos: [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) - - Asyncio: [async | await](ultimatepython/advanced/async.py) ( 🤯 ) - - Referencias débiles: [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) - - Referencia: [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) - - Mocking: [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) - - Expresiones regulares: [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) - - Formatos de datos: [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) - - Fecha y hora: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) - - Coincidencia de patrones: [match | case](ultimatepython/advanced/pattern_matching.py) ( 🤯 ) - -## Recursos adicionales - -👔 = Recurso de entrevista, -🧪 = Ejemplos de código, -🧠 = Ideas para proyecto - -### Repositorios de GitHub - -Sigue aprendiendo leyendo otros buenos recursos. - -- [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔 , 🧪 ) -- [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔 , 🧪 ) -- [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) -- [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) -- [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) -- [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) -- [vinta/awesome-python](https://github.com/vinta/awesome-python) -- [academic/awesome-datascience](https://github.com/academic/awesome-datascience) -- [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) -- [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) -- [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) -- [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) -- [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) -- [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) -- [microsoft/ML-For-Beginners](https://github.com/microsoft/ML-For-Beginners) ( 🧪 ) -- [microsoft/Data-Science-For-Beginners](https://github.com/microsoft/Data-Science-For-Beginners) ( 🧪 ) -- [Avik-Jain/100-Days-Of-ML-Code](https://github.com/Avik-Jain/100-Days-Of-ML-Code) ( 🧪 ) - -### Proyectos del autor - -Proyectos que he creado con Python que muestran lo que puedes crear después de aprender estos conceptos: - -- [huangsam/chowist](https://github.com/huangsam/chowist) ( 🧪 ) -- [huangsam/githooks](https://github.com/huangsam/githooks) ( 🧪 ) -- [huangsam/ragchain](https://github.com/huangsam/ragchain) ( 🧪 ) -- [huangsam/mailprune](https://github.com/huangsam/mailprune) ( 🧪 ) - -### Práctica interactiva - -Continua practicando para que no se oxiden tus habilidades de programación. - -- [codechef.com](https://www.codechef.com/) ( 👔 ) -- [codeforces.com](https://codeforces.com/) -- [codementor.io](https://www.codementor.io) ( 🧠 ) -- [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) -- [codewars.com](https://www.codewars.com/) -- [exercism.io](https://exercism.io/) -- [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) -- [hackerearth.com](https://www.hackerearth.com/) -- [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) -- [kaggle.com](https://www.kaggle.com/) ( 🧠 ) -- [labex.io](https://labex.io/exercises/python)( 🧪 ) -- [leetcode.com](https://leetcode.com/) ( 👔 ) -- [projecteuler.net](https://projecteuler.net/) -- [replit.com](https://replit.com/) -- [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) -- [teclado.com](https://teclado.com/30-days-of-python/#prerequisites) ( 👔 ) -- [fullstakpython.org](https://fullstackpython.org/) ( 🧪 ) - -## Astrónomos en el tiempo - -[![Stargazers over time](https://starchart.cc/huangsam/ultimate-python.svg?variant=adaptive)](https://starchart.cc/huangsam/ultimate-python) diff --git a/README.fr.md b/README.fr.md deleted file mode 100644 index 63698a55..00000000 --- a/README.fr.md +++ /dev/null @@ -1,201 +0,0 @@ -# Guide d’étude Python ultime - -[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) -[![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) -[![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) -[![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) -[![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) - -Guide d’étude Python ultime pour les débutants comme pour les professionnels. 🐍 🐍 🐍 - -```python -print("Guide d’étude Python ultime") -``` - -[English](README.md) | -[한국어](README.ko.md) | -[繁体中文](README.zh_tw.md) | -[Español](README.es.md) | -[Deutsch](README.de.md) | -[Français](README.fr.md) | -[हिन्दी](README.hi.md) | -[Português - Brasil](README.pt_br.md) - -Ultimate Python - -## Motivation - -J’ai créé ce dépôt GitHub pour partager ce que j’ai appris sur le [cœur de Python](https://www.python.org/) -au cours de plus de 5 années d’utilisation: en tant que diplômé universitaire, employé -dans de grandes entreprises et contributeur open-source à des dépôts tels que -[Celery](https://github.com/celery/celery) et -[Full Stack Python](https://github.com/mattmakai/fullstackpython.com). -J’espère voir de plus en plus de personnes apprendre Python et poursuivre leurs passions -grâce à ce langage. 🎓 - -## Objectifs - -Voici les principaux objectifs de ce guide : - -🏆 **Servir de ressource** pour les débutants en Python qui préfèrent apprendre de manière pratique. -Ce dépôt contient une collection de modules indépendants pouvant être exécutés dans un IDE -comme [PyCharm](https://www.jetbrains.com/pycharm/) ou dans le navigateur via -[Replit](https://replit.com/languages/python3). Même un simple terminal suffit -pour exécuter les exemples. La plupart des lignes contiennent des commentaires détaillés -qui guident le lecteur pas à pas. -Les utilisateurs sont encouragés à modifier le code source à leur guise tant que les -routines `main` ne sont pas supprimées et que les programmes -[s’exécutent correctement](runner.py) après chaque modification. - -🏆 **Servir de guide pur** pour ceux qui souhaitent revoir les concepts fondamentaux de Python. -Seules les [bibliothèques intégrées](https://docs.python.org/3/library/) sont utilisées afin de -présenter les concepts sans dépendre de notions spécifiques à un domaine. Ainsi, les -bibliothèques open-source populaires comme `sqlalchemy`, `requests` ou `pandas` -ne sont pas installées. -Cependant, lire le code source de ces frameworks est fortement recommandé -si ton objectif est de devenir un véritable -[Pythonista](https://www.urbandictionary.com/define.php?term=pythonista). - -## Pour commencer - -[![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) - -Clique sur le badge ci-dessus pour lancer un environnement fonctionnel dans ton navigateur -sans avoir besoin d’installer Git ou Python localement. -Si ces outils sont déjà installés, tu peux cloner directement le dépôt. - -Une fois le dépôt accessible, tu es prêt à apprendre à partir des modules indépendants. -Pour tirer le meilleur parti de chaque module, lis le code et exécute-le. - -Deux méthodes sont possibles : - -1. Exécuter un seul module : -  `python ultimatepython/syntax/variable.py` -2. Exécuter tous les modules : -  `python runner.py` - -## Table des matières - -📚 = Ressource externe -🍰 = Sujet débutant -🤯 = Sujet avancé - -1. **À propos de Python** -    - Vue d’ensemble : [Qu’est-ce que Python](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) -    - Philosophie : [Le Zen de Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) -    - Guide de style : [Guide de style du code Python](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) -    - Modèle de données : [Modèle de données](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) -    - Bibliothèque standard : [Bibliothèque standard Python](https://docs.python.org/3/library/) ( 📚, 🤯 ) -    - Fonctions intégrées : [Fonctions intégrées](https://docs.python.org/3/library/functions.html) ( 📚 ) - -2. **Syntaxe** -    - Variable : [Littéraux intégrés](ultimatepython/syntax/variable.py) ( 🍰 ) -    - Expression : [Opérations numériques](ultimatepython/syntax/expression.py) ( 🍰 ) -    - Opérateurs binaires : [Opérateurs binaires](ultimatepython/syntax/bitwise.py) ( 🍰 ), [Complément à un et à deux](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) -    - Conditionnelle : [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) -    - Boucle : [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) -    - Fonction : [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) - - Opérateur morse : [Expressions d'affectation :=](ultimatepython/syntax/walrus_operator.py) ( 🤯 ) - - Application d'arguments : [Positionnels uniquement / | Mots-clés uniquement *](ultimatepython/syntax/arg_enforcement.py) ( 🤯 ) - -3. **Structures de données** -    - Liste : [Opérations sur les listes](ultimatepython/data_structures/list.py) ( 🍰 ) -    - Tuple : [Opérations sur les tuples](ultimatepython/data_structures/tuple.py) -    - Ensemble : [Opérations sur les ensembles](ultimatepython/data_structures/set.py) -    - Dictionnaire : [Opérations sur les dictionnaires](ultimatepython/data_structures/dict.py) ( 🍰 ) - - Union de dictionnaires : [Fusion de dictionnaires | et |=](ultimatepython/data_structures/dict_union.py) ( 🤯 ) -    - Compréhension : [list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) -    - Chaîne : [Opérations sur les chaînes](ultimatepython/data_structures/string.py) ( 🍰 ) -    - Deque : [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) -    - Namedtuple : [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) -    - Defaultdict : [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) -    - Outils d'itérateurs : [Outils d'itérateurs](ultimatepython/data_structures/itertools.py) ( 🤯 ) -    - Complexité temporelle : [Opérations CPython](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) - -4. **Classes** -    - Classe basique : [Définition basique](ultimatepython/classes/basic_class.py) ( 🍰 ) -    - Héritage : [Héritage](ultimatepython/classes/inheritance.py) ( 🍰 ) -    - Classe abstraite : [Définition abstraite](ultimatepython/classes/abstract_class.py) -    - Classe d’exception : [Définition d’exception](ultimatepython/classes/exception_class.py) -    - Itérateur : [Définition d’itérateur | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) -    - Encapsulation : [Définition de l’encapsulation](ultimatepython/classes/encapsulation.py) - -5. **Avancé** -    - Décorateur : [Définition de décorateur | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) -    - Gestion de fichiers : [File Handling](ultimatepython/advanced/file_handling.py) ( 🤯 ) -    - Gestionnaire de contexte : [Context managers](ultimatepython/advanced/context_manager.py) ( 🤯 ) -    - Ordre de résolution des méthodes : [mro](ultimatepython/advanced/mro.py) ( 🤯 ) -    - Mixin : [Définition de Mixin](ultimatepython/advanced/mixin.py) ( 🤯 ) -    - Métaclasse : [Définition de métaclasse](ultimatepython/advanced/meta_class.py) ( 🤯 ) -    - Thread : [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) -    - Asyncio : [async | await](ultimatepython/advanced/async.py) ( 🤯 ) -    - Référence faible : [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) -    - Benchmark : [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) -    - Mocking : [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) -    - Expressions régulières : [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) -    - Format de données : [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) -    - Date et heure : [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) - - Correspondance de motifs : [match | case](ultimatepython/advanced/pattern_matching.py) ( 🤯 ) - -## Ressources supplémentaires - -👔 = Ressource d’entretien -🧪 = Exemples de code -🧠 = Idées de projets - -### Dépôts GitHub - -Continue d’apprendre grâce à ces ressources bien établies : - -- [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔 , 🧪 ) -- [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔 , 🧪 ) -- [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) -- [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) -- [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) -- [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) -- [vinta/awesome-python](https://github.com/vinta/awesome-python) -- [academic/awesome-datascience](https://github.com/academic/awesome-datascience) -- [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) -- [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) -- [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) -- [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) -- [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) -- [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) -- [microsoft/ML-For-Beginners](https://github.com/microsoft/ML-For-Beginners) ( 🧪 ) -- [microsoft/Data-Science-For-Beginners](https://github.com/microsoft/Data-Science-For-Beginners) ( 🧪 ) -- [Avik-Jain/100-Days-Of-ML-Code](https://github.com/Avik-Jain/100-Days-Of-ML-Code) ( 🧪 ) - -### Projets de l'auteur - -Projets que j'ai créés avec Python qui montrent ce que vous pouvez créer après avoir appris ces concepts : - -- [huangsam/chowist](https://github.com/huangsam/chowist) ( 🧪 ) -- [huangsam/githooks](https://github.com/huangsam/githooks) ( 🧪 ) -- [huangsam/ragchain](https://github.com/huangsam/ragchain) ( 🧪 ) -- [huangsam/mailprune](https://github.com/huangsam/mailprune) ( 🧪 ) - -### Pratique interactive - -Continue à t’exercer pour ne pas perdre la main : - -- [codechef.com](https://www.codechef.com/) ( 👔 ) -- [codeforces.com](https://codeforces.com/) -- [codementor.io](https://www.codementor.io) ( 🧠 ) -- [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) -- [codewars.com](https://www.codewars.com/) -- [exercism.io](https://exercism.io/) -- [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) -- [hackerearth.com](https://www.hackerearth.com/) -- [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) -- [kaggle.com](https://www.kaggle.com/) ( 🧠 ) -- [labex.io](https://labex.io/exercises/python)( 🧪 ) -- [leetcode.com](https://leetcode.com/) ( 👔 ) -- [projecteuler.net](https://projecteuler.net/) -- [replit.com](https://replit.com/) -- [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) -- [teclado.com](https://teclado.com/30-days-of-python/#prerequisites) ( 👔 ) -- [fullstakpython.org](https://fullstackpython.org/) ( 🧪 ) - -## Observateurs d'étoiles dans le temps - -[![Stargazers over time](https://starchart.cc/huangsam/ultimate-python.svg?variant=adaptive)](https://starchart.cc/huangsam/ultimate-python) diff --git a/README.hi.md b/README.hi.md deleted file mode 100644 index fdb77a67..00000000 --- a/README.hi.md +++ /dev/null @@ -1,174 +0,0 @@ -# अल्टीमेट Python अध्ययन गाइड - -[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) -[![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) -[![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) -[![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) -[![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) - -नए और पेशेवर लोगों के लिए अल्टीमेट पायथन अध्ययन गाइड। 🐍 🐍 🐍 - -```python -print("Ultimate Python स्टडी गाइड") -``` - -[English](README.md) | -[한국어](README.ko.md) | -[繁体中文](README.zh_tw.md) | -[Español](README.es.md) | -[Deutsch](README.de.md) | -[Français](README.fr.md) | -[हिन्दी](README.hi.md) | -[Português - Brasil](README.pt_br.md) - -Ultimate Python - -## प्रेरणा - -मैंने यह गिटहब रिपोजिटरी [core Python](https://www.python.org/) के बारे में जो कुछ मैंने पिछले 5+ वर्षों में सीखा है, उसे साझा करने के लिए बनाई है। मैंने इसे एक कॉलेज ग्रेजुएट, बड़ी कंपनियों के कर्मचारी, और [Celery](https://github.com/celery/celery) और [Full Stack Python](https://github.com/mattmakai/fullstackpython.com) जैसी रिपोजिटरी के ओपन-सोर्स कंट्रीब्यूटर के रूप में उपयोग किया है। मैं यह देखने के लिए उत्सुक हूँ कि और लोग पायथन सीखें और इसके माध्यम से अपने जुनून को आगे बढ़ाएं। 🎓 - - -## लक्ष्य - -इस गाइड को बनाने के मुख्य लक्ष्य निम्नलिखित हैं: - -🏆 **संसाधन के रूप में सेवा देना** उन नए पायथन उपयोगकर्ताओं के लिए जो प्रैक्टिकल तरीके से सीखना पसंद करते हैं। इस रिपोजिटरी में स्वतंत्र मॉड्यूलों का एक संग्रह है, जिन्हें IDE जैसे [PyCharm](https://www.jetbrains.com/pycharm/) में या [Replit](https://replit.com/languages/python3) जैसे ब्राउज़र में चलाया जा सकता है। पुराने साधारण टर्मिनल में भी इन उदाहरणों को चलाया जा सकता है। अधिकतर लाइनों में बहुत ही अच्छे से लिखे गए comments होते हैं, जो पाठक को प्रोग्राम्स के प्रत्येक चरण के माध्यम से मार्गदर्शन करते हैं। उपयोगकर्ताओं को कोड में बदलाव करने के लिए प्रोत्साहित किया जाता है, बशर्ते कि `main` रूटीन को हटाया न जाए और हर परिवर्तन के बाद [सफलतापूर्वक चलाया जाए](runner.py)। - -🏆 **शुद्ध गाइड के रूप में सेवा देना** उन लोगों के लिए जो मुख्य पायथन अवधारणाओं को फिर से समझना चाहते हैं। केवल [बिल्ट-इन लाइब्रेरीज़](https://docs.python.org/3/library/) का उपयोग किया गया है ताकि इन अवधारणाओं को बिना किसी विशेष डोमेन की अवधारणाओं के सरलता से समझाया जा सके। इसी कारण से लोकप्रिय ओपन-सोर्स लाइब्रेरीज़ और फ्रेमवर्क (जैसे `sqlalchemy`, `requests`, `pandas`) को इंस्टॉल नहीं किया गया है। हालांकि, इन फ्रेमवर्क्स के स्रोत कोड को पढ़ना प्रेरणादायक है और यदि आपका लक्ष्य एक सच्चे [Pythonista](https://www.urbandictionary.com/define.php?term=pythonista) बनने का है तो इसे ज़रूर पढ़ना चाहिए। - - -## शुरूआत - -[![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) - -ऊपर दिए गए बैज पर क्लिक करें ताकि आप ब्राउज़र में एक कार्यशील वातावरण शुरू कर सकें, इसके लिए आपके स्थानीय मशीन पर Git और पायथन की आवश्यकता नहीं होगी। यदि ये आवश्यकताएँ पहले से ही पूरी हो चुकी हैं, तो आप सीधे रिपोजिटरी को क्लोन कर सकते हैं। - -एक बार जब रिपोजिटरी उपलब्ध हो जाती है, तो आप स्वतंत्र मॉड्यूल से सीखने के लिए तैयार हैं। प्रत्येक मॉड्यूल का अधिकतम लाभ उठाने के लिए, मॉड्यूल का कोड पढ़ें और इसे चलाएं। मॉड्यूल चलाने के दो तरीके हैं: - -1. एकल मॉड्यूल चलाएं: `python ultimatepython/syntax/variable.py` -2. सभी मॉड्यूल चलाएं: `python runner.py` - -## विषय सूची - -📚 = बाहरी स्रोत, -🍰 = शुरुआती विषय, -🤯 = उन्नत विषय - - -1. **पायथन के बारे में** - - अवलोकन: [पायथन क्या है](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) - - डिज़ाइन दर्शन: [पायथन का ज़ेन](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) - - शैली मार्गदर्शिका: [पायथन कोड के लिए शैली मार्गदर्शिका](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) - - डेटा मॉडल: [डेटा मॉडल](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) - - मानक पुस्तकालय: [पायथन मानक पुस्तकालय](https://docs.python.org/3/library/) ( 📚, 🤯 ) - - अंतर्निहित कार्य: [अंतर्निहित कार्य](https://docs.python.org/3/library/functions.html) ( 📚 ) -2. **सिंटेक्स** - - वेरिएबल: [अंतर्निहित लिटरल](ultimatepython/syntax/variable.py) ( 🍰 ) - - अभिव्यक्ति: [संख्यात्मक ऑपरेशन्स](ultimatepython/syntax/expression.py) ( 🍰 ) - - बाइनरी: [बाइनरी ऑपरेटर](ultimatepython/syntax/bitwise.py) ( 🍰 ), [एक्स/टू का पूरक](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) - - कंडीशनल: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) - - लूप: [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) - - फ़ंक्शन: [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) - - वॉलरस ऑपरेटर: [असाइनमेंट एक्सप्रेशन :=](ultimatepython/syntax/walrus_operator.py) ( 🤯 ) - - तर्क प्रवर्तन: [केवल स्थितीय / | केवल कीवर्ड *](ultimatepython/syntax/arg_enforcement.py) ( 🤯 ) -3. **डेटा संरचनाएँ** - - लिसट: [लिसट ऑपरेशन्स](ultimatepython/data_structures/list.py) ( 🍰 ) - - ट्यूपल: [ट्यूपल ऑपरेशन्स](ultimatepython/data_structures/tuple.py) - - सेट: [सेट ऑपरेशन्स](ultimatepython/data_structures/set.py) - - डिक्ट: [डिक्शनरी ऑपरेशन्स](ultimatepython/data_structures/dict.py) ( 🍰 ) - - डिक्शनरी यूनियन: [डिक्शनरी मर्ज | और |=](ultimatepython/data_structures/dict_union.py) ( 🤯 ) - - संकलन: [लिसट | ट्यूपल | सेट | डिक्ट](ultimatepython/data_structures/comprehension.py) - - स्ट्रिंग: [स्ट्रिंग ऑपरेशन्स](ultimatepython/data_structures/string.py) ( 🍰 ) - - डेक: [डेक](ultimatepython/data_structures/deque.py) ( 🤯 ) - - नामित ट्यूपल: [नामित ट्यूपल](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) - - डिफ़ॉल्ट डिक्ट: [डिफ़ॉल्ट डिक्ट](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) - - इटरेटर टूल्स: [इटरेटर टूल्स](ultimatepython/data_structures/itertools.py) ( 🤯 ) - - समय कोम्पलेक्सिटी: [cPython ऑपरेशन्स](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) -4. **क्लासेज़** - - बेसिक क्लास: [बेसिक परिभाषा](ultimatepython/classes/basic_class.py) ( 🍰 ) - - इन्हरिटैंस: [इन्हरिटैंस](ultimatepython/classes/inheritance.py) ( 🍰 ) - - एैबस्टराक्ट क्लास: [एैबस्टराक्ट परिभाषा](ultimatepython/classes/abstract_class.py) - - एक्सेपशन क्लास: [एक्सेपशन परिभाषा](ultimatepython/classes/exception_class.py) - - इटरेटर क्लास: [इटरेटर परिभाषा | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) - - ऐनकैपसुलेषन: [ऐनकैपसुलेषन परिभाषा](ultimatepython/classes/encapsulation.py) -5. **उन्नत** - - डेकोरेटर: [डेकोरेटर परिभाषा | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) - - फ़ाइल प्रबंधन: [फ़ाइल प्रबंधन](ultimatepython/advanced/file_handling.py) ( 🤯 ) - - संदर्भ प्रबंधक: [संदर्भ प्रबंधक](ultimatepython/advanced/context_manager.py) ( 🤯 ) - - मेथड रिज़ॉल्यूशन क्रम: [mro](ultimatepython/advanced/mro.py) ( 🤯 ) - - मिक्सिन: [मिक्सिन परिभाषा](ultimatepython/advanced/mixin.py) ( 🤯 ) - - मेटाक्लास: [मेटाक्लास परिभाषा](ultimatepython/advanced/meta_class.py) ( 🤯 ) - - थ्रेड: [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) - - एसिंको: [async | await](ultimatepython/advanced/async.py) ( 🤯 ) - - वीक रेफरेंस: [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) - - बेंचमार्क: [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) - - मॉकिंग: [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) - - नियमित अभिव्यक्ति: [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) - - डेटा फ़ॉर्मेट: [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) - - दिनांक और समय: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) - - पैटर्न मिलान: [match | case](ultimatepython/advanced/pattern_matching.py) ( 🤯 ) - - -## अतिरिक्त संसाधन - -👔 = इंटरव्यू संसाधन, -🧪 = कोड नमूने, -🧠 = प्रोजेक्ट विचार - - -### गिटहब रिपॉजिटरी - -अन्य उच्च मानक संसाधनों से पढ़कर सीखना जारी रखें। - -- [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔 , 🧪 ) -- [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔 , 🧪 ) -- [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) -- [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) -- [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) -- [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) -- [vinta/awesome-python](https://github.com/vinta/awesome-python) -- [academic/awesome-datascience](https://github.com/academic/awesome-datascience) -- [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) -- [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) -- [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) -- [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) -- [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) -- [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) -- [microsoft/ML-For-Beginners](https://github.com/microsoft/ML-For-Beginners) ( 🧪 ) -- [microsoft/Data-Science-For-Beginners](https://github.com/microsoft/Data-Science-For-Beginners) ( 🧪 ) -- [Avik-Jain/100-Days-Of-ML-Code](https://github.com/Avik-Jain/100-Days-Of-ML-Code) ( 🧪 ) - -### लेखक की परियोजनाएँ - -Python से बनाई गई परियोजनाएं जो दिखाती हैं कि इन अवधारणाओं को सीखने के बाद आप क्या बना सकते हैं: - -- [huangsam/chowist](https://github.com/huangsam/chowist) ( 🧪 ) -- [huangsam/githooks](https://github.com/huangsam/githooks) ( 🧪 ) -- [huangsam/ragchain](https://github.com/huangsam/ragchain) ( 🧪 ) -- [huangsam/mailprune](https://github.com/huangsam/mailprune) ( 🧪 ) - -### इंटरैक्टिव प्रैक्टिस - -अभ्यास करते रहें ताकि आपकी कोडिंग कौशल खराब न हों। - -- [codechef.com](https://www.codechef.com/) ( 👔 ) -- [codeforces.com](https://codeforces.com/) -- [codementor.io](https://www.codementor.io) ( 🧠 ) -- [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) -- [codewars.com](https://www.codewars.com/) -- [exercism.io](https://exercism.io/) -- [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) -- [hackerearth.com](https://www.hackerearth.com/) -- [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) -- [kaggle.com](https://www.kaggle.com/) ( 🧠 ) -- [labex.io](https://labex.io/exercises/python)( 🧪 ) -- [leetcode.com](https://leetcode.com/) ( 👔 ) -- [projecteuler.net](https://projecteuler.net/) -- [replit.com](https://replit.com/) -- [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) -- [teclado.com](https://teclado.com/30-days-of-python/#prerequisites) ( 👔 ) -- [fullstakpython.org](https://fullstackpython.org/) ( 🧪 ) - -## समय के खगोलशास्त्री - -[![Stargazers over time](https://starchart.cc/huangsam/ultimate-python.svg?variant=adaptive)](https://starchart.cc/huangsam/ultimate-python) diff --git a/README.ko.md b/README.ko.md deleted file mode 100644 index 42c47f29..00000000 --- a/README.ko.md +++ /dev/null @@ -1,180 +0,0 @@ -# Ultimate Python 학습 가이드 - -[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) -[![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) -[![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) -[![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) -[![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) - -초보자와 전문가 모두를 위한 최고의 Python 학습 가이드입니다. 🐍 🐍 🐍 - -```python -print("Ultimate Python 학습 가이드") -``` - -[English](README.md) | -[한국어](README.ko.md) | -[繁体中文](README.zh_tw.md) | -[Español](README.es.md) | -[Deutsch](README.de.md) | -[Français](README.fr.md) | -[हिन्दी](README.hi.md) | -[Português - Brasil](README.pt_br.md) - -Ultimate Python - -## 동기 - -이 GitHub 저장소는 대학 졸업 후, 대규모 회사에서 근무하면서 -그리고 [Celery](https://github.com/celery/celery)와 [Full Stack Python](https://github.com/mattmakai/fullstackpython.com) 같은 오픈소스 프로젝트에 기여하면서 -지난 5년 이상 동안 배운 [core Python](https://www.python.org/)에 대한 지식을 공유하기 위해 만들었습니다. -저는 더 많은 사람들이 Python을 배우고 자신의 열정을 추구하길 기대합니다. 🎓 - -## 목표 - -이 가이드를 만드는 주요 목표는 다음과 같습니다: - -🏆 실습 학습을 선호하는 Python 초보자를 위한 **학습 자료를 제공합니다.** -이 저장소에는 [PyCharm](https://www.jetbrains.com/pycharm/)과 같은 IDE 및 [Replit](https://replit.com/languages/python3)와 같은 브라우저에서 실행할 수 있는 독립형 모듈 모음이 있습니다. 기본 터미널에서도 예제를 실행할 수 있습니다. -대부분의 코드 라인에 프로그램이 단계별로 어떤 작업을 하는지 안내하는 신중하게 작성된 주석이 있습니다. -사용자는 `main` 루틴을 삭제하지 않고, 각 변경 후에 [성공적으로 실행](runner.py)되는 한 소스 코드를 얼마든지 수정할 수 있습니다. - -🏆 core Python 개념을 다시 복습하고 싶은 사람들을 위한 **순수 가이드를 제공합니다.** -여기서는 오직 [내장 라이브러리](https://docs.python.org/3/library/)만을 사용하여 이러한 개념을 도메인 특화된 개념의 오버헤드 없이 전달합니다. -따라서 유명한 오픈소스 라이브러리와 프레임워크(`sqlalchemy`, `requests`, `pandas` 등)는 설치되어 있지 않습니다. -그러나, 당신의 목표가 진정한 진정한 [Pythonista](https://www.urbandictionary.com/define.php?term=pythonista)이 되는 것 이라면 이러한 프레임워크의 소스 코드를 읽는 것은 매우 고무적이고 권장이 됩니다. - -## 시작하기 - -[![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) - -로컬 컴퓨터에 Git 및 Python을 설치하지 않고도 브라우저에서 작업 환경을 시작하려면 위의 배지를 클릭하세요. 이러한 -요구 사항이 이미 충족된 경우, 저장소를 바로 clone해도 됩니다. - -저장소에 접근할 수 있게 되면 단독 모듈에서 배울 준비가 된 것입니다. 각 모듈을 최대한 활용하려면 모듈 코드를 -읽고 실행하십시오. 모듈을 실행하는 두 가지 방법이 있습니다: - -1. 단일 모듈 실행 : `python ultimatepython/syntax/variable.py` -2. 전체 모듈 실행 : `python runner.py` - -## 목차 - -📚 = 외부 리소스, -🍰 = 초급 주제, -🤯 = 고급 주제 - -1. **Python 정보** - - 개요 : [Python이란 무엇인가](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) - - 디자인 철학 : [The Zen of Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) - - 스타일 가이드 : [Python 코드 스타일 가이드](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) - - 데이터 모델 : [데이터 모델](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) - - 표준 라이브러리 : [Python 표준 라이브러리](https://docs.python.org/3/library/) ( 📚, 🤯 ) - - 내장 함수 : [내장 함수](https://docs.python.org/3/library/functions.html) ( 📚 ) -2. **통사론** - - 변수 : [내장 리터럴](ultimatepython/syntax/variable.py) ( 🍰 ) - - 표현식 : [숫자 연산](ultimatepython/syntax/expression.py) ( 🍰 ) - - 비트 연산 : [비트 연산자](ultimatepython/syntax/bitwise.py) ( 🍰 ), [1의 보수/2의 보수](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) - - 조건문 : [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) - - 반복문 : [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) - - 함수 : [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) - - 바다코끼리 연산자 : [할당 표현식 :=](ultimatepython/syntax/walrus_operator.py) ( 🤯 ) - - 인수 강제 : [위치 전용 / | 키워드 전용 *](ultimatepython/syntax/arg_enforcement.py) ( 🤯 ) -3. **데이터 구조** - - 리스트 : [리스트 연산](ultimatepython/data_structures/list.py) ( 🍰 ) - - 튜플 : [튜플 연산](ultimatepython/data_structures/tuple.py) - - 세트 : [세트 연산](ultimatepython/data_structures/set.py) - - 딕셔너리 : [딕셔너리 연산](ultimatepython/data_structures/dict.py) ( 🍰 ) - - 딕셔너리 합병 : [딕셔너리 병합 | 및 |=](ultimatepython/data_structures/dict_union.py) ( 🤯 ) - - 컴프리헨션 : [리스트 | 튜플 | 세트 | 딕셔너리](ultimatepython/data_structures/comprehension.py) - - 문자열 : [문자열 연산](ultimatepython/data_structures/string.py) ( 🍰 ) - - 덱: [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) - - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) - - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) - - 이터레이터 도구: [이터레이터 도구](ultimatepython/data_structures/itertools.py) ( 🤯 ) - - 시간 복잡도 : [cPython 연산](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) -4. **클래스** - - 기본 클래스 : [기본 정의](ultimatepython/classes/basic_class.py) ( 🍰 ) - - 계승: [계승](ultimatepython/classes/inheritance.py) ( 🍰 ) - - 추상 클래스 : [추상 정의](ultimatepython/classes/abstract_class.py) - - 예외 클래스 : [예외 정의](ultimatepython/classes/exception_class.py) - - 이터레이터 클래스 : [이터레이터 정의 | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) - - 캡슐화: [캡슐화 정의](ultimatepython/classes/encapsulation.py) -5. **고급** - - 데코레이터 : [데코레이터 정의 | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) - - 파일 처리: [파일 처리](ultimatepython/advanced/file_handling.py) ( 🤯 ) - - 컨텍스트 매니저 : [컨텍스트 매니저](ultimatepython/advanced/context_manager.py) ( 🤯 ) - - 메서드 결정 순서 : [mro](ultimatepython/advanced/mro.py) ( 🤯 ) - - 믹스인 : [믹스인 정의](ultimatepython/advanced/mixin.py) ( 🤯 ) - - 메타클래스 : [메타클래스 정의](ultimatepython/advanced/meta_class.py) ( 🤯 ) - - 스레드 : [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) - - Asyncio : [async | await](ultimatepython/advanced/async.py) ( 🤯 ) - - 약한 참조 : [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) - - 벤치마크 : [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) - - 모킹 : [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) - - 정규식 : [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) - - 데이터 포맷 : [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) - - 날짜와 시간 : [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) - - 패턴 매칭: [match | case](ultimatepython/advanced/pattern_matching.py) ( 🤯 ) - -## 추가 자료 - -👔 = 인터뷰 자료, -🧪 = 코드 샘플, -🧠 = 프로젝트 아이디어 - -### GitHub 저장소 - -잘 알려진 다른 자료를 읽으면서 계속 배우세요. - -- [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔 , 🧪 ) -- [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔 , 🧪 ) -- [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) -- [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) -- [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) -- [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) -- [vinta/awesome-python](https://github.com/vinta/awesome-python) -- [academic/awesome-datascience](https://github.com/academic/awesome-datascience) -- [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) -- [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) -- [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) -- [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) -- [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) -- [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) -- [microsoft/ML-For-Beginners](https://github.com/microsoft/ML-For-Beginners) ( 🧪 ) -- [microsoft/Data-Science-For-Beginners](https://github.com/microsoft/Data-Science-For-Beginners) ( 🧪 ) -- [Avik-Jain/100-Days-Of-ML-Code](https://github.com/Avik-Jain/100-Days-Of-ML-Code) ( 🧪 ) - -### 저자의 프로젝트 - -이러한 개념을 익힌 후 무엇을 만들 수 있는지 보여주는 Python으로 제작한 프로젝트들입니다: - -- [huangsam/chowist](https://github.com/huangsam/chowist) ( 🧪 ) -- [huangsam/githooks](https://github.com/huangsam/githooks) ( 🧪 ) -- [huangsam/ragchain](https://github.com/huangsam/ragchain) ( 🧪 ) -- [huangsam/mailprune](https://github.com/huangsam/mailprune) ( 🧪 ) - -### 대화형 연습 - -코딩 실력이 녹슬지 않기 위해 계속 연습하세요. - -- [codechef.com](https://www.codechef.com/) ( 👔 ) -- [codeforces.com](https://codeforces.com/) -- [codementor.io](https://www.codementor.io) ( 🧠 ) -- [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) -- [codewars.com](https://www.codewars.com/) -- [exercism.io](https://exercism.io/) -- [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) -- [hackerearth.com](https://www.hackerearth.com/) -- [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) -- [kaggle.com](https://www.kaggle.com/) ( 🧠 ) -- [labex.io](https://labex.io/exercises/python)( 🧪 ) -- [leetcode.com](https://leetcode.com/) ( 👔 ) -- [projecteuler.net](https://projecteuler.net/) -- [replit.com](https://replit.com/) -- [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) -- [teclado.com](https://teclado.com/30-days-of-python/#prerequisites) ( 👔 ) -- [fullstakpython.org](https://fullstackpython.org/) ( 🧪 ) - -## 시대의 별 관측자 - -[![Stargazers over time](https://starchart.cc/huangsam/ultimate-python.svg?variant=adaptive)](https://starchart.cc/huangsam/ultimate-python) diff --git a/README.md b/README.md index bcdc806b..dcd1a48b 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,38 @@ # Ultimate Python study guide -[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) -[![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) -[![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) -[![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) -[![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) +![](https://img.shields.io/circleci/build/github/huangsam/ultimate-python) +![](https://img.shields.io/github/license/huangsam/ultimate-python) -Ultimate Python study guide for newcomers and professionals alike. 🐍 🐍 🐍 +Ultimate Python study guide for newcomers and professionals alike. :snake: :snake: :snake: ```python print("Ultimate Python study guide") ``` -[English](README.md) | -[한국어](README.ko.md) | -[繁体中文](README.zh_tw.md) | -[Español](README.es.md) | -[Deutsch](README.de.md) | -[Français](README.fr.md) | -[हिन्दी](README.hi.md) | -[Português - Brasil](README.pt_br.md) - -Ultimate Python - ## Motivation -I created this GitHub repo to share what I've learned about [core Python](https://www.python.org/) +I created a GitHub repo to share what I've learned about [core Python](https://www.python.org/) over the past 5+ years of using it as a college graduate, an employee at large-scale companies and an open-source contributor of repositories like [Celery](https://github.com/celery/celery) and [Full Stack Python](https://github.com/mattmakai/fullstackpython.com). I look forward to seeing more people learn Python and pursue their passions -through it. 🎓 +through it. :mortar_board: ## Goals Here are the primary goals of creating this guide: -🏆 **Serve as a resource** for Python newcomers who prefer to learn hands-on. +:trophy: **Serve as a resource** for Python newcomers who prefer to learn hands-on. This repository has a collection of standalone modules which can be run in an IDE like [PyCharm](https://www.jetbrains.com/pycharm/) and in the browser like -[Replit](https://replit.com/languages/python3). Even a plain old terminal will work +[Repl.it](https://repl.it/languages/python3). Even a plain old terminal will work with the examples. Most lines have carefully crafted comments which guide a reader through what the programs are doing step-by-step. Users are encouraged to modify source code anywhere as long as the `main` routines are not deleted and [run successfully](runner.py) after each change. -🏆 **Serve as a pure guide** for those who want to revisit core Python concepts. +:trophy: **Serve as a pure guide** for those who want to revisit core Python concepts. Only [builtin libraries](https://docs.python.org/3/library/) are leveraged so that these concepts can be conveyed without the overhead of domain-specific concepts. As such, popular open-source libraries and frameworks (i.e. `sqlalchemy`, `requests`, @@ -54,139 +40,66 @@ such, popular open-source libraries and frameworks (i.e. `sqlalchemy`, `requests inspiring and highly encouraged if your goal is to become a true [Pythonista](https://www.urbandictionary.com/define.php?term=pythonista). -## Getting started - -[![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) - -Click the badge above to spin up a working environment in the browser without -needing Git and Python installed on your local machine. If these requirements -are already met, feel free to clone the repository directly. - -Once the repository is accessible, you are ready to learn from the standalone -modules. To get the most out of each module, read the module code and run it. -There are two ways of running the modules: - -1. Run a single module: `python ultimatepython/syntax/variable.py` -2. Run all of the modules: `python runner.py` - ## Table of contents -📚 = External resource, -🍰 = Beginner topic, -🤯 = Advanced topic +:books: = External resource, +:cake: = Beginner topic, +:exploding_head: = Advanced topic 1. **About Python** - - Overview: [What is Python](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) - - Design philosophy: [The Zen of Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) - - Style guide: [Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) - - Data model: [Data model](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) - - Standard library: [The Python Standard Library](https://docs.python.org/3/library/) ( 📚, 🤯 ) - - Built-in functions: [Built-in Functions](https://docs.python.org/3/library/functions.html) ( 📚 ) + - Overview: [What is Python](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) (:books:, :cake:) + - Design Philosophy: [The Zen of Python](https://www.python.org/dev/peps/pep-0020/) (:books:) + - Style Guide: [Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) (:books:, :exploding_head:) + - Data Model: [Data model](https://docs.python.org/3/reference/datamodel.html) (:books:, :exploding_head:) 2. **Syntax** - - Variable: [Built-in literals](ultimatepython/syntax/variable.py) ( 🍰 ) - - Expression: [Numeric operations](ultimatepython/syntax/expression.py) ( 🍰 ) - - 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/) ( 📚 ) - - Conditional: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) - - Loop: [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) - - Function: [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) - - Walrus operator: [Assignment expressions :=](ultimatepython/syntax/walrus_operator.py) ( 🤯 ) - - Argument enforcement: [Positional-only / | Keyword-only *](ultimatepython/syntax/arg_enforcement.py) ( 🤯 ) + - Variable: [Built-in literals](ultimatepython/syntax/variable.py) (:cake:) + - Expression: [Numeric operations](ultimatepython/syntax/expression.py) (:cake:) + - Conditional: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) (:cake:) + - Loop: [for-loop | while-loop](ultimatepython/syntax/loop.py) (:cake:) + - Function: [def | lambda](ultimatepython/syntax/function.py) (:cake:) 3. **Data Structures** - - List: [List operations](ultimatepython/data_structures/list.py) ( 🍰 ) + - List: [List operations](ultimatepython/data_structures/list.py) (:cake:) - Tuple: [Tuple operations](ultimatepython/data_structures/tuple.py) - Set: [Set operations](ultimatepython/data_structures/set.py) - - Dict: [Dictionary operations](ultimatepython/data_structures/dict.py) ( 🍰 ) - - Dict union: [Dictionary merge | and |=](ultimatepython/data_structures/dict_union.py) ( 🤯 ) + - Dict: [Dictionary operations](ultimatepython/data_structures/dict.py) (:cake:) - Comprehension: [list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) - - String: [String operations](ultimatepython/data_structures/string.py) ( 🍰 ) - - Deque: [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) - - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) - - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) - - Itertools: [Iterator tools](ultimatepython/data_structures/itertools.py) ( 🤯 ) - - Time complexity: [cPython operations](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) + - String: [String operations](ultimatepython/data_structures/string.py) (:cake:) 4. **Classes** - - Basic class: [Basic definition](ultimatepython/classes/basic_class.py) ( 🍰 ) - - Inheritance: [Inheritance](ultimatepython/classes/inheritance.py) ( 🍰 ) + - Basic class: [Basic definition](ultimatepython/classes/basic_class.py) (:cake:) - Abstract class: [Abstract definition](ultimatepython/classes/abstract_class.py) - Exception class: [Exception definition](ultimatepython/classes/exception_class.py) - - Iterator class: [Iterator definition | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) - - Encapsulation: [Encapsulation definition](ultimatepython/classes/encapsulation.py) + - Iterator class: [Iterator definition | yield](ultimatepython/classes/iterator_class.py) (:exploding_head:) 5. **Advanced** - - Decorator: [Decorator definition | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) - - File Handling: [File Handling](ultimatepython/advanced/file_handling.py) ( 🤯 ) - - Context manager: [Context managers](ultimatepython/advanced/context_manager.py) ( 🤯 ) - - Method resolution order: [mro](ultimatepython/advanced/mro.py) ( 🤯 ) - - Mixin: [Mixin definition](ultimatepython/advanced/mixin.py) ( 🤯 ) - - Metaclass: [Metaclass definition](ultimatepython/advanced/meta_class.py) ( 🤯 ) - - Thread: [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) - - Asyncio: [async | await](ultimatepython/advanced/async.py) ( 🤯 ) - - Weak reference: [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) - - Benchmark: [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) - - Mocking: [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) - - Regular expression: [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) - - Data format: [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) - - Datetime: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) - - Pattern matching: [match | case](ultimatepython/advanced/pattern_matching.py) ( 🤯 ) + - Decorator: [contextlib | wraps](ultimatepython/advanced/decorator.py) (:exploding_head:) + - Metaclass: [Metaclass definition](ultimatepython/advanced/meta_class.py) (:exploding_head:) + - Method Resolution Order: [mro](ultimatepython/advanced/mro.py) (:exploding_head:) + - Asyncio: [async | await](ultimatepython/advanced/async.py) (:exploding_head:) + - Weak reference: [weakref](ultimatepython/advanced/weak_ref.py) (:exploding_head:) + - Benchmark: [cProfile | pstats](ultimatepython/advanced/benchmark.py) (:exploding_head:) ## Additional resources -👔 = Interview resource, -🧪 = Code samples, -🧠 = Project ideas +:necktie: = Interview resource, +:test_tube: = Code samples, +:brain: = Project ideas ### GitHub repositories Keep learning by reading from other well-regarded resources. -- [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔 , 🧪 ) -- [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔 , 🧪 ) -- [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) -- [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) -- [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) -- [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) -- [vinta/awesome-python](https://github.com/vinta/awesome-python) -- [academic/awesome-datascience](https://github.com/academic/awesome-datascience) -- [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) -- [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) -- [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) -- [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) -- [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) -- [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) -- [microsoft/ML-For-Beginners](https://github.com/microsoft/ML-For-Beginners) ( 🧪 ) -- [microsoft/Data-Science-For-Beginners](https://github.com/microsoft/Data-Science-For-Beginners) ( 🧪 ) -- [Avik-Jain/100-Days-Of-ML-Code](https://github.com/Avik-Jain/100-Days-Of-ML-Code) ( 🧪 ) - -### Author projects - -Projects I've built with Python that showcase what you can create after learning these concepts: - -- [huangsam/chowist](https://github.com/huangsam/chowist) ( 🧪 ) -- [huangsam/githooks](https://github.com/huangsam/githooks) ( 🧪 ) -- [huangsam/ragchain](https://github.com/huangsam/ragchain) ( 🧪 ) -- [huangsam/mailprune](https://github.com/huangsam/mailprune) ( 🧪 ) +- [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) (:necktie:, :test_tube:) +- [faif/python-patterns](https://github.com/faif/python-patterns) (:necktie:, :test_tube:) +- [geekcomputers/Python](https://github.com/geekcomputers/Python) (:test_tube:) +- [karan/Projects](https://github.com/karan/Projects) (:brain:) +- [vinta/awesome-python](https://github.com/vinta/awesome-python) (:brain:) +- [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) (:brain:) ### Interactive practice Keep practicing so that your coding skills don't get rusty. -- [codechef.com](https://www.codechef.com/) ( 👔 ) -- [codeforces.com](https://codeforces.com/) -- [codementor.io](https://www.codementor.io) ( 🧠 ) -- [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) -- [codewars.com](https://www.codewars.com/) +- [leetcode.com](https://leetcode.com/) (:necktie:) +- [hackerrank.com](https://www.hackerrank.com/) (:necktie:) +- [codesignal.com](https://codesignal.com/) (:necktie:) - [exercism.io](https://exercism.io/) -- [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) -- [hackerearth.com](https://www.hackerearth.com/) -- [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) -- [kaggle.com](https://www.kaggle.com/) ( 🧠 ) -- [labex.io](https://labex.io/exercises/python)( 🧪 ) -- [leetcode.com](https://leetcode.com/) ( 👔 ) - [projecteuler.net](https://projecteuler.net/) -- [replit.com](https://replit.com/) -- [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) -- [teclado.com](https://teclado.com/30-days-of-python/#prerequisites) ( 👔 ) -- [fullstakpython.org](https://fullstackpython.org/) ( 🧪 ) - -## Stargazers over time - -[![Stargazers over time](https://starchart.cc/huangsam/ultimate-python.svg?variant=adaptive)](https://starchart.cc/huangsam/ultimate-python) diff --git a/README.pt_br.md b/README.pt_br.md deleted file mode 100644 index 1a6b20bd..00000000 --- a/README.pt_br.md +++ /dev/null @@ -1,178 +0,0 @@ -# Ultimate Python - O seu guia de estudos de Python definitivo - -[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) -[![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) -[![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) -[![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) -[![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) - -Guia de estudo definitivo de Python para iniciantes e profissionais. 🐍 🐍 🐍 - -```python -print("Ultimate Python - O seu guia de estudos de Python definitivo") -``` - -[English](README.md) | -[한국어](README.ko.md) | -[繁体中文](README.zh_tw.md) | -[Español](README.es.md) | -[Deutsch](README.de.md) | -[Français](README.fr.md) | -[हिन्दी](README.hi.md) | -[Português - Brasil](README.pt_br.md) - -Ultimate Python - O seu guia de estudos de Python definitivo - -## Motivação - -Eu criei este repositório a fim de compartilhar o que eu aprendi sobre o [básico de Python](https://www.python.org/) nos último 5+ anos de uso como graduado universitário, um empregado em uma empresa de grande porte e um contribuidor de repositórios open-source como [Celery](https://github.com/celery/celery) e -[Full Stack Python](https://github.com/mattmakai/fullstackpython.com). -Eu estou ansiono para ver mais pessoas aprendendo Python e buscando suas paixões através disso. 🎓 - -## Objetivos - -Aqui estão os principais objetivos da criação deste guia: - -🏆 **Servir como um recurso** para iniciantes em Python que preferem aprender na prática. -Este repositório possui uma coleção de módulos autônomos que podem ser executados em um IDE como [PyCharm](https://www.jetbrains.com/pycharm/) e no navegador como [Replit](https://replit.com/languages/python3). Até mesmo um terminal simples funcionará com os exemplos. -A maioria das linhas possui comentários cuidadosamente elaborados que guiam o leitor passo a passo sobre o que os programas estão fazendo. Usuários são incentivados a modificar o código fonte em qualquer lugar, desde que as rotinas `main` não sejam excluídas e [sejam executadas com sucesso](runner.py) após cada alteração. - -🏆 **Servir como um guia prático** para aqueles que queiram revisitar os conceitos básicos de Python. -Apenas [blibliotecas internas](https://docs.python.org/3/library/) são utilizadas para que esses conceitos possam ser transmitidos sem a sobrecarga de conceitos específicos de domínio. -Dessa forma, bibliotecas e frameworks populares de código aberto (como por exemplo `sqlalchemy`, `requests`, -`pandas`) não são instalados. No entanto, ler o código fonte desses estruturas é inspirador e altamente recomendado se o seu objetivo é se tornar um verdadeiro [Pythonista](https://www.urbandictionary.com/define.php?term=pythonista). - -## Começando - -[![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) - -Click no emblema acima para criar um ambiente de trabalho no navegador sem a necessidade de instalar Git e Python na sua máquina local. Se esses requisitos já forem atendidos (se você já tem isso instalado), sinta-se à vontade para clonar o repositório diretamente. - -Uma vez que o repositório esteja acessível você está pronto para aprender com os módulos independentes. Para aproveitar ao máximo cada módulo, leia o código do módulo e execute-o. - -Existem duas maneiras de rodar os módulos: - -1. Execute um módulo único: `python ultimatepython/syntax/variable.py` -2. Execute todos os módulos: `python runner.py` - -## Índice - -📚 = Recurso externo, -🍰 = Tópico para iniciantes, -🤯 = Tópico avançado - -1. **Sobre Python** - - Visão geral: [O que é Python](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) - - Filosofia de design: [O zen do Python](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) - - Guia de estilo: [Guia de estilo para código Python](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) - - Modelo de dados: [Modelo de dados](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) - - Biblioteca padrão: [A Biblioteca padrão do Python](https://docs.python.org/3/library/) ( 📚, 🤯 ) - - Funções integradas: [Funções integradas](https://docs.python.org/3/library/functions.html) ( 📚 ) -2. **Sintaxe** - - Variável: [Literais integrados](ultimatepython/syntax/variable.py) ( 🍰 ) - - Expressão: [Operações numéricas](ultimatepython/syntax/expression.py) ( 🍰 ) - - Bitwise: [Operadores bitwise](ultimatepython/syntax/bitwise.py) ( 🍰 ), [Complemento de Um/Dois](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) - - Condicional: [if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) - - Loop/Laço: [for-loop | while-loop](ultimatepython/syntax/loop.py) ( 🍰 ) - - Função: [def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) - - Operador morsa: [Expressões de atribuição :=](ultimatepython/syntax/walrus_operator.py) ( 🤯 ) - - Aplicação de argumentos: [Somente posicional / | Somente palavra-chave *](ultimatepython/syntax/arg_enforcement.py) ( 🤯 ) -3. **Estrutura de dados** - - Lista: [Operações de lista](ultimatepython/data_structures/list.py) ( 🍰 ) - - Tupla: [Operações de tuplas](ultimatepython/data_structures/tuple.py) - - Conjunto: [Operações de conjuntos](ultimatepython/data_structures/set.py) - - Dicionário: [Operações de dicionários](ultimatepython/data_structures/dict.py) ( 🍰 ) - - União de dicionários: [Fusão de dicionários | e |=](ultimatepython/data_structures/dict_union.py) ( 🤯 ) - - Comprehension: [list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) - - String: [Operações de String](ultimatepython/data_structures/string.py) ( 🍰 ) - - Deque: [deque](ultimatepython/data_structures/deque.py) ( 🤯 ) - - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) - - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) - - Ferramentas de iteradores: [Ferramentas de iteradores](ultimatepython/data_structures/itertools.py) ( 🤯 ) - - Time complexity: [Operações de cPython](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) -4. **Classes** - - O básico de classes: [Definição de classe](ultimatepython/classes/basic_class.py) ( 🍰 ) - - Herança: [Herança](ultimatepython/classes/inheritance.py) ( 🍰 ) - - Classe abstrata: [Definição de classe abstrata](ultimatepython/classes/abstract_class.py) - - Classe de exceção: [Definição de Classe de exceção](ultimatepython/classes/exception_class.py) - - Classe Iterator: [Definição de classe Iterator | yield](ultimatepython/classes/iterator_class.py) ( 🤯 ) - - Encapsulamento: [Definição de encapsulamento](ultimatepython/classes/encapsulation.py) -5. **Avançado** - - Decorator: [Definição de decorator | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) - - Manuseio de arquivos: [Manuseio de arquivos](ultimatepython/advanced/file_handling.py) ( 🤯 ) - - Gerenciador de contexto: [Gerenciador de contexto](ultimatepython/advanced/context_manager.py) ( 🤯 ) - - Ordem de resolução do método: [mro](ultimatepython/advanced/mro.py) ( 🤯 ) - - Mixin: [Definição de mixin](ultimatepython/advanced/mixin.py) ( 🤯 ) - - Metaclass: [Definição de metaclass](ultimatepython/advanced/meta_class.py) ( 🤯 ) - - Thread: [ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) - - Asyncio: [async | await](ultimatepython/advanced/async.py) ( 🤯 ) - - Referência fraca: [weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) - - Benchmark: [cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) - - Mocking: [MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) - - Expressões regulares (regexp): [search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) - - Formato de dados: [json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) - - Datetime: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) - - Correspondência de padrões: [match | case](ultimatepython/advanced/pattern_matching.py) ( 🤯 ) - -## Recursos adicionais - -👔 = Recurso para entrevista, -🧪 = Exemplos de código, -🧠 = Ideias para projetos - -### Repositórios GitHub - -Continue aprendendo lendo outros recursos bem conceituados. - -- [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔 , 🧪 ) -- [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔 , 🧪 ) -- [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) -- [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) -- [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) -- [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) -- [vinta/awesome-python](https://github.com/vinta/awesome-python) -- [academic/awesome-datascience](https://github.com/academic/awesome-datascience) -- [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) -- [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) -- [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) -- [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) -- [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) -- [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) -- [microsoft/ML-For-Beginners](https://github.com/microsoft/ML-For-Beginners) ( 🧪 ) -- [microsoft/Data-Science-For-Beginners](https://github.com/microsoft/Data-Science-For-Beginners) ( 🧪 ) -- [Avik-Jain/100-Days-Of-ML-Code](https://github.com/Avik-Jain/100-Days-Of-ML-Code) ( 🧪 ) - -### Projetos do autor - -Projetos que construí com Python que mostram o que você pode criar após aprender esses conceitos: - -- [huangsam/chowist](https://github.com/huangsam/chowist) ( 🧪 ) -- [huangsam/githooks](https://github.com/huangsam/githooks) ( 🧪 ) -- [huangsam/ragchain](https://github.com/huangsam/ragchain) ( 🧪 ) -- [huangsam/mailprune](https://github.com/huangsam/mailprune) ( 🧪 ) - -### Prática interativa - -Continue praticando para que suas habilidades de codificação não enferrujem. - -- [codechef.com](https://www.codechef.com/) ( 👔 ) -- [codeforces.com](https://codeforces.com/) -- [codementor.io](https://www.codementor.io) ( 🧠 ) -- [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) -- [codewars.com](https://www.codewars.com/) -- [exercism.io](https://exercism.io/) -- [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) -- [hackerearth.com](https://www.hackerearth.com/) -- [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) -- [kaggle.com](https://www.kaggle.com/) ( 🧠 ) -- [labex.io](https://labex.io/exercises/python)( 🧪 ) -- [leetcode.com](https://leetcode.com/) ( 👔 ) -- [projecteuler.net](https://projecteuler.net/) -- [replit.com](https://replit.com/) -- [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) -- [teclado.com](https://teclado.com/30-days-of-python/#prerequisites) ( 👔 ) -- [fullstakpython.org](https://fullstackpython.org/) ( 🧪 ) - -## Astrônomos no tempo - -[![Stargazers over time](https://starchart.cc/huangsam/ultimate-python.svg?variant=adaptive)](https://starchart.cc/huangsam/ultimate-python) diff --git a/README.zh_tw.md b/README.zh_tw.md deleted file mode 100644 index caba49bb..00000000 --- a/README.zh_tw.md +++ /dev/null @@ -1,171 +0,0 @@ -# Ultimate Python 學習大綱 - -[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/huangsam/ultimate-python/ci.yml)](https://github.com/huangsam/ultimate-python/actions) -[![Code Coverage](https://img.shields.io/codecov/c/github/huangsam/ultimate-python)](https://codecov.io/gh/huangsam/ultimate-python) -[![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) -[![License](https://img.shields.io/github/license/huangsam/ultimate-python)](https://github.com/huangsam/ultimate-python/blob/main/LICENSE) -[![r/Python](https://img.shields.io/badge/reddit-original_post-red)](https://www.reddit.com/r/Python/comments/inllmf/ultimate_python_study_guide/) - -Ultimate Python 學習大綱 - 適用於新手和專業人士。🐍 🐍 🐍 - -```python -print("Ultimate Python 學習大綱") -``` - -[English](README.md) | -[한국어](README.ko.md) | -[繁体中文](README.zh_tw.md) | -[Español](README.es.md) | -[Deutsch](README.de.md) | -[Français](README.fr.md) | -[हिन्दी](README.hi.md) | -[Português - Brasil](README.pt_br.md) - -Ultimate Python - -## 動力 - -我為了分享過去五年作為一個學生,大公司員工,以及開源(例如 Celery 和 Full Stack Python)貢獻者所習得的知識而創 -建了這個代碼倉庫。我期待更多人能抱持熱忱並開始一段與Python的美好旅程。🎓 - -## 目標 - -這是創建本指南的主要目標: - -🏆 **為喜歡動手學習的Python新手提供資源。** 本存儲庫集合了不同題目的獨立模組範例,而每個模組可以獨立在普通 -終端機(Terminal),IDE(如PyCharm)或者瀏覽器(如Repl.it)中運行。範例中的註解都經過精心編寫,引導讀者逐步了解程 -式流程。在不刪除主例程(main)並在修改後成功運行大前題下,我鼓勵讀者修改源代碼作練習。 - -🏆 **為想重溫Python核心概念的程式員提供指南。** 本存儲庫主要借助內置庫(builtin libraries)作重溫工具, -故不需額外安裝開源庫(如`sqlalchemy`,`requests`,`pandas`)。但是,如果您的目標是成為一個真正的Python -達人(Pythonista),那麼我會鼓勵您閱讀這些源代碼,而激發靈感。 - -## 學習之旅 - -[![Run on Replit](https://replit.com/badge/github/huangsam/ultimate-python)](https://replit.com/github/huangsam/ultimate-python) - -單擊上面的徽章就可在瀏覽器中啟動工作環境,而無需在電腦上額外安裝Git和Python。當你完成啟動,請複製這存儲庫。 -當你可以開啟你所複製存儲庫後,您就準備好Python學習之旅!善用每個模組,請細讀註解並嘗試運行模組代碼。 - -有兩種運行模組的方式: - -1. 運行單一模組:`python ultimatepython/syntax/variable.py` -2. 運行所有模組:`python runner.py` - -## 目錄 - -📚 = 外部資源, -🍰 = 入門題目, -🤯 = 進階題目 - -1. **關於 Python** - - 概述:[什麼是 Python](https://github.com/trekhleb/learn-python/blob/master/src/getting_started/what_is_python.md) ( 📚, 🍰 ) - - 設計理念:[Python之格言](https://www.python.org/dev/peps/pep-0020/) ( 📚 ) - - 樣式指南:[Python代碼樣式指南](https://www.python.org/dev/peps/pep-0008/) ( 📚, 🤯 ) - - 數據模型:[數據模型](https://docs.python.org/3/reference/datamodel.html) ( 📚, 🤯 ) - - 標準庫:[Python標準庫](https://docs.python.org/3/library/) ( 📚, 🤯 ) - - 內置函式:[內置函式](https://docs.python.org/3/library/functions.html) ( 📚 ) -2. **語法** - - 變數:[內置值](ultimatepython/syntax/variable.py) ( 🍰 ) - - 運算式:[數值運算](ultimatepython/syntax/expression.py) ( 🍰 ) - - 按位: [中的位元運算符](ultimatepython/syntax/bitwise.py) ( 🍰 ), [一個的補語/補碼](https://www.geeksforgeeks.org/difference-between-1s-complement-representation-and-2s-complement-representation-technique/) ( 📚 ) - - 條件運算式:[if | if-else | if-elif-else](ultimatepython/syntax/conditional.py) ( 🍰 ) - - 迴圈:[for迴圈 | while迴圈](ultimatepython/syntax/loop.py) ( 🍰 ) - - 定義函式:[def | lambda](ultimatepython/syntax/function.py) ( 🍰 ) - - 海象運算子:[賦值表達式 :=](ultimatepython/syntax/walrus_operator.py) ( 🤯 ) - - 參數強制:[僅位置 / | 僅關鍵字 *](ultimatepython/syntax/arg_enforcement.py) ( 🤯 ) -3. **資料結構** - - 列表:[列表操作](ultimatepython/data_structures/list.py) ( 🍰 ) - - 元組:[元組操作](ultimatepython/data_structures/tuple.py) - - 集合:[集合操作](ultimatepython/data_structures/set.py) - - 字典:[字典操作](ultimatepython/data_structures/dict.py) ( 🍰 ) - - 字典聯合:[字典合併 | 和 |=](ultimatepython/data_structures/dict_union.py) ( 🤯 ) - - 綜合:[list | tuple | set | dict](ultimatepython/data_structures/comprehension.py) - - 字串:[字串操作](ultimatepython/data_structures/string.py) ( 🍰 ) - - 雙端隊列:[deque](ultimatepython/data_structures/deque.py) ( 🤯 ) - - Namedtuple: [namedtuple](ultimatepython/data_structures/namedtuple.py) ( 🤯 ) - - Defaultdict: [defaultdict](ultimatepython/data_structures/defaultdict.py) ( 🤯 ) - - 迭代器工具:[迭代器工具](ultimatepython/data_structures/itertools.py) ( 🤯 ) - - 時間複雜度:[cPython操作](https://wiki.python.org/moin/TimeComplexity) ( 📚, 🤯 ) -4. **類別** - - 基本類別:[基本定義](ultimatepython/classes/basic_class.py) ( 🍰 ) - - 抽象類別:[抽象定義](ultimatepython/classes/abstract_class.py) - - 異常類別:[異常定義](ultimatepython/classes/exception_class.py) - - 迭代類別:[迭代器定義](ultimatepython/classes/iterator_class.py) ( 🤯 ) - - 封裝: [封裝定義](ultimatepython/classes/encapsulation.py) -5. **進階技巧** - - 裝飾器:[Decorator definition | wraps](ultimatepython/advanced/decorator.py) ( 🤯 ) - - 文件處理: [File Handling](ultimatepython/advanced/file_handling.py) ( 🤯 ) - - 資源管理器:[Context managers](ultimatepython/advanced/context_manager.py) ( 🤯 ) - - 方法解析順序:[mro](ultimatepython/advanced/mro.py) ( 🤯 ) - - Mixin:[Mixin定義](ultimatepython/advanced/mixin.py) ( 🤯 ) - - 元類:[Metaclass定義](ultimatepython/advanced/meta_class.py) ( 🤯 ) - - 執行緒:[ThreadPoolExecutor](ultimatepython/advanced/thread.py) ( 🤯 ) - - 異步:[async | await](ultimatepython/advanced/async.py) ( 🤯 ) - - 弱引用:[weakref](ultimatepython/advanced/weak_ref.py) ( 🤯 ) - - 基準:[cProfile | pstats](ultimatepython/advanced/benchmark.py) ( 🤯 ) - - 模擬:[MagicMock | PropertyMock | patch](ultimatepython/advanced/mocking.py) ( 🤯 ) - - 正規表示式:[search | findall | match | fullmatch](ultimatepython/advanced/regex.py) ( 🤯 ) - - 數據格式:[json | xml | csv](ultimatepython/advanced/data_format.py) ( 🤯 ) - - 日期時間: [datetime | timezone](ultimatepython/advanced/date_time.py) ( 🤯 ) - - 模式匹配:[match | case](ultimatepython/advanced/pattern_matching.py) ( 🤯 ) - -## 額外資源 - -👔 = 面試資源, -🧪 = 代碼範例, -🧠 = 項目構想 - -### GitHub儲存庫 - -通過閱讀其他備受尊重的資源來繼續學習。 - -- [TheAlgorithms/Python](https://github.com/TheAlgorithms/Python) ( 👔, 🧪 ) -- [faif/python-patterns](https://github.com/faif/python-patterns) ( 👔, 🧪 ) -- [geekcomputers/Python](https://github.com/geekcomputers/Python) ( 🧪 ) -- [trekhleb/homemade-machine-learning](https://github.com/trekhleb/homemade-machine-learning) ( 🧪 ) -- [karan/Projects](https://github.com/karan/Projects) ( 🧠 ) -- [MunGell/awesome-for-beginners](https://github.com/MunGell/awesome-for-beginners) ( 🧠 ) -- [vinta/awesome-python](https://github.com/vinta/awesome-python) -- [academic/awesome-datascience](https://github.com/academic/awesome-datascience) -- [josephmisiti/awesome-machine-learning](https://github.com/josephmisiti/awesome-machine-learning) -- [ZuzooVn/machine-learning-for-software-engineers](https://github.com/ZuzooVn/machine-learning-for-software-engineers) -- [30-seconds/30-seconds-of-python](https://github.com/30-seconds/30-seconds-of-python) ( 🧪 ) -- [ml-tooling/best-of-python](https://github.com/ml-tooling/best-of-python) -- [practical-tutorials/project-based-learning](https://github.com/practical-tutorials/project-based-learning#python) -- [freeCodeCamp/freeCodeCamp](https://github.com/freeCodeCamp/freeCodeCamp) ( 👔 ) - -### 作者的專案 - -我用 Python 構建的專案,展示學習這些概念後可以創造的內容: - -- [huangsam/chowist](https://github.com/huangsam/chowist) ( 🧪 ) -- [huangsam/githooks](https://github.com/huangsam/githooks) ( 🧪 ) -- [huangsam/ragchain](https://github.com/huangsam/ragchain) ( 🧪 ) -- [huangsam/mailprune](https://github.com/huangsam/mailprune) ( 🧪 ) - -### 互動練習 - -繼續練習才能使您的編碼技能不會生疏。 - -- [codechef.com](https://www.codechef.com/) ( 👔 ) -- [codeforces.com](https://codeforces.com/) -- [codementor.io](https://www.codementor.io) ( 🧠 ) -- [coderbyte.com](https://www.coderbyte.com/) ( 👔 ) -- [codewars.com](https://www.codewars.com/) -- [exercism.io](https://exercism.io/) -- [geeksforgeeks.org](https://www.geeksforgeeks.org/) ( 👔 ) -- [hackerearth.com](https://www.hackerearth.com/) -- [hackerrank.com](https://www.hackerrank.com/) ( 👔 ) -- [kaggle.com](https://www.kaggle.com/) ( 🧠 ) -- [labex.io](https://labex.io/exercises/python)( 🧪 ) -- [leetcode.com](https://leetcode.com/) ( 👔 ) -- [projecteuler.net](https://projecteuler.net/) -- [replit.com](https://replit.com/) -- [w3schools.com](https://www.w3schools.com/python/) ( 🧪 ) -- [teclado.com](https://teclado.com/30-days-of-python/#prerequisites) ( 👔 ) -- [fullstakpython.org](https://fullstackpython.org/) ( 🧪 ) - -## 歷代觀星者 - -[![Stargazers over time](https://starchart.cc/huangsam/ultimate-python.svg?variant=adaptive)](https://starchart.cc/huangsam/ultimate-python) diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index 1ba81633..00000000 --- a/codecov.yml +++ /dev/null @@ -1,10 +0,0 @@ -# https://docs.codecov.com/docs/common-recipe-list -# https://docs.codecov.com/docs/commit-status -coverage: - status: - project: - default: - target: 90% - patch: - default: - target: 90% diff --git a/images/ultimatepython.webp b/images/ultimatepython.webp deleted file mode 100644 index c055f065..00000000 Binary files a/images/ultimatepython.webp and /dev/null differ diff --git a/pre-commit.sh b/pre-commit.sh deleted file mode 100755 index a9006951..00000000 --- a/pre-commit.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# pre-commit.sh: Run the same checks as CI (see .github/workflows/ci.yml) -# Usage: -# ./pre-commit.sh # Run checks -# ./pre-commit.sh install # Install as .git/hooks/pre-commit - -set -euo pipefail - -if [[ "${1:-}" == "install" ]]; then - hook_path=".git/hooks/pre-commit" - cp -- "$0" "$hook_path" - chmod +x "$hook_path" - echo "Installed pre-commit hook to $hook_path" - exit 0 -fi - -# 1. Find the project root -PROJECT_ROOT="$(git rev-parse --show-toplevel)" - -# 2. Define standard virtual environment names -VENV_NAMES=(".venv" "venv") - -# 3. Locate the virtual environment directory -VENV_DIR="" -for name in "${VENV_NAMES[@]}"; do - CANDIDATE="$PROJECT_ROOT/$name" - if [ -d "$CANDIDATE" ]; then - VENV_DIR="$CANDIDATE" - break - fi -done - -# 4. Check if a virtual environment was found -if [ -z "$VENV_DIR" ]; then - echo "Error: Virtual environment not found. Please create one (e.g., 'python3 -m venv .venv') and run the hook again." - exit 1 -fi - -# 5. Define the full path to the Python interpreter within the found VENV -PYTHON_EXEC="$VENV_DIR/bin/python" - -# 6. Check if the interpreter exists -if [ ! -x "$PYTHON_EXEC" ]; then - echo "Error: Python executable not found at $PYTHON_EXEC" - exit 1 -fi - -# --- Use the specific Python executable for all commands --- - -# Run all examples -"$PYTHON_EXEC" runner.py - -# Lint and format checks (ruff and isort are installed in the venv) -"$PYTHON_EXEC" -m ruff check -"$PYTHON_EXEC" -m isort --check --diff . - -# Coverage -"$PYTHON_EXEC" -m coverage run runner.py -"$PYTHON_EXEC" -m coverage report --fail-under=80 diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 914e24f8..00000000 --- a/pyproject.toml +++ /dev/null @@ -1,28 +0,0 @@ -[tool.ruff] -line-length = 160 - -[tool.isort] -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -use_parentheses = true -ensure_newline_before_comments = true -line_length = 160 - -[tool.coverage.run] -branch = true - -[tool.coverage.report] -exclude_lines = [ - "skip: (if|else)", - "def __repr__", - "raise NotImplementedError", - "if __name__ == .__main__.:", - "any\\(" -] -fail_under = 80 -omit = [ - "venv/**", - "runner.py", - "**/__init__.py" -] diff --git a/requirements.txt b/requirements.txt index 3f45511b..afa7d5ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -coverage==7.13.0 -isort==7.0.0 -ruff==0.14.10 -mypy==1.19.1 +coverage +flake8 +isort diff --git a/runner.py b/runner.py index 5b684ba5..e6fc254c 100644 --- a/runner.py +++ b/runner.py @@ -1,5 +1,9 @@ +import io +import sys +from contextlib import contextmanager from importlib import import_module from inspect import isfunction, signature +from os import devnull from pkgutil import walk_packages from ultimatepython import __name__ as root_name @@ -10,41 +14,52 @@ _STYLE_BOLD = "\033[1m" _STYLE_END = "\033[0m" _RUNNER_PROGRESS = "->" -_RUNNER_MAIN = "main" +_MODULE_MAIN = "main" -def success_text(text: str) -> str: +@contextmanager +def no_stdout(): + """Silence standard output with /dev/null.""" + save_stdout = sys.stdout + with io.open(devnull, "w") as dev_null: + sys.stdout = dev_null + yield + sys.stdout = save_stdout + + +def success_text(text): """Get success text.""" return f"{_STYLE_SUCCESS}{bold_text(text)}{_STYLE_END}" -def bold_text(text: str) -> str: +def bold_text(text): """Get bold text.""" return f"{_STYLE_BOLD}{text}{_STYLE_END}" -def main() -> None: +def main(): print(bold_text(f"Start {root_name} runner")) for item in walk_packages(root_path, f"{root_name}."): mod = import_module(item.name) # Skip modules without a main object - if not hasattr(mod, _RUNNER_MAIN): + if not hasattr(mod, _MODULE_MAIN): continue # By this point, there is a main object in the module - mod_main = getattr(mod, _RUNNER_MAIN) + main_func = getattr(mod, _MODULE_MAIN) # The main object is a function - assert isfunction(mod_main) + assert isfunction(main_func) # The main function has zero parameters - assert len(signature(mod_main).parameters) == 0 + assert len(signature(main_func).parameters) == 0 # The main function should not throw any errors - print(f"{_RUNNER_PROGRESS} Run {mod.__name__}:{_RUNNER_MAIN}", end="") - mod_main() + print(f"{_RUNNER_PROGRESS} Run {mod.__name__}:{_MODULE_MAIN}", end="") + with no_stdout(): + main_func() print(" [PASS]") print(success_text(f"Finish {root_name} runner")) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..db4d247a --- /dev/null +++ b/setup.cfg @@ -0,0 +1,20 @@ +[coverage:run] +branch = True + +[coverage:report] +exclude_lines = + skip: (if|else) + def __repr__ + raise NotImplementedError + if __name__ == .__main__.: + any\( +fail_under = 80 +omit = + venv/** + runner.py + **/__init__.py + +[flake8] +max-line-length = 160 +exclude = + venv diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..5cceefbf --- /dev/null +++ b/setup.py @@ -0,0 +1,13 @@ +from setuptools import find_packages, setup + +setup( + name="ultimatepython", + packages=find_packages(), + description="Ultimate Python study guide", + classifiers=[ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + ], +) diff --git a/ultimatepython/advanced/async.py b/ultimatepython/advanced/async.py index 0265c9e2..7847c548 100644 --- a/ultimatepython/advanced/async.py +++ b/ultimatepython/advanced/async.py @@ -1,26 +1,11 @@ -""" -Concurrent programming with asyncio, introduced in Python 3.4, provides -an event loop for handling asynchronous operations. This module demonstrates -basic asyncio patterns including coroutines, tasks, concurrent execution -with gather, and task cancellation. It uses the context of a scheduler -which runs fire-and-forget operations for starting jobs, assuming that -job startup has some intrinsic delay. - -This module also covers advanced asyncio patterns including task groups -for structured concurrency (Python 3.11+), semaphores for limiting -concurrency, timeouts, exception handling in concurrent tasks, event -loop management, and task shielding to protect critical operations from -cancellation. -""" - import asyncio from dataclasses import dataclass from datetime import datetime from uuid import uuid4 # Module-level constants -_DELAY_SMALL = 0.001 -_DELAY_LARGE = 3600 +_MILLISECOND = .001 +_HOUR = 3600 @dataclass @@ -37,30 +22,23 @@ def _is_valid_record(record): return record.queued_at < record.started_at -def _current_time() -> datetime: +def _current_time(): """Return current time that is timezone-naive.""" return datetime.now() -async def start_job(job_id: str, delay: float) -> JobRecord: - """Start job ID after a certain amount of delay.""" +async def start_job(delay, job_id): + """Start job_id after a certain delay in seconds.""" queue_time = _current_time() await asyncio.sleep(delay) start_time = _current_time() return JobRecord(job_id, queue_time, start_time) -async def failing_job(job_id: str) -> None: - """A job that sometimes fails.""" - if int(job_id[-1]) % 3 == 0: # Fail every 3rd job - raise ValueError(f"Job {job_id} failed!") - await asyncio.sleep(_DELAY_SMALL) - - -async def basic_async_patterns() -> None: - """Basic async patterns demonstration.""" - # Start a job which also represents a coroutine - single_job = start_job(uuid4().hex, _DELAY_SMALL) +async def schedule_jobs(): + """Schedule jobs concurrently.""" + # Create a job which also represents a coroutine + single_job = start_job(_MILLISECOND, uuid4().hex) assert asyncio.iscoroutine(single_job) # Grab a job record from the coroutine @@ -68,21 +46,18 @@ async def basic_async_patterns() -> None: assert _is_valid_record(single_record) # Task is a wrapped coroutine which also represents a future - single_task = asyncio.create_task(start_job(uuid4().hex, _DELAY_LARGE)) + single_task = asyncio.create_task(start_job(_HOUR, uuid4().hex)) assert asyncio.isfuture(single_task) - # Futures are different from other coroutines since they can be cancelled + # Futures are different from coroutines in that they can be cancelled single_task.cancel() - task_failed = False try: await single_task except asyncio.exceptions.CancelledError: assert single_task.cancelled() - task_failed = True - assert task_failed is True # Gather coroutines for batch start - batch_jobs = [start_job(uuid4().hex, _DELAY_SMALL) for _ in range(10)] + batch_jobs = [start_job(_MILLISECOND, uuid4().hex) for _ in range(10)] batch_records = await asyncio.gather(*batch_jobs) # We get the same amount of records as we have coroutines @@ -90,111 +65,8 @@ async def basic_async_patterns() -> None: assert all(_is_valid_record(record) for record in batch_records) -async def advanced_async_patterns() -> None: - """Demonstrate advanced asyncio patterns.""" - - # Task Groups - structured concurrency (Python 3.11+) - async def task_group_example(): - try: - async with asyncio.TaskGroup() as tg: - # Start multiple tasks in a group - for i in range(5): - tg.create_task(start_job(f"task_{i}", _DELAY_SMALL)) - except Exception: - # TaskGroup propagates exceptions from child tasks - pass - - # All tasks in the group complete or fail together - assert True # TaskGroup structure is valid - - await task_group_example() - - # Semaphores for limiting concurrency - semaphore = asyncio.Semaphore(3) # Allow max 3 concurrent operations - - async def limited_concurrency_job(job_id: str): - async with semaphore: - # Only 3 jobs can execute this section at once - await asyncio.sleep(_DELAY_SMALL) - return f"completed_{job_id}" - - # Start 10 jobs but only 3 can run concurrently - concurrent_jobs = [limited_concurrency_job(f"sem_{i}") for i in range(10)] - concurrent_results = await asyncio.gather(*concurrent_jobs) - assert len(concurrent_results) == 10 - assert all("completed_" in result for result in concurrent_results) - - # Exception handling with gather - mixed_jobs = [ - failing_job("job_1"), # succeeds - failing_job("job_2"), # succeeds - failing_job("job_3"), # fails - failing_job("job_4"), # succeeds - ] - - # Return exceptions instead of raising them - results = await asyncio.gather(*mixed_jobs, return_exceptions=True) - assert len(results) == 4 - # Check that we got a mix of results and exceptions - exceptions_found = sum(1 for r in results if isinstance(r, Exception)) - successes_found = sum(1 for r in results if not isinstance(r, Exception)) - assert exceptions_found == 1 # One job failed - assert successes_found == 3 # Three jobs succeeded - - # Timeouts and cancellation - async def slow_job(): - await asyncio.sleep(1.0) # Takes 1 second - return "slow_result" - - try: - # Timeout after 0.1 seconds - result = await asyncio.wait_for(slow_job(), timeout=0.1) - except asyncio.TimeoutError: - result = None - assert result is None # Should timeout - - # Event loop management - loop = asyncio.get_running_loop() - assert isinstance(loop, asyncio.AbstractEventLoop) - - # Schedule callback on the event loop - callback_result = None - - def sync_callback(): - nonlocal callback_result - callback_result = "callback_executed" - - # Schedule callback to run soon - loop.call_soon(sync_callback) - await asyncio.sleep(0) # Let the event loop process callbacks - assert callback_result == "callback_executed" - - # Shielding tasks from cancellation - async def important_task(): - await asyncio.sleep(_DELAY_SMALL) - return "important_result" - - task = asyncio.create_task(important_task()) - shielded_task = asyncio.shield(task) - - # Even if we cancel the shield, the underlying task continues - shielded_task.cancel() - try: - await shielded_task - except asyncio.CancelledError: - pass - - # The original task should still complete - await task # Wait for the original task - assert task.result() == "important_result" - - -def main() -> None: - # Run basic patterns - asyncio.run(basic_async_patterns()) - - # Run advanced patterns - asyncio.run(advanced_async_patterns()) +def main(): + asyncio.run(schedule_jobs()) if __name__ == "__main__": diff --git a/ultimatepython/advanced/benchmark.py b/ultimatepython/advanced/benchmark.py index 0c8a8e58..604f87a5 100644 --- a/ultimatepython/advanced/benchmark.py +++ b/ultimatepython/advanced/benchmark.py @@ -1,28 +1,20 @@ -""" -As programs increase in size, they have the risk of getting slow as new -features are added and extra layers of complexity to the main features. -Benchmarking is an approach that helps developers use profiling metrics -and their code intuition to optimize programs further. This module uses -cProfile to compare the performance of two functions with each other. -""" - import cProfile import io import pstats import time # Module-level constants -_SLEEP_DURATION = 0.001 +_SLEEP_DURATION = .001 def finish_slower(): - """Finish slower by sleeping more.""" + """Finish slower.""" for _ in range(20): time.sleep(_SLEEP_DURATION) def finish_faster(): - """Finish faster by sleeping less.""" + """Finish faster.""" for _ in range(10): time.sleep(_SLEEP_DURATION) @@ -55,7 +47,8 @@ def main(): # large projects. Consider profiling in isolation when analyzing complex # classes and functions ps.print_stats() - time_sleep_called = any("60" in line and "time.sleep" in line for line in buffer.getvalue().split("\n")) + time_sleep_called = any("60" in line and "time.sleep" in line + for line in buffer.getvalue().split("\n")) assert time_sleep_called is True diff --git a/ultimatepython/advanced/context_manager.py b/ultimatepython/advanced/context_manager.py deleted file mode 100644 index 09285431..00000000 --- a/ultimatepython/advanced/context_manager.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -Context managers are used to open and close resources as Python enters -and exits a code block respectively. Some examples of the resources it -can manage are files, database connections and sockets. In this module, -we simulate how a context manager can handle open and close operations of -a file-like object called StringIO. -""" - -from contextlib import contextmanager -from io import StringIO -from typing import Generator - -# Simple directory with file contents -_FILESYSTEM = { - "a.txt": "Hello World", - "b.xml": "Hello World", - "c.out": "10101010", -} - - -@contextmanager -def file(filename: str) -> Generator[StringIO, None, None]: - """File context manager. - - This is the function variant of the context manager. Context managers - are useful for resources that need to be opened and closed such as - files, database connections and sockets. - """ - io_buffer = StringIO(_FILESYSTEM[filename]) - try: - # Pass the buffer to the context block - yield io_buffer - finally: - # Close the buffer unconditionally - io_buffer.close() - - -class FileHandler: - """File handler context manager. - - This is the class variant of the context manager. Just like with - iterators, it depends on context and preference that we design a - class or simply write a function. - """ - - def __init__(self, filename: str) -> None: - self.io_buffer = StringIO(_FILESYSTEM[filename]) - - def __enter__(self) -> StringIO: - """Pass the buffer to the context block.""" - return self.io_buffer - - def __exit__(self, *args) -> None: - """Close the buffer unconditionally.""" - self.io_buffer.close() - - -def main() -> None: - # An example of a function-based context manager - with file("a.txt") as txt_buffer: - assert txt_buffer.read() == "Hello World" - - # An example of a class-based context manager - with FileHandler("b.xml") as xml_buffer: - assert xml_buffer.read() == "Hello World" - - # Examples of context manager failures - for context_obj in (file, FileHandler): - call_failed = False - try: - # Whenever any error happens in the context block, the buffer - # in the context manager gets closed automatically and the - # error gets raised to the outer block - with context_obj("c.out"): - raise RuntimeError("System crash. Abort!") - except RuntimeError: - call_failed = True - assert call_failed is True - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/advanced/data_format.py b/ultimatepython/advanced/data_format.py deleted file mode 100644 index 33133062..00000000 --- a/ultimatepython/advanced/data_format.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -One of the reasons people use Python is that it simplifies parsing and -converting data to serialized objects for further analysis. This module -shows how to parse and process these data formats: JSON, XML and CSV. -""" - -import json -from csv import DictReader -from dataclasses import dataclass, fields -from io import StringIO -from xml.etree import ElementTree as ETree - -# Data in JSON format. For more info on this format: -# https://fileinfo.com/extension/json -_JSON_DATA = """ -[ - { - "author": "John", - "title": "Summer", - "body": "Summer time is hot" - }, - { - "author": "Jane", - "title": "Winter", - "body": "Winter time is cold" - } -] -""" - -# Data in XML format. For more info on this format: -# https://fileinfo.com/extension/xml -_XML_DATA = """ - - - John - Summer - Summer time is hot - - - Jane - Winter - Winter time is cold - - -""" - -# Data in CSV format. For more info on this format: -# https://fileinfo.com/extension/csv -_CSV_DATA = """ -John,Summer,Summer time is hot -Jane,Winter,Winter time is cold -""" - - -@dataclass -class Note: - """Note model. - - We notice that each data format has the notion of a record with fields - associated with them. To streamline the creation and comparison of - these records, we define an in-memory model of what it is. - """ - - author: str - title: str - body: str - - @classmethod - def from_data(cls, data): - """Create note from dictionary data.""" - return cls(**data) - - @classmethod - def fields(cls): - """Get field names to simplify parsing logic.""" - return tuple(field.name for field in fields(cls)) - - -def main(): - # Let's use `json.load` to parse note data from a JSON file - # https://docs.python.org/3/library/json.html - json_content = json.load(StringIO(_JSON_DATA)) - json_notes = [Note.from_data(data) for data in json_content] - assert all(isinstance(note, Note) for note in json_notes) - - # Let's use `ElementTree.parse` to parse note data from a XML file - # https://docs.python.org/3/library/xml.html - tree = ETree.parse(StringIO(_XML_DATA)) - xml_notes = [Note.from_data({field: note_el.findtext(field) for field in Note.fields()}) for note_el in tree.getroot()] - assert all(isinstance(note, Note) for note in xml_notes) - - # Let's use `csv.DictReader` to parse note data from a CSV file - # https://docs.python.org/3/library/csv.html - csv_reader = DictReader(StringIO(_CSV_DATA), fieldnames=Note.fields()) - csv_notes = [Note.from_data(row) for row in csv_reader] - assert all(isinstance(note, Note) for note in csv_notes) - - # All three formats have similar `Note` objects - for json_note, xml_note, csv_note in zip(json_notes, xml_notes, csv_notes): - assert json_note == xml_note == csv_note - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/advanced/date_time.py b/ultimatepython/advanced/date_time.py deleted file mode 100644 index 7b46bbdd..00000000 --- a/ultimatepython/advanced/date_time.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -The `datetime` class is one of the core classes we encounter when tracking -events at a given date and time. By default, creating an instance with -`datetime.now` means that an offset-naive datetime object is produced in -the host's local timezone. - -An offset-naive `datetime` object is useful for scripts that are run on a -personal device. Once we use `datetime` objects for web applications that -are deployed globally, it's important to know the offset that `datetime` -objects are aligned to before processing them. For more on `datetime`: - -https://docs.python.org/3/library/datetime.html - -Backend developers address this by storing time fields with offsets aligned -with the UTC (Coordinated Universal Time) timezone. As a result, time fields -can be displayed in any timezone - at any moment. For more on UTC: - -https://en.wikipedia.org/wiki/Coordinated_Universal_Time - -In this module, we will show the difference between offset-naive and -offset-aware `datetime` objects. We will also highlight the builtin -UTC timezone and show how it can be used to make the default `datetime` -object more powerful. -""" - -from datetime import datetime, timezone - - -def convert_dt_to_utc_epoch(dt: datetime) -> float: - """Convert datetime to UTC epoch seconds. - - Note that the timestamp method assumes that an offset-naive - datetime instance is in the local timezone and converts its - offset to UTC before making it a floating point number. - """ - return dt.timestamp() - - -def convert_utc_epoch_to_dt(epoch: float) -> datetime: - """Convert UTC epoch seconds to datetime.""" - return datetime.fromtimestamp(epoch, tz=timezone.utc) - - -def convert_dt_timezone(dt: datetime, tz: timezone) -> datetime: - """Convert datetime timezone.""" - return dt.astimezone(tz=tz) - - -def get_utc_now_as_dt() -> datetime: - """Get current UTC time as datetime.""" - return datetime.now(tz=timezone.utc) - - -def get_utc_now_as_epoch() -> float: - """Get current UTC time as epoch seconds.""" - return convert_dt_to_utc_epoch(get_utc_now_as_dt()) - - -def main() -> None: - # Create offset-naive datetime - naive_dt = datetime.now() - assert naive_dt.tzinfo is None - - # Change offset-naive datetime to epoch seconds - naive_dt_epoch = convert_dt_to_utc_epoch(naive_dt) - assert naive_dt_epoch > 0 - - # Change epoch seconds to UTC datetime - utc_dt = convert_utc_epoch_to_dt(naive_dt_epoch) - assert utc_dt.tzinfo is timezone.utc - assert convert_dt_to_utc_epoch(utc_dt) == naive_dt_epoch - - # We cannot compute differences between offset-naive and offset-aware - # datetime objects - calc_failed = False - try: - _ = utc_dt - naive_dt - except TypeError: - calc_failed = True - assert calc_failed is True - - # But we can change the timezone of an offset-naive datetime object - # first before running operations on them - assert convert_dt_timezone(naive_dt, timezone.utc) == utc_dt - - # Create new UTC time as datetime - utc_dt_new_one = get_utc_now_as_dt() - assert utc_dt_new_one > utc_dt - - # Create another new UTC time as epoch seconds - utc_epoch_new_two = get_utc_now_as_epoch() - utc_epoch_new_one = convert_dt_to_utc_epoch(utc_dt_new_one) - assert utc_epoch_new_two > utc_epoch_new_one > naive_dt_epoch - utc_dt_new_two = convert_utc_epoch_to_dt(utc_epoch_new_two) - assert utc_dt_new_two > utc_dt_new_one > utc_dt - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/advanced/decorator.py b/ultimatepython/advanced/decorator.py index e4561c9b..b0bcddd6 100644 --- a/ultimatepython/advanced/decorator.py +++ b/ultimatepython/advanced/decorator.py @@ -1,18 +1,7 @@ -""" -Decorators add new functionality to a function or class at runtime. -This module shows how a simple "encryption" function for one string can -be decorated to work with a collection of strings. Note that the decorator -handles nested collections with the use of recursion. -""" - from functools import wraps -from typing import Any, Callable - -# Module-level constants -_MASKING = "*" -def run_with_stringy(fn: Callable[[str], str]) -> Callable[[Any], Any]: +def run_with_stringy(fn): """Run a string function with a string or a collection of strings. We define a custom decorator that allows us to convert a function whose @@ -41,11 +30,11 @@ def run_with_stringy(fn: Callable[[str], str]) -> Callable[[Any], Any]: """ @wraps(fn) - def wrapper(obj: Any) -> Any: + def wrapper(obj): """Apply wrapped function to a string or a collection. This looks like a policy-based engine which runs a `return` statement - if a particular set of rules is true. Otherwise, it aborts. This is + if a particular set of rules is true. Otherwise it aborts. This is an example of the Strategy design pattern. https://en.wikipedia.org/wiki/Strategy_pattern @@ -66,23 +55,14 @@ def wrapper(obj: Any) -> Any: @run_with_stringy -def hide_content(content: str) -> str: +def hide_content(content): """Hide half of the string content.""" start_point = len(content) // 2 num_of_asterisks = len(content) // 2 + len(content) % 2 - return content[:start_point] + _MASKING * num_of_asterisks - - -def _is_hidden(obj: Any) -> bool: - """Check whether string or collection is hidden.""" - if isinstance(obj, str): - return _MASKING in obj - elif isinstance(obj, dict): - return all(_is_hidden(value) for value in obj.values()) - return all(_is_hidden(value) for value in obj) + return content[:start_point] + "*" * num_of_asterisks -def main() -> None: +def main(): # There is so much plain-text data out in the open insecure_data = [ {"username": "johndoe", "country": "USA"}, # User information @@ -100,16 +80,14 @@ def main() -> None: # See what changed between the insecure data and the secure data for insecure_item, secure_item in zip(insecure_data, secure_data): assert insecure_item != secure_item - assert not _is_hidden(insecure_item) - assert _is_hidden(secure_item) # Throw an error on a collection with non-string objects - input_failed = False + input_fails = False try: hide_content([1]) except ValueError: - input_failed = True - assert input_failed is True + input_fails = True + assert input_fails is True if __name__ == "__main__": diff --git a/ultimatepython/advanced/file_handling.py b/ultimatepython/advanced/file_handling.py deleted file mode 100644 index e4908e20..00000000 --- a/ultimatepython/advanced/file_handling.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -File handling is a fundamental concept in Python that involves -opening, reading, writing, and appending to files. This module -demonstrates both traditional and modern approaches using pathlib. - -Traditional approach: The builtin 'open' function works with string -paths and different modes like reading ('r'), writing ('w'), and -appending ('a'). - -Modern approach: pathlib.Path provides an object-oriented interface -for working with filesystem paths, offering cleaner syntax and -cross-platform support. pathlib is preferred for new code as it -replaces older os.path operations with an intuitive API. -""" - -import os -from pathlib import Path - -_TARGET_FILE = "sample.txt" - - -def read_file(filename: str) -> str: - """Read content from existing file.""" - with open(filename, "r") as file: - content = file.read() - return content - - -def write_file(filename: str, content: str) -> str: - """Write content to new file.""" - with open(filename, "w") as file: - file.write(content) - return f"Content written to '{filename}'." - - -def append_file(filename: str, content: str) -> str: - """Append content to existing file.""" - with open(filename, "a") as file: - file.write(content) - return f"Content appended to '{filename}'." - - -def delete_file(filename: str) -> str: - """Delete content of existing file.""" - os.remove(filename) - return f"'{filename}' has been deleted." - - -def write_file_pathlib(filename: str, content: str) -> str: - """Write content using pathlib.Path.""" - path = Path(filename) - path.write_text(content) - return f"Content written to '{filename}' using pathlib." - - -def read_file_pathlib(filename: str) -> str: - """Read content using pathlib.Path.""" - path = Path(filename) - return path.read_text() - - -def append_file_pathlib(filename: str, content: str) -> str: - """Append content using pathlib.Path.""" - path = Path(filename) - current = path.read_text() - path.write_text(current + content) - return f"Content appended to '{filename}' using pathlib." - - -def delete_file_pathlib(filename: str) -> str: - """Delete file using pathlib.Path.""" - path = Path(filename) - path.unlink() - return f"'{filename}' has been deleted using pathlib." - - -def main() -> None: - # Test traditional file operations - result = write_file(_TARGET_FILE, "This is a test.") - assert result == f"Content written to '{_TARGET_FILE}'." - - content = read_file(_TARGET_FILE) - assert content == "This is a test." - - append_result = append_file(_TARGET_FILE, "\nThis is an appended line.") - assert append_result == f"Content appended to '{_TARGET_FILE}'." - - content = read_file(_TARGET_FILE) - assert content == "This is a test.\nThis is an appended line." - - delete_result = delete_file(_TARGET_FILE) - assert delete_result == f"'{_TARGET_FILE}' has been deleted." - - # Test pathlib operations - pathlib_file = "pathlib_sample.txt" - result = write_file_pathlib(pathlib_file, "Pathlib is modern.") - assert result == f"Content written to '{pathlib_file}' using pathlib." - - content = read_file_pathlib(pathlib_file) - assert content == "Pathlib is modern." - - append_result = append_file_pathlib(pathlib_file, "\nIt's object-oriented.") - assert append_result == f"Content appended to '{pathlib_file}' using pathlib." - - content = read_file_pathlib(pathlib_file) - assert content == "Pathlib is modern.\nIt's object-oriented." - - # Test path operations with pathlib - path = Path(pathlib_file) - assert path.exists() - assert path.is_file() - assert path.suffix == ".txt" - assert path.stem == "pathlib_sample" - - delete_result = delete_file_pathlib(pathlib_file) - assert delete_result == f"'{pathlib_file}' has been deleted using pathlib." - assert not path.exists() - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/advanced/meta_class.py b/ultimatepython/advanced/meta_class.py index 51fe51ba..c41ff339 100644 --- a/ultimatepython/advanced/meta_class.py +++ b/ultimatepython/advanced/meta_class.py @@ -1,9 +1,3 @@ -""" -Metaclass are used to modify a class as it is being created at runtime. -This module shows how a metaclass can add database attributes and tables -to "logic-free" model classes for the developer. -""" - from abc import ABC @@ -13,11 +7,7 @@ class ModelMeta(type): By studying how SQLAlchemy and Django ORM work under the hood, we can see a metaclass can add useful abstractions to class definitions at runtime. That being said, this metaclass is a toy example and does not reflect - everything that happens in either framework. Check out the source code - in SQLAlchemy and Django to see what actually happens: - - https://github.com/sqlalchemy/sqlalchemy - https://github.com/django/django + everything that happens in either framework. The main use cases for a metaclass are (A) to modify a class before it is visible to a developer and (B) to add a class to a dynamic registry @@ -33,24 +23,14 @@ class ModelMeta(type): """ # Model table registry - tables: dict[str, "ModelTable"] = {} + tables = {} def __new__(mcs, name, bases, attrs): - """Factory for modifying the defined class at runtime. - - Here are the following steps that we take: - - 1. Get the defined model class - 2. Add a model_name attribute to it - 3. Add a model_fields attribute to it - 4. Add a model_table attribute to it - 5. Link its model_table to a registry of model tables - 6. Return the modified model class - """ + """Factory for modifying the defined class at runtime.""" kls = super().__new__(mcs, name, bases, attrs) # Abstract model does not have a `model_name` but a real model does. - # We will leverage this fact later on this routine + # We will leverage this fact later on this routine. if attrs.get("__abstract__") is True: kls.model_name = None else: @@ -67,19 +47,24 @@ def __new__(mcs, name, bases, attrs): kls.model_fields.update(base.model_fields) # Fill model fields from itself - kls.model_fields.update({field_name: field_obj for field_name, field_obj in attrs.items() if isinstance(field_obj, BaseField)}) + kls.model_fields.update({ + field_name: field_obj + for field_name, field_obj in attrs.items() + if isinstance(field_obj, BaseField) + }) # Register a real table (a table with valid `model_name`) to # the metaclass `table` registry. After all the tables are # registered, the registry can be sent to a database adapter # which uses each table to create a properly defined schema - # for the database of choice (i.e. PostgresSQL, MySQL) + # for the database of choice (i.e. PostgreSQL, MySQL). if kls.model_name: kls.model_table = ModelTable(kls.model_name, kls.model_fields) ModelMeta.tables[kls.model_name] = kls.model_table else: kls.model_table = None + # Return newly modified class return kls @property @@ -95,10 +80,17 @@ def __init__(self, table_name, table_fields): self.table_name = table_name self.table_fields = table_fields + def __repr__(self): + return f"" + class BaseField(ABC): """Base field.""" + def __repr__(self): + """Brief representation of any field.""" + return f"<{type(self).__name__}>" + class CharField(BaseField): """Character field.""" @@ -118,14 +110,12 @@ class BaseModel(metaclass=ModelMeta): In short, think of a metaclass as the creator of classes. This is very similar to how classes are the creator of instances. """ - __abstract__ = True # This is NOT a real table row_id = IntegerField() class UserModel(BaseModel): """User model.""" - __table_name__ = "user_rocks" # This is a custom table name username = CharField() password = CharField() @@ -135,7 +125,6 @@ class UserModel(BaseModel): class AddressModel(BaseModel): """Address model.""" - user_id = IntegerField() address = CharField() state = CharField() @@ -143,16 +132,10 @@ class AddressModel(BaseModel): def main(): - # Real models are given a name at runtime with `ModelMeta` + # Real models are modified at runtime with `ModelMeta` assert UserModel.model_name == "user_rocks" assert AddressModel.model_name == "address" - # Real models are given fields at runtime with `ModelMeta` - assert "row_id" in UserModel.model_fields - assert "row_id" in AddressModel.model_fields - assert "username" in UserModel.model_fields - assert "address" in AddressModel.model_fields - # Real models are registered at runtime with `ModelMeta` assert UserModel.is_registered assert AddressModel.is_registered @@ -168,7 +151,8 @@ def main(): # Every model is created by `ModelMeta` assert isinstance(BaseModel, ModelMeta) - assert all(isinstance(model, ModelMeta) for model in BaseModel.__subclasses__()) + assert all(isinstance(model, ModelMeta) + for model in BaseModel.__subclasses__()) # And `ModelMeta` is created by `type` assert isinstance(ModelMeta, type) @@ -180,8 +164,7 @@ def main(): assert isinstance(BaseModel, object) assert isinstance(ModelMeta, object) assert isinstance(type, object) - assert isinstance(object, object) -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/ultimatepython/advanced/mixin.py b/ultimatepython/advanced/mixin.py deleted file mode 100644 index 0f7b1174..00000000 --- a/ultimatepython/advanced/mixin.py +++ /dev/null @@ -1,172 +0,0 @@ -""" -Mixins are a way to provide implementation details that simplify the work -for a developer to conform to an opaque interface specification. In this -module, we have one request handler interface and two request handler -mixins to illustrate how mixins can make our lives easier when defining -concrete classes. -""" - -from abc import ABC, abstractmethod -from dataclasses import dataclass - - -@dataclass -class Request: - """Request data model. - - Assumes only GET requests for simplicity so there is no method - attribute associated with this class. - """ - - url: str - user: str - - -class RequestHandler(ABC): - """Request handler interface. - - In the real world, a URL is expected to handle different kinds of HTTP - methods. To support this, we would define a `View` class with a method - that dispatches the request payload to the appropriate HTTP handler. - Afterward, we would register the class to a URL router. Check out - the source code in Django and Flask to see how that works: - - https://github.com/django/django - https://github.com/pallets/flask - """ - - @abstractmethod - def handle(self, request): - """Handle incoming request.""" - raise NotImplementedError - - -class TemplateHandlerMixin(RequestHandler): - """Abstract template mixin for RequestHandler. - - This is a mixin because it's an abstract class that provides a - concrete implementation of the `handle` method. In other words, it - adds additional structure for implementing the `handle` routine. This - class helps if downstream developers typically implement request - handlers that retrieve template content. - """ - - template_suffix = ".template" - - def handle(self, request): - template_name = self.get_template_name(request.url) - if not self.is_valid_template(template_name): - return self.handle_invalid_template(request) - return self.render_template(template_name) - - @abstractmethod - def get_template_name(self, request_url): - """Get template name.""" - raise NotImplementedError - - def is_valid_template(self, template_name): - """Check if template name is valid.""" - return template_name.endswith(self.template_suffix) - - @staticmethod - def handle_invalid_template(request): - """Handle request for invalid template.""" - return f"

Invalid entry for {request.url}

" - - @abstractmethod - def render_template(self, template_name): - """Render contents of specified template name.""" - raise NotImplementedError - - -class AuthHandlerMixin(RequestHandler): - """Abstract auth mixin for RequestHandler. - - This is another mixin class where authentication helper methods are - defined in this abstract class and must be implemented in concrete - classes. Notice that the `handle` method is implemented and returns - the output of the parent's `handle` method. This means that we can - continue to chain mixin effects as long as this mixin is to the left - of another mixin in a concrete class MRO. - """ - - def handle(self, request): - if not self.is_valid_user(request.user): - return self.handle_invalid_user(request) - return super().handle(request) - - @abstractmethod - def is_valid_user(self, request_user): - """Check if user is valid.""" - raise NotImplementedError - - @staticmethod - def handle_invalid_user(request): - """Handle request for invalid user.""" - return f"

Access denied for {request.url}

" - - -class TemplateFolderHandler(TemplateHandlerMixin): - """Concrete template handler. - - This concrete class implements the abstract methods of its parent - mixin. By extension, it has implemented everything that is needed - for the `handle` method. - """ - - def __init__(self, template_dir): - self.template_dir = template_dir - - def get_template_name(self, request_url): - return request_url[1:] - - def is_valid_template(self, template_name): - return super().is_valid_template(template_name) and template_name in self.template_dir - - def render_template(self, template_name): - return self.template_dir[template_name] - - -class AdminTemplateHandler(AuthHandlerMixin, TemplateFolderHandler): - """Concrete auth and template handler. - - This concrete class gets the benefits of the previous concrete - class but also gets authentication for free just by implementing - the abstract method of the authentication mixin. - """ - - def __init__(self, admin_users, template_dir): - super().__init__(template_dir) - self.admin_users = admin_users - - def is_valid_user(self, request_user): - return request_user in self.admin_users - - -def main(): - # Handle requests with simple template handler - simple_dir = {"welcome.template": "

Hello world

", "about.template": "

About me

"} - simple_handler = TemplateFolderHandler(simple_dir) - welcome_from_nobody = Request("/welcome.template", "nobody") - about_from_nobody = Request("/about.template", "nobody") - foo_from_nobody = Request("/foo.bar", "nobody") - assert simple_handler.handle(welcome_from_nobody) == "

Hello world

" - assert simple_handler.handle(about_from_nobody) == "

About me

" - assert simple_handler.handle(foo_from_nobody) == "

Invalid entry for /foo.bar

" - - # Handle requests with admin template handler - admin_users = {"john", "jane"} - admin_dir = {"fqdn.template": "

server.example.com

", "salary.template": "

123456789.00

"} - admin_handler = AdminTemplateHandler(admin_users, admin_dir) - fqdn_from_john = Request("/fqdn.template", "john") - salary_from_jane = Request("/salary.template", "jane") - salary_from_nobody = Request("/salary.template", "nobody") - foo_from_john = Request("/foo.bar", "john") - assert admin_handler.handle(fqdn_from_john) == "

server.example.com

" - assert admin_handler.handle(salary_from_jane) == "

123456789.00

" - assert admin_handler.handle(salary_from_nobody) == "

Access denied for /salary.template

" - assert admin_handler.handle(foo_from_john) == "

Invalid entry for /foo.bar

" - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/advanced/mocking.py b/ultimatepython/advanced/mocking.py deleted file mode 100644 index 8cef4e41..00000000 --- a/ultimatepython/advanced/mocking.py +++ /dev/null @@ -1,111 +0,0 @@ -""" -Mocking objects is a common strategy that developers use to test code that -depends on an external system or external resources for it to work -properly. This module shows how to use mocking to modify an application -server so that it is easier to test. -""" - -from collections import Counter -from unittest.mock import MagicMock, PropertyMock, patch - -# Module-level constants -_COUNTER = Counter(pid=1) -_START_SUCCESS = "success" -_START_FAILURE = "failure" -_PROTOCOL_HTTP = "http" -_PROTOCOL_HTTPS = "https" -_FAKE_BASE_URL = f"{_PROTOCOL_HTTPS}://www.google.com:443" -_FAKE_PID = 127 - - -class AppServer: - """Application server. - - Normally we don't mock an application server because it is the runtime - environment (AKA central nervous system) for business logic, database - endpoints, network sockets and more. However, this server definition - is lightweight, so it's okay to mock this. - """ - - def __init__(self, host, port, proto): - self._host = host - self._port = port - self._proto = proto - self._pid = -1 - - @property - def endpoint(self): - """Get application server endpoint URL.""" - return f"{self._proto}://{self._host}:{self._port}" - - @property - def pid(self): - """Get application server process ID.""" - return self._pid - - @property - def started(self): - """Check if application server is started.""" - return self.pid > 0 - - def start(self): - """Start application server.""" - if self.started: - return _START_FAILURE - self._pid = _COUNTER["pid"] - _COUNTER["pid"] += 1 - return _START_SUCCESS - - -class FakeServer(AppServer): - """Subclass parent and fake some routines.""" - - @property - def endpoint(self): - """Mock output of endpoint URL.""" - return _FAKE_BASE_URL - - @property - def pid(self): - """Mock output of process ID.""" - return _FAKE_PID - - -def main(): - # This is the original class instance and it works as expected - app_server = AppServer("localhost", 8000, _PROTOCOL_HTTP) - assert app_server.endpoint == f"{_PROTOCOL_HTTP}://localhost:8000" - assert app_server.start() == _START_SUCCESS - assert app_server.started is True - assert app_server.start() == _START_FAILURE - - # But sometimes we cannot test the finer details of a class because - # its methods depend on the availability of external resources. This - # is where mocking comes to the rescue. There are a couple approaches - # that developers use when it comes to mocking - - # Approach 1: Use a `MagicMock` in place of a real class instance - mock_server = MagicMock() - assert isinstance(mock_server, MagicMock) - assert isinstance(mock_server.start_server(), MagicMock) - mock_server.start_server.assert_called() - mock_server.endpoint.assert_not_called() - - # Approach 2: Patch a method in the original class - with patch.object(AppServer, "endpoint", PropertyMock(return_value=_FAKE_BASE_URL)): - patch_server = AppServer("localhost", 8080, _PROTOCOL_HTTP) - assert isinstance(patch_server, AppServer) - assert patch_server.endpoint == _FAKE_BASE_URL - assert patch_server.started is False - assert patch_server.start() == _START_SUCCESS - - # Approach 3: Create a new class that inherits the original class - fake_server = FakeServer("localhost", 8080, _PROTOCOL_HTTP) - assert isinstance(fake_server, AppServer) - assert fake_server.endpoint == _FAKE_BASE_URL - assert fake_server.started is True - assert patch_server.start() == _START_FAILURE - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/advanced/mro.py b/ultimatepython/advanced/mro.py index 46f85c5b..791f5710 100644 --- a/ultimatepython/advanced/mro.py +++ b/ultimatepython/advanced/mro.py @@ -1,11 +1,3 @@ -""" -MRO stands for method resolution order, and it's used by class definitions -to determine which method will be run by a class instance. This module -shows how the MRO is useful for the classic diamond problem where classes -B and C depend on class A, and class D depends on classes B and C. -""" - - class BasePlayer: """Base player.""" @@ -49,7 +41,12 @@ def ping(self): def ping_pong(self): """Run `ping` and `pong` in different ways.""" - return [self.ping(), super().ping(), self.pong(), super().pong()] + return [ + self.ping(), + super().ping(), + self.pong(), + super().pong() + ] class IndecisivePlayer(NeutralPlayer, PongPlayer): @@ -59,8 +56,9 @@ class IndecisivePlayer(NeutralPlayer, PongPlayer): even though the MRO of `ConfusedPlayer` is different. Notice that one of the `super()` calls uses additional parameters to - start the MRO process from another class. This is generally discouraged - as this bypasses the default method resolution process. + start the MRO process from another class. This is used for demonstrative + purposes and is highly discouraged as this bypasses the default method + resolution process. """ def pong(self): @@ -73,16 +71,18 @@ def ping_pong(self): self.ping(), super().ping(), self.pong(), - super(PongPlayer, self).pong(), # bypass MRO to `BasePlayer` + super(PongPlayer, self).pong() # bypass MRO to `BasePlayer` ] def main(): # `ConfusedPlayer` methods are resolved from child to parent like this - assert ConfusedPlayer.mro() == [ConfusedPlayer, PongPlayer, NeutralPlayer, BasePlayer, object] + assert ConfusedPlayer.mro() == [ + ConfusedPlayer, PongPlayer, NeutralPlayer, BasePlayer, object] # `IndecisivePlayer` methods are resolved from child to parent like this - assert IndecisivePlayer.mro() == [IndecisivePlayer, NeutralPlayer, PongPlayer, BasePlayer, object] + assert IndecisivePlayer.mro() == [ + IndecisivePlayer, NeutralPlayer, PongPlayer, BasePlayer, object] # Show `ConfusedPlayer` method resolution in action assert ConfusedPlayer().ping_pong() == ["pINg", "ping", "PONG", "PONG"] @@ -90,17 +90,17 @@ def main(): # Show `IndecisivePlayer` method resolution in action assert IndecisivePlayer().ping_pong() == ["ping", "ping", "pONg", "pong"] - class_creation_failed = False + class_creation_fails = False try: # Creating a new class `ConfusedPlayer` and `IndecisivePlayer` - # results in a `TypeError` because both classes do not have - # matching MRO outputs. This means that they cannot be reconciled - # as one class. Hence, `MissingPlayer` will not be created + # results in a `TypeError` because both classes have mismatched + # MRO outputs. This means that they cannot be reconciled as + # one class. Hence `MissingPlayer` will not be created type("MissingPlayer", (ConfusedPlayer, IndecisivePlayer), {}) except TypeError: - class_creation_failed = True - assert class_creation_failed is True + class_creation_fails = True + assert class_creation_fails is True -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/ultimatepython/advanced/pattern_matching.py b/ultimatepython/advanced/pattern_matching.py deleted file mode 100644 index 73f8119e..00000000 --- a/ultimatepython/advanced/pattern_matching.py +++ /dev/null @@ -1,335 +0,0 @@ -""" -Structural pattern matching allows you to match complex data structures -against patterns and extract values in a clean, readable way. This feature -is similar to switch-case statements in other languages but much more powerful. - -Pattern matching was introduced in Python 3.10 through PEP 634, PEP 635, -and PEP 636. It uses the 'match' and 'case' keywords. -""" - - -def classify_number(value) -> str: - """Classify a number using pattern matching with literals. - - This demonstrates matching against specific literal values. - """ - match value: - case 0: - return "zero" - case 1: - return "one" - case 2: - return "two" - case _: - # The underscore _ is a wildcard that matches anything - return "other" - - -def classify_http_status(status) -> str: - """Classify HTTP status codes using pattern matching. - - This shows how pattern matching can make code more readable - than a series of if-elif-else statements. - """ - match status: - case 200: - return "OK" - case 201: - return "Created" - case 400: - return "Bad Request" - case 401: - return "Unauthorized" - case 404: - return "Not Found" - case 500: - return "Internal Server Error" - case _: - return "Unknown Status" - - -def process_point(point) -> str: - """Process a point tuple using pattern matching with sequences. - - This demonstrates pattern matching against tuple structures - and extracting values from them. - """ - match point: - case (0, 0): - return "Origin" - case (0, y): - # Match any point on the y-axis, capture y coordinate - return f"Y-axis at y={y}" - case (x, 0): - # Match any point on the x-axis, capture x coordinate - return f"X-axis at x={x}" - case (x, y): - # Match any other point, capture both coordinates - return f"Point at ({x}, {y})" - case _: - return "Not a valid 2D point" - - -def analyze_sequence(data) -> str: - """Analyze sequences using pattern matching. - - This shows how to match lists with specific structures - and extract elements. - """ - match data: - case []: - return "Empty list" - case [x]: - # Match a list with exactly one element - return f"Single element: {x}" - case [x, y]: - # Match a list with exactly two elements - return f"Pair: {x}, {y}" - case [first, *rest]: - # Match a list with at least one element - # The *rest captures remaining elements - return f"First: {first}, Rest: {rest}" - case _: - return "Not a list" # pragma: no cover - - -def process_command(command) -> str: - """Process commands using pattern matching with guards. - - Guards are if conditions that provide additional filtering - after a pattern match. - """ - match command: - case ["quit"]: - return "Quitting" - case ["go", direction] if direction in ["north", "south", "east", "west"]: - # Guard clause: only match if direction is valid - return f"Going {direction}" - case ["go", direction]: - # This matches any direction that failed the guard above - return f"Invalid direction: {direction}" - case ["take", item]: - return f"Taking {item}" - case ["take", item, quantity] if quantity > 0: - return f"Taking {quantity} {item}" - case ["take", item, quantity]: - return f"Invalid quantity: {quantity}" - case _: - return "Unknown command" - - -class Point: - """A simple 2D point class for pattern matching examples.""" - - def __init__(self, x, y): - self.x = x - self.y = y - - -class Circle: - """A circle with center and radius for pattern matching examples.""" - - def __init__(self, center, radius): - self.center = center - self.radius = radius - - -def describe_shape(shape) -> str: - """Describe shapes using pattern matching with class patterns. - - This demonstrates matching against class instances and - extracting their attributes. - """ - match shape: - case Point(x=0, y=0): - # Match a Point at the origin - return "Point at origin" - case Point(x=0, y=y): - # Match a Point on the y-axis - return f"Point on Y-axis at {y}" - case Point(x=x, y=0): - # Match a Point on the x-axis - return f"Point on X-axis at {x}" - case Point(x=x, y=y) if x == y: - # Match a Point on the diagonal line y=x - return f"Point on diagonal at ({x}, {y})" - case Point(x=x, y=y): - # Match any other Point - return f"Point at ({x}, {y})" - case Circle(center=Point(x=0, y=0), radius=r): - # Match a Circle centered at origin - return f"Circle at origin with radius {r}" - case Circle(center=Point(x=x, y=y), radius=r): - # Match any other Circle - return f"Circle at ({x}, {y}) with radius {r}" - case _: - return "Unknown shape" - - -def analyze_nested(data) -> str: - """Analyze nested structures using pattern matching.""" - match data: - case [["pair", x, y], ["pair", a, b]]: - # Match nested structure - return f"Two pairs: ({x},{y}) and ({a},{b})" - case [["single", val]]: - return f"Single value: {val}" - case _: - return "Unknown structure" - - -def check_value(val) -> str: - """Check value using OR patterns.""" - match val: - case 0 | 1 | 2: - # Match any of these values - return "small" - case 3 | 4 | 5: - return "medium" - case _: - return "large" - - -def process_range(data) -> str: - """Process range data with AS patterns.""" - match data: - case [x, y] as pair if x < y: - # Capture the entire matched value with 'as' - return f"Valid range: {pair}" - case [x, y]: - return f"Invalid range: [{x}, {y}]" - case _: - return "Not a pair" - - -def process_json_data(data) -> str: - """Process JSON-like dictionary data with pattern matching. - - This shows how to match against dictionary structures. - """ - match data: - case {"type": "user", "name": name, "age": age}: - return f"User {name} is {age} years old" - case {"type": "user", "name": name}: - # Match user without age - return f"User {name} with unknown age" - case {"type": "product", "name": name, "price": price} if price > 0: - return f"Product {name} costs ${price}" - case {"type": "product", "name": name, "price": price}: - return f"Product {name} has invalid price: {price}" - case {"type": type_name}: - # Match any dict with a type key - return f"Unknown type: {type_name}" - case _: - return "Invalid data" - - -def main() -> None: - # Test literal pattern matching - assert classify_number(0) == "zero" - assert classify_number(1) == "one" - assert classify_number(2) == "two" - assert classify_number(5) == "other" - assert classify_number(100) == "other" - - # Test HTTP status classification - assert classify_http_status(200) == "OK" - assert classify_http_status(404) == "Not Found" - assert classify_http_status(999) == "Unknown Status" - assert classify_http_status(201) == "Created" - assert classify_http_status(400) == "Bad Request" - assert classify_http_status(401) == "Unauthorized" - assert classify_http_status(500) == "Internal Server Error" - - # Test sequence pattern matching with tuples - assert process_point((0, 0)) == "Origin" - assert process_point((0, 5)) == "Y-axis at y=5" - assert process_point((3, 0)) == "X-axis at x=3" - assert process_point((4, 7)) == "Point at (4, 7)" - assert process_point("invalid") == "Not a valid 2D point" - - # Test sequence pattern matching with lists - assert analyze_sequence([]) == "Empty list" - assert analyze_sequence([42]) == "Single element: 42" - assert analyze_sequence([1, 2]) == "Pair: 1, 2" - assert analyze_sequence([1, 2, 3, 4]) == "First: 1, Rest: [2, 3, 4]" - assert analyze_sequence("not a list") == "Not a list" - - # Test pattern matching with guards - assert process_command(["quit"]) == "Quitting" - assert process_command(["go", "north"]) == "Going north" - assert process_command(["go", "west"]) == "Going west" - assert process_command(["go", "up"]) == "Invalid direction: up" - assert process_command(["take", "key"]) == "Taking key" - assert process_command(["take", "coin", 5]) == "Taking 5 coin" - assert process_command(["take", "coin", 0]) == "Invalid quantity: 0" - assert process_command(["take", "coin", -1]) == "Invalid quantity: -1" - assert process_command(["jump"]) == "Unknown command" - - # Test class pattern matching - p1 = Point(0, 0) - assert describe_shape(p1) == "Point at origin" - - p2 = Point(0, 5) - assert describe_shape(p2) == "Point on Y-axis at 5" - - p3 = Point(3, 0) - assert describe_shape(p3) == "Point on X-axis at 3" - - p4 = Point(5, 5) - assert describe_shape(p4) == "Point on diagonal at (5, 5)" - - p5 = Point(3, 7) - assert describe_shape(p5) == "Point at (3, 7)" - - c1 = Circle(Point(0, 0), 10) - assert describe_shape(c1) == "Circle at origin with radius 10" - - c2 = Circle(Point(5, 5), 3) - assert describe_shape(c2) == "Circle at (5, 5) with radius 3" - - # Test unknown shape - assert describe_shape("unknown") == "Unknown shape" - - # Test dictionary pattern matching - user1 = {"type": "user", "name": "Alice", "age": 30} - assert process_json_data(user1) == "User Alice is 30 years old" - - user2 = {"type": "user", "name": "Bob"} - assert process_json_data(user2) == "User Bob with unknown age" - - product1 = {"type": "product", "name": "Laptop", "price": 999} - assert process_json_data(product1) == "Product Laptop costs $999" - - product2 = {"type": "product", "name": "Free Sample", "price": 0} - assert process_json_data(product2) == "Product Free Sample has invalid price: 0" - - unknown = {"type": "order"} - assert process_json_data(unknown) == "Unknown type: order" - - invalid = {"data": "something"} - assert process_json_data(invalid) == "Invalid data" - - # Pattern matching with OR patterns - assert check_value(0) == "small" - assert check_value(2) == "small" - assert check_value(3) == "medium" - assert check_value(10) == "large" - - # Pattern matching with AS patterns (walrus-like capture) - assert process_range([1, 5]) == "Valid range: [1, 5]" - assert process_range([5, 1]) == "Invalid range: [5, 1]" - assert process_range("not a pair") == "Not a pair" - - # Nested pattern matching - assert analyze_nested([["pair", 1, 2], ["pair", 3, 4]]) == "Two pairs: (1,2) and (3,4)" - assert analyze_nested([["single", 42]]) == "Single value: 42" - assert analyze_nested("invalid") == "Unknown structure" - - # Pattern matching is particularly useful for parsing and handling - # structured data like API responses, configuration files, or - # abstract syntax trees in compilers/interpreters - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/advanced/regex.py b/ultimatepython/advanced/regex.py deleted file mode 100644 index 365ad861..00000000 --- a/ultimatepython/advanced/regex.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -Using regular expressions is a robust way to search for text. Implementing -them is difficult but Python provides a package for us to use them easily. -This module shows a few examples of how to use the `re` package to search -predefined text snippets stored in module-level constants. -""" - -import re - -# Module-level constants -_TEXT_HELLO = "World Hello Hello" -_TEXT_NAMES = "John, Jane" -_TEXT_ABC123 = "abc123" -_TEXT_BYE = "Bye for now" -_TEXT_EMAILS = "My work email is kayode@dodo.ng while nerdthejohn@yahoo.com is personal" - - -def main(): - # Running `search` with "Hello" has a match for first Hello - assert re.search(r"Hello", _TEXT_HELLO).start() == 6 - - # Running `search` with "Hello$" has a match for last Hello - assert re.search(r"Hello$", _TEXT_HELLO).start() == 12 - - # Running `search` with "(Hello) (Hello)" has matches for Hello - assert re.search(r"(Hello) (Hello)", _TEXT_HELLO).groups() == ("Hello", "Hello") - - # Running `findall` with "Hi \w+" has a list of strings - assert re.findall(r"\w+", _TEXT_NAMES) == ["John", "Jane"] - - # Running `findall` with "[a-z]+@[a-z]+\.[a-z]+" has a list of email strings - assert re.findall(r"[a-z]+@[a-z]+\.[a-z]+", _TEXT_EMAILS) == ["kayode@dodo.ng", "nerdthejohn@yahoo.com"] - - # Running `match` with "[123]+" has nothing - assert re.match(r"[123]+", _TEXT_ABC123) is None - - # Running `match` with "[abc]+" has a match for abc - assert re.match(r"[abc]+", _TEXT_ABC123).group(0) == "abc" - - # Running `fullmatch` with "[\w]+" has nothing - assert re.fullmatch(r"[\w]+", _TEXT_BYE) is None - - # Running `fullmatch` with "[\w ]+" has a full match - assert re.fullmatch(r"[\w ]+", _TEXT_BYE).group(0) == _TEXT_BYE - - # To learn more about regular expressions: - # https://en.wikipedia.org/wiki/Regular_expression - # https://github.com/ziishaned/learn-regex - - # To play around with regular expressions in the browser: - # https://regex101.com - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/advanced/thread.py b/ultimatepython/advanced/thread.py deleted file mode 100644 index 61522e79..00000000 --- a/ultimatepython/advanced/thread.py +++ /dev/null @@ -1,89 +0,0 @@ -""" -Threaded programming is used by developers to improve the performance of -an application. This module shows how a multiplication operation with -some delay can be parallelized using `ThreadPoolExecutor`. - -A good grasp of threads is recommended, but not necessary, before -reading the code below. - -Here are some resources to learn more about threads: - -https://realpython.com/intro-to-python-threading/ -https://docs.python.org/3/library/threading.html - -Python threads are not suitable for CPU-heavy tasks in the CPython -interpreter due to the GIL. To address this, we typically resort to -forking processes or running C externally. - -Here are some resources to learn more about the GIL: - -https://realpython.com/python-gil/ -https://wiki.python.org/moin/GlobalInterpreterLock -""" - -import time -from concurrent.futures import ThreadPoolExecutor, as_completed -from datetime import datetime -from typing import Callable, Iterable - -# Module-level constants -_MULTIPLY_DELAY = 0.01 # delay is long enough for threads to be faster - - -def multiply_by_two(item: int) -> int: - """This multiplication has a small delay.""" - time.sleep(_MULTIPLY_DELAY) - return item * 2 - - -def run_thread_workers(work: Callable[[int], int], data: Iterable[int]) -> set[int]: - """Run thread workers that invoke work on each data element. - - The inspiration for this function comes directly from an example - in the Python 3.x documentation: - - https://docs.python.org/3/library/concurrent.futures.html - """ - results: set[int] = set() - - # We can use a with statement to ensure workers are cleaned up promptly - with ThreadPoolExecutor() as executor: - # Note that results are returned out of order - work_queue = (executor.submit(work, item) for item in data) - for future in as_completed(work_queue): - results.add(future.result()) - - return results - - -def main() -> None: - original_data = {num for num in range(5)} - expected_data = {(item * 2) for item in original_data} - - # Let's get the data using the simple approach - simple_start = datetime.now() - simple_data = {multiply_by_two(item) for item in original_data} - simple_duration = datetime.now() - simple_start - - # The simple approach has the expected data - assert simple_data == expected_data - - # Let's get the data using the threaded approach - thread_start = datetime.now() - thread_data = run_thread_workers(multiply_by_two, original_data) - thread_duration = datetime.now() - thread_start - - # The threaded approach has the expected data - assert thread_data == expected_data - - # The threaded approach is faster than the simple approach in this case - # because a blocking I/O call like time.sleep forces the current thread - # to yield its control over to a waiting thread to start running. That - # means the threaded approach can run blocking operations in parallel. - # The cost of creating threads is somewhat cheap which means we often - # create more than one thread to speed up I/O-heavy workloads - assert thread_duration < simple_duration - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/advanced/weak_ref.py b/ultimatepython/advanced/weak_ref.py index 689969bb..e746e8ef 100644 --- a/ultimatepython/advanced/weak_ref.py +++ b/ultimatepython/advanced/weak_ref.py @@ -1,10 +1,3 @@ -""" -Weak references are a way to help the Python interpreter remove unused data -more easily. This module shows how it can be used to keep a server registry -up-to-date as it explicitly sets up and implicitly tears down servers as -the program enters and leaves a function scope. -""" - import weakref from uuid import uuid4 @@ -19,7 +12,6 @@ class Server: @classmethod def create(cls, role, provider=_CLOUD_PROVIDER): - """Create server with autogenerated SSID.""" return cls(uuid4().hex, role, provider) def __init__(self, ssid, role, provider): @@ -36,16 +28,13 @@ def __init__(self): @property def servers(self): - """Get set of added servers.""" return {s for s in self._servers} @property def server_count(self): - """Get count of added servers.""" return len(self.servers) def add(self, server): - """Add server to registry.""" self._servers.add(server) @@ -53,7 +42,8 @@ def setup_and_teardown_servers(registry): """Explicitly setup and implicitly teardown servers.""" app_servers = {} - # Let's create all the servers and store them properly + # Create all of the servers and put them in the registry and the + # dictionary and we'll tally things at the end for app in _CLOUD_APPS: app_servers[app] = set() for component in _CLOUD_APP_COMPONENTS: @@ -61,23 +51,25 @@ def setup_and_teardown_servers(registry): registry.add(server) app_servers[app].add(server) - # All of these counts are equivalent. This is no surprise since our - # for loop unconditionally creates a server for every permutation of - # apps and components. The loop also adds each server to the registry - # and dictionary unconditionally + # All of these counts are equivalent and this is no surprise since + # our for loop unconditionally creates a server for every permutation + # of apps and components, and adds each server to the registry and + # dictionary unconditionally assert ( registry.server_count == len(_CLOUD_APPS) * len(_CLOUD_APP_COMPONENTS) - == len([(app, server) for app, servers in app_servers.items() for server in servers]) + == len([(app, server) + for app, servers in app_servers.items() + for server in servers]) ) - # What's fascinating is that servers go away when we leave the + # What's really interesting is that servers go away when we leave the # scope of this function. In this function, each server is created and # strongly referenced by the `app_servers` variable. When we leave this # function, the `app_servers` variable no longer exists which brings # the reference count for each server from 1 to 0. A reference count of # 0 for each server triggers the garbage collector to run the cleanup - # process for all the servers in this function scope + # process for all of the servers in this function scope def main(): @@ -96,5 +88,5 @@ def main(): assert registry.server_count == 0 -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/ultimatepython/classes/abstract_class.py b/ultimatepython/classes/abstract_class.py index eef63d2e..5f7a9979 100644 --- a/ultimatepython/classes/abstract_class.py +++ b/ultimatepython/classes/abstract_class.py @@ -1,40 +1,31 @@ -""" -Abstract class is an extension of a basic class. Like a basic class, an -abstract class has methods and state. Unlike a basic class, it inherits -the `ABC` class and has at least one `abstractmethod`. That means we -cannot create an instance directly from its constructor. In this module, -we will create an abstract class and two concrete classes. - -For more about abstract classes, click the link below: - -https://www.python.org/dev/peps/pep-3119/ -""" - from abc import ABC, abstractmethod class Employee(ABC): """Abstract definition of an employee. - Any employee can work and relax. The way that one type of employee - can work and relax is different from another type of employee. + The Employee class is abstract because it inherits the `ABC` class + and has at least one `abstractmethod`. That means we cannot create + an instance directly from its constructor. + + For more about abstract classes, click the link below: + + https://www.python.org/dev/peps/pep-3119/ """ - def __init__(self, name: str, title: str) -> None: + def __init__(self, name, title): self.name = name self.title = title - def __str__(self) -> str: + def __str__(self): return self.name @abstractmethod - def do_work(self) -> str: - """Do something for work.""" + def do_work(self): raise NotImplementedError @abstractmethod - def do_relax(self) -> str: - """Do something to relax.""" + def do_relax(self): raise NotImplementedError @@ -49,14 +40,14 @@ class Engineer(Employee): is something that a manager prefers not to do. """ - def __init__(self, name: str, title: str, skill: str) -> None: + def __init__(self, name, title, skill): super().__init__(name, title) self.skill = skill - def do_work(self) -> str: + def do_work(self): return f"{self} is coding in {self.skill}" - def do_relax(self) -> str: + def do_relax(self): return f"{self} is watching YouTube" def do_refactor(self): @@ -73,22 +64,22 @@ class is concrete. Notice that a manager has direct reports and engineer. """ - def __init__(self, name: str, title: str, direct_reports: list) -> None: + def __init__(self, name, title, direct_reports): super().__init__(name, title) self.direct_reports = direct_reports - def do_work(self) -> str: + def do_work(self): return f"{self} is meeting up with {len(self.direct_reports)} reports" - def do_relax(self) -> str: + def do_relax(self): return f"{self} is taking a trip to the Bahamas" - def do_hire(self) -> str: + def do_hire(self): """Do the hard work of hiring employees, unlike engineers.""" return f"{self} is hiring employees" -def main() -> None: +def main(): # Declare two engineers engineer_john = Engineer("John Doe", "Software Engineer", "Android") engineer_jane = Engineer("Jane Doe", "Software Engineer", "iOS") @@ -116,5 +107,5 @@ def main() -> None: assert manager_max.do_hire() == "Max Doe is hiring employees" -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/ultimatepython/classes/basic_class.py b/ultimatepython/classes/basic_class.py index 9c9216e4..0eb64038 100644 --- a/ultimatepython/classes/basic_class.py +++ b/ultimatepython/classes/basic_class.py @@ -1,48 +1,41 @@ -""" -A class is made up of methods and state. This allows code and data to be -combined as one logical entity. This module defines a basic car class, -creates a car instance and uses it for demonstration purposes. -""" - -from inspect import isfunction, ismethod, signature +from inspect import signature class Car: """Basic definition of a car. - We begin with a simple mental model of what a car is. That way, we - can start exploring the core concepts that are associated with a - class definition. + A car is a good entity for defining with a class because it has state + and methods associated with it. We start with a simple mental model + of what a car is, so that we can start with core concepts associated + with a class definition. """ - def __init__(self, make: str, model: str, year: int, miles: float) -> None: + def __init__(self, make, model, year, miles): """Constructor logic.""" self.make = make self.model = model self.year = year self.miles = miles - def __repr__(self) -> str: + def __repr__(self): """Formal representation for developers.""" return f"" - def __str__(self) -> str: + def __str__(self): """Informal representation for users.""" return f"{self.make} {self.model} ({self.year})" - def drive(self, rate_in_mph: int) -> str: - """Drive car at a certain rate in MPH.""" + def drive(self, rate_in_mph): + """Drive car at a certain rate.""" return f"{self} is driving at {rate_in_mph} MPH" -def main() -> None: +def main(): # Create a car with the provided class constructor car = Car("Bumble", "Bee", 2000, 200000.0) - # Formal representation is good for debugging issues + # Formal and informal representations are not the same assert repr(car) == "" - - # Informal representation is good for user output assert str(car) == "Bumble Bee (2000)" # Call a method on the class constructor @@ -51,9 +44,10 @@ def main() -> None: # As a reminder: everything in Python is an object! And that applies # to classes in the most interesting way - because they're not only # subclasses of object - they are also instances of object. This - # means that we can modify the `Car` class at runtime, just like any + # means that we can modify the Car class at runtime, just like any # other piece of data we define in Python - assert issubclass(Car, object) and isinstance(Car, object) + assert issubclass(Car, object) + assert isinstance(Car, object) # To emphasize the idea that everything is an object, let's look at # the `drive` method in more detail @@ -65,9 +59,6 @@ def main() -> None: # The variable method is bound to the instance assert driving.__self__ == car - # That is why `driving` is considered a method and not a function - assert ismethod(driving) and not isfunction(driving) - # And there is only one parameter for `driving` because `__self__` # binding is implicit driving_params = signature(driving).parameters diff --git a/ultimatepython/classes/encapsulation.py b/ultimatepython/classes/encapsulation.py deleted file mode 100644 index 568738e3..00000000 --- a/ultimatepython/classes/encapsulation.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -Encapsulation is a feature of OOP that allows you to hide the -implementation details of a class from its users. -Encapsulation allows us to limit the access of certain attributes -within a class. This prevents users from directly accessing and modifying such -attributes from outside the class. Instead, users must use methods to access and -modify attributes. -""" - -import secrets - -# Module-level constant -_INVALID_AMOUNT_MESSAGE = "Invalid amount." -_INSUFFICIENT_BALANCE_MESSAGE = "Insufficient balance." - - -class BankAccount: - def __init__(self, account_holder_name: str) -> None: - """ - In Python, a class attribute can be made private by prefixing it with two underscores. - This makes it inaccessible to users outside the class. - By default, class attributes are public. Therefore, they can be accessed and modified - outside the class. - - Here, account_number and balance are private while account_holder_name is public. - """ - self.account_holder_name = account_holder_name - """ - The account number is generated automatically using the randbelow function from - the random module when a new instance of the class is created. - The balance is set to 0 by default. - """ - self.__account_number = secrets.randbelow(10**10) # generate a random account number of 10 digits. - self.__balance = 0 - - def deposit(self, balance: int) -> None: - """ - The deposit function is used to add new balance to the account. - The provided balance is added to the existing balance. - """ - self.__balance += int(balance) - - def withdraw(self, balance: int) -> None: - """ - The withdrawal method is used to deduct the balance from the account. - In case there is insufficient balance, or the input is invalid, - a value error is raised. - """ - if balance <= 0: - raise ValueError(_INVALID_AMOUNT_MESSAGE) - if balance > self.__balance: - raise ValueError(_INSUFFICIENT_BALANCE_MESSAGE) - - self.__balance -= balance - - def get_balance(self) -> int: - """ - This function returns the available balance in the account. - """ - return self.__balance - - def get_account_number(self) -> int: - """ - The account number is generated randomly when a new instance of the class is created. - Since the attribute is also private, it cannot be accessed directly from outside the class. - The get_account_number method allows you to access the account number outside the class. - But since we do not define a setter method for this variable, we cannot modify it outside the class. - Therefore, the account number generated while creating an object of the BankAccount class cannot be changed - but can only be read using this function. - """ - return self.__account_number - - def __set_account_number(self, number: int) -> None: - """ - This is a private method. Similar to private variables, - private methods also cannot be accessed outside the class. - """ - self.__account_number = number - - def remove_account_details(self) -> None: - """ - This method is used to reset the account details. - Here, the __set_account_number function is private. - This, it cannot be called from outside the class. - However, the remove_account_details calls the function from - inside the class and as it is a public method, it can be called from - outside the class. - """ - self.__balance = 0 - self.__set_account_number(0) - self.account_holder_name = "" - - -def main() -> None: - # Account names constants. - user1 = "John Doe" - user2 = "Jane Doe" - - # Account instances. - account1 = BankAccount(user1) - account2 = BankAccount(user2) - - assert account1.account_holder_name == user1 - assert account2.account_holder_name == user2 - - # Deposit amount and check if the balance is updated. - account1.deposit(100) - assert account1.get_balance() == 100 - - # Withdraw amount and check if the balance is updated. - account1.withdraw(50) - assert account1.get_balance() == 50 - - # validating invalid amounts. - error_inputs = [-10, 0, 150] - for input in error_inputs: - try: - account1.withdraw(input) - except ValueError as e: - assert str(e) in {_INSUFFICIENT_BALANCE_MESSAGE, _INVALID_AMOUNT_MESSAGE} - - # Remove account details and assert values. - account1.remove_account_details() - - assert account1.get_balance() == 0 - assert account1.get_account_number() == 0 - assert account1.account_holder_name == "" - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/classes/exception_class.py b/ultimatepython/classes/exception_class.py index 560926d7..df9c2baa 100644 --- a/ultimatepython/classes/exception_class.py +++ b/ultimatepython/classes/exception_class.py @@ -1,12 +1,3 @@ -""" -Exception classes are used to indicate that something has gone wrong with -the program at runtime. Functions use the `raise` keyword, if an error is -anticipated, and specify the exception class they intend to throw. This -module defines a handful of custom exception classes and shows how they -can be used in the context of a function. -""" - - class CustomError(Exception): """Custom class of errors. @@ -15,9 +6,9 @@ class CustomError(Exception): consumption by downstream services and command-line tools. If we designed a standalone application with no downstream consumers, then - it makes little sense to define a custom hierarchy of exceptions. In that - case, we should use the existing hierarchy of builtin exception - classes which are listed in the Python docs: + it makes little sense to define a custom hierarchy of exceptions. Instead, + try using the existing hierarchy of builtin exception classes, which are + listed in the Python docs: https://docs.python.org/3/library/exceptions.html """ @@ -39,41 +30,41 @@ class DivisionError(CustomError): """ -def divide_positive_numbers(dividend: int, divisor: int) -> int: +def divide_positive_numbers(dividend, divisor): """Divide a positive number by another positive number. - Writing a program in this style is considered defensive programming. - For more on this programming style, check the Wikipedia link below: + Writing a program in this style is what is considered defensive + programming. For more on this programming style, check out the + Wikipedia link below: https://en.wikipedia.org/wiki/Defensive_programming """ - if dividend <= 0: - raise DivisionError(f"Non-positive dividend: {dividend}") - elif divisor <= 0: - raise DivisionError(f"Non-positive divisor: {divisor}") + if divisor == 0: + raise DivisionError("Cannot have a zero divisor") + elif dividend <= 0: + raise DivisionError("Cannot have a negative dividend") + elif divisor < 0: + raise DivisionError("Cannot have a negative divisor") return dividend // divisor -def main() -> None: +def main(): # Exception classes are no different from concrete classes in that # they all have inheritance baked in assert issubclass(DivisionError, CustomError) # Try a couple of inputs that are known to throw an error based on # the exceptions thrown in `divide_positive_numbers` - for dividend, divisor in [(0, 1), (1, 0), (-1, 1), (1, -1)]: - division_failed = False + for dividend, divisor in [(1, 0), (-1, 1), (1, -1)]: try: divide_positive_numbers(dividend, divisor) except DivisionError as e: - division_failed = True - assert str(e).startswith("Non-positive") - assert division_failed is True + assert str(e).startswith("Cannot have a") # Now let's do it correctly to skip all the exceptions result = divide_positive_numbers(1, 1) assert result == 1 -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/ultimatepython/classes/inheritance.py b/ultimatepython/classes/inheritance.py deleted file mode 100644 index 166d40a9..00000000 --- a/ultimatepython/classes/inheritance.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -Inheritance is a way to reuse code and data from a parent class. This -allows us to avoid repeating ourselves and to build upon existing -functionality. This module defines a basic vehicle class, creates a car -class that inherits from vehicle, then creates a truck class that -inherits from car and use it for demonstration purposes. -""" - -from inspect import isfunction, ismethod - - -class Vehicle: - """Basic definition of a vehicle. - - We begin with a simple mental model of what a vehicle is. It has - a make, model, year, and miles. That way, we can start exploring - the core concepts that are associated with a class definition. - """ - - def __init__(self, make: str, model: str, year: int, miles: float) -> None: - """Construct a vehicle with make, model, year, and miles.""" - self.make = make - self.model = model - self.year = year - self.miles = miles - - def __repr__(self) -> str: - """Return the formal representation of a vehicle.""" - return f"" - - def __str__(self) -> str: - """Return the informal representation of a vehicle.""" - return f"{self.make} {self.model} ({self.year})" - - def drive(self, rate_in_mph: int) -> str: - """Drive a vehicle at a certain rate in MPH.""" - return f"{self} is driving at {rate_in_mph} MPH" - - -class Car(Vehicle): - """Definition of a car. - - We inherit from the vehicle class to reuse the code and data that - we have already defined. In addition, we add a new attribute called - `wheels` to the car class. This is an example of extending the - functionality of a parent class. In __init__, we call the parent - constructor with the `super` function. This is a way to invoke the - parent constructor without having to explicitly name the parent - class. We also override the method `__repr__` to have a different - output than the vehicle. - """ - - def __init__(self, make: str, model: str, year: int, miles: float) -> None: - """Construct a car with make, model, year, miles, and wheels.""" - super().__init__(make, model, year, miles) - self.wheels = 4 - - def __repr__(self) -> str: - """Return the formal representation of a car.""" - return f"" - - -class Truck(Vehicle): - """Definition of a truck. - - We inherit from vehicle just like we did with the car class. In this case we - will also override the method `drive` to have a different output than the - car and the vehicle. - """ - - def __init__(self, make: str, model: str, year: int, miles: float) -> None: - """Construct a truck with make, model, year, miles, and wheels.""" - super().__init__(make, model, year, miles) - self.wheels = 6 - - def __repr__(self) -> str: - """Return the formal representation of a truck.""" - return f"" - - def drive(self, rate_in_mph: int) -> str: - """Drive a truck at a certain rate in MPH.""" - return f"{self} is driving a truck at {rate_in_mph} MPH" - - -def main() -> None: - # Create a vehicle with the provided class constructor - vehicle = Vehicle("Mistery Machine", "Van", 1969, 100000.0) - - # Formal representation - assert repr(vehicle) == "" - - # Informal representation - assert str(vehicle) == "Mistery Machine Van (1969)" - - # Call a method on the class constructor - assert vehicle.drive(50) == "Mistery Machine Van (1969) is driving at 50 MPH" - - # Check the type of the method drive - assert ismethod(vehicle.drive) and not isfunction(vehicle.drive) - - # Now we create a car with the provided class constructor - car = Car("DeLorean", "DMC-12", 1982, 220000.0) - - # The informal representation is similar to the vehicle - assert str(car) == "DeLorean DMC-12 (1982)" - - # But the formal representation is different because we included - # the wheels attribute - assert repr(car) == "" - - # And we can check the type of the method drive like we did with - # the vehicle - assert ismethod(car.drive) and not isfunction(car.drive) - - # If we call the method drive, we can see that we did not - # write any code for the car class, but we can still use it - # because it is inherited from the vehicle class and the - # behavior is the same as the vehicle - assert car.drive(50) == "DeLorean DMC-12 (1982) is driving at 50 MPH" - - # Now we create a truck with the provided class constructor - truck = Truck("Optimus Prime", "Truck", 1984, 1000000.0) - - # Like car and vehicle, the informal representation is similar - assert str(truck) == "Optimus Prime Truck (1984)" - - # And the formal representation is different from the vehicle - # because we included the wheels attribute - assert repr(truck) == "" - - # And we can check the type of the method drive like we did with - # the vehicle - assert ismethod(truck.drive) and not isfunction(truck.drive) - - # For the last part, we can see that the method drive is different - # for the truck - assert truck.drive(50) == "Optimus Prime Truck (1984) is driving a truck at 50 MPH" - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/classes/iterator_class.py b/ultimatepython/classes/iterator_class.py index 9ee96e0d..7a2d0ea5 100644 --- a/ultimatepython/classes/iterator_class.py +++ b/ultimatepython/classes/iterator_class.py @@ -1,10 +1,3 @@ -""" -Iterator classes implement the `__iter__` and `__next__` magic methods. -This module defines an employee iterator class that iterates through each -employee in a hierarchy one-by-one. This module also shows how a similar -approach can be achieved with a generator function. -""" - # Module-level constants _ITERATION_MESSAGE = "Cyclic loop detected" @@ -32,11 +25,14 @@ class Employee: https://en.wikipedia.org/wiki/Design_Patterns """ - def __init__(self, name: str, title: str, direct_reports: list) -> None: + def __init__(self, name, title, direct_reports): self.name = name self.title = title self.direct_reports = direct_reports + def __repr__(self): + return f"" + class IterationError(RuntimeError): """Any error that comes while iterating through objects. @@ -65,21 +61,21 @@ class EmployeeIterator: https://en.wikipedia.org/wiki/Iterator_pattern """ - def __init__(self, employee: Employee) -> None: + def __init__(self, employee): """Constructor logic.""" self.employees_to_visit = [employee] - self.employees_visited: set[str] = set() + self.employees_visited = set() - def __iter__(self) -> "EmployeeIterator": + def __iter__(self): """Iterator is self by convention.""" return self - def __next__(self) -> Employee: + def __next__(self): """Return the next employee available. The logic may seem complex, but it's actually a common algorithm used in traversing a relationship graph. It is called depth-first - search, and it can be found on Wikipedia: + search and it can be found on Wikipedia: https://en.wikipedia.org/wiki/Depth-first_search """ @@ -94,7 +90,7 @@ def __next__(self) -> Employee: return employee -def employee_generator(top_employee: Employee): +def employee_generator(top_employee): """Employee generator. It is essentially the same logic as above except constructed as a @@ -126,9 +122,12 @@ def employee_generator(top_employee: Employee): yield employee -def main() -> None: +def main(): # Manager with two direct reports - manager = Employee("Max Doe", "Engineering Manager", [Employee("John Doe", "Software Engineer", []), Employee("Jane Doe", "Software Engineer", [])]) + manager = Employee("Max Doe", "Engineering Manager", [ + Employee("John Doe", "Software Engineer", []), + Employee("Jane Doe", "Software Engineer", []) + ]) # We should provide the same three employees in the same order regardless # of whether we use the iterator class or the generator function @@ -143,14 +142,11 @@ def main() -> None: hacker = Employee("Unknown", "Hacker", []) hacker.direct_reports.append(hacker) - for iter_obj in (EmployeeIterator, employee_generator): - call_failed = False + for iter_fn in (EmployeeIterator, employee_generator): try: - list(iter_obj(hacker)) + list(iter_fn(hacker)) except IterationError as e: - call_failed = True assert str(e) == _ITERATION_MESSAGE - assert call_failed is True if __name__ == "__main__": diff --git a/ultimatepython/data_structures/comprehension.py b/ultimatepython/data_structures/comprehension.py index daae75ff..fd38ecbf 100644 --- a/ultimatepython/data_structures/comprehension.py +++ b/ultimatepython/data_structures/comprehension.py @@ -1,17 +1,12 @@ -""" -This module shows one-liner comprehensions where we make lists, tuples, -sets and dictionaries by looping through iterators. -""" - - -def main() -> None: +def main(): # One interesting fact about data structures is that we can build # them with comprehensions. Let's explain how the first one works: # we just want to create zeros so our expression is set to `0` # since no computing is required; because `0` is a constant value, # we can set the item that we compute with to `_`; and we want to - # create five zeros, so we set the iterator as `range(5)` - assert [0 for _ in range(5)] == [0] * 5 == [0, 0, 0, 0, 0] + # create five zeros so we set the iterator as `range(5)` + list_comp = [0 for _ in range(5)] + assert list_comp == [0] * 5 # For the next comprehension operations, let's see what we can do # with a list of 3-5 letter words @@ -29,14 +24,10 @@ def main() -> None: # Dictionary comprehension can map each word to its length dict_comp = {word: len(word) for word in words} assert len(dict_comp) == len(words) - assert dict_comp == {"cat": 3, "mice": 4, "horse": 5, "bat": 3} - - # Comprehensions can also be used with inline conditionals to - # get filtered values from the original list. In this example, - # we grab only odd numbers from the original list - nums = [31, 13, 64, 12, 767, 84] - odds = [_ for _ in nums if _ % 2 == 1] - assert odds == [31, 13, 767] + assert dict_comp == {"cat": 3, + "mice": 4, + "horse": 5, + "bat": 3} if __name__ == "__main__": diff --git a/ultimatepython/data_structures/defaultdict.py b/ultimatepython/data_structures/defaultdict.py deleted file mode 100644 index 944d5387..00000000 --- a/ultimatepython/data_structures/defaultdict.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -This module demonstrates the use of defaultdict, which is a dictionary that is -possible to set up a default value in its creation. -""" - -from collections import defaultdict - -# Module-level constants -_GPA_MIN = 0.0 -_GPA_MAX = 4.0 -_EPS = 0.000001 - - -def main() -> None: - # Let's create a defaultdict with student keys and GPA values. The first - # parameter is called default_factory, and it is the initialization value for - # first use of a key. It can be a common type or a function - student_gpa = defaultdict(float, [("john", 3.5), ("bob", 2.8), ("mary", 3.2)]) - - # There are three student records in this dictionary - assert len(student_gpa) == 3 - - # Each student has a name key and a GPA value - assert len(student_gpa.keys()) == len(student_gpa.values()) - - # We can get the names in isolation. Note that in Python 3.7 and - # above, dictionary entries are sorted in the order that they were - # defined or inserted - student_names = [] - for student in student_gpa.keys(): - student_names.append(student) - assert student_names == ["john", "bob", "mary"] - - # We can get the GPA for a specific student - assert abs(student_gpa["john"] < 3.5) < _EPS - - # And the defaultdict allow us to get the GPA of a student that is not in - # the data structure yet, returning a default value for float that is 0.0 - assert student_gpa["jane"] == _GPA_MIN - - # And now there are four student records in this dictionary - assert len(student_gpa) == 4 - - # You can set the default value in default_factory attribute - def set_default_to_gpa_max(): - return _GPA_MAX - - student_gpa.default_factory = set_default_to_gpa_max - - assert student_gpa["rika"] == _GPA_MAX - - # And now there are five student records in this dictionary - assert len(student_gpa) == 5 - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/data_structures/deque.py b/ultimatepython/data_structures/deque.py deleted file mode 100644 index e1a8abf4..00000000 --- a/ultimatepython/data_structures/deque.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -A deque is similar to all the other sequential data structures but -has some implementation details that are different from other sequences -like a list. This module highlights those differences and shows how -a deque can be used as a LIFO stack and a FIFO queue. -""" - -from collections import deque - - -def main() -> None: - # A list is identical to a vector where a new array is created when - # there are too many elements in the old array, and the old array - # elements are moved over to the new array one-by-one. The time - # involved with growing a list increases linearly. A deque is - # identical to a doubly linked list whose nodes have a left pointer - # and a right pointer. In order to grow the linked list, a new node - # is created and added to the left, or the right, of the linked list. - # The time complexity involved with growing a deque is constant. - # Check out the source code for a list and a deque here: - # https://github.com/python/cpython/blob/3.8/Objects/listobject.c - # https://github.com/python/cpython/blob/3.8/Modules/_collectionsmodule.c - dq: deque[int] = deque() - - for i in range(1, 5): - # Similar to adding a new node to the right of the linked list - dq.append(i) - - # Similar to adding a new node to the left of the linked list - dq.appendleft(i * 2) - - # A deque can be iterated over to build any data structure - assert [el for el in dq] == [8, 6, 4, 2, 1, 2, 3, 4] - assert tuple(el for el in dq) == (8, 6, 4, 2, 1, 2, 3, 4) - assert {el for el in dq} == {8, 6, 4, 2, 1, 3} - - # A deque can be used as a stack - # https://en.wikipedia.org/wiki/Stack_(abstract_data_type) - assert dq.pop() == 4 - assert dq.pop() == 3 - - # A deque can be used as a queue - # https://en.wikipedia.org/wiki/Queue_(abstract_data_type) - assert dq.popleft() == 8 - assert dq.popleft() == 6 - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/data_structures/dict.py b/ultimatepython/data_structures/dict.py index 5ce62ac2..d5944510 100644 --- a/ultimatepython/data_structures/dict.py +++ b/ultimatepython/data_structures/dict.py @@ -1,19 +1,9 @@ -""" -Dictionaries are a mapping of keys to values. This module shows how to -access, modify, remove and extend key-value pairs with this data -structure. -""" - -import math - -# Module-level constants -_GPA_MIN = 0.0 -_GPA_MAX = 4.0 - - -def main() -> None: +def main(): # Let's create a dictionary with student keys and GPA values - student_gpa = {"john": 3.5, "jane": _GPA_MAX, "bob": 2.8, "mary": 3.2} + student_gpa = {"john": 3.5, + "jane": 4.0, + "bob": 2.8, + "mary": 3.2} # There are four student records in this dictionary assert len(student_gpa) == 4 @@ -21,63 +11,20 @@ def main() -> None: # Each student has a name key and a GPA value assert len(student_gpa.keys()) == len(student_gpa.values()) - # We can get the names in isolation. Note that in Python 3.7 and - # above, dictionary entries are sorted in the order that they were - # defined or inserted - student_names = [] + # We can get the names in isolation for student in student_gpa.keys(): - student_names.append(student) - assert student_names == ["john", "jane", "bob", "mary"] - - # We can check that `student_gpa` has the names that were stored - # in `student_names` from the loop above - for student in student_names: - assert student in student_gpa + assert len(student) > 2 # We can get the GPAs in isolation - gpa_values = [] for gpa in student_gpa.values(): - gpa_values.append(gpa) - assert gpa_values == [3.5, _GPA_MAX, 2.8, 3.2] + assert gpa > 2.0 # We can get the GPA for a specific student - assert math.isclose(student_gpa["john"], 3.5) - - # If the key does not always exist inside a dictionary, we - # can check for its existence by using `in` - assert "bob" in student_gpa - assert "alice" not in student_gpa - - # If we want to retrieve a value that may not exist inside - # the dictionary, we can use `get` which allows us to return a - # default value in case the checked key is missing - gpa_jane = student_gpa.get("jane", _GPA_MIN) - assert gpa_jane == _GPA_MAX - gpa_alice = student_gpa.get("alice", _GPA_MIN) - assert gpa_alice == _GPA_MIN - - # We can update the GPA for a specific student - student_gpa["john"] = _GPA_MAX - - # Or update the GPA for multiple students - student_gpa.update(bob=_GPA_MIN, mary=_GPA_MIN) + assert student_gpa["john"] == 3.5 # We can access the student and GPA simultaneously - gpa_binary = [] for student, gpa in student_gpa.items(): assert student_gpa[student] == gpa - gpa_binary.append(gpa) - assert gpa_binary == [_GPA_MAX, _GPA_MAX, _GPA_MIN, _GPA_MIN] - - # Let's remove all the students - for student in student_names: - student_gpa.pop(student) - assert len(student_gpa) == 0 - - # Let's add all the students back in - for student, gpa in zip(student_names, gpa_binary): - student_gpa[student] = gpa - assert len(student_gpa) == len(student_names) if __name__ == "__main__": diff --git a/ultimatepython/data_structures/dict_union.py b/ultimatepython/data_structures/dict_union.py deleted file mode 100644 index 5f52c59b..00000000 --- a/ultimatepython/data_structures/dict_union.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -Dictionary union operators allow you to merge dictionaries using -the | (union) and |= (in-place union) operators. These operators -provide a clean and intuitive syntax for combining dictionaries. - -This feature was introduced in Python 3.9 through PEP 584. Before -this, you had to use methods like dict.update() or {**dict1, **dict2} -syntax to merge dictionaries. -""" - - -def main() -> None: - # Traditional dictionary merging before Python 3.9 - # Method 1: Using dict.update() (modifies the original) - dict1_old = {"a": 1, "b": 2} - dict2_old = {"c": 3, "d": 4} - dict1_old.update(dict2_old) - assert dict1_old == {"a": 1, "b": 2, "c": 3, "d": 4} - - # Method 2: Using dictionary unpacking (creates a new dict) - dict3_old = {"a": 1, "b": 2} - dict4_old = {"c": 3, "d": 4} - merged_old = {**dict3_old, **dict4_old} - assert merged_old == {"a": 1, "b": 2, "c": 3, "d": 4} - - # With Python 3.9+, we can use the | operator for union - # This creates a new dictionary without modifying the originals - dict1 = {"a": 1, "b": 2} - dict2 = {"c": 3, "d": 4} - merged = dict1 | dict2 - assert merged == {"a": 1, "b": 2, "c": 3, "d": 4} - - # The original dictionaries remain unchanged - assert dict1 == {"a": 1, "b": 2} - assert dict2 == {"c": 3, "d": 4} - - # When there are overlapping keys, the right operand's values take precedence - # This is the same behavior as dict.update() and {**d1, **d2} - dict3 = {"a": 1, "b": 2, "c": 3} - dict4 = {"b": 20, "c": 30, "d": 4} - merged2 = dict3 | dict4 - # Keys 'b' and 'c' from dict4 override those from dict3 - assert merged2 == {"a": 1, "b": 20, "c": 30, "d": 4} - - # The order matters! Left operand is the base, right operand overwrites - merged3 = dict4 | dict3 - # Now keys 'b' and 'c' from dict3 override those from dict4 - assert merged3 == {"b": 2, "c": 3, "d": 4, "a": 1} - - # The |= operator performs in-place union (augmented assignment) - # This is equivalent to dict.update() but with cleaner syntax - dict5 = {"a": 1, "b": 2} - dict6 = {"c": 3, "d": 4} - dict5 |= dict6 - # dict5 is modified in place - assert dict5 == {"a": 1, "b": 2, "c": 3, "d": 4} - # dict6 remains unchanged - assert dict6 == {"c": 3, "d": 4} - - # The |= operator also handles overlapping keys - dict7 = {"a": 1, "b": 2, "c": 3} - dict8 = {"b": 20, "d": 4} - dict7 |= dict8 - # 'b' from dict8 overwrites 'b' in dict7 - assert dict7 == {"a": 1, "b": 20, "c": 3, "d": 4} - - # You can chain multiple | operations - dict9 = {"a": 1} - dict10 = {"b": 2} - dict11 = {"c": 3} - dict12 = {"d": 4} - combined = dict9 | dict10 | dict11 | dict12 - assert combined == {"a": 1, "b": 2, "c": 3, "d": 4} - - # When chaining with overlapping keys, rightmost values win - dict13 = {"a": 1, "x": 10} - dict14 = {"b": 2, "x": 20} - dict15 = {"c": 3, "x": 30} - combined2 = dict13 | dict14 | dict15 - # 'x' ends up with value 30 from the rightmost dictionary - assert combined2 == {"a": 1, "b": 2, "c": 3, "x": 30} - - # The union operator works with empty dictionaries - empty: dict[str, int] = {} - dict16 = {"a": 1, "b": 2} - assert empty | dict16 == {"a": 1, "b": 2} - assert dict16 | empty == {"a": 1, "b": 2} - assert empty | empty == {} - - # The union operator can be used with dict() constructor results - dict17 = dict(a=1, b=2) - dict18 = dict(c=3, d=4) - merged4 = dict17 | dict18 - assert merged4 == {"a": 1, "b": 2, "c": 3, "d": 4} - - # You can mix different value types in merged dictionaries - dict19 = {"name": "Alice", "age": 30} - dict20 = {"city": "NYC", "scores": [85, 90, 95]} - dict21 = {"active": True} - person = dict19 | dict20 | dict21 - assert person == {"name": "Alice", "age": 30, "city": "NYC", "scores": [85, 90, 95], "active": True} - - # Practical use case: Configuration merging - # Start with default configuration - default_config = {"timeout": 30, "retries": 3, "debug": False, "log_level": "INFO"} - - # User provides custom configuration (partial) - user_config = {"timeout": 60, "debug": True} - - # Merge configurations, user settings override defaults - final_config = default_config | user_config - assert final_config == { - "timeout": 60, # Overridden by user - "retries": 3, # From default - "debug": True, # Overridden by user - "log_level": "INFO", # From default - } - - # Practical use case: Building objects incrementally - # Start with base attributes - base = {"id": 1, "type": "user"} - - # Add authentication info - with_auth = base | {"username": "john", "email": "john@example.com"} - - # Add profile info - with_profile = with_auth | {"bio": "Developer", "location": "USA"} - - assert with_profile == {"id": 1, "type": "user", "username": "john", "email": "john@example.com", "bio": "Developer", "location": "USA"} - - # Practical use case: Updating records with |= - user_record = {"id": 100, "name": "Jane", "status": "active", "login_count": 5} - - # Apply update from an external source - update = {"status": "inactive", "login_count": 6, "last_login": "2024-01-15"} - user_record |= update - - assert user_record == {"id": 100, "name": "Jane", "status": "inactive", "login_count": 6, "last_login": "2024-01-15"} - - # The union operators only work with dictionaries - # Attempting to use them with non-dict types raises TypeError - dict22 = {"a": 1} - error_raised = False - try: - # This will fail because list is not a dict - dict22 | [("b", 2)] # type: ignore [operator] - except TypeError: - error_raised = True - assert error_raised is True - - # However, you can use dict() to convert compatible types first - dict23 = {"a": 1} - dict24 = dict([("b", 2), ("c", 3)]) # Convert list of tuples to dict - merged5 = dict23 | dict24 - assert merged5 == {"a": 1, "b": 2, "c": 3} - - # Comparison with the older approaches shows the clarity improvement: - - # OLD: Using update() - modifies original, no expression result - old1 = {"a": 1} - old1.update({"b": 2}) - assert old1 == {"a": 1, "b": 2} - - # OLD: Using unpacking - verbose for multiple merges - old2 = {**{"a": 1}, **{"b": 2}, **{"c": 3}} - assert old2 == {"a": 1, "b": 2, "c": 3} - - # NEW: Using union operator - clean and chainable - new1 = {"a": 1} | {"b": 2} | {"c": 3} - assert new1 == {"a": 1, "b": 2, "c": 3} - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/data_structures/heap.py b/ultimatepython/data_structures/heap.py deleted file mode 100644 index b6c83259..00000000 --- a/ultimatepython/data_structures/heap.py +++ /dev/null @@ -1,62 +0,0 @@ -import heapq - - -def main() -> None: - # Define the list of numbers - nums = [3, 1, 4, 1, 5] - - # Creating a min-heap - min_heap: list[int] = [] - for num in nums: - heapq.heappush(min_heap, num) - assert min_heap[0] == 1 # The root of the heap is the smallest element - - # Pop the smallest element - smallest = heapq.heappop(min_heap) - assert smallest == 1 - - # Adding a new element - heapq.heappush(min_heap, 5) - assert min_heap[0] == 1 # The root remains the smallest element - - # Creating a max-heap - max_heap: list[int] = [] - for num in nums: - heapq.heappush(max_heap, -num) # Negate numbers for a max-heap - assert -max_heap[0] == 5 # The root of the heap is the largest element - - # Pop the largest element - largest = -heapq.heappop(max_heap) - assert largest == 5 - - # Converting a list to a heap in-place - data = [3, 1, 4, 1, 5] - heapq.heapify(data) - assert data[0] == 1 # The root is the smallest element - - # Extending a heap - more_data = [2, 6, 5] - for item in more_data: - heapq.heappush(data, item) - assert data[0] == 1 # The root is still the smallest element - - # Using heap for sorting - sorted_data = [heapq.heappop(data) for _ in range(len(data))] - assert sorted_data == [1, 1, 2, 3, 4, 5, 5, 6] - - # Getting the n smallest or largest elements from a list - n_smallest = heapq.nsmallest(3, nums) # Get the 3 smallest elements - assert n_smallest == [1, 1, 3] - - n_largest = heapq.nlargest(3, nums) # Get the 3 largest elements - assert n_largest == [5, 4, 3] - - # Merging multiple sorted lists into a single sorted list using a heap - list1 = [1, 3, 5, 7] - list2 = [2, 4, 6, 8] - merged_list = list(heapq.merge(list1, list2)) - assert merged_list == [1, 2, 3, 4, 5, 6, 7, 8] - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/data_structures/itertools.py b/ultimatepython/data_structures/itertools.py deleted file mode 100644 index 77ea8de7..00000000 --- a/ultimatepython/data_structures/itertools.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -Itertools provides a collection of tools for handling iterators. This -module demonstrates how to use itertools functions to efficiently work -with sequences, combine iterables, and create infinite iterators. -""" - -import itertools - - -def main() -> None: - # chain() combines multiple iterables into a single iterator - letters = ["a", "b", "c"] - numbers = [1, 2, 3] - combined = list(itertools.chain(letters, numbers)) - assert combined == ["a", "b", "c", 1, 2, 3] - - # cycle() creates an infinite iterator that cycles through the elements - # We'll use islice to take only the first few elements - cycled = list(itertools.islice(itertools.cycle(["A", "B"]), 6)) - assert cycled == ["A", "B", "A", "B", "A", "B"] - - # repeat() creates an iterator that repeats a value infinitely - repeated = list(itertools.islice(itertools.repeat("hello"), 4)) - assert repeated == ["hello", "hello", "hello", "hello"] - - # count() creates an infinite iterator that counts up from a start value - counted = list(itertools.islice(itertools.count(10), 5)) - assert counted == [10, 11, 12, 13, 14] - - # islice() allows slicing of iterators (similar to list slicing) - data = itertools.count() # infinite count from 0 - sliced = list(itertools.islice(data, 2, 8, 2)) # start=2, stop=8, step=2 - assert sliced == [2, 4, 6] - - # tee() creates multiple independent iterators from one - original = iter([1, 2, 3, 4, 5]) - iter1, iter2 = itertools.tee(original, 2) - list1 = list(iter1) - list2 = list(iter2) - assert list1 == [1, 2, 3, 4, 5] - assert list2 == [1, 2, 3, 4, 5] - - # groupby() groups consecutive equal elements - group_data = [1, 1, 2, 2, 2, 3, 1, 1] - groups = [(key, list(group)) for key, group in itertools.groupby(group_data)] - assert groups == [(1, [1, 1]), (2, [2, 2, 2]), (3, [3]), (1, [1, 1])] - - # product() creates cartesian product of input iterables - colors = ["red", "blue"] - sizes = ["S", "M"] - combinations = list(itertools.product(colors, sizes)) - assert combinations == [("red", "S"), ("red", "M"), ("blue", "S"), ("blue", "M")] - - # permutations() generates all possible orderings - perms = list(itertools.permutations([1, 2, 3], 2)) # length 2 permutations - assert len(perms) == 6 # 3! / (3-2)! = 6 - assert (1, 2) in perms - assert (2, 1) in perms - - # combinations() generates combinations (order doesn't matter) - combos = list(itertools.combinations([1, 2, 3, 4], 2)) - assert len(combos) == 6 # C(4,2) = 6 - assert (1, 2) in combos - assert (2, 1) not in combos # order doesn't matter - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/data_structures/list.py b/ultimatepython/data_structures/list.py index 54245da4..e847b6e3 100644 --- a/ultimatepython/data_structures/list.py +++ b/ultimatepython/data_structures/list.py @@ -1,11 +1,4 @@ -""" -Lists are a sequence of values that can be modified at runtime. This -module shows how lists are created, iterated, accessed, extended -and shortened. -""" - - -def main() -> None: +def main(): # This is a list of strings where # "a" is a string at index 0 and # "e" is a string at index 4 @@ -38,27 +31,20 @@ def main() -> None: # Note that a list is ordered and mutable. If we want to reverse the order # of the `numbers` list, we can start at index 0 and end halfway. At each - # step of the `for` loop, we swap a value from the first half of the list - # with a value from the second half of the list + # cycle, we swap values in the front with values in the back for ix_front in range(len(numbers) // 2): ix_back = len(numbers) - ix_front - 1 numbers[ix_front], numbers[ix_back] = numbers[ix_back], numbers[ix_front] - # Let's check that `numbers` is in reverse order - assert numbers == [5, 4, 3, 2, 1] - # Suppose that we want to go back to the original order, we can use the # builtin `reverse` method in lists numbers.reverse() - # Let's check that `numbers` is in the original order - assert numbers == [1, 2, 3, 4, 5] - # Print letters and numbers side-by-side using the `zip` function. Notice # that we pair the letter at index 0 with the number at index 0, and # do the same for the remaining indices. To see the indices and values # of a list at the same time, we can use `enumerate` to transform the - # list of values into an iterator of index-value pairs + # list of values into an iterator of index-number pairs for index, (letter, number) in enumerate(zip(letters, numbers)): assert letters[index] == letter assert numbers[index] == number @@ -68,12 +54,10 @@ def main() -> None: # Lists can be nested at arbitrary levels matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] - assert matrix[0][0] == 1 - assert matrix[0][1] == 2 assert matrix[1][0] == 4 - assert matrix[1][1] == 5 + assert matrix[0][1] == 2 - # This matrix just so happens to be a square so that the length of each + # This matrix just so happens to be a square so the the length of each # row is the same as the number of rows in the matrix for row in matrix: assert len(matrix) == len(row) @@ -87,18 +71,6 @@ def main() -> None: lengthy.pop() # pop out the 4 from the back assert lengthy == [0, 1, 2, 3] - # Let's sort this list in ascending order - numbers = [5, 4, 3, 2, 1] - numbers.sort() - assert numbers == [1, 2, 3, 4, 5] - - # Let's check if these lists are empty - assert len(numbers) == 5 - empty_list: list[object] = [] - assert len(empty_list) == 0 - assert not empty_list - assert len([None]) == 1 - if __name__ == "__main__": main() diff --git a/ultimatepython/data_structures/namedtuple.py b/ultimatepython/data_structures/namedtuple.py deleted file mode 100644 index dec56c8a..00000000 --- a/ultimatepython/data_structures/namedtuple.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -This module demonstrates the use of named tuples, which are a data structure -with named fields, similar to a class but lightweight and immutable. Named -tuples are created using the namedtuple function from the collections module. -""" - -from collections import namedtuple - - -def main() -> None: - # Named Tuple Attributes: - # - namedtuple: Callable from collections to define a named tuple - # - Point: A named tuple type with fields "x" and "y" - Point = namedtuple("Point", ["x", "y"]) # type: Any - - # Named Tuple Fields: - # - x and y: Fields of the named tuple Point representing coordinates - # - point1 and point2: Instances of the Point named tuple - point1 = Point(x=1, y=2) - point2 = Point(x=3, y=4) - assert isinstance(point1, Point) is True - assert isinstance(point2, Point) is True - - # Named Tuple Operations: - # - Accessing fields using dot notation - # - Named tuples are immutable - # - Named tuples support tuple operations - # - Converting named tuples to dictionaries and vice versa - # - Additional methods and attributes - assert point1.x == 1 - assert point1.y == 2 - assert point2.x == 3 - assert point2.y == 4 - - # Attempt to change the "x" field of point1 (raises an error) - access_immutable_error = False - try: - # Direct assignment to a namedtuple field is not allowed (immutable). - # Use setattr to demonstrate an attempted write at runtime while - # keeping static analyzers from treating it as a real attribute write. - setattr(point1, "x", 5) # will raise AttributeError on namedtuple - except AttributeError: - access_immutable_error = True - assert access_immutable_error is True - - # One can access Point data by indexes - assert point1[0] + point2[0] == 4 - assert point1[0] + point2[1] == 5 - assert point1[1] + point2[0] == 5 - assert point1[1] + point2[1] == 6 - - point_dict = point1._asdict() - assert point_dict == {"x": 1, "y": 2} - - # It is possible to initialize a Point without explicit parameters - point3 = Point(10, 20) - assert point3.x == 10 - assert point3.y == 20 - assert Point._fields == ("x", "y") - - # It is also possible to create a new point out of an existing one - point4 = point1._replace(x=5) - assert point4.x == 5 - assert point4.y == 2 - - # Note that point4 is not the same as point1 - assert id(point4) != id(point1) - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/data_structures/set.py b/ultimatepython/data_structures/set.py index 3b6d94ba..7df337d0 100644 --- a/ultimatepython/data_structures/set.py +++ b/ultimatepython/data_structures/set.py @@ -1,18 +1,10 @@ -""" -Sets are an unordered collection of unique values that can be modified at -runtime. This module shows how sets are created, iterated, accessed, -extended and shortened. -""" - - -def main() -> None: +def main(): # Let's define one `set` for starters simple_set = {0, 1, 2} # A set is dynamic like a `list` and `tuple` simple_set.add(3) - simple_set.remove(0) - assert simple_set == {1, 2, 3} + simple_set.add(4) # Unlike a `list and `tuple`, it is not an ordered sequence as it # does not allow duplicates to be added @@ -21,11 +13,6 @@ def main() -> None: simple_set.add(4) assert simple_set == {0, 1, 2, 3, 4} - # Use `pop` return any random element from a set - random_element = simple_set.pop() - assert random_element in {0, 1, 2, 3, 4} - assert random_element not in simple_set - # Now let's define two new `set` collections multiples_two = set() multiples_four = set() @@ -42,34 +29,24 @@ def main() -> None: # We cannot decide in which order the numbers come out - so let's # look for fundamental truths instead, such as divisibility against # 2 and 4. We do this by checking whether the modulus of 2 and 4 - # yields 0 (i.e. no remainder from performing a division). We can - # also use `&` to perform set intersection + # yields 0 (i.e. no remainder from performing a division) multiples_common = multiples_two.intersection(multiples_four) - multiples_common_shorthand = multiples_two & multiples_four - for number in multiples_common: assert number % 2 == 0 and number % 4 == 0 - for number in multiples_common_shorthand: - assert number % 2 == 0 and number % 4 == 0 - - # We can compute exclusive multiples. We can also use `-` to perform - # set difference + # We can compute exclusive multiples multiples_two_exclusive = multiples_two.difference(multiples_four) - multiples_two_exclusive_shorthand = multiples_two - multiples_four multiples_four_exclusive = multiples_four.difference(multiples_two) assert len(multiples_two_exclusive) > 0 assert len(multiples_four_exclusive) > 0 - assert len(multiples_two_exclusive_shorthand) > 0 # Numbers in this bracket are greater than 2 * 9 and less than 4 * 10 for number in multiples_four_exclusive: assert 18 < number < 40 # By computing a set union against the two sets, we have all integers - # in this program. We can also use `|` to perform set union + # in this program multiples_all = multiples_two.union(multiples_four) - multiples_all_shorthand = multiples_two | multiples_four # Check if set A is a subset of set B assert multiples_four_exclusive.issubset(multiples_four) @@ -78,7 +55,6 @@ def main() -> None: # Check if set A is a subset and superset of itself assert multiples_all.issubset(multiples_all) assert multiples_all.issuperset(multiples_all) - assert multiples_all_shorthand.issuperset(multiples_all_shorthand) # Check if set A is a superset of set B assert multiples_all.issuperset(multiples_two) diff --git a/ultimatepython/data_structures/string.py b/ultimatepython/data_structures/string.py index d2be2469..d77bd18d 100644 --- a/ultimatepython/data_structures/string.py +++ b/ultimatepython/data_structures/string.py @@ -1,21 +1,15 @@ -""" -Strings are an ordered collection of unicode characters that cannot be -modified at runtime. This module shows how strings are created, iterated, -accessed and concatenated. -""" - # Module-level constants _DELIMITER = " | " -def main() -> None: +def main(): # Strings are some of the most robust data structures around content = "Ultimate Python study guide" - # We can compute the length of a string just like all other data structures + # We can compute a string's length just like all other data structures assert len(content) > 0 - # We can use range slices to get substrings from a string + # We can use range slices to get substrings from the content assert content[:8] == "Ultimate" assert content[9:15] == "Python" assert content[::-1] == "ediug yduts nohtyP etamitlU" @@ -42,20 +36,20 @@ def main() -> None: assert lower_content in new_content assert new_content.endswith(lower_content) - # Notice that `upper_content` and `lower_content` are smaller in length - # than `new_content` and have the same length as the original `content` - # they were derived from + # Notice that `upper_content` and `lower_content` are smaller + # than `new_content` and have the same length as the original + # `content` they were derived from assert len(upper_content) < len(new_content) assert len(lower_content) < len(new_content) assert len(upper_content) == len(lower_content) == len(content) # We can also join `upper_content` and `lower_content` back into one # string with the same contents as `new_content`. The `join` method is - # useful for joining an arbitrary amount of text items together + # useful for joining an arbitrary amount of text items together. joined_content = _DELIMITER.join(split_content) assert isinstance(joined_content, str) assert new_content == joined_content -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/ultimatepython/data_structures/tuple.py b/ultimatepython/data_structures/tuple.py index 784f6ada..5d96ebd9 100644 --- a/ultimatepython/data_structures/tuple.py +++ b/ultimatepython/data_structures/tuple.py @@ -1,11 +1,4 @@ -""" -Tuples are an ordered collection of values that cannot be modified at -runtime. This module shows how tuples are created, iterated, accessed -and combined. -""" - - -def main() -> None: +def main(): # This is a tuple of integers immutable = (1, 2, 3, 4) @@ -16,8 +9,6 @@ def main() -> None: # It can be sliced like a list assert immutable[1:3] == (2, 3) assert immutable[3:4] == (4,) - assert immutable[1::2] == (2, 4) - assert immutable[::-1] == (4, 3, 2, 1) # It can be iterated over like a list for ix, number in enumerate(immutable): @@ -30,18 +21,6 @@ def main() -> None: smaller_immutable = immutable[0:2] assert smaller_immutable == (1, 2) - # We use tuples when the number of items is consistent. An example - # where this can help is a 2D game with X and Y coordinates. Using a - # tuple with two numbers can ensure that the number of coordinates - # doesn't change to one, three, four, etc. - moved_count = 0 - pos_x, pos_y = (0, 0) - for i in range(1, 5, 2): - moved_count += 1 - pos_x, pos_y = (pos_x + 10 * i, pos_y + 15 * i) - assert moved_count == 2 - assert pos_x == 40 and pos_y == 60 - if __name__ == "__main__": main() diff --git a/ultimatepython/syntax/arg_enforcement.py b/ultimatepython/syntax/arg_enforcement.py deleted file mode 100644 index 65d5ca8c..00000000 --- a/ultimatepython/syntax/arg_enforcement.py +++ /dev/null @@ -1,243 +0,0 @@ -""" -Positional-only and keyword-only parameters allow you to enforce how -arguments are passed to a function. This feature helps prevent misuse -of function APIs and makes code more maintainable. - -- Positional-only parameters (/) were introduced in Python 3.8 (PEP 570) -- Keyword-only parameters (*) were introduced in Python 3.0 (PEP 3102) - -These features give you fine-grained control over your function signatures. -""" - - -def traditional_function(a, b, c): - """A traditional function where all parameters can be passed either way. - - This function accepts arguments positionally or by keyword name. - While flexible, this can lead to API instability if parameter names change. - """ - return a + b + c - - -def positional_only(a, b, /): - """Function with positional-only parameters. - - The / symbol marks that parameters before it MUST be passed positionally. - This is useful when parameter names are not meaningful or when you want - to reserve the right to change parameter names without breaking callers. - - Parameters before / cannot be passed as keyword arguments. - """ - return a + b - - -def keyword_only(*, x, y): - """Function with keyword-only parameters. - - The * symbol marks that parameters after it MUST be passed by keyword. - This is useful for improving readability at call sites and preventing - accidental argument order mistakes. - - Parameters after * cannot be passed positionally. - """ - return x * y - - -def mixed_parameters(pos_only, /, pos_or_kw, *, kw_only): - """Function that combines all parameter types. - - - pos_only: Must be passed positionally (before /) - - pos_or_kw: Can be passed either way (between / and *) - - kw_only: Must be passed by keyword (after *) - - This gives maximum control over the function interface. - """ - return f"{pos_only}-{pos_or_kw}-{kw_only}" - - -def positional_with_defaults(a, b=10, /): - """Positional-only parameters can have default values. - - Default values work the same way as in traditional functions, - but the parameters still must be passed positionally if provided. - """ - return a + b - - -def keyword_with_defaults(*, x=5, y=3): - """Keyword-only parameters can have default values. - - When providing arguments, you must use the keyword names. - """ - return x**y - - -def complex_signature(a, b, /, c, d=10, *, e, f=20): - """A function demonstrating a complex but valid signature. - - - a, b: positional-only - - c: positional-or-keyword (no default) - - d: positional-or-keyword (with default) - - e: keyword-only (no default) - - f: keyword-only (with default) - """ - return a + b + c + d + e + f - - -def main() -> None: - # Traditional function: can be called either way - assert traditional_function(1, 2, 3) == 6 - assert traditional_function(a=1, b=2, c=3) == 6 - assert traditional_function(1, b=2, c=3) == 6 - - # Positional-only function: must use positional arguments - assert positional_only(5, 3) == 8 - - # Trying to use keyword arguments with positional-only parameters - # will raise a TypeError - positional_error = False - try: - # This will fail because 'a' and 'b' are positional-only - positional_only(a=5, b=3) # type: ignore [call-arg] - except TypeError: - positional_error = True - assert positional_error is True - - # You also can't mix positional and keyword for positional-only params - positional_error2 = False - try: - # This will fail because 'b' is positional-only - positional_only(5, b=3) # type: ignore [call-arg] - except TypeError: - positional_error2 = True - assert positional_error2 is True - - # Keyword-only function: must use keyword arguments - assert keyword_only(x=4, y=5) == 20 - - # Trying to use positional arguments with keyword-only parameters - # will raise a TypeError - keyword_error = False - try: - # This will fail because 'x' and 'y' are keyword-only - keyword_only(4, 5) # type: ignore [misc] - except TypeError: - keyword_error = True - assert keyword_error is True - - # Mixed parameters demonstrate all three types - result = mixed_parameters("first", "second", kw_only="third") - assert result == "first-second-third" - - # The middle parameter can be passed either way - result2 = mixed_parameters("first", pos_or_kw="second", kw_only="third") - assert result2 == "first-second-third" - - # But positional-only must be positional - mixed_error = False - try: - mixed_parameters(pos_only="first", pos_or_kw="second", kw_only="third") # type: ignore [call-arg] - except TypeError: - mixed_error = True - assert mixed_error is True - - # And keyword-only must be keyword - mixed_error2 = False - try: - mixed_parameters("first", "second", "third") # type: ignore [misc] - except TypeError: - mixed_error2 = True - assert mixed_error2 is True - - # Positional-only with defaults - assert positional_with_defaults(5) == 15 # Uses default b=10 - assert positional_with_defaults(5, 20) == 25 # Overrides b with 20 - - # Even with defaults, must use positional syntax - positional_default_error = False - try: - positional_with_defaults(a=5, b=20) # type: ignore [call-arg] - except TypeError: - positional_default_error = True - assert positional_default_error is True - - # Keyword-only with defaults - assert keyword_with_defaults() == 125 # Uses defaults: 5^3 - assert keyword_with_defaults(x=2) == 8 # 2^3 - assert keyword_with_defaults(y=2) == 25 # 5^2 - assert keyword_with_defaults(x=3, y=4) == 81 # 3^4 - - # Must still use keyword syntax even when providing defaults - keyword_default_error = False - try: - keyword_with_defaults(2, 3) # type: ignore [misc] - except TypeError: - keyword_default_error = True - assert keyword_default_error is True - - # Complex signature: demonstrating all parameter types - # Minimal call with required params only - result3 = complex_signature(1, 2, 3, e=4) - assert result3 == 40 # 1+2+3+10(default)+4+20(default) - - # Providing all parameters - result4 = complex_signature(1, 2, 3, 4, e=5, f=6) - assert result4 == 21 # 1+2+3+4+5+6 - - # Middle parameter 'c' can be passed by keyword - result5 = complex_signature(1, 2, c=3, e=4) - assert result5 == 40 - - # Parameter 'd' can also be passed by keyword - result6 = complex_signature(1, 2, 3, d=15, e=4) - assert result6 == 45 # 1+2+3+15+4+20 - - # But 'a' and 'b' must be positional - complex_error = False - try: - complex_signature(a=1, b=2, c=3, e=4) # type: ignore [call-arg] - except TypeError: - complex_error = True - assert complex_error is True - - # And 'e' must be keyword (even though 'f' has a default) - complex_error2 = False - try: - complex_signature(1, 2, 3, 10, 4) # type: ignore [misc] - except TypeError: - complex_error2 = True - assert complex_error2 is True - - # Practical use case: Positional-only is great for functions where - # parameter names are not meaningful or may change - def distance(x1, y1, x2, y2, /): - """Calculate distance between two points. - - The parameter names here are somewhat arbitrary (could be p1_x, etc.) - so we make them positional-only to give us flexibility to rename them - without breaking existing code. - """ - return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5 - - assert abs(distance(0, 0, 3, 4) - 5.0) < 0.01 - - # Practical use case: Keyword-only is great for boolean flags or - # optional parameters where the intent should be clear at call site - def create_user(username, *, admin=False, active=True, send_email=False): - """Create a user with clear intent for optional parameters. - - Making admin, active, and send_email keyword-only ensures that - callers must specify exactly what they're setting, improving - readability and preventing accidental mistakes. - """ - return {"username": username, "admin": admin, "active": active, "send_email": send_email} - - # Clear intent at call site - user = create_user("john_doe", admin=True, send_email=True) - assert user["admin"] is True - assert user["active"] is True # Used default - assert user["send_email"] is True - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/syntax/bitwise.py b/ultimatepython/syntax/bitwise.py deleted file mode 100644 index b26f25b8..00000000 --- a/ultimatepython/syntax/bitwise.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Bitwise operators in Python allow you to manipulate individual bits of integers. -This module demonstrates the use of bitwise operators and their behavior. -""" - - -def main() -> None: - # Define some integer values for demonstration - a = 5 # Binary: 0101 - b = 3 # Binary: 0011 - - # Bitwise AND (&) operator compares each bit of two integers and returns 1 - # if both bits are 1, otherwise returns 0 - result_and = a & b # Binary: 0001 (Decimal: 1) - assert result_and == 1 - - # Bitwise OR (|) operator compares each bit of two integers and returns 1 - # if at least one bit is 1, otherwise returns 0 - result_or = a | b # Binary: 0111 (Decimal: 7) - assert result_or == 7 - - # Bitwise XOR (^) operator compares each bit of two integers and returns 1 - # if the bits are different (one is 1 and the other is 0), otherwise returns 0 - result_xor = a ^ b # Binary: 0110 (Decimal: 6) - assert result_xor == 6 - - # Bitwise NOT (~) operator inverts all bits of an integer - # It returns the one's complement of the integer - result_not_a = ~a # Binary: 11111010 (Decimal: -6) - assert result_not_a == -6 - - # Bitwise left shift (<<) operator shifts the bits of an integer to the left by - # a specified number of positions, filling with zeros - result_left_shift = a << 2 # Binary: 010100 (Decimal: 20) - assert result_left_shift == 20 - - # Bitwise right shift (>>) operator shifts the bits of an integer to the right - # by a specified number of positions, filling with zeros for positive numbers - # and with ones for negative numbers - result_right_shift = a >> 1 # Binary: 0010 (Decimal: 2) - assert result_right_shift == 2 - - # Note that bitwise shifts have lower precedence than arithmetic operations - # https://docs.python.org/3/reference/expressions.html - result_right_shift_with_addition = a >> 1 + 1 # Equivalent to a >> (1 + 1) - assert result_right_shift_with_addition == 1 # Binary: 0001 (Decimal: 1) - - -if __name__ == "__main__": - main() diff --git a/ultimatepython/syntax/conditional.py b/ultimatepython/syntax/conditional.py index 197c5ec5..7c0dc031 100644 --- a/ultimatepython/syntax/conditional.py +++ b/ultimatepython/syntax/conditional.py @@ -1,10 +1,4 @@ -""" -This module shows how to use if blocks, if-else blocks and if-elif-else -blocks to decide which lines of code to run (and skip). -""" - - -def main() -> None: +def main(): x = 1 x_add_two = x + 2 @@ -21,16 +15,16 @@ def main() -> None: assert ran_2 is True # There are `else` statements as well, which run if the initial condition - # fails. Notice that one line gets skipped and this conditional does not - # help us make a conclusion on the variable's true value + # fails. Notice that one line gets skipped, and that this conditional + # does not help one make a conclusion on the variable's true value if x_add_two == 1: ran_3 = False # skip: if else: ran_3 = True # run assert ran_3 is True - # The `else` statement also runs once all other `if` and `elif` conditions - # fail. Notice that multiple lines get skipped, and that all the + # The `else` statement also run once all other `if` and `elif` conditions + # fail. Notice that multiple lines get skipped, and that all of the # conditions could have been compressed to `x_add_two != 3` for # simplicity. In this case, less logic results in more clarity if x_add_two == 1: @@ -43,24 +37,6 @@ def main() -> None: ran_4 = True # run assert ran_4 is True - # Conditionals can also be written in one line using `if` and `else` - # with the following form: A if condition else B. This can be used - # for assignments as shown below - ran_5 = False - ran_5 = True if x_add_two == 3 else False - assert ran_5 is True - - # Python is one of the few programming languages that allows chained - # comparisons. This is useful for checking if a variable is within - # a range of values. You can see that in this example, the expression - # `0 < x_add_two < 2` is equivalent to `x_add_two > 0 and x_add_two < 2` - ran_6 = False - if 0 < x_add_two < 2: - ran_6 = False # skip: if - else: - ran_6 = True # run - assert ran_6 is True - if __name__ == "__main__": main() diff --git a/ultimatepython/syntax/expression.py b/ultimatepython/syntax/expression.py index 9822af09..4132fae8 100644 --- a/ultimatepython/syntax/expression.py +++ b/ultimatepython/syntax/expression.py @@ -1,16 +1,8 @@ -""" -This module shows how to create new integers by applying math expressions -on existing integers. -""" - -import math - - -def main() -> None: +def main(): # This is a simple integer x = 1 - # Its value can be used as part of expressions + # Its value can used as part of expressions assert x + 1 == 2 # An expression can be chained indefinitely. This concept of chaining @@ -18,20 +10,18 @@ def main() -> None: # of code into larger pieces of code over time assert x * 2 * 2 * 2 == 8 - # Division is tricky because Python 3.x returns 0.5 of type `float` - # whereas Python 2.x returns 0 of type `int`. If this line fails, it - # is a sign that the wrong version of Python was used - assert math.isclose(x / 2, 0.5) + # Division is a bit tricky in Python because it returns a result + # of type 'float' by default + assert x / 2 == 0.5 # If an integer division is desired, then an extra slash must be - # added to the expression. In Python 2.x and Python 3.x, the behavior - # is exactly the same + # added to the expression assert x // 2 == 0 # Powers of an integer can be leveraged too. If more features are # needed, then leverage the builtin `math` library or a third-party # library. Otherwise, we have to build our own math library - assert x * 2**3 == 8 + assert x * 2 ** 3 == 8 if __name__ == "__main__": diff --git a/ultimatepython/syntax/function.py b/ultimatepython/syntax/function.py index 0ab84c9d..bec654e7 100644 --- a/ultimatepython/syntax/function.py +++ b/ultimatepython/syntax/function.py @@ -1,31 +1,21 @@ -""" -Functions allow us to consolidate simple / complex code into a single -block that can be invoked with specific parameters. This module defines -a simple function and a composite function that uses the simple function -in an interesting way. -""" - -from typing import Any, Callable - - -def add(x: Any, y: Any) -> Any: +def add(x, y): """Add two objects together to produce a new object. Two differences between `add` and `main` are that: - - It accepts input parameters - - It returns a value + A) It accepts input parameters + B) It returns a value """ return x + y -def sum_until(fn: Callable[[int], int], n: int) -> int: - """Sum function results from 0 until n - 1. +def sum_until(fn, n): + """Sum a function output from 0 until n - 1. This expects a function to be provided as its first input and an integer - as its second input. Like `add`, `sum_until` returns a value. + as its second input. Like `add`, `run_until` returns a value. - The fact that a function can be passed into `sum_until` highlights a core + The fact that a function can be passed into `run_until` highlights a core concept that was mentioned before: everything in Python is an object, and that includes this docstring! """ @@ -35,18 +25,7 @@ def sum_until(fn: Callable[[int], int], n: int) -> int: return total -def without_parameters() -> object: - """A function that does not accept parameters and does not return a value. - - The return type is annotated as `object` to allow callers that assert - on the returned value (e.g. `assert without_parameters() is None`) without - triggering static checker complaints about a function annotated as - returning None being used as a value. - """ - return None - - -def main() -> None: +def main(): # The `add` function can be used for numbers as expected add_result_int = add(1, 2) assert add_result_int == 3 @@ -58,18 +37,14 @@ def main() -> None: # Run the input function multiple times. Notice that we make use of # `lambda` to create an anonymous function (i.e. a function without # a name) that accepts one input and does something with it. Anonymous - # functions are powerful because they allow us to write functions - # inline, unlike `add` and `sum_until` + # functions are powerful because they allow one to write functions + # inline, unlike `add` and `run_until` run_results = sum_until(lambda i: i * 100, 5) assert run_results == 1000, run_results - # We can see the `sum_until` docstring by accessing the `__doc__` magic + # We can see the `run_until` docstring by accessing the `__doc__` magic # attribute! Remember this - everything in Python is an object - # `__doc__` may be None in some environments, coalesce to an empty string - assert "includes this docstring!" in (sum_until.__doc__ or "") - - # Call a function without parameters - assert without_parameters() is None + assert "includes this docstring!" in sum_until.__doc__ if __name__ == "__main__": diff --git a/ultimatepython/syntax/loop.py b/ultimatepython/syntax/loop.py index c7747695..0dc6b9a7 100644 --- a/ultimatepython/syntax/loop.py +++ b/ultimatepython/syntax/loop.py @@ -1,17 +1,4 @@ -""" -Loops are to expressions as multiplication is to addition. They help us -run the same code many times until a certain condition is not met. This -module shows how to use the for-loop and while-loop, and also shows how -`continue` and `break` give us precise control over a loop's lifecycle. - -Note that for-else and while-else loops exist in Python, but they are -not commonly used. Please visit this link for some examples: - -https://stackoverflow.com/a/59491247/9921431 -""" - - -def main() -> None: +def main(): # This is a `for` loop that iterates on values 0..4 and adds each # value to `total`. It leverages the `range` iterator. Providing # a single integer implies that the start point is 0, the end point @@ -24,19 +11,19 @@ def main() -> None: assert total == 10 # This is a `for` loop that iterates on values 5..1 and multiplies each - # value to `fact`. The `range` iterator is used here more precisely by + # value to `fib`. The `range` iterator is used here more explicitly by # setting the start point at 5, the end point at 0 and the increment # step at -1 (going backward one step) - fact = 1 + fib = 1 for i in range(5, 0, -1): - fact *= i + fib *= i # The answer is...120! - assert fact == 120 + assert fib == 120 # This is a simple `while` loop, similar to a `for` loop except that the - # counter is declared outside the loop and its state is explicitly - # managed inside the loop. The loop will continue until the counter + # counter is declared outside of the loop and its state is explicitly + # managed inside of the loop. The loop will continue until the counter # exceeds 8 i = 0 while i < 8: @@ -45,14 +32,11 @@ def main() -> None: # The `while` loop terminated at this value assert i == 8 - # This is a `while` loop that stops with `break` and its counter is + # This is a `while` loop that is stopped with `break` and its counter is # multiplied in the loop, showing that we can do anything to the # counter. Like the previous `while` loop, this one continues until # the counter exceeds 8 i = 1 - break_hit = False - continue_hit = False - other_hit = False while True: i *= 2 @@ -60,26 +44,16 @@ def main() -> None: # The `break` statement stops the current `while` loop. # If this `while` loop was nested in another loop, # this statement would not stop the parent loop - break_hit = True break if i == 2: # The `continue` statement returns to the start of the # current `while` loop - continue_hit = True continue - # This statement runs when the counter equals 4 - other_hit = True - # The `while` loop terminated at this value assert i == 8 - # The `while` loop hit the `break` and `continue` blocks - assert break_hit is True - assert continue_hit is True - assert other_hit is True - if __name__ == "__main__": main() diff --git a/ultimatepython/syntax/variable.py b/ultimatepython/syntax/variable.py index 36cb3df7..1d95fe81 100644 --- a/ultimatepython/syntax/variable.py +++ b/ultimatepython/syntax/variable.py @@ -1,13 +1,4 @@ -""" -Variables allow us to store values in named records that can be used in -a program. This module shows how to define variables and make assertions -about the state of each defined variable. -""" - -import math - - -def main() -> None: +def main(): # Here are the main literal types to be aware of a = 1 b = 2.0 @@ -37,27 +28,6 @@ def main() -> None: assert isinstance(c, object) and isinstance(c_type, object) assert isinstance(d, object) and isinstance(d_type, object) - # We can represent integer literals in Python using 4 bases: decimal, - # hexadecimal, octal, and binary. Decimal literals do not require any - # prefix while other bases require prefixes: - # - `0x` for hexadecimal - # - `0o` for octal - # - `0b` for binary - assert 100 == 0x64 == 0o144 == 0b1100100 - - # We can use underscores (literal `_`) to separate digit groups in - # integer literals - assert 10_000 == 10000 - assert 0x01_0F_2C == 69_420 - assert math.isclose(3.456_290e-1, 0.3_456_290) - - # There is also a special literal called None. This literal is used to - # point that a particular variable or object is not created - e = None - e_type = type(e) - assert e_type is type(None) - assert isinstance(e, object) and isinstance(e_type, object) - if __name__ == "__main__": main() diff --git a/ultimatepython/syntax/walrus_operator.py b/ultimatepython/syntax/walrus_operator.py deleted file mode 100644 index 733e3c01..00000000 --- a/ultimatepython/syntax/walrus_operator.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -The walrus operator, also known as the assignment expression operator, -allows you to assign values to variables as part of an expression. This -feature was introduced in Python 3.8 through PEP 572. - -The walrus operator uses the := syntax and is particularly useful in -reducing redundancy when you need to compute a value and then use it -in a condition or comprehension. -""" - - -def main() -> None: - # Traditional approach: compute a value and check it separately - # Let's say we want to check if a string has more than 5 characters - text = "Hello, Python!" - length = len(text) - if length > 5: - assert length == 14 - - # With the walrus operator, we can assign and check in one expression. - # This is cleaner and avoids repeating the computation or storing - # intermediate variables unnecessarily - text2 = "Ultimate" - if (length2 := len(text2)) > 5: - # The walrus operator assigned len(text2) to length2 AND returned it - # for the comparison, all in the same line - assert length2 == 8 - - # The walrus operator is especially powerful in while loops. Here's a - # traditional approach that requires reading input twice - numbers_old = [] - n = int("5") # Simulating user input - while n != 0: - numbers_old.append(n) - n = int("0") # Simulating next input - assert numbers_old == [5] - - # With the walrus operator, we can assign and check in the loop condition. - # This is more concise and avoids the duplication of the input reading logic - numbers_new = [] - inputs = ["3", "7", "0"] # Simulating a sequence of inputs - index = 0 - - # Note: In a real scenario, you'd read from input() instead of a list - def get_next_input(): - nonlocal index - if index < len(inputs): - result = int(inputs[index]) - index += 1 - return result - return 0 - - while (num := get_next_input()) != 0: - # The walrus operator assigns get_next_input() to num and checks if it's not 0 - numbers_new.append(num) - assert numbers_new == [3, 7] - - # Ensure the function returns 0 when no more inputs - assert get_next_input() == 0 - - # The walrus operator shines in list comprehensions when you need to - # compute a value once and reuse it. Without walrus, you'd either: - # 1. Compute the value multiple times (inefficient) - # 2. Use a for loop instead of comprehension (less elegant) - data = ["apple", "banana", "cherry", "date"] - - # Traditional approach: computing len() twice per item is wasteful - long_words_old = [word for word in data if len(word) > 5 and len(word) < 7] - assert long_words_old == ["banana", "cherry"] - - # With walrus operator: compute len() once and reuse the result - # The walrus operator assigns len(word) to word_len, which we can - # then use multiple times in the same comprehension - long_words_new = [word for word in data if 5 < (word_len := len(word)) < 7] - assert long_words_new == ["banana", "cherry"] - - # The walrus operator can be used in comprehensions to filter and transform - # data simultaneously. Here we square numbers but only keep those where - # the square is less than 50 - numbers = [3, 5, 7, 9, 11] - - # Without walrus: we'd need to compute the square twice or use a for loop - squares_old = [n * n for n in numbers if n * n < 50] - assert squares_old == [9, 25, 49] - - # With walrus: compute the square once, store it, and use it - # This is both more efficient and clearer about the intent - squares_new = [square for n in numbers if (square := n * n) < 50] - assert squares_new == [9, 25, 49] - - # The walrus operator works in set comprehensions too - # Let's find unique word lengths greater than 4 - words = ["hi", "hello", "world", "python", "code"] - - # With walrus operator in a set comprehension - long_lengths = {word_len for word in words if (word_len := len(word)) > 4} - assert long_lengths == {5, 6} - - # And in dictionary comprehensions as well - # Create a dict of words to their lengths, but only for words > 4 chars - word_length_map = {word: word_len for word in words if (word_len := len(word)) > 4} - assert word_length_map == {"hello": 5, "world": 5, "python": 6} - - # Important note: The walrus operator creates variables in the enclosing scope. - # This means variables assigned with := inside a comprehension are accessible - # outside of it (unlike traditional loop variables in comprehensions) - [result for x in [1, 2, 3] if (result := x * 2) > 2] - # The variable 'result' is now accessible here, with its last assigned value - assert result == 6 - - # The walrus operator can be nested, though this can reduce readability - # Use nesting sparingly and only when it genuinely improves the code - values = [1, 2, 3, 4, 5] - if (total := sum(doubled := [x * 2 for x in values])) > 15: - # Here 'doubled' is assigned inside the expression for 'total' - assert doubled == [2, 4, 6, 8, 10] - assert total == 30 - - -if __name__ == "__main__": - main()