diff --git a/basic-input-output-in-python/adventure_game.py b/basic-input-output-in-python/adventure_game.py
index e634754a35..1d3e363d81 100644
--- a/basic-input-output-in-python/adventure_game.py
+++ b/basic-input-output-in-python/adventure_game.py
@@ -4,7 +4,13 @@
enemy_health = 3
while health > 0 and enemy_health > 0:
- if input("Attack or Run? ").lower() == "attack":
+ # Normalize input to handle extra spaces and case variations.
+ action = input("Attack or Run? ").strip().lower()
+ if action not in {"attack", "run"}:
+ print("Invalid choice. Please type 'Attack' or 'Run'.")
+ continue
+
+ if action == "attack":
enemy_health -= 1
print("You hit the enemy!")
# Implement a 50% chance that the enemy strikes back.
diff --git a/basic-input-output-in-python/guess_the_number.py b/basic-input-output-in-python/guess_the_number.py
index 3d485326ef..437b5d7af3 100644
--- a/basic-input-output-in-python/guess_the_number.py
+++ b/basic-input-output-in-python/guess_the_number.py
@@ -6,4 +6,4 @@
if guess == number:
print("You got it!")
else:
- print(f"Sorry, the number was {number}.")
+ print("Sorry, the number was", number)
diff --git a/celery-async-tasks/source_code_final/requirements.txt b/celery-async-tasks/source_code_final/requirements.txt
index bb1f70b615..55274c7b99 100644
--- a/celery-async-tasks/source_code_final/requirements.txt
+++ b/celery-async-tasks/source_code_final/requirements.txt
@@ -1,22 +1,18 @@
-amqp==5.1.1
-asgiref==3.5.2
-async-timeout==4.0.2
-billiard==3.6.4.0
-celery==5.2.7
-click==8.1.3
-click-didyoumean==0.3.0
+amqp==5.3.1
+asgiref==3.8.1
+billiard==4.2.1
+celery==5.4.0
+click==8.1.7
+click-didyoumean==0.3.1
click-plugins==1.1.1
-click-repl==0.2.0
-Deprecated==1.2.13
-Django==4.0.6
-kombu==5.2.4
-packaging==21.3
-prompt-toolkit==3.0.30
-pyparsing==3.0.9
-pytz==2022.1
-redis==4.3.4
+click-repl==0.3.0
+Django==5.1.3
+kombu==5.4.2
+prompt_toolkit==3.0.48
+python-dateutil==2.9.0.post0
+redis==5.2.0
six==1.16.0
-sqlparse==0.4.2
-vine==5.0.0
-wcwidth==0.2.5
-wrapt==1.14.1
+sqlparse==0.5.2
+tzdata==2024.2
+vine==5.1.0
+wcwidth==0.2.13
diff --git a/celery-async-tasks/source_code_initial/requirements.txt b/celery-async-tasks/source_code_initial/requirements.txt
index bb1f70b615..55274c7b99 100644
--- a/celery-async-tasks/source_code_initial/requirements.txt
+++ b/celery-async-tasks/source_code_initial/requirements.txt
@@ -1,22 +1,18 @@
-amqp==5.1.1
-asgiref==3.5.2
-async-timeout==4.0.2
-billiard==3.6.4.0
-celery==5.2.7
-click==8.1.3
-click-didyoumean==0.3.0
+amqp==5.3.1
+asgiref==3.8.1
+billiard==4.2.1
+celery==5.4.0
+click==8.1.7
+click-didyoumean==0.3.1
click-plugins==1.1.1
-click-repl==0.2.0
-Deprecated==1.2.13
-Django==4.0.6
-kombu==5.2.4
-packaging==21.3
-prompt-toolkit==3.0.30
-pyparsing==3.0.9
-pytz==2022.1
-redis==4.3.4
+click-repl==0.3.0
+Django==5.1.3
+kombu==5.4.2
+prompt_toolkit==3.0.48
+python-dateutil==2.9.0.post0
+redis==5.2.0
six==1.16.0
-sqlparse==0.4.2
-vine==5.0.0
-wcwidth==0.2.5
-wrapt==1.14.1
+sqlparse==0.5.2
+tzdata==2024.2
+vine==5.1.0
+wcwidth==0.2.13
diff --git a/django-user-management/README.md b/django-user-management/README.md
new file mode 100644
index 0000000000..d70eeeb218
--- /dev/null
+++ b/django-user-management/README.md
@@ -0,0 +1,46 @@
+# Get Started With Django User Management
+
+Follow the [step-by-step instructions](https://realpython.com/django-user-management/) on Real Python.
+
+## Setup
+
+You can run the provided example project on your local machine by following the steps outlined below.
+
+Create a new virtual environment:
+
+```bash
+$ python3 -m venv venv/
+```
+
+Activate the virtual environment:
+
+```bash
+$ source venv/bin/activate
+```
+
+Install the dependencies for this project if you haven't installed them yet:
+
+```bash
+(venv) $ python -m pip install -r requirements.txt
+```
+
+Navigate into the project's directory:
+
+```bash
+(venv) $ cd user_auth_intro/
+```
+
+Make and apply the migrations for the project to build your local database:
+
+```bash
+(venv) $ python manage.py makemigrations
+(venv) $ python manage.py migrate
+```
+
+Run the Django development server:
+
+```bash
+(venv) $ python manage.py runserver
+```
+
+Navigate to `http://localhost:8000/dashboard` to see the project in action.
diff --git a/django-user-management/requirements.txt b/django-user-management/requirements.txt
new file mode 100644
index 0000000000..e2ae4cc169
--- /dev/null
+++ b/django-user-management/requirements.txt
@@ -0,0 +1,3 @@
+asgiref==3.8.1
+Django==5.1.3
+sqlparse==0.5.2
diff --git a/django-user-management/user_auth_intro/manage.py b/django-user-management/user_auth_intro/manage.py
new file mode 100755
index 0000000000..c67a51c556
--- /dev/null
+++ b/django-user-management/user_auth_intro/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ """Run administrative tasks."""
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "user_auth_intro.settings")
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/django-user-management/user_auth_intro/user_auth_intro/__init__.py b/django-user-management/user_auth_intro/user_auth_intro/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/django-user-management/user_auth_intro/user_auth_intro/asgi.py b/django-user-management/user_auth_intro/user_auth_intro/asgi.py
new file mode 100644
index 0000000000..a86a136712
--- /dev/null
+++ b/django-user-management/user_auth_intro/user_auth_intro/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for user_auth_intro project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "user_auth_intro.settings")
+
+application = get_asgi_application()
diff --git a/django-user-management/user_auth_intro/user_auth_intro/settings.py b/django-user-management/user_auth_intro/user_auth_intro/settings.py
new file mode 100644
index 0000000000..41db9704f8
--- /dev/null
+++ b/django-user-management/user_auth_intro/user_auth_intro/settings.py
@@ -0,0 +1,128 @@
+"""
+Django settings for user_auth_intro project.
+
+Generated by 'django-admin startproject' using Django 5.1.3.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/5.1/ref/settings/
+"""
+
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = (
+ "django-insecure-%&$tji0geb7vpx8@9-&qbf3_%3$s=5*5amo4tr)yg!6&6@bbhl"
+)
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ "users.apps.UsersConfig",
+ "django.contrib.admin",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
+]
+
+MIDDLEWARE = [
+ "django.middleware.security.SecurityMiddleware",
+ "django.contrib.sessions.middleware.SessionMiddleware",
+ "django.middleware.common.CommonMiddleware",
+ "django.middleware.csrf.CsrfViewMiddleware",
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
+ "django.contrib.messages.middleware.MessageMiddleware",
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
+]
+
+ROOT_URLCONF = "user_auth_intro.urls"
+
+TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [],
+ "APP_DIRS": True,
+ "OPTIONS": {
+ "context_processors": [
+ "django.template.context_processors.debug",
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = "user_auth_intro.wsgi.application"
+
+
+# Database
+# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
+
+DATABASES = {
+ "default": {
+ "ENGINE": "django.db.backends.sqlite3",
+ "NAME": BASE_DIR / "db.sqlite3",
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
+ },
+ {
+ "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/5.1/topics/i18n/
+
+LANGUAGE_CODE = "en-us"
+
+TIME_ZONE = "UTC"
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/5.1/howto/static-files/
+
+STATIC_URL = "static/"
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
diff --git a/django-user-management/user_auth_intro/user_auth_intro/urls.py b/django-user-management/user_auth_intro/user_auth_intro/urls.py
new file mode 100644
index 0000000000..b9a774f5ea
--- /dev/null
+++ b/django-user-management/user_auth_intro/user_auth_intro/urls.py
@@ -0,0 +1,7 @@
+from django.contrib import admin
+from django.urls import include, path
+
+urlpatterns = [
+ path("", include("users.urls")),
+ path("admin/", admin.site.urls),
+]
diff --git a/django-user-management/user_auth_intro/user_auth_intro/wsgi.py b/django-user-management/user_auth_intro/user_auth_intro/wsgi.py
new file mode 100644
index 0000000000..8413683629
--- /dev/null
+++ b/django-user-management/user_auth_intro/user_auth_intro/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for user_auth_intro project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "user_auth_intro.settings")
+
+application = get_wsgi_application()
diff --git a/django-user-management/user_auth_intro/users/__init__.py b/django-user-management/user_auth_intro/users/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/django-user-management/user_auth_intro/users/admin.py b/django-user-management/user_auth_intro/users/admin.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/django-user-management/user_auth_intro/users/apps.py b/django-user-management/user_auth_intro/users/apps.py
new file mode 100644
index 0000000000..88f7b1798e
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class UsersConfig(AppConfig):
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "users"
diff --git a/django-user-management/user_auth_intro/users/forms.py b/django-user-management/user_auth_intro/users/forms.py
new file mode 100644
index 0000000000..37ef39ddbd
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/forms.py
@@ -0,0 +1,6 @@
+from django.contrib.auth.forms import UserCreationForm
+
+
+class CustomUserCreationForm(UserCreationForm):
+ class Meta(UserCreationForm.Meta):
+ fields = UserCreationForm.Meta.fields + ("email",)
diff --git a/django-user-management/user_auth_intro/users/migrations/__init__.py b/django-user-management/user_auth_intro/users/migrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/django-user-management/user_auth_intro/users/models.py b/django-user-management/user_auth_intro/users/models.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/django-user-management/user_auth_intro/users/templates/base.html b/django-user-management/user_auth_intro/users/templates/base.html
new file mode 100644
index 0000000000..3b233d2011
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/base.html
@@ -0,0 +1,12 @@
+
+
+
+
+ User Management Intro
+
+
+ Welcome!
+ {% block content %}
+ {% endblock content %}
+
+
diff --git a/django-user-management/user_auth_intro/users/templates/registration/_logout.html b/django-user-management/user_auth_intro/users/templates/registration/_logout.html
new file mode 100644
index 0000000000..938250f08d
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/registration/_logout.html
@@ -0,0 +1,6 @@
+
diff --git a/django-user-management/user_auth_intro/users/templates/registration/login.html b/django-user-management/user_auth_intro/users/templates/registration/login.html
new file mode 100644
index 0000000000..031a80676d
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/registration/login.html
@@ -0,0 +1,14 @@
+{% extends "base.html" %}
+{% block content %}
+ Login
+
+
+ Forgot your password?
+ Back to dashboard
+
+{% endblock content %}
diff --git a/django-user-management/user_auth_intro/users/templates/registration/password_change_done.html b/django-user-management/user_auth_intro/users/templates/registration/password_change_done.html
new file mode 100644
index 0000000000..fe4de16bff
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/registration/password_change_done.html
@@ -0,0 +1,5 @@
+{% extends "base.html" %}
+{% block content %}
+ Password changed
+ Back to dashboard
+{% endblock content %}
diff --git a/django-user-management/user_auth_intro/users/templates/registration/password_change_form.html b/django-user-management/user_auth_intro/users/templates/registration/password_change_form.html
new file mode 100644
index 0000000000..cb7bfa1701
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/registration/password_change_form.html
@@ -0,0 +1,10 @@
+{% extends "base.html" %}
+{% block content %}
+ Change password
+
+ Back to dashboard
+{% endblock content %}
diff --git a/django-user-management/user_auth_intro/users/templates/registration/password_reset_complete.html b/django-user-management/user_auth_intro/users/templates/registration/password_reset_complete.html
new file mode 100644
index 0000000000..85c89b5f22
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/registration/password_reset_complete.html
@@ -0,0 +1,5 @@
+{% extends "base.html" %}
+{% block content %}
+ Password reset completed
+ Login
+{% endblock content %}
diff --git a/django-user-management/user_auth_intro/users/templates/registration/password_reset_confirm.html b/django-user-management/user_auth_intro/users/templates/registration/password_reset_confirm.html
new file mode 100644
index 0000000000..1f98383069
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/registration/password_reset_confirm.html
@@ -0,0 +1,10 @@
+{% extends "base.html" %}
+{% block content %}
+ Confirm password reset
+
+ Back to dashboard
+{% endblock content %}
diff --git a/django-user-management/user_auth_intro/users/templates/registration/password_reset_done.html b/django-user-management/user_auth_intro/users/templates/registration/password_reset_done.html
new file mode 100644
index 0000000000..d6aa80f9db
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/registration/password_reset_done.html
@@ -0,0 +1,5 @@
+{% extends "base.html" %}
+{% block content %}
+ Password reset link sent
+ Back to dashboard
+{% endblock content %}
diff --git a/django-user-management/user_auth_intro/users/templates/registration/password_reset_form.html b/django-user-management/user_auth_intro/users/templates/registration/password_reset_form.html
new file mode 100644
index 0000000000..fb3ce5c3e4
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/registration/password_reset_form.html
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+{% block content %}
+ Send password reset link
+
+
+ Back to dashboard
+
+{% endblock content %}
diff --git a/django-user-management/user_auth_intro/users/templates/registration/sign_up.html b/django-user-management/user_auth_intro/users/templates/registration/sign_up.html
new file mode 100644
index 0000000000..66894c1493
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/registration/sign_up.html
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+{% block content %}
+ Sign Up
+
+
+ Back to dashboard
+
+{% endblock content %}
diff --git a/django-user-management/user_auth_intro/users/templates/users/dashboard.html b/django-user-management/user_auth_intro/users/templates/users/dashboard.html
new file mode 100644
index 0000000000..c54024366b
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/templates/users/dashboard.html
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+{% block content %}
+ Hello, {{ user.username|default:"Guest" }}!
+
+ {% if user.is_authenticated %}
+ {% include "registration/_logout.html" %}
+ Change password
+ {% else %}
+ Login
+ Sign up
+ {% endif %}
+{% endblock content %}
diff --git a/django-user-management/user_auth_intro/users/tests.py b/django-user-management/user_auth_intro/users/tests.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/django-user-management/user_auth_intro/users/urls.py b/django-user-management/user_auth_intro/users/urls.py
new file mode 100644
index 0000000000..242774ac89
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/urls.py
@@ -0,0 +1,9 @@
+from django.urls import include, path
+
+from . import views
+
+urlpatterns = [
+ path("accounts/", include("django.contrib.auth.urls")),
+ path("dashboard/", views.dashboard, name="dashboard"),
+ path("sign_up/", views.sign_up, name="sign_up"),
+]
diff --git a/django-user-management/user_auth_intro/users/views.py b/django-user-management/user_auth_intro/users/views.py
new file mode 100644
index 0000000000..fb0c0069c8
--- /dev/null
+++ b/django-user-management/user_auth_intro/users/views.py
@@ -0,0 +1,23 @@
+from django.contrib.auth import login
+
+# Remove: from django.contrib.auth.forms import UserCreationForm
+from django.shortcuts import redirect, render
+from django.urls import reverse
+
+from .forms import CustomUserCreationForm
+
+
+def dashboard(request):
+ return render(request, "users/dashboard.html")
+
+
+def sign_up(request):
+ if request.method == "POST":
+ form = CustomUserCreationForm(request.POST)
+ if form.is_valid():
+ user = form.save()
+ login(request, user)
+ return redirect(reverse("dashboard"))
+ else:
+ form = CustomUserCreationForm()
+ return render(request, "registration/sign_up.html", {"form": form})
diff --git a/expressions-vs-statements/README.md b/expressions-vs-statements/README.md
new file mode 100644
index 0000000000..ace4085f6e
--- /dev/null
+++ b/expressions-vs-statements/README.md
@@ -0,0 +1,66 @@
+# Expression vs Statement in Python: What's the Difference?
+
+This folder contains sample code from the Real Python tutorial [Expression vs Statement in Python: What's the Difference?](https://realpython.com/python-expression-vs-statement/)
+
+## Code Inspector
+
+Identify whether a piece of Python code is an expression or a statement:
+
+```shell
+$ python code_inspector.py
+Type a Python code snippet or leave empty to exit.
+>>> yield
+statement
+>>> (yield)
+expression
+>>> 2 +
+invalid
+```
+
+## GUI App
+
+Register a lambda expression as a callback, which delegates to a function with statements:
+
+```shell
+$ python gui_app.py
+```
+
+## Echo Program
+
+Compile with a C compiler and pipe stdin to the echo program:
+
+```shell
+$ gcc echo.c -o echo.x
+$ echo "Hello, World!" | ./echo.x
+Hello, World!
+```
+
+## HEX Reader
+
+Read a binary file and display its bytes in hexadecimal format:
+
+```shell
+$ python hex_reader.py /path/to/HelloJava.class --columns 8
+ca fe ba be 00 00 00 41
+00 0f 0a 00 02 00 03 07
+00 04 0c 00 05 00 06 01
+(...)
+```
+
+## Generators
+
+Generate a random signal and use a low-pass filter to make it smooth:
+
+```shell
+$ python generators.py
+-0.96: -0.96
+-0.81: -0.89
+-0.52: -0.67
+ 0.22: -0.15
+ 0.51: 0.37
+ 0.40: 0.46
+-0.08: 0.16
+-0.24: -0.16
+ 0.80: 0.28
+ 0.47: 0.64
+```
diff --git a/expressions-vs-statements/code_inspector.py b/expressions-vs-statements/code_inspector.py
new file mode 100644
index 0000000000..b91a1eff77
--- /dev/null
+++ b/expressions-vs-statements/code_inspector.py
@@ -0,0 +1,31 @@
+import ast
+
+
+def main():
+ print("Type a Python code snippet or leave empty to exit.")
+ while code := input(">>> "):
+ print(describe(code))
+
+
+def describe(code):
+ if valid(code, mode="eval"):
+ return "expression"
+ elif valid(code, mode="exec"):
+ return "statement"
+ else:
+ return "invalid"
+
+
+def valid(code, mode):
+ try:
+ ast.parse(code, mode=mode)
+ return True
+ except SyntaxError:
+ return False
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except EOFError:
+ pass
diff --git a/expressions-vs-statements/echo.c b/expressions-vs-statements/echo.c
new file mode 100644
index 0000000000..99c9b342d7
--- /dev/null
+++ b/expressions-vs-statements/echo.c
@@ -0,0 +1,11 @@
+#include
+
+int main() {
+ int x;
+ while (x = fgetc(stdin)) {
+ if (x == EOF)
+ break;
+ putchar(x);
+ }
+ return 0;
+}
diff --git a/expressions-vs-statements/generators.py b/expressions-vs-statements/generators.py
new file mode 100644
index 0000000000..a324e00bd2
--- /dev/null
+++ b/expressions-vs-statements/generators.py
@@ -0,0 +1,24 @@
+import random
+
+
+def main():
+ lf = lowpass_filter()
+ lf.send(None)
+ for value in generate_noise(10):
+ print(f"{value:>5.2f}: {lf.send(value):>5.2f}")
+
+
+def generate_noise(size):
+ for _ in range(size):
+ yield 2 * random.random() - 1
+
+
+def lowpass_filter():
+ a = yield
+ b = yield a
+ while True:
+ a, b = b, (yield (a + b) / 2)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/expressions-vs-statements/gui_app.py b/expressions-vs-statements/gui_app.py
new file mode 100644
index 0000000000..0a995bb6b7
--- /dev/null
+++ b/expressions-vs-statements/gui_app.py
@@ -0,0 +1,19 @@
+import tkinter as tk
+
+
+def main():
+ window = tk.Tk()
+ button = tk.Button(window, text="Click", command=lambda: on_click(42))
+ button.pack(padx=10, pady=10)
+ window.mainloop()
+
+
+def on_click(age):
+ if age > 18:
+ print("You're an adult.")
+ else:
+ print("You're a minor.")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/expressions-vs-statements/hex_reader.py b/expressions-vs-statements/hex_reader.py
new file mode 100644
index 0000000000..904719a27f
--- /dev/null
+++ b/expressions-vs-statements/hex_reader.py
@@ -0,0 +1,24 @@
+import argparse
+import itertools
+
+MAX_BYTES = 1024
+
+
+def main(args):
+ buffer = bytearray()
+ with open(args.path, mode="rb") as file:
+ while chunk := file.read(MAX_BYTES):
+ buffer.extend(chunk)
+ for row in itertools.batched(buffer, args.columns):
+ print(" ".join(f"{byte:02x}" for byte in row))
+
+
+def parse_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("path")
+ parser.add_argument("-c", "--columns", type=int, default=16)
+ return parser.parse_args()
+
+
+if __name__ == "__main__":
+ main(parse_args())
diff --git a/how-to-remove-item-from-list-python/README.md b/how-to-remove-item-from-list-python/README.md
new file mode 100644
index 0000000000..002ac70cac
--- /dev/null
+++ b/how-to-remove-item-from-list-python/README.md
@@ -0,0 +1,3 @@
+# How to Remove Items From Lists in Python
+
+This folder provides the code examples for the Real Python tutorial [How to Remove Items From Lists in Python](https://realpython.com/remove-item-from-list-python/).
\ No newline at end of file
diff --git a/how-to-remove-item-from-list-python/books.py b/how-to-remove-item-from-list-python/books.py
new file mode 100644
index 0000000000..ad517c6d61
--- /dev/null
+++ b/how-to-remove-item-from-list-python/books.py
@@ -0,0 +1,36 @@
+books = ["Dragonsbane", "The Hobbit", "Wonder", "Jaws"]
+print(books.pop(0))
+print(books)
+
+books = ["Dragonsbane", "The Hobbit", "Wonder", "Jaws"]
+read_books = []
+read = books.pop(0)
+read_books.append(read)
+print(read_books)
+print(books)
+
+books = ["Dragonsbane", "The Hobbit", "Wonder", "Wonder", "Jaws", "Jaws"]
+del books[2]
+print(books)
+del books[-1]
+print(books)
+
+books = ["Dragonsbane", "The Hobbit", "Wonder", "Jaws"]
+books.remove("The Hobbit")
+print(books)
+
+# books = ["Dragonsbane", "The Hobbit", "Wonder", "Jaws"]
+# books.remove("The Two Towers")
+# print(books)
+
+books = ["Dragonsbane", "The Hobbit", "Wonder", "Jaws"]
+del books[0:3]
+print(books)
+
+books = ["Dragonsbane", "The Hobbit", "Wonder", "Jaws", "It"]
+del books[-3:-1]
+print(books)
+
+books = ["Dragonsbane", "The Hobbit", "Wonder", "Jaws", "It"]
+books.clear()
+print(books)
diff --git a/how-to-remove-item-from-list-python/phone_book.py b/how-to-remove-item-from-list-python/phone_book.py
new file mode 100644
index 0000000000..4444f84b91
--- /dev/null
+++ b/how-to-remove-item-from-list-python/phone_book.py
@@ -0,0 +1,15 @@
+phone_numbers = ["54123", "54123", "54456", "54789", "54789", "54123"]
+for phone_number in phone_numbers[:]:
+ while phone_numbers.count(phone_number) > 1:
+ phone_numbers.remove(phone_number)
+print(phone_numbers)
+
+
+phone_numbers = ["54123", "54123", "54456", "54789", "54789", "54123"]
+phone_numbers = list(dict.fromkeys(phone_numbers))
+print(phone_numbers)
+
+
+phone_numbers = ["54123", "54123", "54456", "54789", "54789", "54123"]
+phone_numbers = set(phone_numbers)
+print(phone_numbers)
diff --git a/name-main-idiom/echo.py b/name-main-idiom/echo.py
index 5b7b5d2d3c..940b7664b6 100644
--- a/name-main-idiom/echo.py
+++ b/name-main-idiom/echo.py
@@ -1,9 +1,7 @@
def echo(text: str, repetitions: int = 3) -> str:
"""Imitate a real-world echo."""
- echoed_text = ""
- for i in range(repetitions, 0, -1):
- echoed_text += f"{text[-i:]}\n"
- return f"{echoed_text.lower()}."
+ echoes = [text[-i:].lower() for i in range(repetitions, 0, -1)]
+ return "\n".join(echoes + ["."])
if __name__ == "__main__":
diff --git a/name-main-idiom/echo_args.py b/name-main-idiom/echo_args.py
index b33a75f23e..4cad04ff4b 100644
--- a/name-main-idiom/echo_args.py
+++ b/name-main-idiom/echo_args.py
@@ -3,10 +3,8 @@
def echo(text: str, repetitions: int = 3) -> str:
"""Imitate a real-world echo."""
- echoed_text = ""
- for i in range(repetitions, 0, -1):
- echoed_text += f"{text[-i:]}\n"
- return f"{echoed_text.lower()}."
+ echoes = [text[-i:].lower() for i in range(repetitions, 0, -1)]
+ return "\n".join(echoes + ["."])
def main() -> None:
diff --git a/name-main-idiom/echo_demo.py b/name-main-idiom/echo_demo.py
index 5e9f5bd9fa..fb7ff89fff 100644
--- a/name-main-idiom/echo_demo.py
+++ b/name-main-idiom/echo_demo.py
@@ -1,9 +1,7 @@
def echo(text: str, repetitions: int = 3) -> str:
"""Imitate a real-world echo."""
- echoed_text = ""
- for i in range(repetitions, 0, -1):
- echoed_text += f"{text[-i:]}\n"
- return f"{echoed_text.lower()}."
+ echoes = [text[-i:].lower() for i in range(repetitions, 0, -1)]
+ return "\n".join(echoes + ["."])
if __name__ == "__main__":
diff --git a/numpy-examples/full_portfolio.csv b/numpy-examples/full_portfolio.csv
new file mode 100644
index 0000000000..2285eed597
--- /dev/null
+++ b/numpy-examples/full_portfolio.csv
@@ -0,0 +1,7 @@
+Company,Sector,Mon,Tue,Wed,Thu,Fri
+Company_A,technology,100.5,101.2,102,101.8,112.5
+Company_B,finance,200.1,199.8,200.5,201.0,200.8
+Company_C,healthcare,50.3,50.5,51.0,50.8,51.2
+Company_D,technology,110.5,101.2,102,111.8,97.5
+Company_E,finance,200.1,200.8,200.5,211.0,200.8
+Company_F,healthcare,55.3,50.5,53.0,50.8,52.2
diff --git a/numpy-examples/issued_checks.csv b/numpy-examples/issued_checks.csv
index 79ebe66d15..c4a57d0e5d 100644
--- a/numpy-examples/issued_checks.csv
+++ b/numpy-examples/issued_checks.csv
@@ -1,5 +1,5 @@
Check_ID,Payee,Amount,Date_Issued
-1341,K.Starmer,150.00,2024-03-29
+1341,K Starmer,150.00,2024-03-29
1342,R Sunak,175.00,2024-03-29
1343,L Truss,30.00,2024-03-29
1344,B Johnson,45.00,2024-03-22
@@ -8,4 +8,4 @@ Check_ID,Payee,Amount,Date_Issued
1347,G Brown,100.00,2024-03-15
1348,T Blair,250.00,2024-03-15
1349,J Major,500.00,2024-03-15
-1350,M Thatcher,220.00,2024-03-15
\ No newline at end of file
+1350,M Thatcher,220.00,2024-03-15
diff --git a/numpy-examples/passports.csv b/numpy-examples/passports.csv
index 729d3351f9..91d80d959e 100644
--- a/numpy-examples/passports.csv
+++ b/numpy-examples/passports.csv
@@ -4,7 +4,7 @@ passport_no,passenger_no,nationality
493456399,3,American
375456228,4,American
457345975,5,Austrian
-345957363,6,Norewegian
+345957363,6,Norwegian
567546577,7,French
453667456,8,German
456785778,9,Danish
@@ -19,4 +19,4 @@ passport_no,passenger_no,nationality
654672278,18,Spanish
683637288,19,Norwegian
768357788,20,British
-768357788,21,American
\ No newline at end of file
+768357788,21,American
diff --git a/numpy-examples/tutorial_code.ipynb b/numpy-examples/tutorial_code.ipynb
index 453c501358..e24f9e54df 100644
--- a/numpy-examples/tutorial_code.ipynb
+++ b/numpy-examples/tutorial_code.ipynb
@@ -15,10 +15,8 @@
"metadata": {},
"outputs": [],
"source": [
- "!python -m pip install numpy\n",
- "!python -m pip install matplotlib\n",
- "!python -m pip install pathlib\n",
- "!python -m pip install jupyterlab"
+ "# !python -m pip install numpy\n",
+ "# !python -m pip install matplotlib"
]
},
{
@@ -39,16 +37,10 @@
"import numpy as np\n",
"from pathlib import Path\n",
"\n",
- "array = np.zeros(\n",
- " (\n",
- " 3,\n",
- " 2,\n",
- " 3,\n",
- " )\n",
- ")\n",
+ "array = np.zeros((3, 2, 3))\n",
"print(id(array))\n",
"\n",
- "for file_count, csv_file in enumerate(Path.cwd().glob(\"file?.csv\")):\n",
+ "for file_count, csv_file in enumerate(sorted(Path.cwd().glob(\"file?.csv\"))):\n",
" array[file_count] = np.loadtxt(csv_file.name, delimiter=\",\")\n",
"\n",
"print(id(array))\n",
@@ -63,15 +55,9 @@
"metadata": {},
"outputs": [],
"source": [
- "array = np.zeros(\n",
- " (\n",
- " 4,\n",
- " 2,\n",
- " 3,\n",
- " )\n",
- ")\n",
+ "array = np.zeros((4, 2, 3))\n",
"\n",
- "for file_count, csv_file in enumerate(Path.cwd().glob(\"file?.csv\")):\n",
+ "for file_count, csv_file in enumerate(sorted(Path.cwd().glob(\"file?.csv\"))):\n",
" array[file_count] = np.loadtxt(csv_file.name, delimiter=\",\")\n",
"\n",
"array[3, 0] = np.loadtxt(\"short_file.csv\", delimiter=\",\")\n",
@@ -86,24 +72,16 @@
"metadata": {},
"outputs": [],
"source": [
- "array = np.zeros(\n",
- " (\n",
- " 4,\n",
- " 2,\n",
- " 3,\n",
- " )\n",
- ")\n",
+ "array = np.zeros((4, 2, 3))\n",
"print(id(array))\n",
"\n",
- "for file_count, csv_file in enumerate(Path.cwd().glob(\"file?.csv\")):\n",
+ "for file_count, csv_file in enumerate(sorted(Path.cwd().glob(\"file?.csv\"))):\n",
" array[file_count] = np.loadtxt(csv_file.name, delimiter=\",\")\n",
"\n",
"array = np.insert(arr=array, obj=2, values=0, axis=1)\n",
- "\n",
"array[3] = np.loadtxt(\"long_file.csv\", delimiter=\",\")\n",
"\n",
"print(id(array))\n",
- "\n",
"array"
]
},
@@ -117,21 +95,10 @@
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": null,
"id": "6d760bcd-1be5-4396-8eb8-d729768909d6",
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "array(['At The Back', 'Fast Eddie', 'Almost There'], dtype=' first_day:\n",
- " return True\n",
- " return False\n",
- "\n",
+ "def profit_with_bonus(first_day, last_day):\n",
+ " if last_day >= first_day * 1.01:\n",
+ " return (last_day - first_day) * 1.1\n",
+ " else:\n",
+ " return last_day - first_day\n",
"\n",
- "monday_prices = portfolio[\"mon\"]\n",
- "friday_prices = portfolio[\"fri\"]\n",
"\n",
- "in_profit(monday_prices, friday_prices)"
+ "# The following causes an error because in_profit() doesn't know\n",
+ "# how to work with NumPy arrays:\n",
+ "#\n",
+ "# profit_with_bonus(portfolio[\"mon\"], portfolio[\"fri\"])"
]
},
{
@@ -476,27 +438,15 @@
"metadata": {},
"outputs": [],
"source": [
- "def in_profit(first_day, last_day):\n",
- " if last_day > first_day:\n",
- " return True\n",
- " return False\n",
+ "def profit_with_bonus(first_day, last_day):\n",
+ " if last_day >= first_day * 1.01:\n",
+ " return (last_day - first_day) * 1.1\n",
+ " else:\n",
+ " return last_day - first_day\n",
"\n",
"\n",
- "monday_prices = portfolio[\"mon\"]\n",
- "friday_prices = portfolio[\"fri\"]\n",
- "\n",
- "vectorized_in_profit = np.vectorize(in_profit)\n",
- "vectorized_in_profit(monday_prices, friday_prices)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "05eaa992-bed3-4af0-9508-c58be2f36381",
- "metadata": {},
- "outputs": [],
- "source": [
- "portfolio[vectorized_in_profit(monday_prices, friday_prices)]"
+ "vectorized_profit_with_bonus = np.vectorize(profit_with_bonus)\n",
+ "vectorized_profit_with_bonus(portfolio[\"mon\"], portfolio[\"fri\"])"
]
},
{
@@ -506,7 +456,7 @@
"metadata": {},
"outputs": [],
"source": [
- "in_profit(3, 5)"
+ "profit_with_bonus(3, 5)"
]
},
{
@@ -517,18 +467,14 @@
"outputs": [],
"source": [
"@np.vectorize\n",
- "def in_profit(first_day, last_day):\n",
- " if last_day > first_day:\n",
- " return True\n",
- " return False\n",
- "\n",
- "\n",
- "monday_prices = portfolio[\"mon\"]\n",
- "friday_prices = portfolio[\"fri\"]\n",
+ "def profit_with_bonus(first_day, last_day):\n",
+ " if last_day >= first_day * 1.01:\n",
+ " return (last_day - first_day) * 1.1\n",
+ " else:\n",
+ " return last_day - first_day\n",
"\n",
- "print(in_profit(monday_prices, friday_prices))\n",
"\n",
- "portfolio[in_profit(monday_prices, friday_prices)]"
+ "profit_with_bonus(portfolio[\"mon\"], portfolio[\"fri\"])"
]
},
{
@@ -538,7 +484,7 @@
"metadata": {},
"outputs": [],
"source": [
- "in_profit(3, 5)"
+ "profit_with_bonus(3, 5)"
]
},
{
@@ -548,7 +494,11 @@
"metadata": {},
"outputs": [],
"source": [
- "portfolio[np.where(friday_prices > monday_prices, True, False)]"
+ "np.where(\n",
+ " portfolio[\"fri\"] > portfolio[\"mon\"] * 1.01,\n",
+ " (portfolio[\"fri\"] - portfolio[\"mon\"]) * 1.1,\n",
+ " portfolio[\"fri\"] - portfolio[\"mon\"],\n",
+ ")"
]
}
],
@@ -568,7 +518,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.12.0"
+ "version": "3.12.7"
}
},
"nbformat": 4,
diff --git a/polars-missing-data/tutorial_code.ipynb b/polars-missing-data/tutorial_code.ipynb
index d4efb09e7d..408e1ce561 100644
--- a/polars-missing-data/tutorial_code.ipynb
+++ b/polars-missing-data/tutorial_code.ipynb
@@ -15,13 +15,13 @@
"metadata": {},
"outputs": [],
"source": [
- "!python -m pip install polars"
+ "!python -m pip install polars\n"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "22c85bb2-8b10-4075-ab58-3b212f1ed050",
+ "id": "8a05aa96-ae34-41de-a7ef-1498e6d94cab",
"metadata": {},
"outputs": [],
"source": [
@@ -29,7 +29,20 @@
"\n",
"tips = pl.scan_parquet(\"tips.parquet\")\n",
"\n",
- "tips.null_count().collect()"
+ "tips.collect()\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "22c85bb2-8b10-4075-ab58-3b212f1ed050",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "(\n",
+ " tips\n",
+ " .null_count()\n",
+ ").collect()\n"
]
},
{
@@ -51,7 +64,28 @@
"\n",
"tips = pl.scan_parquet(\"tips.parquet\")\n",
"\n",
- "tips.filter(pl.col(\"total\").is_null() & pl.col(\"tip\").is_null()).collect()"
+ "(\n",
+ " tips\n",
+ " .filter(\n",
+ " pl.col(\"total\").is_null() & pl.col(\"tip\").is_null()\n",
+ " )\n",
+ ").collect()\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d79f6c04-cfcd-45e5-aa36-4a097d6e2082",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "(\n",
+ " tips\n",
+ " .drop_nulls(pl.col(\"total\"))\n",
+ " .filter(\n",
+ " pl.col(\"total\").is_null() & pl.col(\"tip\").is_null()\n",
+ " )\n",
+ ").collect()\n"
]
},
{
@@ -62,10 +96,10 @@
"outputs": [],
"source": [
"(\n",
- " tips.drop_nulls(\"total\")\n",
+ " tips.drop_nulls(pl.col(\"total\"))\n",
" .with_columns(pl.col(\"tip\").fill_null(0))\n",
" .filter(pl.col(\"tip\").is_null())\n",
- ").collect()"
+ ").collect()\n"
]
},
{
@@ -87,7 +121,7 @@
"\n",
"tips = pl.scan_parquet(\"tips.parquet\")\n",
"\n",
- "tips.filter(pl.col(\"time\").is_null()).collect()"
+ "(tips.filter(pl.col(\"time\").is_null())).collect()\n"
]
},
{
@@ -97,7 +131,12 @@
"metadata": {},
"outputs": [],
"source": [
- "tips.filter(pl.col(\"record_id\").is_in([2, 3, 4, 14, 15, 16])).collect()"
+ "(\n",
+ " tips\n",
+ " .filter(\n",
+ " pl.col(\"record_id\").is_in([2, 3, 4, 14, 15, 16])\n",
+ " )\n",
+ ").collect()\n"
]
},
{
@@ -108,15 +147,12 @@
"outputs": [],
"source": [
"(\n",
- " tips.drop_nulls(\"total\")\n",
+ " tips\n",
+ " .drop_nulls(\"total\")\n",
" .with_columns(pl.col(\"tip\").fill_null(0))\n",
- " .with_columns(\n",
- " pl.when(pl.col(\"record_id\") == 2)\n",
- " .then(pl.col(\"time\").fill_null(strategy=\"forward\"))\n",
- " .otherwise(pl.col(\"time\").fill_null(strategy=\"backward\"))\n",
- " )\n",
+ " .with_columns(pl.col(\"time\").fill_null(strategy=\"forward\"))\n",
" .filter(pl.col(\"record_id\").is_in([3, 15]))\n",
- ").collect()"
+ ").collect()\n"
]
},
{
@@ -134,21 +170,16 @@
"metadata": {},
"outputs": [],
"source": [
- "tips = pl.scan_parquet(\"tips.parquet\")\n",
+ "import polars as pl\n",
"\n",
- "(tips.filter(pl.all_horizontal(pl.col(\"total\", \"tip\").is_null()))).collect()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "91b280c0-f7f7-4874-86b6-df349b8b6927",
- "metadata": {},
- "outputs": [],
- "source": [
"tips = pl.scan_parquet(\"tips.parquet\")\n",
"\n",
- "(tips.filter(pl.all_horizontal(pl.col(\"total\", \"tip\").is_null()))).collect()"
+ "(\n",
+ " tips\n",
+ " .filter(\n",
+ " pl.all_horizontal(pl.col(\"total\", \"tip\").is_null())\n",
+ " )\n",
+ ").collect()\n"
]
},
{
@@ -158,7 +189,14 @@
"metadata": {},
"outputs": [],
"source": [
- "(tips.filter(~pl.all_horizontal(pl.col(\"total\", \"tip\").is_null()))).collect()"
+ "tips = pl.scan_parquet(\"tips.parquet\")\n",
+ "\n",
+ "(\n",
+ " tips\n",
+ " .filter(\n",
+ " ~pl.all_horizontal(pl.col(\"total\", \"tip\").is_null())\n",
+ " )\n",
+ ").collect()\n"
]
},
{
@@ -173,14 +211,13 @@
"tips = pl.scan_parquet(\"tips.parquet\")\n",
"\n",
"(\n",
- " tips.filter(~pl.all_horizontal(pl.col(\"total\", \"tip\").is_null()))\n",
- " .with_columns(pl.col(\"tip\").fill_null(0))\n",
- " .with_columns(\n",
- " pl.when(pl.col(\"record_id\") == 2)\n",
- " .then(pl.col(\"time\").fill_null(strategy=\"forward\"))\n",
- " .otherwise(pl.col(\"time\").fill_null(strategy=\"backward\"))\n",
+ " tips\n",
+ " .filter(\n",
+ " ~pl.all_horizontal(pl.col(\"total\", \"tip\").is_null())\n",
" )\n",
- ").null_count().collect()"
+ " .with_columns(pl.col(\"tip\").fill_null(0))\n",
+ " .with_columns(pl.col(\"time\").fill_null(strategy=\"forward\"))\n",
+ ").null_count().collect()\n"
]
},
{
@@ -210,7 +247,7 @@
" }\n",
")\n",
"\n",
- "scientists.collect()"
+ "scientists.collect()\n"
]
},
{
@@ -226,7 +263,7 @@
" scientists.with_columns(cs.string().fill_null(\"Unknown\")).with_columns(\n",
" cs.integer().fill_null(0)\n",
" )\n",
- ").collect()"
+ ").collect()\n"
]
},
{
@@ -248,7 +285,7 @@
"\n",
"sales_trends = pl.scan_csv(\"sales_trends.csv\")\n",
"\n",
- "sales_trends.collect()"
+ "sales_trends.collect()\n"
]
},
{
@@ -259,12 +296,13 @@
"outputs": [],
"source": [
"(\n",
- " sales_trends.with_columns(\n",
+ " sales_trends\n",
+ " .with_columns(\n",
" pl.col(\"next_year\").replace(\n",
" [float(\"inf\"), -float(\"inf\"), float(\"NaN\")], None\n",
" )\n",
" )\n",
- ").collect()"
+ ").collect()\n"
]
},
{
@@ -275,17 +313,19 @@
"outputs": [],
"source": [
"(\n",
- " sales_trends.with_columns(\n",
+ " sales_trends\n",
+ " .with_columns(\n",
" pl.col(\"next_year\").replace(\n",
" [float(\"inf\"), -float(\"inf\"), float(\"NaN\")], None\n",
" )\n",
- " ).with_columns(\n",
+ " )\n",
+ " .with_columns(\n",
" pl.col(\"next_year\").fill_null(\n",
" pl.col(\"current_year\")\n",
" + (pl.col(\"current_year\") - pl.col(\"last_year\"))\n",
" )\n",
" )\n",
- ").collect()"
+ ").collect()\n"
]
},
{
@@ -307,7 +347,7 @@
"\n",
"episodes = pl.scan_parquet(\"ft_exercise.parquet\")\n",
"\n",
- "episodes.null_count().collect()"
+ "episodes.null_count().collect()\n"
]
},
{
@@ -321,17 +361,22 @@
"\n",
"episodes = pl.scan_parquet(\"ft_exercise.parquet\")\n",
"\n",
- "episodes.with_columns(\n",
- " pl.when(pl.col(\"episode\") == 6)\n",
- " .then(pl.col(\"series\").fill_null(strategy=\"forward\"))\n",
- " .otherwise(pl.col(\"series\").fill_null(strategy=\"backward\"))\n",
- ").with_columns(\n",
- " pl.when(pl.col(\"episode\") == 4)\n",
- " .then(pl.col(\"title\").fill_null(\"The Hotel Inspectors\"))\n",
- " .otherwise(pl.col(\"title\").fill_null(\"Waldorf Salad\"))\n",
- ").with_columns(\n",
- " pl.col(\"original_date\").interpolate()\n",
- ").null_count().collect()"
+ "(\n",
+ " episodes\n",
+ " .with_columns(\n",
+ " pl.when(pl.col(\"episode\") == 6)\n",
+ " .then(pl.col(\"series\").fill_null(strategy=\"forward\"))\n",
+ " .otherwise(pl.col(\"series\").fill_null(strategy=\"backward\"))\n",
+ " )\n",
+ " .with_columns(\n",
+ " pl.when(pl.col(\"episode\") == 4)\n",
+ " .then(pl.col(\"title\").fill_null(\"The Hotel Inspectors\"))\n",
+ " .otherwise(pl.col(\"title\").fill_null(\"Waldorf Salad\"))\n",
+ " )\n",
+ " .with_columns(\n",
+ " pl.col(\"original_date\").interpolate()\n",
+ " )\n",
+ ").null_count().collect()\n"
]
}
],
diff --git a/python-dicts/README.md b/python-dicts/README.md
new file mode 100644
index 0000000000..ac4a108380
--- /dev/null
+++ b/python-dicts/README.md
@@ -0,0 +1,3 @@
+# Dictionaries in Python
+
+This folder provides the code examples for the Real Python tutorial [Dictionaries in Python](https://realpython.com/python-dicts/).
diff --git a/python-dicts/configs.py b/python-dicts/configs.py
new file mode 100644
index 0000000000..4e7c01c880
--- /dev/null
+++ b/python-dicts/configs.py
@@ -0,0 +1,62 @@
+config = {
+ "color": "green",
+ "width": 42,
+ "height": 100,
+ "font": "Courier",
+}
+
+# Access a value through its key
+print(config["color"])
+
+# Update a value
+config["font"] = "Helvetica"
+print(config)
+
+config = {
+ "color": "green",
+ "width": 42,
+ "height": 100,
+ "font": "Courier",
+}
+user_config = {
+ "path": "/home",
+ "color": "red",
+ "font": "Arial",
+ "position": (200, 100),
+}
+config.update(user_config)
+print(config)
+config.update([("width", 200), ("api_key", 1234)])
+print(config)
+config.update(color="yellow", script="__main__.py")
+print(config)
+
+default_config = {
+ "color": "green",
+ "width": 42,
+ "height": 100,
+ "font": "Courier",
+}
+user_config = {
+ "path": "/home",
+ "color": "red",
+ "font": "Arial",
+ "position": (200, 100),
+}
+config = default_config | user_config
+print(config)
+
+config = {
+ "color": "green",
+ "width": 42,
+ "height": 100,
+ "font": "Courier",
+}
+user_config = {
+ "path": "/home",
+ "color": "red",
+ "font": "Arial",
+ "position": (200, 100),
+}
+config |= user_config
+print(config)
diff --git a/python-dicts/counter.py b/python-dicts/counter.py
new file mode 100644
index 0000000000..511cac6f08
--- /dev/null
+++ b/python-dicts/counter.py
@@ -0,0 +1,3 @@
+from collections import Counter
+
+print(Counter("mississippi"))
diff --git a/python-dicts/dict_zip.py b/python-dicts/dict_zip.py
new file mode 100644
index 0000000000..6038d67fdc
--- /dev/null
+++ b/python-dicts/dict_zip.py
@@ -0,0 +1,4 @@
+cities = ["Colorado", "Chicago", "Boston", "Minnesota", "Milwaukee", "Seattle"]
+teams = ["Rockies", "White Sox", "Red Sox", "Twins", "Brewers", "Mariners"]
+
+print(dict(zip(cities, teams)))
diff --git a/python-dicts/employees.py b/python-dicts/employees.py
new file mode 100644
index 0000000000..6671bc6390
--- /dev/null
+++ b/python-dicts/employees.py
@@ -0,0 +1,15 @@
+from collections import defaultdict
+
+employees = [
+ ("Sales", "John"),
+ ("Sales", "Martin"),
+ ("Accounting", "Kate"),
+ ("Marketing", "Elizabeth"),
+ ("Marketing", "Linda"),
+]
+
+departments = defaultdict(list)
+for department, employee in employees:
+ departments[department].append(employee)
+
+print(departments)
diff --git a/python-dicts/equality.py b/python-dicts/equality.py
new file mode 100644
index 0000000000..822bceba5b
--- /dev/null
+++ b/python-dicts/equality.py
@@ -0,0 +1,4 @@
+print([1, 2, 3] == [3, 2, 1])
+print({1: 1, 2: 2, 3: 3} == {3: 3, 2: 2, 1: 1})
+print([1, 2, 3] != [3, 2, 1])
+print({1: 1, 2: 2, 3: 3} != {3: 3, 2: 2, 1: 1})
diff --git a/python-dicts/from_keys.py b/python-dicts/from_keys.py
new file mode 100644
index 0000000000..ab7815163b
--- /dev/null
+++ b/python-dicts/from_keys.py
@@ -0,0 +1,2 @@
+inventory = dict.fromkeys(["apple", "orange", "banana", "mango"], 0)
+print(inventory)
diff --git a/python-dicts/inventory.py b/python-dicts/inventory.py
new file mode 100644
index 0000000000..dc58767e33
--- /dev/null
+++ b/python-dicts/inventory.py
@@ -0,0 +1,12 @@
+inventory = {"apple": 100, "orange": 80, "banana": 100}
+inventory.get("apple")
+
+print(inventory.get("mango"))
+
+print(inventory.get("mango", 0))
+
+print(inventory.values())
+
+print(inventory.keys())
+
+print(inventory.items())
diff --git a/python-dicts/iteration.py b/python-dicts/iteration.py
new file mode 100644
index 0000000000..27c1ebe1a5
--- /dev/null
+++ b/python-dicts/iteration.py
@@ -0,0 +1,32 @@
+students = {
+ "Alice": 89.5,
+ "Bob": 76.0,
+ "Charlie": 92.3,
+ "Diana": 84.7,
+ "Ethan": 88.9,
+ "Fiona": 95.6,
+ "George": 73.4,
+ "Hannah": 81.2,
+}
+for student in students:
+ print(student)
+
+for student in students.keys():
+ print(student)
+
+for student in students:
+ print(student, "->", students[student])
+
+MLB_teams = {
+ "Colorado": "Rockies",
+ "Chicago": "White Sox",
+ "Boston": "Red Sox",
+ "Minnesota": "Twins",
+ "Milwaukee": "Brewers",
+ "Seattle": "Mariners",
+}
+for team in MLB_teams.values():
+ print(team)
+
+for city, team in MLB_teams.items():
+ print(city, "->", team)
diff --git a/python-dicts/membership.py b/python-dicts/membership.py
new file mode 100644
index 0000000000..b3c1d6fc0e
--- /dev/null
+++ b/python-dicts/membership.py
@@ -0,0 +1,32 @@
+import timeit
+
+MLB_teams = {
+ "Colorado": "Rockies",
+ "Chicago": "White Sox",
+ "Boston": "Red Sox",
+ "Minnesota": "Twins",
+ "Milwaukee": "Brewers",
+ "Seattle": "Mariners",
+}
+
+# Run timeit to compare the membership test
+time_in_dict = timeit.timeit(
+ '"Milwaukee" in MLB_teams', globals=globals(), number=1000000
+)
+time_in_keys = timeit.timeit(
+ '"Milwaukee" in MLB_teams.keys()', globals=globals(), number=1000000
+)
+time_not_in_dict = timeit.timeit(
+ '"Indianapolis" in MLB_teams', globals=globals(), number=1000000
+)
+time_not_in_keys = timeit.timeit(
+ '"Indianapolis" in MLB_teams.keys()', globals=globals(), number=1000000
+)
+
+print(
+ f"{time_in_dict = } seconds",
+ f"{time_in_keys = } seconds",
+ f"{time_not_in_dict = } seconds",
+ f"{time_not_in_keys = } seconds",
+ sep="\n",
+)
diff --git a/python-dicts/mlb_teams.py b/python-dicts/mlb_teams.py
new file mode 100644
index 0000000000..82751e201b
--- /dev/null
+++ b/python-dicts/mlb_teams.py
@@ -0,0 +1,33 @@
+MLB_teams = {
+ "Colorado": "Rockies",
+ # "Chicago": "White Sox",
+ "Chicago": "Chicago Cubs",
+ "Boston": "Red Sox",
+ "Minnesota": "Twins",
+ "Milwaukee": "Brewers",
+ "Seattle": "Mariners",
+}
+print(MLB_teams)
+
+MLB_teams = dict(
+ [
+ ("Colorado", "Rockies"),
+ ("Chicago", "White Sox"),
+ ("Boston", "Red Sox"),
+ ("Minnesota", "Twins"),
+ ("Milwaukee", "Brewers"),
+ ("Seattle", "Mariners"),
+ ]
+)
+print(MLB_teams)
+
+
+print("Milwaukee" in MLB_teams)
+print("Indianapolis" in MLB_teams)
+print("Indianapolis" not in MLB_teams)
+print("Milwaukee" in MLB_teams.keys())
+print("Indianapolis" in MLB_teams.keys())
+print("Indianapolis" not in MLB_teams.keys())
+
+print(("Boston", "Red Sox") in MLB_teams.items())
+print(("Boston", "Red Sox") not in MLB_teams.items())
diff --git a/python-dicts/number.py b/python-dicts/number.py
new file mode 100644
index 0000000000..204e6c17f6
--- /dev/null
+++ b/python-dicts/number.py
@@ -0,0 +1,6 @@
+class Number:
+ def __init__(self, value):
+ self.value = value
+
+
+print(Number(42).__dict__)
diff --git a/python-dicts/person.py b/python-dicts/person.py
new file mode 100644
index 0000000000..3c28b64260
--- /dev/null
+++ b/python-dicts/person.py
@@ -0,0 +1,21 @@
+person = {
+ "first_name": "John",
+ "last_name": "Doe",
+ "age": 35,
+ "spouse": "Jane",
+ "children": ["Ralph", "Betty", "Bob"],
+ "pets": {"dog": "Frieda", "cat": "Sox"},
+}
+
+print(person["children"][0])
+print(person["children"][2])
+print(person["pets"]["dog"])
+
+person = {}
+person["first_name"] = "John"
+person["last_name"] = "Doe"
+person["age"] = 35
+person["spouse"] = "Jane"
+person["children"] = ["Ralph", "Betty", "Bob"]
+person["pets"] = {"dog": "Frieda", "cat": "Sox"}
+print(person)
diff --git a/python-dicts/sorted_dict.py b/python-dicts/sorted_dict.py
new file mode 100644
index 0000000000..b6d4208042
--- /dev/null
+++ b/python-dicts/sorted_dict.py
@@ -0,0 +1,35 @@
+class SortableDict(dict):
+ def sort_by_keys(self, reverse=False):
+ sorted_items = sorted(
+ self.items(), key=lambda item: item[0], reverse=reverse
+ )
+ self.clear()
+ self.update(sorted_items)
+
+ def sort_by_values(self, reverse=False):
+ sorted_items = sorted(
+ self.items(), key=lambda item: item[1], reverse=reverse
+ )
+ self.clear()
+ self.update(sorted_items)
+
+
+students = SortableDict(
+ {
+ "Alice": 89.5,
+ "Bob": 76.0,
+ "Charlie": 92.3,
+ "Diana": 84.7,
+ "Ethan": 88.9,
+ "Fiona": 95.6,
+ "George": 73.4,
+ "Hannah": 81.2,
+ }
+)
+
+print(id(students))
+students.sort_by_keys()
+print(students)
+students.sort_by_values(reverse=True)
+print(students)
+print(id(students))
diff --git a/python-dicts/squares.py b/python-dicts/squares.py
new file mode 100644
index 0000000000..7a78da28af
--- /dev/null
+++ b/python-dicts/squares.py
@@ -0,0 +1,10 @@
+squares = {}
+
+for integer in range(1, 10):
+ squares[integer] = integer**2
+
+print(squares)
+
+squares = {integer: integer**2 for integer in range(1, 10)}
+
+print(squares)
diff --git a/python-dicts/students.py b/python-dicts/students.py
new file mode 100644
index 0000000000..5fdeba916d
--- /dev/null
+++ b/python-dicts/students.py
@@ -0,0 +1,12 @@
+students = {
+ "Alice": 89.5,
+ "Bob": 76.0,
+ "Charlie": 92.3,
+ "Diana": 84.7,
+ "Ethan": 88.9,
+ "Fiona": 95.6,
+ "George": 73.4,
+ "Hannah": 81.2,
+}
+print(dict(sorted(students.items(), key=lambda item: item[1])))
+print(dict(sorted(students.items(), key=lambda item: item[1], reverse=True)))
diff --git a/python-dicts/values.py b/python-dicts/values.py
new file mode 100644
index 0000000000..c85a45c026
--- /dev/null
+++ b/python-dicts/values.py
@@ -0,0 +1,14 @@
+class Point:
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
+
+
+print(
+ {
+ "colors": ["red", "green", "blue"],
+ "plugins": {"py_code", "dev_sugar", "fasting_py"},
+ "timeout": 3,
+ "position": Point(42, 21),
+ }
+)
diff --git a/python-f-string/README.md b/python-f-string/README.md
index 6b2bfa0c4c..d014672494 100644
--- a/python-f-string/README.md
+++ b/python-f-string/README.md
@@ -1,3 +1,3 @@
-# Python's F-String: An Improved String Interpolation and Formatting Tool
+# Python's F-String for String Interpolation and Formatting
-This folder provides the code examples for the Real Python tutorial [Python's F-String: An Improved String Interpolation and Formatting Tool](https://realpython.com/python-f-string/).
\ No newline at end of file
+This folder provides the code examples for the Real Python tutorial [Python's F-String for String Interpolation and Formatting](https://realpython.com/python-f-strings/).
diff --git a/python-get-all-files-in-directory/create_large_dir.py b/python-get-all-files-in-directory/create_large_dir.py
index 2cf4623c49..5e7c9671e5 100644
--- a/python-get-all-files-in-directory/create_large_dir.py
+++ b/python-get-all-files-in-directory/create_large_dir.py
@@ -66,18 +66,18 @@ class Item:
def create_item(item: Item, path_to: Path = Path.cwd()) -> None:
- if not item.children and not item.junk_files:
- path_to.joinpath(item.name).touch()
+ if not item.children and not item.num_junk_files:
+ path_to.joinpath(item.name).touch(exist_ok=True)
return
root = path_to.joinpath(item.name)
- root.mkdir()
+ root.mkdir(exist_ok=True)
for child in item.children:
create_item(child, path_to=root)
for i in range(item.num_junk_files):
- root.joinpath(f"{i}.txt").touch()
+ root.joinpath(f"{i}.txt").touch(exist_ok=True)
create_item(folder_structure)
diff --git a/python-range/README.md b/python-range/README.md
index 138a72e91d..6b06fe92b6 100644
--- a/python-range/README.md
+++ b/python-range/README.md
@@ -2,6 +2,22 @@
This repository holds the code for Real Python's [Python `range()`: Represent Numerical Ranges](https://realpython.com/python-range/) tutorial.
+## reverse_range()
+
+In [`reverse_range.py`](reverse_range.py), you can find an explicit implementation of a function that can reverse a general range.
+
+```python
+>>> from reverse_range import reverse_range
+
+>>> reverse_range(range(1, 20, 4))
+range(17, 0, -4)
+
+>>> list(reverse_range(range(1, 20, 4)))
+[17, 13, 9, 5, 1]
+```
+
+In practical applications, you should use `reversed(range(1, 20, 4))` or `range(1, 20, 4)[::-1]` instead.
+
## PiDigits
The file [`pi_digits.py`](pi_digits.py) shows the implementation of `PiDigits` which is an integer-like type that can be used as arguments to `range()`:
diff --git a/python-range/reverse_range.py b/python-range/reverse_range.py
new file mode 100644
index 0000000000..4b776905f1
--- /dev/null
+++ b/python-range/reverse_range.py
@@ -0,0 +1,27 @@
+def reverse_range(rng):
+ """Explicitly calculate necessary parameters to reverse a general range.
+
+ In practice, you should use reversed() or [::-1] instead.
+ """
+ adj = 1 if rng.step > 0 else -1
+ return range(
+ (rng.stop - adj) - (rng.stop - rng.start - adj) % rng.step,
+ rng.start - adj,
+ -rng.step,
+ )
+
+
+if __name__ == "__main__":
+ numbers = range(1, 20, 4)
+
+ print("\nOriginal:")
+ print(numbers)
+ print(list(numbers))
+
+ print("\nReversed:")
+ print(reverse_range(numbers))
+ print(list(reverse_range(numbers)))
+
+ print("\nTwice reversed, has the same elements as the original:")
+ print(reverse_range(reverse_range(numbers)))
+ print(list(reverse_range(reverse_range(numbers))))
diff --git a/python-set-comprehension/README.md b/python-set-comprehension/README.md
new file mode 100644
index 0000000000..a0022a23fe
--- /dev/null
+++ b/python-set-comprehension/README.md
@@ -0,0 +1,3 @@
+# Python Set Comprehensions: How and When to Use Them
+
+This folder provides the code examples for the Real Python tutorial [Python Set Comprehensions: How and When to Use Them](https://realpython.com/python-set-comprehension/).
diff --git a/python-set-comprehension/colors.py b/python-set-comprehension/colors.py
new file mode 100644
index 0000000000..a7fab40509
--- /dev/null
+++ b/python-set-comprehension/colors.py
@@ -0,0 +1,4 @@
+colors = {"blue", "red", "green", "orange", "green"}
+print(colors)
+colors.add("purple")
+print(colors)
diff --git a/python-set-comprehension/complex_expression.py b/python-set-comprehension/complex_expression.py
new file mode 100644
index 0000000000..b23821e1b2
--- /dev/null
+++ b/python-set-comprehension/complex_expression.py
@@ -0,0 +1,13 @@
+numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+
+print({number**2 if number % 2 == 0 else number**3 for number in numbers})
+
+result_set = set()
+for number in numbers:
+ if number % 2 == 0:
+ value = number**2
+ else:
+ value = number**3
+ result_set.add(value)
+
+print(result_set)
diff --git a/python-set-comprehension/emails.py b/python-set-comprehension/emails.py
new file mode 100644
index 0000000000..138c79ca95
--- /dev/null
+++ b/python-set-comprehension/emails.py
@@ -0,0 +1,10 @@
+emails = {
+ " alice@example.org ",
+ "BOB@example.com",
+ "charlie@EXAMPLE.com",
+ "David@example.net",
+ " bob@example.com",
+ "JohnDoe@example.com",
+}
+
+print({email.strip().lower() for email in emails})
diff --git a/python-set-comprehension/filter_emails.py b/python-set-comprehension/filter_emails.py
new file mode 100644
index 0000000000..9552a7e326
--- /dev/null
+++ b/python-set-comprehension/filter_emails.py
@@ -0,0 +1,9 @@
+emails_set = {
+ "alice@example.org",
+ "bob@example.com",
+ "johndoe@example.com",
+ "charlie@example.com",
+ "david@example.net",
+}
+
+print({email for email in emails_set if email.endswith(".com")})
diff --git a/python-set-comprehension/matrix.py b/python-set-comprehension/matrix.py
new file mode 100644
index 0000000000..91ba5d3f66
--- /dev/null
+++ b/python-set-comprehension/matrix.py
@@ -0,0 +1,8 @@
+matrix = [
+ [9, 3, 8, 3],
+ [4, 5, 2, 8],
+ [6, 4, 3, 1],
+ [1, 0, 4, 5],
+]
+
+print({value**2 for row in matrix for value in row})
diff --git a/python-set-comprehension/text.py b/python-set-comprehension/text.py
new file mode 100644
index 0000000000..0e75e62995
--- /dev/null
+++ b/python-set-comprehension/text.py
@@ -0,0 +1,18 @@
+unique_words = set()
+text = """
+Beautiful is better than ugly
+Explicit is better than implicit
+Simple is better than complex
+Complex is better than complicated
+""".lower()
+
+for word in text.split():
+ unique_words.add(word)
+
+print(unique_words)
+
+print(set(text.split()))
+
+unique_words = {word for word in text.split()}
+
+print(unique_words)
diff --git a/python-set-comprehension/tools.py b/python-set-comprehension/tools.py
new file mode 100644
index 0000000000..ee3f1dea32
--- /dev/null
+++ b/python-set-comprehension/tools.py
@@ -0,0 +1,7 @@
+tools = ["Python", "Django", "Flask", "pandas", "NumPy"]
+tools_set = {tool.lower() for tool in tools}
+
+print(tools_set)
+print("python".lower() in tools_set)
+print("Pandas".lower() in tools_set)
+print("Numpy".lower() in tools_set)