From 4a02752551f77c3c20b272f8a8cdc594a79e02a6 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Thu, 13 Apr 2023 20:04:15 +0200 Subject: [PATCH 01/20] translation #1 --- README.md | 275 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 170 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 55d393a4..ede6948b 100644 --- a/README.md +++ b/README.md @@ -1,119 +1,183 @@

What the f*ck Python! đŸ˜±

-

Exploring and understanding Python through surprising snippets.

+

Entdecke und verstehe Python durch ĂŒberraschende Code-Schnipsel.

-Translations: [Chinese äž­æ–‡](https://github.com/robertparley/wtfpython-cn) | [Vietnamese Tiáșżng Việt](https://github.com/vuduclyunitn/wtfptyhon-vi) | [Spanish Español](https://web.archive.org/web/20220511161045/https://github.com/JoseDeFreitas/wtfpython-es) | [Korean 한ꔭ얎](https://github.com/buttercrab/wtfpython-ko) | [Russian РуссĐșĐžĐč](https://github.com/frontdevops/wtfpython) | [Add translation](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) +Übersetzungen: [English](https://github.com/robertparley/wtfpython-cn) | -Other modes: [Interactive](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) +Andere Modi: [Interaktiv](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) -Python, being a beautifully designed high-level and interpreter-based programming language, provides us with many features for the programmer's comfort. But sometimes, the outcomes of a Python snippet may not seem obvious at first sight. +Python, bekannt als gut designte High-Level und Interpreter-basierte Programmiersprache, stellt viele Features zur VerfĂŒgung, um dem Programmierer das Leben zu erleichtern. Allerdings kann es vorkommen, dass ein Python-Schnipsel ein unerwartetes Verhalten zeigt. -Here's a fun project attempting to explain what exactly is happening under the hood for some counter-intuitive snippets and lesser-known features in Python. +Hier ist ein schönes Projekt, das versucht die Dinge aufzuzeigen, die bei einigen Code-Schnipseln unter der Haube passieren und darĂŒber hinaus einige weniger bekannte Features von Python zu erklĂ€ren. -While some of the examples you see below may not be WTFs in the truest sense, but they'll reveal some of the interesting parts of Python that you might be unaware of. I find it a nice way to learn the internals of a programming language, and I believe that you'll find it interesting too! +WĂ€hrend manche Beispiele nicht unbedingt beeindruckend erscheinen, zeigen sie dennoch interessante Details von Python, die dir womöglich noch nicht aufgefallen sind. Ich finde, dass es eine schöne Möglichkeit ist, die Interna einer Programmiersprache zu lernen und ich glaube das findest du auch ! -If you're an experienced Python programmer, you can take it as a challenge to get most of them right in the first attempt. You may have already experienced some of them before, and I might be able to revive sweet old memories of yours! :sweat_smile: +Wenn du ein erfahrener Python-Programmierer bist, kannst du dies als Herausforderung ansehen, um möglichst viel beim ersten Anlauf +richtig zu machen. Du hast vielleicht manches schon erlebt, sodass ich möglicherweise alte Erinnerungen wecken kann! :sweat_smile: -PS: If you're a returning reader, you can learn about the new modifications [here](https://github.com/satwikkansal/wtfpython/releases/) (the examples marked with asterisk are the ones added in the latest major revision). +PS: Wenn du bereits mehrfach hier warst, kannst du dich [hier](https://github.com/satwikkansal/wtfpython/releases/) ĂŒber neue Modifikationen informieren (die Beispiele, die mit einem Stern markiert sind, sind Teil des letzten Releases). -So, here we go... +Also, los gehts... -# Table of Contents +# Inhaltsverzeichnis +- [Inhaltsverzeichnis](#inhaltsverzeichnis) - [Structure of the Examples](#structure-of-the-examples) - + [▶ Some fancy Title](#-some-fancy-title) -- [Usage](#usage) -- [👀 Examples](#-examples) - * [Section: Strain your brain!](#section-strain-your-brain) - + [▶ First things first! *](#-first-things-first-) - + [▶ Strings can be tricky sometimes](#-strings-can-be-tricky-sometimes) - + [▶ Be careful with chained operations](#-be-careful-with-chained-operations) - + [▶ How not to use `is` operator](#-how-not-to-use-is-operator) - + [▶ Hash brownies](#-hash-brownies) - + [▶ Deep down, we're all the same.](#-deep-down-were-all-the-same) - + [▶ Disorder within order *](#-disorder-within-order-) - + [▶ Keep trying... *](#-keep-trying-) - + [▶ For what?](#-for-what) - + [▶ Evaluation time discrepancy](#-evaluation-time-discrepancy) - + [▶ `is not ...` is not `is (not ...)`](#-is-not--is-not-is-not-) - + [▶ A tic-tac-toe where X wins in the first attempt!](#-a-tic-tac-toe-where-x-wins-in-the-first-attempt) - + [▶ Schrödinger's variable](#-schrödingers-variable-) - + [▶ The chicken-egg problem *](#-the-chicken-egg-problem-) - + [▶ Subclass relationships](#-subclass-relationships) - + [▶ Methods equality and identity](#-methods-equality-and-identity) - + [▶ All-true-ation *](#-all-true-ation-) - + [▶ The surprising comma](#-the-surprising-comma) - + [▶ Strings and the backslashes](#-strings-and-the-backslashes) - + [▶ not knot!](#-not-knot) - + [▶ Half triple-quoted strings](#-half-triple-quoted-strings) - + [▶ What's wrong with booleans?](#-whats-wrong-with-booleans) - + [▶ Class attributes and instance attributes](#-class-attributes-and-instance-attributes) - + [▶ yielding None](#-yielding-none) - + [▶ Yielding from... return! *](#-yielding-from-return-) - + [▶ Nan-reflexivity *](#-nan-reflexivity-) - + [▶ Mutating the immutable!](#-mutating-the-immutable) - + [▶ The disappearing variable from outer scope](#-the-disappearing-variable-from-outer-scope) - + [▶ The mysterious key type conversion](#-the-mysterious-key-type-conversion) - + [▶ Let's see if you can guess this?](#-lets-see-if-you-can-guess-this) - + [▶ Exceeds the limit for integer string conversion](#-exceeds-the-limit-for-integer-string-conversion) - * [Section: Slippery Slopes](#section-slippery-slopes) - + [▶ Modifying a dictionary while iterating over it](#-modifying-a-dictionary-while-iterating-over-it) - + [▶ Stubborn `del` operation](#-stubborn-del-operation) - + [▶ The out of scope variable](#-the-out-of-scope-variable) - + [▶ Deleting a list item while iterating](#-deleting-a-list-item-while-iterating) - + [▶ Lossy zip of iterators *](#-lossy-zip-of-iterators-) - + [▶ Loop variables leaking out!](#-loop-variables-leaking-out) - + [▶ Beware of default mutable arguments!](#-beware-of-default-mutable-arguments) - + [▶ Catching the Exceptions](#-catching-the-exceptions) - + [▶ Same operands, different story!](#-same-operands-different-story) - + [▶ Name resolution ignoring class scope](#-name-resolution-ignoring-class-scope) - + [▶ Rounding like a banker *](#-rounding-like-a-banker-) - + [▶ Needles in a Haystack *](#-needles-in-a-haystack-) - + [▶ Splitsies *](#-splitsies-) - + [▶ Wild imports *](#-wild-imports-) - + [▶ All sorted? *](#-all-sorted-) - + [▶ Midnight time doesn't exist?](#-midnight-time-doesnt-exist) - * [Section: The Hidden treasures!](#section-the-hidden-treasures) - + [▶ Okay Python, Can you make me fly?](#-okay-python-can-you-make-me-fly) - + [▶ `goto`, but why?](#-goto-but-why) - + [▶ Brace yourself!](#-brace-yourself) - + [▶ Let's meet Friendly Language Uncle For Life](#-lets-meet-friendly-language-uncle-for-life) - + [▶ Even Python understands that love is complicated](#-even-python-understands-that-love-is-complicated) - + [▶ Yes, it exists!](#-yes-it-exists) - + [▶ Ellipsis *](#-ellipsis-) - + [▶ Inpinity](#-inpinity) - + [▶ Let's mangle](#-lets-mangle) - * [Section: Appearances are deceptive!](#section-appearances-are-deceptive) - + [▶ Skipping lines?](#-skipping-lines) - + [▶ Teleportation](#-teleportation) - + [▶ Well, something is fishy...](#-well-something-is-fishy) - * [Section: Miscellaneous](#section-miscellaneous) - + [▶ `+=` is faster](#--is-faster) - + [▶ Let's make a giant string!](#-lets-make-a-giant-string) - + [▶ Slowing down `dict` lookups *](#-slowing-down-dict-lookups-) - + [▶ Bloating instance `dict`s *](#-bloating-instance-dicts-) - + [▶ Minor Ones *](#-minor-ones-) +- [Benutzung](#benutzung) +- [👀 Beispiele](#-beispiele) + - [Kapitel: Strain your brain!](#kapitel-strain-your-brain) + - [▶ First things first! \*](#-first-things-first-) + - [💡 ErklĂ€rung](#-erklĂ€rung) + - [▶ Strings can be tricky sometimes](#-strings-can-be-tricky-sometimes) + - [💡 Explanation:](#-explanation) + - [▶ Be careful with chained operations](#-be-careful-with-chained-operations) + - [💡 Explanation:](#-explanation-1) + - [▶ How not to use `is` operator](#-how-not-to-use-is-operator) + - [💡 Explanation:](#-explanation-2) + - [▶ Hash brownies](#-hash-brownies) + - [💡 Explanation](#-explanation-3) + - [▶ Deep down, we're all the same.](#-deep-down-were-all-the-same) + - [💡 Explanation:](#-explanation-4) + - [▶ Disorder within order \*](#-disorder-within-order-) + - [💡 Explanation:](#-explanation-5) + - [▶ Keep trying... \*](#-keep-trying-) + - [💡 Explanation:](#-explanation-6) + - [▶ For what?](#-for-what) + - [💡 Explanation:](#-explanation-7) + - [▶ Evaluation time discrepancy](#-evaluation-time-discrepancy) + - [💡 Explanation](#-explanation-8) + - [▶ `is not ...` is not `is (not ...)`](#-is-not--is-not-is-not-) + - [💡 Explanation](#-explanation-9) + - [▶ A tic-tac-toe where X wins in the first attempt!](#-a-tic-tac-toe-where-x-wins-in-the-first-attempt) + - [💡 Explanation:](#-explanation-10) + - [▶ Schrödinger's variable \*](#-schrödingers-variable-) + - [💡 Explanation:](#-explanation-11) + - [▶ The chicken-egg problem \*](#-the-chicken-egg-problem-) + - [💡 Explanation](#-explanation-12) + - [▶ Subclass relationships](#-subclass-relationships) + - [💡 Explanation:](#-explanation-13) + - [▶ Methods equality and identity](#-methods-equality-and-identity) + - [💡 Explanation](#-explanation-14) + - [▶ All-true-ation \*](#-all-true-ation-) + - [💡 Explanation:](#-explanation-15) + - [💡 Explanation:](#-explanation-16) + - [▶ Strings and the backslashes](#-strings-and-the-backslashes) + - [💡 Explanation](#-explanation-17) + - [▶ not knot!](#-not-knot) + - [💡 Explanation:](#-explanation-18) + - [▶ Half triple-quoted strings](#-half-triple-quoted-strings) + - [💡 Explanation:](#-explanation-19) + - [▶ What's wrong with booleans?](#-whats-wrong-with-booleans) + - [💡 Explanation:](#-explanation-20) + - [▶ Class attributes and instance attributes](#-class-attributes-and-instance-attributes) + - [💡 Explanation:](#-explanation-21) + - [▶ yielding None](#-yielding-none) + - [💡 Explanation:](#-explanation-22) + - [▶ Yielding from... return! \*](#-yielding-from-return-) + - [💡 Explanation:](#-explanation-23) + - [▶ Nan-reflexivity \*](#-nan-reflexivity-) + - [💡 Explanation:](#-explanation-24) + - [▶ Mutating the immutable!](#-mutating-the-immutable) + - [💡 Explanation:](#-explanation-25) + - [▶ The disappearing variable from outer scope](#-the-disappearing-variable-from-outer-scope) + - [💡 Explanation:](#-explanation-26) + - [▶ The mysterious key type conversion](#-the-mysterious-key-type-conversion) + - [💡 Explanation:](#-explanation-27) + - [▶ Let's see if you can guess this?](#-lets-see-if-you-can-guess-this) + - [💡 Explanation:](#-explanation-28) + - [▶ Exceeds the limit for integer string conversion](#-exceeds-the-limit-for-integer-string-conversion) + - [💡 Explanation:](#-explanation-29) + - [Section: Slippery Slopes](#section-slippery-slopes) + - [▶ Modifying a dictionary while iterating over it](#-modifying-a-dictionary-while-iterating-over-it) + - [💡 Explanation:](#-explanation-30) + - [▶ Stubborn `del` operation](#-stubborn-del-operation) + - [💡 Explanation:](#-explanation-31) + - [▶ The out of scope variable](#-the-out-of-scope-variable) + - [💡 Explanation:](#-explanation-32) + - [▶ Deleting a list item while iterating](#-deleting-a-list-item-while-iterating) + - [💡 Explanation:](#-explanation-33) + - [▶ Lossy zip of iterators \*](#-lossy-zip-of-iterators-) + - [💡 Explanation:](#-explanation-34) + - [▶ Loop variables leaking out!](#-loop-variables-leaking-out) + - [💡 Explanation:](#-explanation-35) + - [▶ Beware of default mutable arguments!](#-beware-of-default-mutable-arguments) + - [💡 Explanation:](#-explanation-36) + - [▶ Catching the Exceptions](#-catching-the-exceptions) + - [💡 Explanation](#-explanation-37) + - [▶ Same operands, different story!](#-same-operands-different-story) + - [💡 Explanation:](#-explanation-38) + - [▶ Name resolution ignoring class scope](#-name-resolution-ignoring-class-scope) + - [💡 Explanation](#-explanation-39) + - [▶ Rounding like a banker \*](#-rounding-like-a-banker-) + - [💡 Explanation:](#-explanation-40) + - [▶ Needles in a Haystack \*](#-needles-in-a-haystack-) + - [💡 Explanation:](#-explanation-41) + - [▶ Splitsies \*](#-splitsies-) + - [💡 Explanation:](#-explanation-42) + - [▶ Wild imports \*](#-wild-imports-) + - [💡 Explanation:](#-explanation-43) + - [▶ All sorted? \*](#-all-sorted-) + - [💡 Explanation:](#-explanation-44) + - [▶ Midnight time doesn't exist?](#-midnight-time-doesnt-exist) + - [💡 Explanation:](#-explanation-45) + - [Section: The Hidden treasures!](#section-the-hidden-treasures) + - [▶ Okay Python, Can you make me fly?](#-okay-python-can-you-make-me-fly) + - [💡 Explanation:](#-explanation-46) + - [▶ `goto`, but why?](#-goto-but-why) + - [💡 Explanation:](#-explanation-47) + - [▶ Brace yourself!](#-brace-yourself) + - [💡 Explanation:](#-explanation-48) + - [▶ Let's meet Friendly Language Uncle For Life](#-lets-meet-friendly-language-uncle-for-life) + - [💡 Explanation:](#-explanation-49) + - [▶ Even Python understands that love is complicated](#-even-python-understands-that-love-is-complicated) + - [💡 Explanation:](#-explanation-50) + - [▶ Yes, it exists!](#-yes-it-exists) + - [💡 Explanation:](#-explanation-51) + - [▶ Ellipsis \*](#-ellipsis-) + - [💡 Explanation](#-explanation-52) + - [▶ Inpinity](#-inpinity) + - [💡 Explanation:](#-explanation-53) + - [▶ Let's mangle](#-lets-mangle) + - [💡 Explanation:](#-explanation-54) + - [Section: Appearances are deceptive!](#section-appearances-are-deceptive) + - [▶ Skipping lines?](#-skipping-lines) + - [💡 Explanation](#-explanation-55) + - [▶ Teleportation](#-teleportation) + - [💡 Explanation:](#-explanation-56) + - [▶ Well, something is fishy...](#-well-something-is-fishy) + - [💡 Explanation](#-explanation-57) + - [Section: Miscellaneous](#section-miscellaneous) + - [▶ `+=` is faster](#--is-faster) + - [💡 Explanation:](#-explanation-58) + - [▶ Let's make a giant string!](#-lets-make-a-giant-string) + - [💡 Explanation](#-explanation-59) + - [▶ Slowing down `dict` lookups \*](#-slowing-down-dict-lookups-) + - [💡 Explanation:](#-explanation-60) + - [▶ Bloating instance `dict`s \*](#-bloating-instance-dicts-) + - [💡 Explanation:](#-explanation-61) + - [▶ Minor Ones \*](#-minor-ones-) - [Contributing](#contributing) - [Acknowledgements](#acknowledgements) + - [Some nice Links!](#some-nice-links) - [🎓 License](#-license) - * [Surprise your friends as well!](#surprise-your-friends-as-well) - * [More content like this?](#more-content-like-this) + - [Surprise your friends as well!](#surprise-your-friends-as-well) + - [Need a pdf version?](#need-a-pdf-version) # Structure of the Examples -All the examples are structured like below: +Alle Beispiele sind nach folgendem Muster aufgebaut: > ### ▶ Some fancy Title > > ```py > # Set up the code. -> # Preparation for the magic... +> # Vorbereitung fĂŒr etwas Magisches... > ``` > > **Output (Python version(s)):** @@ -127,9 +191,9 @@ All the examples are structured like below: > > #### 💡 Explanation: > -> * Brief explanation of what's happening and why is it happening. +> * Kurze ErklĂ€rung was und warum es passiert. > ```py -> # Set up code +> # Aufsetzen des Codes > # More examples for further clarification (if necessary) > ``` > **Output (Python version(s)):** @@ -139,35 +203,36 @@ All the examples are structured like below: > # some justified output > ``` -**Note:** All the examples are tested on Python 3.5.2 interactive interpreter, and they should work for all the Python versions unless explicitly specified before the output. +**Note:** Alle Beispiele sind mit Pythons 3.5.2 interaktiven Interpreter getestet, und sie sollten fĂŒr alle Python Versionen funktionieren. Ausnahmen werden vor dem Output kenntlich gemacht. -# Usage +# Benutzung -A nice way to get the most out of these examples, in my opinion, is to read them in sequential order, and for every example: -- Carefully read the initial code for setting up the example. If you're an experienced Python programmer, you'll successfully anticipate what's going to happen next most of the time. -- Read the output snippets and, - + Check if the outputs are the same as you'd expect. - + Make sure if you know the exact reason behind the output being the way it is. - - If the answer is no (which is perfectly okay), take a deep breath, and read the explanation (and if you still don't understand, shout out! and create an issue [here](https://github.com/satwikkansal/wtfpython/issues/new)). - - If yes, give a gentle pat on your back, and you may skip to the next example. +Ein guter Weg, um die Beispiele bestmöglich zu nutzen, ist es, sie von anfang an durchzugehen und bei jedem Beispiel folgendes zu tun: +- Lese vorsichtig den initialen Code des Beispiels. Wenn du ein erfahrener Python-Programmierer bist, wirst du wahrscheinlich wissen, was +als nĂ€chstes kommt. +- Lies die Schnippsel durch und + + ÜberprĂŒfe, dass die Ausgabe die ist, die du erwartet hast + + Weißt du, warum sich die Ausgabe so gestaltet, wie sie es tut ? + - Wenn die Antwort Nein ist (was vollkommen in Ordnung ist), nimm einen tiefen Atemzug, und lies dir die ErklĂ€rung durch. Wenn du es dann immernoch nicht verstanden hast, frage nach Hilfe, indem du [hier](https://github.com/satwikkansal/wtfpython/issues/new) ein Issue erstellst. + - Wenn Ja, kannst du dir auf die Schulter klopfen und zum nĂ€chsten Beispiel springen. -PS: You can also read WTFPython at the command line using the [pypi package](https://pypi.python.org/pypi/wtfpython), +PS: Du kannst dir auch WTFPython im Terminal ansehen, indem du das [pypi package](https://pypi.python.org/pypi/wtfpython) nutzt: ```sh $ pip install wtfpython -U $ wtfpython ``` --- -# 👀 Examples +# 👀 Beispiele -## Section: Strain your brain! +## Kapitel: Strain your brain! ### ▶ First things first! * -For some reason, the Python 3.8's "Walrus" operator (`:=`) has become quite popular. Let's check it out, +Aus irgendwelchen GrĂŒnden ist der "Walrus" Operator (`:=`) in Python 3.8 ziemlich beliebt. Lass uns starten, 1\. @@ -184,7 +249,7 @@ File "", line 1 ^ SyntaxError: invalid syntax ->>> (a := "wtf_walrus") # This works though +>>> (a := "wtf_walrus") # Das funktioniert merkwĂŒrdigerweise 'wtf_walrus' >>> a 'wtf_walrus' @@ -213,10 +278,10 @@ SyntaxError: invalid syntax ^ SyntaxError: invalid syntax ->>> (a, b := 16, 19) # This prints out a weird 3-tuple +>>> (a, b := 16, 19) # Dies gibt ein eigenartiges 3-Tupel aus (6, 16, 19) ->>> a # a is still unchanged? +>>> a # Ist a immernoch unverĂ€ndert ? 6 >>> b @@ -225,7 +290,7 @@ SyntaxError: invalid syntax -#### 💡 Explanation +#### 💡 ErklĂ€rung **Quick walrus operator refresher** From 25b43e62726ea917cc07f3a7e6778b79a54eca33 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Mon, 17 Apr 2023 20:54:07 +0200 Subject: [PATCH 02/20] translation #2 --- README.md | 594 +++++++++++++++++++++++++++--------------------------- 1 file changed, 297 insertions(+), 297 deletions(-) diff --git a/README.md b/README.md index ede6948b..41778a95 100644 --- a/README.md +++ b/README.md @@ -26,184 +26,184 @@ Also, los gehts... - [Inhaltsverzeichnis](#inhaltsverzeichnis) -- [Structure of the Examples](#structure-of-the-examples) +- [Sruktur der Beispiele](#sruktur-der-beispiele) - [Benutzung](#benutzung) - [👀 Beispiele](#-beispiele) - [Kapitel: Strain your brain!](#kapitel-strain-your-brain) - - [▶ First things first! \*](#-first-things-first-) + - [▶ Das Wichtigste zuerst! \*](#-das-wichtigste-zuerst-) - [💡 ErklĂ€rung](#-erklĂ€rung) - - [▶ Strings can be tricky sometimes](#-strings-can-be-tricky-sometimes) - - [💡 Explanation:](#-explanation) - - [▶ Be careful with chained operations](#-be-careful-with-chained-operations) - - [💡 Explanation:](#-explanation-1) + - [▶ Strings können manchmal schwierig sein](#-strings-können-manchmal-schwierig-sein) + - [💡 ErklĂ€rung:](#-erklĂ€rung-1) + - [▶ Vorsicht bei verketteten Operationen](#-vorsicht-bei-verketteten-operationen) + - [💡 ErklĂ€rung:](#-erklĂ€rung-2) - [▶ How not to use `is` operator](#-how-not-to-use-is-operator) - - [💡 Explanation:](#-explanation-2) + - [💡 ErklĂ€rung:](#-erklĂ€rung-3) - [▶ Hash brownies](#-hash-brownies) - - [💡 Explanation](#-explanation-3) + - [💡 ErklĂ€rung](#-erklĂ€rung-4) - [▶ Deep down, we're all the same.](#-deep-down-were-all-the-same) - - [💡 Explanation:](#-explanation-4) + - [💡 ErklĂ€rung:](#-erklĂ€rung-5) - [▶ Disorder within order \*](#-disorder-within-order-) - - [💡 Explanation:](#-explanation-5) + - [💡 ErklĂ€rung:](#-erklĂ€rung-6) - [▶ Keep trying... \*](#-keep-trying-) - - [💡 Explanation:](#-explanation-6) + - [💡 ErklĂ€rung:](#-erklĂ€rung-7) - [▶ For what?](#-for-what) - - [💡 Explanation:](#-explanation-7) + - [💡 ErklĂ€rung:](#-erklĂ€rung-8) - [▶ Evaluation time discrepancy](#-evaluation-time-discrepancy) - - [💡 Explanation](#-explanation-8) + - [💡 ErklĂ€rung](#-erklĂ€rung-9) - [▶ `is not ...` is not `is (not ...)`](#-is-not--is-not-is-not-) - - [💡 Explanation](#-explanation-9) + - [💡 ErklĂ€rung](#-erklĂ€rung-10) - [▶ A tic-tac-toe where X wins in the first attempt!](#-a-tic-tac-toe-where-x-wins-in-the-first-attempt) - - [💡 Explanation:](#-explanation-10) + - [💡 ErklĂ€rung:](#-erklĂ€rung-11) - [▶ Schrödinger's variable \*](#-schrödingers-variable-) - - [💡 Explanation:](#-explanation-11) + - [💡 ErklĂ€rung:](#-erklĂ€rung-12) - [▶ The chicken-egg problem \*](#-the-chicken-egg-problem-) - - [💡 Explanation](#-explanation-12) + - [💡 ErklĂ€rung](#-erklĂ€rung-13) - [▶ Subclass relationships](#-subclass-relationships) - - [💡 Explanation:](#-explanation-13) + - [💡 ErklĂ€rung:](#-erklĂ€rung-14) - [▶ Methods equality and identity](#-methods-equality-and-identity) - - [💡 Explanation](#-explanation-14) + - [💡 ErklĂ€rung](#-erklĂ€rung-15) - [▶ All-true-ation \*](#-all-true-ation-) - - [💡 Explanation:](#-explanation-15) - - [💡 Explanation:](#-explanation-16) + - [💡 ErklĂ€rung:](#-erklĂ€rung-16) + - [💡 ErklĂ€rung:](#-erklĂ€rung-17) - [▶ Strings and the backslashes](#-strings-and-the-backslashes) - - [💡 Explanation](#-explanation-17) + - [💡 ErklĂ€rung](#-erklĂ€rung-18) - [▶ not knot!](#-not-knot) - - [💡 Explanation:](#-explanation-18) + - [💡 ErklĂ€rung:](#-erklĂ€rung-19) - [▶ Half triple-quoted strings](#-half-triple-quoted-strings) - - [💡 Explanation:](#-explanation-19) + - [💡 ErklĂ€rung:](#-erklĂ€rung-20) - [▶ What's wrong with booleans?](#-whats-wrong-with-booleans) - - [💡 Explanation:](#-explanation-20) + - [💡 ErklĂ€rung:](#-erklĂ€rung-21) - [▶ Class attributes and instance attributes](#-class-attributes-and-instance-attributes) - - [💡 Explanation:](#-explanation-21) + - [💡 ErklĂ€rung:](#-erklĂ€rung-22) - [▶ yielding None](#-yielding-none) - - [💡 Explanation:](#-explanation-22) + - [💡 ErklĂ€rung:](#-erklĂ€rung-23) - [▶ Yielding from... return! \*](#-yielding-from-return-) - - [💡 Explanation:](#-explanation-23) + - [💡 ErklĂ€rung:](#-erklĂ€rung-24) - [▶ Nan-reflexivity \*](#-nan-reflexivity-) - - [💡 Explanation:](#-explanation-24) + - [💡 ErklĂ€rung:](#-erklĂ€rung-25) - [▶ Mutating the immutable!](#-mutating-the-immutable) - - [💡 Explanation:](#-explanation-25) + - [💡 ErklĂ€rung:](#-erklĂ€rung-26) - [▶ The disappearing variable from outer scope](#-the-disappearing-variable-from-outer-scope) - - [💡 Explanation:](#-explanation-26) + - [💡 ErklĂ€rung:](#-erklĂ€rung-27) - [▶ The mysterious key type conversion](#-the-mysterious-key-type-conversion) - - [💡 Explanation:](#-explanation-27) + - [💡 ErklĂ€rung:](#-erklĂ€rung-28) - [▶ Let's see if you can guess this?](#-lets-see-if-you-can-guess-this) - - [💡 Explanation:](#-explanation-28) + - [💡 ErklĂ€rung:](#-erklĂ€rung-29) - [▶ Exceeds the limit for integer string conversion](#-exceeds-the-limit-for-integer-string-conversion) - - [💡 Explanation:](#-explanation-29) + - [💡 ErklĂ€rung:](#-erklĂ€rung-30) - [Section: Slippery Slopes](#section-slippery-slopes) - [▶ Modifying a dictionary while iterating over it](#-modifying-a-dictionary-while-iterating-over-it) - - [💡 Explanation:](#-explanation-30) + - [💡 ErklĂ€rung:](#-erklĂ€rung-31) - [▶ Stubborn `del` operation](#-stubborn-del-operation) - - [💡 Explanation:](#-explanation-31) + - [💡 ErklĂ€rung:](#-erklĂ€rung-32) - [▶ The out of scope variable](#-the-out-of-scope-variable) - - [💡 Explanation:](#-explanation-32) + - [💡 ErklĂ€rung:](#-erklĂ€rung-33) - [▶ Deleting a list item while iterating](#-deleting-a-list-item-while-iterating) - - [💡 Explanation:](#-explanation-33) + - [💡 ErklĂ€rung:](#-erklĂ€rung-34) - [▶ Lossy zip of iterators \*](#-lossy-zip-of-iterators-) - - [💡 Explanation:](#-explanation-34) + - [💡 ErklĂ€rung:](#-erklĂ€rung-35) - [▶ Loop variables leaking out!](#-loop-variables-leaking-out) - - [💡 Explanation:](#-explanation-35) + - [💡 ErklĂ€rung:](#-erklĂ€rung-36) - [▶ Beware of default mutable arguments!](#-beware-of-default-mutable-arguments) - - [💡 Explanation:](#-explanation-36) + - [💡 ErklĂ€rung:](#-erklĂ€rung-37) - [▶ Catching the Exceptions](#-catching-the-exceptions) - - [💡 Explanation](#-explanation-37) + - [💡 ErklĂ€rung](#-erklĂ€rung-38) - [▶ Same operands, different story!](#-same-operands-different-story) - - [💡 Explanation:](#-explanation-38) + - [💡 ErklĂ€rung:](#-erklĂ€rung-39) - [▶ Name resolution ignoring class scope](#-name-resolution-ignoring-class-scope) - - [💡 Explanation](#-explanation-39) + - [💡 ErklĂ€rung](#-erklĂ€rung-40) - [▶ Rounding like a banker \*](#-rounding-like-a-banker-) - - [💡 Explanation:](#-explanation-40) + - [💡 ErklĂ€rung:](#-erklĂ€rung-41) - [▶ Needles in a Haystack \*](#-needles-in-a-haystack-) - - [💡 Explanation:](#-explanation-41) + - [💡 ErklĂ€rung:](#-erklĂ€rung-42) - [▶ Splitsies \*](#-splitsies-) - - [💡 Explanation:](#-explanation-42) + - [💡 ErklĂ€rung:](#-erklĂ€rung-43) - [▶ Wild imports \*](#-wild-imports-) - - [💡 Explanation:](#-explanation-43) + - [💡 ErklĂ€rung:](#-erklĂ€rung-44) - [▶ All sorted? \*](#-all-sorted-) - - [💡 Explanation:](#-explanation-44) + - [💡 ErklĂ€rung:](#-erklĂ€rung-45) - [▶ Midnight time doesn't exist?](#-midnight-time-doesnt-exist) - - [💡 Explanation:](#-explanation-45) + - [💡 ErklĂ€rung:](#-erklĂ€rung-46) - [Section: The Hidden treasures!](#section-the-hidden-treasures) - [▶ Okay Python, Can you make me fly?](#-okay-python-can-you-make-me-fly) - - [💡 Explanation:](#-explanation-46) + - [💡 ErklĂ€rung:](#-erklĂ€rung-47) - [▶ `goto`, but why?](#-goto-but-why) - - [💡 Explanation:](#-explanation-47) + - [💡 ErklĂ€rung:](#-erklĂ€rung-48) - [▶ Brace yourself!](#-brace-yourself) - - [💡 Explanation:](#-explanation-48) + - [💡 ErklĂ€rung:](#-erklĂ€rung-49) - [▶ Let's meet Friendly Language Uncle For Life](#-lets-meet-friendly-language-uncle-for-life) - - [💡 Explanation:](#-explanation-49) + - [💡 ErklĂ€rung:](#-erklĂ€rung-50) - [▶ Even Python understands that love is complicated](#-even-python-understands-that-love-is-complicated) - - [💡 Explanation:](#-explanation-50) + - [💡 ErklĂ€rung:](#-erklĂ€rung-51) - [▶ Yes, it exists!](#-yes-it-exists) - - [💡 Explanation:](#-explanation-51) + - [💡 ErklĂ€rung:](#-erklĂ€rung-52) - [▶ Ellipsis \*](#-ellipsis-) - - [💡 Explanation](#-explanation-52) + - [💡 ErklĂ€rung](#-erklĂ€rung-53) - [▶ Inpinity](#-inpinity) - - [💡 Explanation:](#-explanation-53) + - [💡 ErklĂ€rung:](#-erklĂ€rung-54) - [▶ Let's mangle](#-lets-mangle) - - [💡 Explanation:](#-explanation-54) + - [💡 ErklĂ€rung:](#-erklĂ€rung-55) - [Section: Appearances are deceptive!](#section-appearances-are-deceptive) - [▶ Skipping lines?](#-skipping-lines) - - [💡 Explanation](#-explanation-55) + - [💡 ErklĂ€rung](#-erklĂ€rung-56) - [▶ Teleportation](#-teleportation) - - [💡 Explanation:](#-explanation-56) + - [💡 ErklĂ€rung:](#-erklĂ€rung-57) - [▶ Well, something is fishy...](#-well-something-is-fishy) - - [💡 Explanation](#-explanation-57) + - [💡 ErklĂ€rung](#-erklĂ€rung-58) - [Section: Miscellaneous](#section-miscellaneous) - [▶ `+=` is faster](#--is-faster) - - [💡 Explanation:](#-explanation-58) + - [💡 ErklĂ€rung:](#-erklĂ€rung-59) - [▶ Let's make a giant string!](#-lets-make-a-giant-string) - - [💡 Explanation](#-explanation-59) + - [💡 ErklĂ€rung](#-erklĂ€rung-60) - [▶ Slowing down `dict` lookups \*](#-slowing-down-dict-lookups-) - - [💡 Explanation:](#-explanation-60) + - [💡 ErklĂ€rung:](#-erklĂ€rung-61) - [▶ Bloating instance `dict`s \*](#-bloating-instance-dicts-) - - [💡 Explanation:](#-explanation-61) + - [💡 ErklĂ€rung:](#-erklĂ€rung-62) - [▶ Minor Ones \*](#-minor-ones-) - [Contributing](#contributing) -- [Acknowledgements](#acknowledgements) - - [Some nice Links!](#some-nice-links) +- [Anerkennung](#anerkennung) + - [Ein paar nĂŒtzliche Links!](#ein-paar-nĂŒtzliche-links) - [🎓 License](#-license) - - [Surprise your friends as well!](#surprise-your-friends-as-well) - - [Need a pdf version?](#need-a-pdf-version) + - [Überrasche auch deine Freunde!](#ĂŒberrasche-auch-deine-freunde) + - [Brauchst du eine pdf version?](#brauchst-du-eine-pdf-version) -# Structure of the Examples +# Sruktur der Beispiele Alle Beispiele sind nach folgendem Muster aufgebaut: -> ### ▶ Some fancy Title +> ### ▶ Ein schicker Titel > > ```py -> # Set up the code. +> # Vorbereitung des Codes. > # Vorbereitung fĂŒr etwas Magisches... > ``` > -> **Output (Python version(s)):** +> **Ausgabe (Python version(en)):** > > ```py > >>> triggering_statement -> Some unexpected output +> Irgendeine unerwartete Ausgabe > ``` -> (Optional): One line describing the unexpected output. +> (Optional): Eine Zeile, die die unerwartete Ausgabe beschreibt. > > -> #### 💡 Explanation: +> #### 💡 ErklĂ€rung: > > * Kurze ErklĂ€rung was und warum es passiert. > ```py > # Aufsetzen des Codes -> # More examples for further clarification (if necessary) +> # Mehr Beispiele fĂŒr ein besseres VerstĂ€ndnis (wenn erforderlich) > ``` -> **Output (Python version(s)):** +> **Ausgabe (Python version(en)):** > > ```py -> >>> trigger # some example that makes it easy to unveil the magic -> # some justified output +> >>> trigger # Ein Beispiel, das es einfach macht, die Magie zu verstehen +> # Eine begrĂŒndete Ausgabe > ``` -**Note:** Alle Beispiele sind mit Pythons 3.5.2 interaktiven Interpreter getestet, und sie sollten fĂŒr alle Python Versionen funktionieren. Ausnahmen werden vor dem Output kenntlich gemacht. +**Note:** Alle Beispiele sind mit Pythons 3.5.2 interaktiven Interpreter getestet, und sie sollten fĂŒr alle Python Versionen funktionieren. Ausnahmen werden vor dem Ausgabe kenntlich gemacht. # Benutzung @@ -227,7 +227,7 @@ $ wtfpython ## Kapitel: Strain your brain! -### ▶ First things first! * +### ▶ Das Wichtigste zuerst! * @@ -269,7 +269,7 @@ SyntaxError: invalid syntax >>> a 6 ->>> a, b = 6, 9 # Typical unpacking +>>> a, b = 6, 9 # Typisches Auspacken >>> a, b (6, 9) >>> (a, b = 16, 19) # Oops @@ -292,31 +292,32 @@ SyntaxError: invalid syntax #### 💡 ErklĂ€rung -**Quick walrus operator refresher** +**Schneller RĂŒckblick zum Walrus Operator** -The Walrus operator (`:=`) was introduced in Python 3.8, it can be useful in situations where you'd want to assign values to variables within an expression. +Der Walrus Operator (`:=`) wurde in Python 3.8 eingefĂŒhrt. Er kann in Situationen sinvoll sein, in +denen du ein Wert einer Variablen in einem Ausdruck zuweisen möchtest. ```py -def some_func(): - # Assume some expensive computation here +def irgendeine_funktion(): + # Irgendeine Berechnung, die teuer ist (=> sehr viel Zeit und Ressourcen in Aspruch nimmt) # time.sleep(1000) return 5 -# So instead of, -if some_func(): - print(some_func()) # Which is bad practice since computation is happening twice +# Anstatt: +if irgendeine_funktion(): + print(irgendeine_funktion()) # Schlechter Stil, da die Funktion zweimal aufgerufen wird -# or -a = some_func() +# Oder: +a = irgendeine_funktion() if a: print(a) -# Now you can concisely write -if a := some_func(): +# Nun kannst du folgendes schreiben: +if a := irgendeine_funktion(): print(a) ``` -**Output (> 3.8):** +**Ausgabe (> 3.8):** ```py 5 @@ -324,7 +325,7 @@ if a := some_func(): 5 ``` -This saved one line of code, and implicitly prevented invoking `some_func` twice. +Das hat uns eine Zeile Code erspart. Zudem spart es einen zusĂ€tzlichen Aufruf der Funktion `irgendeine_funktion`. - Unparenthesized "assignment expression" (use of walrus operator), is restricted at the top level, hence the `SyntaxError` in the `a := "wtf_walrus"` statement of the first snippet. Parenthesizing it worked as expected and assigned `a`. @@ -332,7 +333,7 @@ This saved one line of code, and implicitly prevented invoking `some_func` twice - The syntax of the Walrus operator is of the form `NAME:= expr`, where `NAME` is a valid identifier, and `expr` is a valid expression. Hence, iterable packing and unpacking are not supported which means, - - `(a := 6, 9)` is equivalent to `((a := 6), 9)` and ultimately `(a, 9) ` (where `a`'s value is 6') + - `(a := 6, 9)` ist Ă€quivalent zu `((a := 6), 9)` und zu `(a, 9) ` (where `a`'s value is 6') ```py >>> (a := 6, 9) == ((a := 6), 9) @@ -344,20 +345,20 @@ This saved one line of code, and implicitly prevented invoking `some_func` twice True ``` - - Similarly, `(a, b := 16, 19)` is equivalent to `(a, (b := 16), 19)` which is nothing but a 3-tuple. + - Ähnlich: `(a, b := 16, 19)` ist Ă€quivalent zu `(a, (b := 16), 19)`, was einfach ein 3-Tupel ist. --- -### ▶ Strings can be tricky sometimes +### ▶ Strings können manchmal schwierig sein 1\. ```py ->>> a = "some_string" +>>> a = "irgendein_string" >>> id(a) 140420665652016 ->>> id("some" + "_" + "string") # Notice that both the ids are same. +>>> id("irgendein" + "_" + "string") # Beachte, dass beide ids dieselben sind. 140420665652016 ``` @@ -379,26 +380,26 @@ False ```py >>> a, b = "wtf!", "wtf!" ->>> a is b # All versions except 3.7.x +>>> a is b # Alle Versionen außer 3.7.x True >>> a = "wtf!"; b = "wtf!" ->>> a is b # This will print True or False depending on where you're invoking it (python shell / ipython / as a script) +>>> a is b # Das wird True oder False ausgeben, je nach dem wo du es aufrufst (Python Shell / iPython / in einem Skript) False ``` ```py -# This time in file some_file.py +# Dieses mal in einer Datei: some_file.py a = "wtf!" b = "wtf!" print(a is b) -# prints True when the module is invoked! +# Gibt True aus, wenn das Modul aufgerufen wird! ``` 4\. -**Output (< Python3.7 )** +**Ausgabe (< Python3.7 )** ```py >>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa' @@ -407,9 +408,9 @@ True False ``` -Makes sense, right? +Ergibt Sinn, Oder? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: + The behavior in first and second snippets is due to a CPython optimization (called string interning) that tries to use existing immutable objects in some cases rather than creating a new object every time. + After being "interned," many variables may reference the same string object in memory (saving memory thereby). + In the snippets above, strings are implicitly interned. The decision of when to implicitly intern a string is implementation-dependent. There are some rules that can be used to guess if a string will be interned or not: @@ -419,13 +420,13 @@ Makes sense, right? ![image](/images/string-intern/string_intern.png) + When `a` and `b` are set to `"wtf!"` in the same line, the Python interpreter creates a new object, then references the second variable at the same time. If you do it on separate lines, it doesn't "know" that there's already `"wtf!"` as an object (because `"wtf!"` is not implicitly interned as per the facts mentioned above). It's a compile-time optimization. This optimization doesn't apply to 3.7.x versions of CPython (check this [issue](https://github.com/satwikkansal/wtfpython/issues/100) for more discussion). + A compile unit in an interactive environment like IPython consists of a single statement, whereas it consists of the entire module in case of modules. `a, b = "wtf!", "wtf!"` is single statement, whereas `a = "wtf!"; b = "wtf!"` are two statements in a single line. This explains why the identities are different in `a = "wtf!"; b = "wtf!"`, and also explain why they are same when invoked in `some_file.py` -+ The abrupt change in the output of the fourth snippet is due to a [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) technique known as Constant folding. This means the expression `'a'*20` is replaced by `'aaaaaaaaaaaaaaaaaaaa'` during compilation to save a few clock cycles during runtime. Constant folding only occurs for strings having a length of less than 21. (Why? Imagine the size of `.pyc` file generated as a result of the expression `'a'*10**10`). [Here's](https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288) the implementation source for the same. ++ The abrupt change in the Ausgabe of the fourth snippet is due to a [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) technique known as Constant folding. This means the expression `'a'*20` is replaced by `'aaaaaaaaaaaaaaaaaaaa'` during compilation to save a few clock cycles during runtime. Constant folding only occurs for strings having a length of less than 21. (Why? Imagine the size of `.pyc` file generated as a result of the expression `'a'*10**10`). [Here's](https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288) the implementation source for the same. + Note: In Python 3.7, Constant folding was moved out from peephole optimizer to the new AST optimizer with some change in logic as well, so the fourth snippet doesn't work for Python 3.7. You can read more about the change [here](https://bugs.python.org/issue11549). --- -### ▶ Be careful with chained operations +### ▶ Vorsicht bei verketteten Operationen ```py >>> (False == False) in [False] # makes sense @@ -448,7 +449,7 @@ False False ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: As per https://docs.python.org/3/reference/expressions.html#comparisons @@ -503,7 +504,7 @@ True ``` 3\. -**Output** +**Ausgabe** ```py >>> a, b = 257, 257 @@ -511,7 +512,7 @@ True True ``` -**Output (Python 3.7.x specifically)** +**Ausgabe (Python 3.7.x specifically)** ```py >>> a, b = 257, 257 @@ -519,7 +520,7 @@ True False ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: **The difference between `is` and `==`** @@ -564,7 +565,7 @@ Similar optimization applies to other **immutable** objects like empty tuples as **Both `a` and `b` refer to the same object when initialized with same value in the same line.** -**Output** +**Ausgabe** ```py >>> a, b = 257, 257 @@ -605,7 +606,7 @@ some_dict[5.0] = "Ruby" some_dict[5] = "Python" ``` -**Output:** +**Ausgabe:** ```py >>> some_dict[5.5] @@ -625,7 +626,7 @@ complex So, why is Python all over the place? -#### 💡 Explanation +#### 💡 ErklĂ€rung * Uniqueness of keys in a Python dictionary is by *equivalence*, not identity. So even though `5`, `5.0`, and `5 + 0j` are distinct objects of different types, since they're equal, they can't both be in the same `dict` (or `set`). As soon as you insert any one of them, attempting to look up any distinct but equivalent key will succeed with the original mapped value (rather than failing with a `KeyError`): ```py @@ -668,7 +669,7 @@ class WTF: pass ``` -**Output:** +**Ausgabe:** ```py >>> WTF() == WTF() # two different instances can't be equal False @@ -680,7 +681,7 @@ True True ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * When `id` was called, Python created a `WTF` class object and passed it to the `id` function. The `id` function takes its `id` (its memory location), and throws away the object. The object is destroyed. * When we do this twice in succession, Python allocates the same memory location to this second object as well. Since (in CPython) `id` uses the memory location as the object id, the id of the two objects is the same. @@ -692,7 +693,7 @@ True def __del__(self): print("D") ``` - **Output:** + **Ausgabe:** ```py >>> WTF() is WTF() I @@ -738,7 +739,7 @@ class OrderedDictWithHash(OrderedDict): __hash__ = lambda self: 0 ``` -**Output** +**Ausgabe** ```py >>> dictionary == ordered_dict # If a == b True @@ -771,7 +772,7 @@ TypeError: unhashable type: 'dict' What is going on here? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - The reason why intransitive equality didn't hold among `dictionary`, `ordered_dict` and `another_ordered_dict` is because of the way `__eq__` method is implemented in `OrderedDict` class. From the [docs](https://docs.python.org/3/library/collections.html#ordereddict-objects) @@ -840,7 +841,7 @@ def one_more_func(): # A gotcha! print("Zero division error occurred", e) ``` -**Output:** +**Ausgabe:** ```py >>> some_func() @@ -861,7 +862,7 @@ Iteration 0 ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - When a `return`, `break` or `continue` statement is executed in the `try` suite of a "try
finally" statement, the `finally` clause is also executed on the way out. - The return value of a function is determined by the last `return` statement executed. Since the `finally` clause always executes, a `return` statement executed in the `finally` clause will always be the last one executed. @@ -879,13 +880,13 @@ for i, some_dict[i] in enumerate(some_string): i = 10 ``` -**Output:** +**Ausgabe:** ```py >>> some_dict # An indexed dict appears. {0: 'w', 1: 't', 2: 'f'} ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * A `for` statement is defined in the [Python grammar](https://docs.python.org/3/reference/grammar.html) as: ``` @@ -899,7 +900,7 @@ for i, some_dict[i] in enumerate(some_string): i = 10 ``` - **Output:** + **Ausgabe:** ``` 0 1 @@ -909,7 +910,7 @@ for i, some_dict[i] in enumerate(some_string): Did you expect the loop to run just once? - **💡 Explanation:** + **💡 ErklĂ€rung:** - The assignment statement `i = 10` never affects the iterations of the loop because of the way for loops work in Python. Before the beginning of every iteration, the next item provided by the iterator (`range(4)` in this case) is unpacked and assigned the target list variables (`i` in this case). @@ -933,7 +934,7 @@ gen = (x for x in array if array.count(x) > 0) array = [2, 8, 22] ``` -**Output:** +**Ausgabe:** ```py >>> print(list(gen)) # Where did the other values go? @@ -952,7 +953,7 @@ gen_2 = (x for x in array_2) array_2[:] = [1,2,3,4,5] ``` -**Output:** +**Ausgabe:** ```py >>> print(list(gen_1)) [1, 2, 3, 4] @@ -972,17 +973,17 @@ array_3 = [4, 5, 6] array_4 = [400, 500, 600] ``` -**Output:** +**Ausgabe:** ```py >>> print(list(gen)) [401, 501, 601, 402, 502, 602, 403, 503, 603] ``` -#### 💡 Explanation +#### 💡 ErklĂ€rung - In a [generator](https://wiki.python.org/moin/Generators) expression, the `in` clause is evaluated at declaration time, but the conditional clause is evaluated at runtime. - So before runtime, `array` is re-assigned to the list `[2, 8, 22]`, and since out of `1`, `8` and `15`, only the count of `8` is greater than `0`, the generator only yields `8`. -- The differences in the output of `g1` and `g2` in the second part is due the way variables `array_1` and `array_2` are re-assigned values. +- The differences in the Ausgabe of `g1` and `g2` in the second part is due the way variables `array_1` and `array_2` are re-assigned values. - In the first case, `array_1` is bound to the new object `[1,2,3,4,5]` and since the `in` clause is evaluated at the declaration time it still refers to the old object `[1,2,3,4]` (which is not destroyed). - In the second case, the slice assignment to `array_2` updates the same old object `[1,2,3,4]` to `[1,2,3,4,5]`. Hence both the `g2` and `array_2` still have reference to the same object (which has now been updated to `[1,2,3,4,5]`). - Okay, going by the logic discussed so far, shouldn't be the value of `list(gen)` in the third snippet be `[11, 21, 31, 12, 22, 32, 13, 23, 33]`? (because `array_3` and `array_4` are going to behave just like `array_1`). The reason why (only) `array_4` values got updated is explained in [PEP-289](https://www.python.org/dev/peps/pep-0289/#the-details) @@ -1001,7 +1002,7 @@ True False ``` -#### 💡 Explanation +#### 💡 ErklĂ€rung - `is not` is a single binary operator, and has behavior different than using `is` and `not` separated. - `is not` evaluates to `False` if the variables on either side of the operator point to the same object and `True` otherwise. @@ -1019,7 +1020,7 @@ row = [""] * 3 #row i['', '', ''] board = [row] * 3 ``` -**Output:** +**Ausgabe:** ```py >>> board @@ -1035,7 +1036,7 @@ board = [row] * 3 We didn't assign three `"X"`s, did we? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: When we initialize `row` variable, this visualization explains what happens in the memory @@ -1072,7 +1073,7 @@ for x in range(7): funcs_results = [func() for func in funcs] ``` -**Output (Python version):** +**Ausgabe (Python version):** ```py >>> results [0, 1, 2, 3, 4, 5, 6] @@ -1090,7 +1091,7 @@ The values of `x` were different in every iteration prior to appending `some_fun [512, 512, 512, 512, 512, 512, 512, 512, 512, 512] ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * When defining a function inside a loop that uses the loop variable in its body, the loop function's closure is bound to the *variable*, not its *value*. The function looks up `x` in the surrounding context, rather than using the value of `x` at the time the function is created. So all of the functions use the latest value assigned to the variable for computation. We can see that it's using the `x` from the surrounding context (i.e. *not* a local variable) with: ```py >>> import inspect @@ -1115,7 +1116,7 @@ for x in range(7): funcs.append(some_func) ``` -**Output:** +**Ausgabe:** ```py >>> funcs_results = [func() for func in funcs] @@ -1170,7 +1171,7 @@ False ``` -#### 💡 Explanation +#### 💡 ErklĂ€rung - `type` is a [metaclass](https://realpython.com/python-metaclasses/) in Python. - **Everything** is an `object` in Python, which includes classes as well as their objects (instances). @@ -1184,7 +1185,7 @@ False ### ▶ Subclass relationships -**Output:** +**Ausgabe:** ```py >>> from collections import Hashable >>> issubclass(list, object) @@ -1197,12 +1198,12 @@ False The Subclass relationships were expected to be transitive, right? (i.e., if `A` is a subclass of `B`, and `B` is a subclass of `C`, the `A` _should_ a subclass of `C`) -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * Subclass relationships are not necessarily transitive in Python. Anyone is allowed to define their own, arbitrary `__subclasscheck__` in a metaclass. * When `issubclass(cls, Hashable)` is called, it simply looks for non-Falsey "`__hash__`" method in `cls` or anything it inherits from. * Since `object` is hashable, but `list` is non-hashable, it breaks the transitivity relation. -* More detailed explanation can be found [here](https://www.naftaliharris.com/blog/python-subclass-intransitivity/). +* More detailed ErklĂ€rung can be found [here](https://www.naftaliharris.com/blog/python-subclass-intransitivity/). --- @@ -1224,7 +1225,7 @@ class SomeClass: pass ``` -**Output:** +**Ausgabe:** ```py >>> print(SomeClass.method is SomeClass.method) True @@ -1245,7 +1246,7 @@ o1 = SomeClass() o2 = SomeClass() ``` -**Output:** +**Ausgabe:** ```py >>> print(o1.method == o2.method) False @@ -1263,7 +1264,7 @@ True Accessing` classm` or `method` twice, creates equal but not *same* objects for the same instance of `SomeClass`. -#### 💡 Explanation +#### 💡 ErklĂ€rung * Functions are [descriptors](https://docs.python.org/3/howto/descriptor.html). Whenever a function is accessed as an attribute, the descriptor is invoked, creating a method object which "binds" the function with the object owning the attribute. If called, the method calls the function, implicitly passing the bound object as the first argument @@ -1327,7 +1328,7 @@ True Why's this True-False alteration? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - The implementation of `all` function is equivalent to @@ -1347,7 +1348,7 @@ Why's this True-False alteration? ### ▶ The surprising comma -**Output (< 3.6):** +**Ausgabe (< 3.6):** ```py >>> def f(x, y,): @@ -1369,7 +1370,7 @@ SyntaxError: invalid syntax SyntaxError: invalid syntax ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - Trailing comma is not always legal in formal parameters list of a Python function. - In Python, the argument list is defined partially with leading commas and partially with trailing commas. This conflict causes situations where a comma is trapped in the middle, and no rule accepts it. @@ -1379,7 +1380,7 @@ SyntaxError: invalid syntax ### ▶ Strings and the backslashes -**Output:** +**Ausgabe:** ```py >>> print("\"") " @@ -1397,7 +1398,7 @@ SyntaxError: EOL while scanning string literal True ``` -#### 💡 Explanation +#### 💡 ErklĂ€rung - In a usual python string, the backslash is used to escape characters that may have a special meaning (like single-quote, double-quote, and the backslash itself). ```py @@ -1427,7 +1428,7 @@ x = True y = False ``` -**Output:** +**Ausgabe:** ```py >>> not x == y True @@ -1438,7 +1439,7 @@ True SyntaxError: invalid syntax ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * Operator precedence affects how an expression is evaluated, and `==` operator has higher precedence than `not` operator in Python. * So `not x == y` is equivalent to `not (x == y)` which is equivalent to `not (True == False)` finally evaluating to `True`. @@ -1449,7 +1450,7 @@ SyntaxError: invalid syntax ### ▶ Half triple-quoted strings -**Output:** +**Ausgabe:** ```py >>> print('wtfpython''') wtfpython @@ -1464,7 +1465,7 @@ wtfpython SyntaxError: EOF while scanning triple-quoted string literal ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: + Python supports implicit [string literal concatenation](https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation), Example, ``` >>> print("wtf" "python") @@ -1494,7 +1495,7 @@ for item in mixed_list: booleans_found_so_far += 1 ``` -**Output:** +**Ausgabe:** ```py >>> integers_found_so_far 4 @@ -1522,7 +1523,7 @@ def tell_truth(): print("I have lost faith in truth!") ``` -**Output (< 3.x):** +**Ausgabe (< 3.x):** ```py >>> tell_truth() @@ -1531,7 +1532,7 @@ I have lost faith in truth! -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * `bool` is a subclass of `int` in Python @@ -1580,7 +1581,7 @@ class C(A): pass ``` -**Output:** +**Ausgabe:** ```py >>> A.x, B.x, C.x (1, 1, 1) @@ -1610,7 +1611,7 @@ class SomeClass: self.another_list += [x] ``` -**Output:** +**Ausgabe:** ```py >>> some_obj = SomeClass(420) @@ -1629,7 +1630,7 @@ True True ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * Class variables and variables in class instances are internally handled as dictionaries of a class object. If a variable name is not found in the dictionary of the current class, the parent classes are searched for it. * The `+=` operator modifies the mutable object in-place without creating a new object. So changing the attribute of one instance affects the other instances and the class attribute as well. @@ -1645,7 +1646,7 @@ def some_func(val): return "something" ``` -**Output (<= 3.7.x):** +**Ausgabe (<= 3.7.x):** ```py >>> [x for x in some_iterable] @@ -1660,9 +1661,9 @@ def some_func(val): ['a', 'something', 'b', 'something'] ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - This is a bug in CPython's handling of `yield` in generators and comprehensions. -- Source and explanation can be found here: https://stackoverflow.com/questions/32139885/yield-in-list-comprehensions-and-generator-expressions +- Source and ErklĂ€rung can be found here: https://stackoverflow.com/questions/32139885/yield-in-list-comprehensions-and-generator-expressions - Related bug report: https://bugs.python.org/issue10544 - Python 3.8+ no longer allows `yield` inside list comprehension and will throw a `SyntaxError`. @@ -1681,7 +1682,7 @@ def some_func(x): yield from range(x) ``` -**Output (> 3.3):** +**Ausgabe (> 3.3):** ```py >>> list(some_func(3)) @@ -1701,7 +1702,7 @@ def some_func(x): yield i ``` -**Output:** +**Ausgabe:** ```py >>> list(some_func(3)) @@ -1710,7 +1711,7 @@ def some_func(x): The same result, this didn't work either. -#### 💡 Explanation: +#### 💡 ErklĂ€rung: + From Python 3.3 onwards, it became possible to use `return` statement with values inside generators (See [PEP380](https://www.python.org/dev/peps/pep-0380/)). The [official docs](https://www.python.org/dev/peps/pep-0380/#enhancements-to-stopiteration) say that, @@ -1747,7 +1748,7 @@ c = float('-iNf') # These strings are case-insensitive d = float('nan') ``` -**Output:** +**Ausgabe:** ```py >>> a @@ -1787,7 +1788,7 @@ True -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - `'inf'` and `'nan'` are special strings (case-insensitive), which, when explicitly typecast-ed to `float` type, are used to represent mathematical "infinity" and "not a number" respectively. @@ -1821,7 +1822,7 @@ some_tuple = ("A", "tuple", "with", "values") another_tuple = ([1, 2], [3, 4], [5, 6]) ``` -**Output:** +**Ausgabe:** ```py >>> some_tuple[2] = "change this" TypeError: 'tuple' object does not support item assignment @@ -1836,7 +1837,7 @@ TypeError: 'tuple' object does not support item assignment But I thought tuples were immutable... -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * Quoting from https://docs.python.org/3/reference/datamodel.html @@ -1844,7 +1845,7 @@ But I thought tuples were immutable... An object of an immutable sequence type cannot change once it is created. (If the object contains references to other objects, these other objects may be mutable and may be modified; however, the collection of objects directly referenced by an immutable object cannot change.) * `+=` operator changes the list in-place. The item assignment doesn't work, but when the exception occurs, the item has already been changed in place. -* There's also an explanation in [official Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works). +* There's also an ErklĂ€rung in [official Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works). --- @@ -1859,19 +1860,19 @@ except Exception as e: pass ``` -**Output (Python 2.x):** +**Ausgabe (Python 2.x):** ```py >>> print(e) # prints nothing ``` -**Output (Python 3.x):** +**Ausgabe (Python 3.x):** ```py >>> print(e) NameError: name 'e' is not defined ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * Source: https://docs.python.org/3/reference/compound_stmts.html#except @@ -1905,7 +1906,7 @@ NameError: name 'e' is not defined y = [5, 4, 3] ``` - **Output:** + **Ausgabe:** ```py >>> f(x) UnboundLocalError: local variable 'x' referenced before assignment @@ -1919,7 +1920,7 @@ NameError: name 'e' is not defined * In Python 2.x, the variable name `e` gets assigned to `Exception()` instance, so when you try to print, it prints nothing. - **Output (Python 2.x):** + **Ausgabe (Python 2.x):** ```py >>> e Exception() @@ -1939,7 +1940,7 @@ class SomeClass(str): some_dict = {'s': 42} ``` -**Output:** +**Ausgabe:** ```py >>> type(list(some_dict.keys())[0]) str @@ -1951,7 +1952,7 @@ str str ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * Both the object `s` and the string `"s"` hash to the same value because `SomeClass` inherits the `__hash__` method of `str` class. * `SomeClass("s") == "s"` evaluates to `True` because `SomeClass` also inherits `__eq__` method from `str` class. @@ -1973,7 +1974,7 @@ str some_dict = {'s':42} ``` - **Output:** + **Ausgabe:** ```py >>> s = SomeClass('s') >>> some_dict[s] = 40 @@ -1992,13 +1993,13 @@ str a, b = a[b] = {}, 5 ``` -**Output:** +**Ausgabe:** ```py >>> a {5: ({...}, 5)} ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * According to [Python language reference](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements), assignment statements have the form ``` @@ -2016,7 +2017,7 @@ a, b = a[b] = {}, 5 * The second target list is `a[b]` (you may expect this to throw an error because both `a` and `b` have not been defined in the statements before. But remember, we just assigned `a` to `{}` and `b` to `5`). -* Now, we are setting the key `5` in the dictionary to the tuple `({}, 5)` creating a circular reference (the `{...}` in the output refers to the same object that `a` is already referencing). Another simpler example of circular reference could be +* Now, we are setting the key `5` in the dictionary to the tuple `({}, 5)` creating a circular reference (the `{...}` in the Ausgabe refers to the same object that `a` is already referencing). Another simpler example of circular reference could be ```py >>> some_list = some_list[0] = [0] >>> some_list @@ -2053,7 +2054,7 @@ a, b = a[b] = {}, 5 >>> int("2" * 5432) ``` -**Output:** +**Ausgabe:** ```py >>> # Python 3.10.6 222222222222222222222222222222222222222222222222222222222222222... @@ -2066,7 +2067,7 @@ ValueError: Exceeds the limit (4300) for integer string conversion: to increase the limit. ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: This call to `int()` works fine in Python 3.10.6 and raises a ValueError in Python 3.10.8. Note that Python can still work with large integers. The error is only raised when converting between integers and strings. Fortunately, you can increase the limit for the allowed number of digits when you expect an operation to exceed it. To do this, you can use one of the following: @@ -2093,7 +2094,7 @@ for i in x: print(i) ``` -**Output (Python 2.7- Python 3.5):** +**Ausgabe (Python 2.7- Python 3.5):** ``` 0 @@ -2108,7 +2109,7 @@ for i in x: Yes, it runs for exactly **eight** times and stops. -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * Iteration over a dictionary that you edit at the same time is not supported. * It runs eight times because that's the point at which the dictionary resizes to hold more keys (we have eight deletion entries, so a resize is needed). This is actually an implementation detail. @@ -2128,7 +2129,7 @@ class SomeClass: print("Deleted!") ``` -**Output:** +**Ausgabe:** 1\. ```py >>> x = SomeClass() @@ -2155,10 +2156,10 @@ Deleted! Okay, now it's deleted :confused: -#### 💡 Explanation: +#### 💡 ErklĂ€rung: + `del x` doesn’t directly call `x.__del__()`. + When `del x` is encountered, Python deletes the name `x` from current scope and decrements by 1 the reference count of the object `x` referenced. `__del__()` is called only when the object's reference count reaches zero. -+ In the second output snippet, `__del__()` was not called because the previous statement (`>>> y`) in the interactive interpreter created another reference to the same object (specifically, the `_` magic variable which references the result value of the last non `None` expression on the REPL), thus preventing the reference count from reaching zero when `del y` was encountered. ++ In the second Ausgabe snippet, `__del__()` was not called because the previous statement (`>>> y`) in the interactive interpreter created another reference to the same object (specifically, the `_` magic variable which references the result value of the last non `None` expression on the REPL), thus preventing the reference count from reaching zero when `del y` was encountered. + Calling `globals` (or really, executing anything that will have a non `None` result) caused `_` to reference the new result, dropping the existing reference. Now the reference count reached 0 and we can see "Deleted!" being printed (finally!). --- @@ -2193,7 +2194,7 @@ def another_closure_func(): return another_inner_func() ``` -**Output:** +**Ausgabe:** ```py >>> some_func() 1 @@ -2206,7 +2207,7 @@ UnboundLocalError: local variable 'a' referenced before assignment UnboundLocalError: local variable 'a' referenced before assignment ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * When you make an assignment to a variable in scope, it becomes local to that scope. So `a` becomes local to the scope of `another_func`, but it has not been initialized previously in the same scope, which throws an error. * To modify the outer scope variable `a` in `another_func`, we have to use the `global` keyword. ```py @@ -2216,7 +2217,7 @@ UnboundLocalError: local variable 'a' referenced before assignment return a ``` - **Output:** + **Ausgabe:** ```py >>> another_func() 2 @@ -2233,7 +2234,7 @@ UnboundLocalError: local variable 'a' referenced before assignment return another_inner_func() ``` - **Output:** + **Ausgabe:** ```py >>> another_func() 2 @@ -2264,7 +2265,7 @@ for idx, item in enumerate(list_4): list_4.pop(idx) ``` -**Output:** +**Ausgabe:** ```py >>> list_1 [1, 2, 3, 4] @@ -2276,9 +2277,9 @@ for idx, item in enumerate(list_4): [2, 4] ``` -Can you guess why the output is `[2, 4]`? +Can you guess why the Ausgabe is `[2, 4]`? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * It's never a good idea to change the object you're iterating over. The correct way to do so is to iterate over a copy of the object instead, and `list_3[:]` does just that. @@ -2295,7 +2296,7 @@ Can you guess why the output is `[2, 4]`? * `remove` removes the first matching value, not a specific index, raises `ValueError` if the value is not found. * `pop` removes the element at a specific index and returns it, raises `IndexError` if an invalid index is specified. -**Why the output is `[2, 4]`?** +**Why the Ausgabe is `[2, 4]`?** - The list iteration is done index by index, and when we remove `1` from `list_2` or `list_4`, the contents of the lists are now `[2, 3, 4]`. The remaining elements are shifted down, i.e., `2` is at index 0, and `3` is at index 1. Since the next iteration is going to look at index 1 (which is the `3`), the `2` gets skipped entirely. A similar thing will happen with every alternate element in the list sequence. * Refer to this StackOverflow [thread](https://stackoverflow.com/questions/45946228/what-happens-when-you-try-to-delete-a-list-element-while-iterating-over-it) explaining the example @@ -2323,7 +2324,7 @@ Can you guess why the output is `[2, 4]`? ``` Where did element `3` go from the `numbers` list? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - From Python [docs](https://docs.python.org/3.3/library/functions.html#zip), here's an approximate implementation of zip function, ```py @@ -2363,7 +2364,7 @@ for x in range(7): print(x, ': x in global') ``` -**Output:** +**Ausgabe:** ```py 6 : for x inside loop 6 : x in global @@ -2381,7 +2382,7 @@ for x in range(7): print(x, ': x in global') ``` -**Output:** +**Ausgabe:** ```py 6 : for x inside loop 6 : x in global @@ -2389,7 +2390,7 @@ print(x, ': x in global') 3\. -**Output (Python 2.x):** +**Ausgabe (Python 2.x):** ```py >>> x = 1 >>> print([x for x in range(5)]) @@ -2398,7 +2399,7 @@ print(x, ': x in global') 4 ``` -**Output (Python 3.x):** +**Ausgabe (Python 3.x):** ```py >>> x = 1 >>> print([x for x in range(5)]) @@ -2407,11 +2408,11 @@ print(x, ': x in global') 1 ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - In Python, for-loops use the scope they exist in and leave their defined loop-variable behind. This also applies if we explicitly defined the for-loop variable in the global namespace before. In this case, it will rebind the existing variable. -- The differences in the output of Python 2.x and Python 3.x interpreters for list comprehension example can be explained by following change documented in [What’s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) changelog: +- The differences in the Ausgabe of Python 2.x and Python 3.x interpreters for list comprehension example can be explained by following change documented in [What’s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) changelog: > "List comprehensions no longer support the syntactic form `[... for var in item1, item2, ...]`. Use `[... for var in (item1, item2, ...)]` instead. Also, note that list comprehensions have different semantics: they are closer to syntactic sugar for a generator expression inside a `list()` constructor, and in particular, the loop control variables are no longer leaked into the surrounding scope." @@ -2426,7 +2427,7 @@ def some_func(default_arg=[]): return default_arg ``` -**Output:** +**Ausgabe:** ```py >>> some_func() ['some_string'] @@ -2438,7 +2439,7 @@ def some_func(default_arg=[]): ['some_string', 'some_string', 'some_string'] ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - The default mutable arguments of functions in Python aren't really initialized every time you call the function. Instead, the recently assigned value to them is used as the default value. When we explicitly passed `[]` to `some_func` as the argument, the default value of the `default_arg` variable was not used, so the function returned as expected. @@ -2448,7 +2449,7 @@ def some_func(default_arg=[]): return default_arg ``` - **Output:** + **Ausgabe:** ```py >>> some_func.__defaults__ #This will show the default argument values for the function ([],) @@ -2492,14 +2493,14 @@ except IndexError, ValueError: print("Caught again!") ``` -**Output (Python 2.x):** +**Ausgabe (Python 2.x):** ```py Caught! ValueError: list.remove(x): x not in list ``` -**Output (Python 3.x):** +**Ausgabe (Python 3.x):** ```py File "", line 3 except IndexError, ValueError: @@ -2507,7 +2508,7 @@ ValueError: list.remove(x): x not in list SyntaxError: invalid syntax ``` -#### 💡 Explanation +#### 💡 ErklĂ€rung * To add multiple Exceptions to the except clause, you need to pass them as parenthesized tuple as the first argument. The second argument is an optional name, which when supplied will bind the Exception instance that has been raised. Example, ```py @@ -2519,12 +2520,12 @@ SyntaxError: invalid syntax print("Caught again!") print(e) ``` - **Output (Python 2.x):** + **Ausgabe (Python 2.x):** ``` Caught again! list.remove(x): x not in list ``` - **Output (Python 3.x):** + **Ausgabe (Python 3.x):** ```py File "", line 4 except (IndexError, ValueError), e: @@ -2542,7 +2543,7 @@ SyntaxError: invalid syntax print("Caught again!") print(e) ``` - **Output:** + **Ausgabe:** ``` Caught again! list.remove(x): x not in list @@ -2559,7 +2560,7 @@ b = a a = a + [5, 6, 7, 8] ``` -**Output:** +**Ausgabe:** ```py >>> a [1, 2, 3, 4, 5, 6, 7, 8] @@ -2574,7 +2575,7 @@ b = a a += [5, 6, 7, 8] ``` -**Output:** +**Ausgabe:** ```py >>> a [1, 2, 3, 4, 5, 6, 7, 8] @@ -2582,7 +2583,7 @@ a += [5, 6, 7, 8] [1, 2, 3, 4, 5, 6, 7, 8] ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * `a += b` doesn't always behave the same way as `a = a + b`. Classes *may* implement the *`op=`* operators differently, and lists do this. @@ -2602,7 +2603,7 @@ class SomeClass: y = (x for i in range(10)) ``` -**Output:** +**Ausgabe:** ```py >>> list(SomeClass.y)[0] 5 @@ -2616,19 +2617,19 @@ class SomeClass: y = [x for i in range(10)] ``` -**Output (Python 2.x):** +**Ausgabe (Python 2.x):** ```py >>> SomeClass.y[0] 17 ``` -**Output (Python 3.x):** +**Ausgabe (Python 3.x):** ```py >>> SomeClass.y[0] 5 ``` -#### 💡 Explanation +#### 💡 ErklĂ€rung - Scopes nested inside class definition ignore names bound at the class level. - A generator expression has its own scope. - Starting from Python 3.X, list comprehensions also have their own scope. @@ -2659,7 +2660,7 @@ def get_middle(some_list): ``` It seems as though Python rounded 2.5 to 2. -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - This is not a float precision error, in fact, this behavior is intentional. Since Python 3.0, `round()` uses [banker's rounding](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even) where .5 fractions are rounded to the nearest **even** number: @@ -2697,7 +2698,7 @@ I haven't met even a single experience Pythonist till date who has not come acro x, y = (0, 1) if True else None, None ``` -**Output:** +**Ausgabe:** ```py >>> x, y # expected (0, 1) @@ -2719,7 +2720,7 @@ t = () print(t) ``` -**Output:** +**Ausgabe:** ```py one @@ -2747,7 +2748,7 @@ ten_words_list = [ ] ``` -**Output** +**Ausgabe** ```py >>> len(ten_words_list) @@ -2761,7 +2762,7 @@ a = "python" b = "javascript" ``` -**Output:** +**Ausgabe:** ```py # An assert statement with an assertion failure message. @@ -2783,7 +2784,7 @@ some_list = some_list.append(4) some_dict = some_dict.update({"key_4": 4}) ``` -**Output:** +**Ausgabe:** ```py >>> print(some_list) @@ -2810,7 +2811,7 @@ def similar_recursive_func(a): return a ``` -**Output:** +**Ausgabe:** ```py >>> some_recursive_func([5, 0]) @@ -2819,7 +2820,7 @@ def similar_recursive_func(a): 4 ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * For 1, the correct statement for expected behavior is `x, y = (0, 1) if True else (None, None)`. @@ -2881,7 +2882,7 @@ def similar_recursive_func(a): 1 ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - It might appear at first that the default separator for split is a single space `' '`, but as per the [docs](https://docs.python.org/3/library/stdtypes.html#str.split) > If sep is not specified or is `None`, a different splitting algorithm is applied: runs of consecutive whitespace are regarded as a single separator, and the result will contain no empty strings at the start or end if the string has leading or trailing whitespace. Consequently, splitting an empty string or a string consisting of just whitespace with a None separator returns `[]`. @@ -2913,7 +2914,7 @@ def _another_weird_name_func(): ``` -**Output** +**Ausgabe** ```py >>> from module import * @@ -2925,7 +2926,7 @@ Traceback (most recent call last): NameError: name '_another_weird_name_func' is not defined ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - It is often advisable to not use wildcard imports. The first obvious reason for this is, in wildcard imports, the names with a leading underscore don't get imported. This may lead to errors during runtime. - Had we used `from ... import a, b, c` syntax, the above `NameError` wouldn't have occurred. @@ -2944,7 +2945,7 @@ NameError: name '_another_weird_name_func' is not defined def _another_weird_name_func(): print("works!") ``` - **Output** + **Ausgabe** ```py >>> _another_weird_name_func() @@ -2973,7 +2974,7 @@ True False ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - The `sorted` method always returns a list, and comparing lists and tuples always returns `False` in Python. @@ -3016,14 +3017,14 @@ if noon_time: print("Time at noon is", noon_time) ``` -**Output (< 3.5):** +**Ausgabe (< 3.5):** ```py ('Time at noon is', datetime.time(12, 0)) ``` The midnight time is not printed. -#### 💡 Explanation: +#### 💡 ErklĂ€rung: Before Python 3.5, the boolean value for `datetime.time` object was considered to be `False` if it represented midnight in UTC. It is error-prone when using the `if obj:` syntax to check if the `obj` is null or some equivalent of "empty." @@ -3044,10 +3045,10 @@ Well, here you go import antigravity ``` -**Output:** +**Ausgabe:** Sshh... It's a super-secret. -#### 💡 Explanation: +#### 💡 ErklĂ€rung: + `antigravity` module is one of the few easter eggs released by Python developers. + `import antigravity` opens up a web browser pointing to the [classic XKCD comic](https://xkcd.com/353/) about Python. + Well, there's more to it. There's **another easter egg inside the easter egg**. If you look at the [code](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), there's a function defined that purports to implement the [XKCD's geohashing algorithm](https://xkcd.com/426/). @@ -3069,14 +3070,14 @@ label .breakout print("Freedom!") ``` -**Output (Python 2.3):** +**Ausgabe (Python 2.3):** ```py I am trapped, please rescue! I am trapped, please rescue! Freedom! ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - A working version of `goto` in Python was [announced](https://mail.python.org/pipermail/python-announce-list/2004-April/002982.html) as an April Fool's joke on 1st April 2004. - Current versions of Python do not have this module. - Although it works, but please don't use it. Here's the [reason](https://docs.python.org/3/faq/design.html#why-is-there-no-goto) to why `goto` is not present in Python. @@ -3091,7 +3092,7 @@ If you are one of the people who doesn't like using whitespace in Python to deno from __future__ import braces ``` -**Output:** +**Ausgabe:** ```py File "some_file.py", line 1 from __future__ import braces @@ -3100,7 +3101,7 @@ SyntaxError: not a chance Braces? No way! If you think that's disappointing, use Java. Okay, another surprising thing, can you find where's the `SyntaxError` raised in `__future__` module [code](https://github.com/python/cpython/blob/master/Lib/__future__.py)? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: + The `__future__` module is normally used to provide features from future versions of Python. The "future" in this specific context is however, ironic. + This is an easter egg concerned with the community's feelings on this issue. + The code is actually present [here](https://github.com/python/cpython/blob/025eb98dc0c1dc27404df6c544fc2944e0fa9f3a/Python/future.c#L49) in `future.c` file. @@ -3110,7 +3111,7 @@ Braces? No way! If you think that's disappointing, use Java. Okay, another surpr ### ▶ Let's meet Friendly Language Uncle For Life -**Output (Python 3.x)** +**Ausgabe (Python 3.x)** ```py >>> from __future__ import barry_as_FLUFL >>> "Ruby" != "Python" # there's no doubt about it @@ -3125,7 +3126,7 @@ True There we go. -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - This is relevant to [PEP-401](https://www.python.org/dev/peps/pep-0401/) released on April 1, 2009 (now you know, what it means). - Quoting from the PEP-401 @@ -3147,7 +3148,7 @@ import this Wait, what's **this**? `this` is love :heart: -**Output:** +**Ausgabe:** ``` The Zen of Python, by Tim Peters @@ -3188,7 +3189,7 @@ True True ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * `this` module in Python is an easter egg for The Zen Of Python ([PEP 20](https://www.python.org/dev/peps/pep-0020)). * And if you think that's already interesting enough, check out the implementation of [this.py](https://hg.python.org/cpython/file/c3896275c0f6/Lib/this.py). Interestingly, **the code for the Zen violates itself** (and that's probably the only place where this happens). @@ -3210,7 +3211,7 @@ True print("Does not exist") ``` -**Output:** +**Ausgabe:** ```py >>> some_list = [1, 2, 3, 4, 5] >>> does_exists_num(some_list, 4) @@ -3230,12 +3231,12 @@ else: print("Try block executed successfully...") ``` -**Output:** +**Ausgabe:** ```py Try block executed successfully... ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - The `else` clause after a loop is executed only when there's no explicit `break` after all the iterations. You can think of it as a "nobreak" clause. - `else` clause after a try block is also called "completion clause" as reaching the `else` clause in a `try` statement means that the try block actually completed successfully. @@ -3247,10 +3248,10 @@ def some_func(): Ellipsis ``` -**Output** +**Ausgabe** ```py >>> some_func() -# No output, No Error +# No Ausgabe, No Error >>> SomeRandomString Traceback (most recent call last): @@ -3261,7 +3262,7 @@ NameError: name 'SomeRandomString' is not defined Ellipsis ``` -#### 💡 Explanation +#### 💡 ErklĂ€rung - In Python, `Ellipsis` is a globally available built-in object which is equivalent to `...`. ```py >>> ... @@ -3304,7 +3305,7 @@ Ellipsis The spelling is intended. Please, don't submit a patch for this. -**Output (Python 3.x):** +**Ausgabe (Python 3.x):** ```py >>> infinity = float('infinity') >>> hash(infinity) @@ -3313,7 +3314,7 @@ The spelling is intended. Please, don't submit a patch for this. -314159 ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: - Hash of infinity is 10⁔ x π. - Interestingly, the hash of `float('-inf')` is "-10⁔ x π" in Python 3, whereas "-10⁔ x e" in Python 2. @@ -3329,7 +3330,7 @@ class Yo(object): self.bro = True ``` -**Output:** +**Ausgabe:** ```py >>> Yo().bro True @@ -3348,7 +3349,7 @@ class Yo(object): self.bro = True ``` -**Output:** +**Ausgabe:** ```py >>> Yo().bro True @@ -3371,7 +3372,7 @@ class A(object): return __variable # not initialized anywhere yet ``` -**Output:** +**Ausgabe:** ```py >>> A().__variable Traceback (most recent call last): @@ -3383,7 +3384,7 @@ AttributeError: 'A' object has no attribute '__variable' ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * [Name Mangling](https://en.wikipedia.org/wiki/Name_mangling) is used to avoid naming collisions between different namespaces. * In Python, the interpreter modifies (mangles) the class member names starting with `__` (double underscore a.k.a "dunder") and not ending with more than one trailing underscore by adding `_NameOfTheClass` in front. @@ -3399,7 +3400,7 @@ AttributeError: 'A' object has no attribute '__variable' ### ▶ Skipping lines? -**Output:** +**Ausgabe:** ```py >>> value = 11 >>> valuĐ” = 32 @@ -3411,7 +3412,7 @@ Wut? **Note:** The easiest way to reproduce this is to simply copy the statements from the above snippet and paste them into your file/shell. -#### 💡 Explanation +#### 💡 ErklĂ€rung Some non-Western characters look identical to letters in the English alphabet but are considered distinct by the interpreter. @@ -3450,7 +3451,7 @@ def energy_receive(): return np.empty((), dtype=np.float).tolist() ``` -**Output:** +**Ausgabe:** ```py >>> energy_send(123.456) >>> energy_receive() @@ -3459,7 +3460,7 @@ def energy_receive(): Where's the Nobel Prize? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: * Notice that the numpy array created in the `energy_send` function is not returned, so that memory space is free to reallocate. * `numpy.empty()` returns the next free memory slot without reinitializing it. This memory spot just happens to be the same one that was just freed (usually, but not always). @@ -3479,7 +3480,7 @@ def square(x): return sum_so_far ``` -**Output (Python 2.x):** +**Ausgabe (Python 2.x):** ```py >>> square(10) @@ -3490,7 +3491,7 @@ Shouldn't that be 100? **Note:** If you're not able to reproduce this, try running the file [mixed_tabs_and_spaces.py](/mixed_tabs_and_spaces.py) via the shell. -#### 💡 Explanation +#### 💡 ErklĂ€rung * **Don't mix tabs and spaces!** The character just preceding return is a "tab", and the code is indented by multiple of "4 spaces" elsewhere in the example. * This is how Python handles tabs: @@ -3499,7 +3500,7 @@ Shouldn't that be 100? * So the "tab" at the last line of `square` function is replaced with eight spaces, and it gets into the loop. * Python 3 is kind enough to throw an error for such cases automatically. - **Output (Python 3.x):** + **Ausgabe (Python 3.x):** ```py TabError: inconsistent use of tabs and spaces in indentation ``` @@ -3522,7 +3523,7 @@ Shouldn't that be 100? 0.012188911437988281 ``` -#### 💡 Explanation: +#### 💡 ErklĂ€rung: + `+=` is faster than `+` for concatenating more than two strings because the first string (example, `s1` for `s1 += s2 + s3`) is not destroyed while calculating the complete string. --- @@ -3559,7 +3560,7 @@ def convert_list_to_string(l, iters): assert len(s) == 3*iters ``` -**Output:** +**Ausgabe:** ```py # Executed in ipython shell using %timeit for better readability of results. @@ -3597,7 +3598,7 @@ Let's increase the number of iterations by a factor of 10. 86.3 ”s ± 2 ”s per loop (mean ± std. dev. of 7 runs, 1000 loops each) ``` -#### 💡 Explanation +#### 💡 ErklĂ€rung - You can read more about [timeit](https://docs.python.org/3/library/timeit.html) or [%timeit](https://ipython.org/ipython-doc/dev/interactive/magics.html#magic-timeit) on these links. They are used to measure the execution time of code pieces. - Don't use `+` for generating long strings — In Python, `str` is immutable, so the left and right strings have to be copied into the new string for every pair of concatenations. If you concatenate four strings of length 10, you'll be copying (10+10) + ((10+10)+10) + (((10+10)+10)+10) = 90 characters instead of just 40 characters. Things get quadratically worse as the number and size of the string increases (justified with the execution times of `add_bytes_with_plus` function) - Therefore, it's advised to use `.format.` or `%` syntax (however, they are slightly slower than `+` for very short strings). @@ -3628,7 +3629,7 @@ some_dict = {str(i): 1 for i in range(1_000_000)} another_dict = {str(i): 1 for i in range(1_000_000)} ``` -**Output:** +**Ausgabe:** ```py >>> %timeit some_dict['5'] 28.6 ns ± 0.115 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) @@ -3647,7 +3648,7 @@ KeyError: 1 ``` Why are same lookups becoming slower? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: + CPython has a generic dictionary lookup function that handles all types of keys (`str`, `int`, any object ...), and a specialized one for the common case of dictionaries composed of `str`-only keys. + The specialized function (named `lookdict_unicode` in CPython's [source](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841)) knows all existing keys (including the looked-up key) are strings, and uses the faster & simpler string comparison to compare keys, instead of calling the `__eq__` method. + The first time a `dict` instance is accessed with a non-`str` key, it's modified so future lookups use the generic function. @@ -3672,7 +3673,7 @@ def dict_size(o): ``` -**Output:** (Python 3.8, other Python 3 versions may vary a little) +**Ausgabe:** (Python 3.8, other Python 3 versions may vary a little) ```py >>> o1 = SomeClass() >>> o2 = SomeClass() @@ -3708,7 +3709,7 @@ Let's try again... In a new interpreter: What makes those dictionaries become bloated? And why are newly created objects bloated as well? -#### 💡 Explanation: +#### 💡 ErklĂ€rung: + CPython is able to reuse the same "keys" object in multiple dictionaries. This was added in [PEP 412](https://www.python.org/dev/peps/pep-0412/) with the motivation to reduce memory usage, specifically in dictionaries of instances - where keys (instance attributes) tend to be common to all instances. + This optimization is entirely seamless for instance dictionaries, but it is disabled if certain assumptions are broken. + Key-sharing dictionaries do not support deletion; if an instance attribute is deleted, the dictionary is "unshared", and key-sharing is disabled for all future instances of the same class. @@ -3720,7 +3721,7 @@ What makes those dictionaries become bloated? And why are newly created objects * `join()` is a string operation instead of list operation. (sort of counter-intuitive at first usage) - **💡 Explanation:** If `join()` is a method on a string, then it can operate on any iterable (list, tuple, iterators). If it were a method on a list, it'd have to be implemented separately by every type. Also, it doesn't make much sense to put a string-specific method on a generic `list` object API. + **💡 ErklĂ€rung:** If `join()` is a method on a string, then it can operate on any iterable (list, tuple, iterators). If it were a method on a list, it'd have to be implemented separately by every type. Also, it doesn't make much sense to put a string-specific method on a generic `list` object API. * Few weird looking but semantically correct statements: + `[] = ()` is a semantically correct statement (unpacking an empty `tuple` into an empty `list`) @@ -3738,9 +3739,9 @@ What makes those dictionaries become bloated? And why are newly created objects 5 ``` - **💡 Explanation:** + **💡 ErklĂ€rung:** + There is no `++` operator in Python grammar. It is actually two `+` operators. - + `++a` parses as `+(+a)` which translates to `a`. Similarly, the output of the statement `--a` can be justified. + + `++a` parses as `+(+a)` which translates to `a`. Similarly, the Ausgabe of the statement `--a` can be justified. + This StackOverflow [thread](https://stackoverflow.com/questions/3654830/why-are-there-no-and-operators-in-python) discusses the rationale behind the absence of increment and decrement operators in Python. * You must be aware of the Walrus operator in Python. But have you ever heard about *the space-invader operator*? @@ -3756,7 +3757,7 @@ What makes those dictionaries become bloated? And why are newly created objects >>> a >>> 44 ``` - **💡 Explanation:** This prank comes from [Raymond Hettinger's tweet](https://twitter.com/raymondh/status/1131103570856632321?lang=en). The space invader operator is actually just a malformatted `a -= (-1)`. Which is equivalent to `a = a - (- 1)`. Similar for the `a += (+ 1)` case. + **💡 ErklĂ€rung:** This prank comes from [Raymond Hettinger's tweet](https://twitter.com/raymondh/status/1131103570856632321?lang=en). The space invader operator is actually just a malformatted `a -= (-1)`. Which is equivalent to `a = a - (- 1)`. Similar for the `a += (+ 1)` case. * Python has an undocumented [converse implication](https://en.wikipedia.org/wiki/Converse_implication) operator. @@ -3771,7 +3772,7 @@ What makes those dictionaries become bloated? And why are newly created objects True ``` - **💡 Explanation:** If you replace `False` and `True` by 0 and 1 and do the maths, the truth table is equivalent to a converse implication operator. ([Source](https://github.com/cosmologicon/pywat/blob/master/explanation.md#the-undocumented-converse-implication-operator)) + **💡 ErklĂ€rung:** If you replace `False` and `True` by 0 and 1 and do the maths, the truth table is equivalent to a converse implication operator. ([Source](https://github.com/cosmologicon/pywat/blob/master/ErklĂ€rung.md#the-undocumented-converse-implication-operator)) * Since we are talking operators, there's also `@` operator for matrix multiplication (don't worry, this time it's for real). @@ -3781,7 +3782,7 @@ What makes those dictionaries become bloated? And why are newly created objects 46 ``` - **💡 Explanation:** The `@` operator was added in Python 3.5 keeping the scientific community in mind. Any object can overload `__matmul__` magic method to define behavior for this operator. + **💡 ErklĂ€rung:** The `@` operator was added in Python 3.5 keeping the scientific community in mind. Any object can overload `__matmul__` magic method to define behavior for this operator. * From Python 3.8 onwards you can use a typical f-string syntax like `f'{some_var=}` for quick debugging. Example, ```py @@ -3816,7 +3817,7 @@ What makes those dictionaries become bloated? And why are newly created objects time.sleep(3) ``` - This will print the `wtfpython` after 3 seconds due to the `end` argument because the output buffer is flushed either after encountering `\n` or when the program finishes execution. We can force the buffer to flush by passing `flush=True` argument. + This will print the `wtfpython` after 3 seconds due to the `end` argument because the Ausgabe buffer is flushed either after encountering `\n` or when the program finishes execution. We can force the buffer to flush by passing `flush=True` argument. * List slicing with out of the bounds indices throws no errors ```py @@ -3863,23 +3864,23 @@ What makes those dictionaries become bloated? And why are newly created objects # Contributing -A few ways in which you can contribute to wtfpython, +Ein paar Wege, wie du zu wtfpython beitragen kannst: -- Suggesting new examples -- Helping with translation (See [issues labeled translation](https://github.com/satwikkansal/wtfpython/issues?q=is%3Aissue+is%3Aopen+label%3Atranslation)) -- Minor corrections like pointing out outdated snippets, typos, formatting errors, etc. -- Identifying gaps (things like inadequate explanation, redundant examples, etc.) -- Any creative suggestions to make this project more fun and useful +- neue Beispiele vorschlagen +- bei der Übersetzung helfen (Siehe [issues sind mit 'translation' markiert](https://github.com/satwikkansal/wtfpython/issues?q=is%3Aissue+is%3Aopen+label%3Atranslation)) +- Verbesserungen vorschlagen, z.B. Aufzeigen von veralteten Schnipseln, Typen, Formatfehlern, etc. +- LĂŒcken identifizieren (z.B. unzureichende ErklĂ€rungen, ĂŒberflĂŒssige Beispiele, etc.) +- Irgendwelche kreativen VorschlĂ€ge unterbreiten, um dieses Projekt spaßiger und nĂŒtzlicher zu machen -Please see [CONTRIBUTING.md](/CONTRIBUTING.md) for more details. Feel free to create a new [issue](https://github.com/satwikkansal/wtfpython/issues/new) to discuss things. +FĂŒr mehr Details, wirf bitte einen Blick auf [CONTRIBUTING.md](/CONTRIBUTING.md). Erstelle ruhig ein neues [Issue](https://github.com/satwikkansal/wtfpython/issues/new), um zu diskutieren. -PS: Please don't reach out with backlinking requests, no links will be added unless they're highly relevant to the project. +PS: Bitte keine Anfragen mit Links erstellen. Es werden keine Links hinzugefĂŒgt, es sein denn sie sind fĂŒr das Projekt relevant. -# Acknowledgements +# Anerkennung -The idea and design for this collection were initially inspired by Denys Dovhan's awesome project [wtfjs](https://github.com/denysdovhan/wtfjs). The overwhelming support by Pythonistas gave it the shape it is in right now. +Die Idee und das Design fĂŒr diese Sammlung wurden durch Denys Dovhans tolles Projekt inspiriert [wtfjs](https://github.com/denysdovhan/wtfjs). Der ĂŒberragende Support von Pythonisten hat es zu dem gemacht, was es heute ist. -#### Some nice Links! +#### Ein paar nĂŒtzliche Links! * https://www.youtube.com/watch?v=sH4XF6pKKmk * https://www.reddit.com/r/Python/comments/3cu6ej/what_are_some_wtf_things_about_python * https://sopython.com/wiki/Common_Gotchas_In_Python @@ -3900,15 +3901,14 @@ The idea and design for this collection were initially inspired by Denys Dovhan' [license-url]: http://www.wtfpl.net [license-image]: https://img.shields.io/badge/License-WTFPL%202.0-lightgrey.svg?style=flat-square -## Surprise your friends as well! +## Überrasche auch deine Freunde! -If you like wtfpython, you can use these quick links to share it with your friends, +Wenn du wtfpython cool findest, kannst du diese Quick-Links nutzen, um es mit deinen Freunden zu teilen: [Twitter](https://twitter.com/intent/tweet?url=https://github.com/satwikkansal/wtfpython&text=If%20you%20really%20think%20you%20know%20Python,%20think%20once%20more!%20Check%20out%20wtfpython&hashtags=python,wtfpython) | [Linkedin](https://www.linkedin.com/shareArticle?url=https://github.com/satwikkansal&title=What%20the%20f*ck%20Python!&summary=If%20you%20really%20thing%20you%20know%20Python,%20think%20once%20more!) | [Facebook](https://www.facebook.com/dialog/share?app_id=536779657179021&display=page&href=https%3A%2F%2Fgithub.com%2Fsatwikkansal%2Fwtfpython"e=If%20you%20really%20think%20you%20know%20Python%2C%20think%20once%20more!) -## Need a pdf version? - -I've received a few requests for the pdf (and epub) version of wtfpython. You can add your details [here](https://form.jotform.com/221593245656057) to get them as soon as they are finished. +## Brauchst du eine pdf version? +Ich habe ein paar Anfragen fĂŒr eine pdf (und epub) Version von wtfpython erhalten. Du kannst [hier](https://form.jotform.com/221593245656057) deine Daten angeben, um sie schnellstmöglich zu bekommen. -**That's all folks!** For upcoming content like this, you can add your email [here](https://form.jotform.com/221593598380062). +**Das ist alles, Freunde!** Um neue Updates zu erhalten, kannst du deine email [hier](https://form.jotform.com/221593598380062) hinzufĂŒgen. From e05f4f1094846ad3fbc91cccd6f3b0712e3322ab Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Mon, 17 Apr 2023 21:36:38 +0200 Subject: [PATCH 03/20] translation #3 --- README.md | 56 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 41778a95..a74f833d 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Also, los gehts... - [💡 ErklĂ€rung:](#-erklĂ€rung-1) - [▶ Vorsicht bei verketteten Operationen](#-vorsicht-bei-verketteten-operationen) - [💡 ErklĂ€rung:](#-erklĂ€rung-2) - - [▶ How not to use `is` operator](#-how-not-to-use-is-operator) + - [▶ Wie man den `is` Operator nicht nutzt](#-wie-man-den-is-operator-nicht-nutzt) - [💡 ErklĂ€rung:](#-erklĂ€rung-3) - [▶ Hash brownies](#-hash-brownies) - [💡 ErklĂ€rung](#-erklĂ€rung-4) @@ -451,29 +451,34 @@ False #### 💡 ErklĂ€rung: -As per https://docs.python.org/3/reference/expressions.html#comparisons +Zitat von https://docs.python.org/3/reference/expressions.html#comparisons > Formally, if a, b, c, ..., y, z are expressions and op1, op2, ..., opN are comparison operators, then a op1 b op2 c ... y opN z is equivalent to a op1 b and b op2 c and ... y opN z, except that each expression is evaluated at most once. -While such behavior might seem silly to you in the above examples, it's fantastic with stuff like `a == b == c` and `0 <= x <= 100`. +Übersetzt: -* `False is False is False` is equivalent to `(False is False) and (False is False)` -* `True is False == False` is equivalent to `(True is False) and (False == False)` and since the first part of the statement (`True is False`) evaluates to `False`, the overall expression evaluates to `False`. -* `1 > 0 < 1` is equivalent to `(1 > 0) and (0 < 1)` which evaluates to `True`. -* The expression `(1 > 0) < 1` is equivalent to `True < 1` and +> Formal ausgedrĂŒckt: wenn a, b, c, ..., y, z AusdrĂŒcke und op1, op2, ..., opN Vergleichsoperatoren sind, dann sind a op1 b op2 c ... y opN z Ă€quivalent zu a op1 b and b op2 c and ... y opN z, mit der Ausnahme, dass jeder Ausdruck höchstens einmal ausgewertet wird. + + +WĂ€hrend dieses Verhalten in den Beispielen vielleicht unsinnig erscheint, kann es super verwendet werden, z.B. `a == b == c` und `0 <= x <= 100`. + +* `False is False is False` ist Ă€quivalent zu `(False is False) and (False is False)` +* `True is False == False` ist Ă€quivalent zu `(True is False) and (False == False)` und wĂ€hrend der erste Teil des Statements (`True is False`) zu `False` ausgewertet wird, wird der gesamt Ausdruck zu `False` ausgewertet. +* `1 > 0 < 1` ist Ă€quivalent zu `(1 > 0) and (0 < 1)` which evaluates to `True`. +* Der Ausdruck `(1 > 0) < 1` ist Ă€quivalent zu `True < 1` und ```py >>> int(True) 1 - >>> True + 1 #not relevant for this example, but just for fun + >>> True + 1 # Nicht relevant fĂŒr dieses Beispiel, aber trotzdem nur zum Spaß 2 ``` - So, `1 < 1` evaluates to `False` + So wird `1 < 1` zu `False` ausgewertet --- -### ▶ How not to use `is` operator +### ▶ Wie man den `is` Operator nicht nutzt -The following is a very famous example present all over the internet. +Das folgende Beispiel ist im Internet ĂŒberall bekannt. 1\. @@ -512,7 +517,7 @@ True True ``` -**Ausgabe (Python 3.7.x specifically)** +**Ausgabe (Python 3.7.x spezifisch)** ```py >>> a, b = 257, 257 @@ -522,24 +527,29 @@ False #### 💡 ErklĂ€rung: -**The difference between `is` and `==`** +**Der Unterschied zwischen `is` und `==`** -* `is` operator checks if both the operands refer to the same object (i.e., it checks if the identity of the operands matches or not). -* `==` operator compares the values of both the operands and checks if they are the same. -* So `is` is for reference equality and `==` is for value equality. An example to clear things up, +* `is` Operator checkt, ob sich beide Operanden auf dasselbe Objekt beziehen (i.e., it checks if the identity of the operands matches or not). +* `==` Operator vergleicht die Werte der beiden Operanden und ĂŒberprĂŒft, ob diese gleich sind. +* Also `is` wird fĂŒr Beziehungsgleichheit und `==` fĂŒr Wertgleichheit benutzt. Ein Beispiel, um das Gesagte zu vertiefen: ```py >>> class A: pass - >>> A() is A() # These are two empty objects at two different memory locations. + >>> A() is A() # Das sind zwei leere Objekte an zwei verschiedenen Orten im Speicher. False ``` -**`256` is an existing object but `257` isn't** +**`256` ist ein existierendes Objekt, aber `257` nicht** -When you start up python the numbers from `-5` to `256` will be allocated. These numbers are used a lot, so it makes sense just to have them ready. +Wenn du Python startest, werden die Nummern von `-5` bis `256` bereitgestellt. Diese Nummern werden sehr oft benutzt, also ergibt es Sinn, +sie schnell bereit zu haben. -Quoting from https://docs.python.org/3/c-api/long.html +Zitat von https://docs.python.org/3/c-api/long.html > The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you just get back a reference to the existing object. So it should be possible to change the value of 1. I suspect the behavior of Python, in this case, is undefined. :-) +Übersetzung: +> Die momentane Implementation stellt ein Array aus Integer-Objekten fĂŒr alle Integer zwischen -5 und 256 bereit. Wenn du einen int in diesem Bereich erstellst, bekommst du nur eine Referenz auf das existierende Objekt zurĂŒck. Also sollte es möglich sein, den Wert von 1 zu Ă€ndern. Ich vermute das Verhalten von Python ist in diesem Fall undefiniert. :-) + + ```py >>> id(256) 10922528 @@ -559,11 +569,11 @@ Quoting from https://docs.python.org/3/c-api/long.html 140084850247344 ``` -Here the interpreter isn't smart enough while executing `y = 257` to recognize that we've already created an integer of the value `257,` and so it goes on to create another object in the memory. +Hier ist der Interpreter nicht schlau genug wĂ€hrend des AusfĂŒhrens von `y = 257` zu erkennen, dass wir bereits ein Integer mit dem Wert `257` erstellt haben und daher wird ein neues Objekt im Speicher angelegt. -Similar optimization applies to other **immutable** objects like empty tuples as well. Since lists are mutable, that's why `[] is []` will return `False` and `() is ()` will return `True`. This explains our second snippet. Let's move on to the third one, +Ähnliche Optimierungen treffen auf andere **immutable** Objekte zu, z.B. leere Tuples. Da Listen mutable sind, wird `[] is []` zu `False` ausgewertet und `() is ()` wird zu `True` ausgewertet. Das erklĂ€rt unser zweiter Schnipsel. Lass uns mit dem dritten Beispiell weiter machen: -**Both `a` and `b` refer to the same object when initialized with same value in the same line.** +**Sowohl `a` und `b` beziehen sich auf dasselbe Objekt wenn sie in derselben Zeile mit demselben Wert initialisiert werden.** **Ausgabe** From 2561daa5cbf3a2554255091fa13e80495c6a50d5 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Tue, 18 Apr 2023 20:34:41 +0200 Subject: [PATCH 04/20] translation #3 --- README.md | 243 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 124 insertions(+), 119 deletions(-) diff --git a/README.md b/README.md index a74f833d..c014157d 100644 --- a/README.md +++ b/README.md @@ -40,126 +40,126 @@ Also, los gehts... - [💡 ErklĂ€rung:](#-erklĂ€rung-3) - [▶ Hash brownies](#-hash-brownies) - [💡 ErklĂ€rung](#-erklĂ€rung-4) - - [▶ Deep down, we're all the same.](#-deep-down-were-all-the-same) + - [▶ Tief im Inneren sind wir alle gleich](#-tief-im-inneren-sind-wir-alle-gleich) - [💡 ErklĂ€rung:](#-erklĂ€rung-5) - - [▶ Disorder within order \*](#-disorder-within-order-) + - [▶ Unordnung in der Ordnung \*](#-unordnung-in-der-ordnung-) - [💡 ErklĂ€rung:](#-erklĂ€rung-6) - - [▶ Keep trying... \*](#-keep-trying-) + - [▶ Versuche es weiter... \*](#-versuche-es-weiter-) - [💡 ErklĂ€rung:](#-erklĂ€rung-7) - - [▶ For what?](#-for-what) + - [▶ WofĂŒr?](#-wofĂŒr) - [💡 ErklĂ€rung:](#-erklĂ€rung-8) - - [▶ Evaluation time discrepancy](#-evaluation-time-discrepancy) + - [▶ Diskrepanz in der Auswertungszeit](#-diskrepanz-in-der-auswertungszeit) - [💡 ErklĂ€rung](#-erklĂ€rung-9) - - [▶ `is not ...` is not `is (not ...)`](#-is-not--is-not-is-not-) + - [▶ `is not ...` ist nicht `is (not ...)`](#-is-not--ist-nicht-is-not-) - [💡 ErklĂ€rung](#-erklĂ€rung-10) - - [▶ A tic-tac-toe where X wins in the first attempt!](#-a-tic-tac-toe-where-x-wins-in-the-first-attempt) + - [▶ Ein tic-tac-toe wo X im ersten Versuch gewinnt!](#-ein-tic-tac-toe-wo-x-im-ersten-versuch-gewinnt) - [💡 ErklĂ€rung:](#-erklĂ€rung-11) - - [▶ Schrödinger's variable \*](#-schrödingers-variable-) + - [▶ Schrödingers Variable \*](#-schrödingers-variable-) - [💡 ErklĂ€rung:](#-erklĂ€rung-12) - - [▶ The chicken-egg problem \*](#-the-chicken-egg-problem-) + - [▶ Das Henne-Ei-Problem \*](#-das-henne-ei-problem-) - [💡 ErklĂ€rung](#-erklĂ€rung-13) - - [▶ Subclass relationships](#-subclass-relationships) + - [▶ Beziehungen in Unterklassen](#-beziehungen-in-unterklassen) - [💡 ErklĂ€rung:](#-erklĂ€rung-14) - - [▶ Methods equality and identity](#-methods-equality-and-identity) + - [▶ Methodengleichheit und -identitĂ€t](#-methodengleichheit-und--identitĂ€t) - [💡 ErklĂ€rung](#-erklĂ€rung-15) - [▶ All-true-ation \*](#-all-true-ation-) - [💡 ErklĂ€rung:](#-erklĂ€rung-16) - [💡 ErklĂ€rung:](#-erklĂ€rung-17) - - [▶ Strings and the backslashes](#-strings-and-the-backslashes) + - [▶ Strings und die Backslashes](#-strings-und-die-backslashes) - [💡 ErklĂ€rung](#-erklĂ€rung-18) - [▶ not knot!](#-not-knot) - [💡 ErklĂ€rung:](#-erklĂ€rung-19) - - [▶ Half triple-quoted strings](#-half-triple-quoted-strings) + - [▶ Halbe Zeichenketten in dreifachen AnfĂŒhrungszeichen](#-halbe-zeichenketten-in-dreifachen-anfĂŒhrungszeichen) - [💡 ErklĂ€rung:](#-erklĂ€rung-20) - - [▶ What's wrong with booleans?](#-whats-wrong-with-booleans) + - [▶ Was ist falsch an booleans?](#-was-ist-falsch-an-booleans) - [💡 ErklĂ€rung:](#-erklĂ€rung-21) - - [▶ Class attributes and instance attributes](#-class-attributes-and-instance-attributes) + - [▶ Klassen- und Instanzattribute](#-klassen--und-instanzattribute) - [💡 ErklĂ€rung:](#-erklĂ€rung-22) - [▶ yielding None](#-yielding-none) - [💡 ErklĂ€rung:](#-erklĂ€rung-23) - [▶ Yielding from... return! \*](#-yielding-from-return-) - [💡 ErklĂ€rung:](#-erklĂ€rung-24) - - [▶ Nan-reflexivity \*](#-nan-reflexivity-) + - [▶ Nan-ReflexivitĂ€t \*](#-nan-reflexivitĂ€t-) - [💡 ErklĂ€rung:](#-erklĂ€rung-25) - - [▶ Mutating the immutable!](#-mutating-the-immutable) + - [▶ VerĂ€ndern des UnverĂ€nderlichen!](#-verĂ€ndern-des-unverĂ€nderlichen) - [💡 ErklĂ€rung:](#-erklĂ€rung-26) - - [▶ The disappearing variable from outer scope](#-the-disappearing-variable-from-outer-scope) + - [▶ Die verschwindende Variable aus dem Ă€ußeren GĂŒltigkeitsbereich](#-die-verschwindende-variable-aus-dem-Ă€ußeren-gĂŒltigkeitsbereich) - [💡 ErklĂ€rung:](#-erklĂ€rung-27) - - [▶ The mysterious key type conversion](#-the-mysterious-key-type-conversion) + - [▶ Die mysteriöse key type Umwandlung](#-die-mysteriöse-key-type-umwandlung) - [💡 ErklĂ€rung:](#-erklĂ€rung-28) - - [▶ Let's see if you can guess this?](#-lets-see-if-you-can-guess-this) + - [▶ Lass uns sehen, ob du dies errĂ€tst?](#-lass-uns-sehen-ob-du-dies-errĂ€tst) - [💡 ErklĂ€rung:](#-erklĂ€rung-29) - - [▶ Exceeds the limit for integer string conversion](#-exceeds-the-limit-for-integer-string-conversion) + - [▶ Überschreitet den Grenzwert fĂŒr die Umwandlung von Integer-Strings](#-ĂŒberschreitet-den-grenzwert-fĂŒr-die-umwandlung-von-integer-strings) - [💡 ErklĂ€rung:](#-erklĂ€rung-30) - [Section: Slippery Slopes](#section-slippery-slopes) - - [▶ Modifying a dictionary while iterating over it](#-modifying-a-dictionary-while-iterating-over-it) + - [▶ Modifizieren eines Dictionarys wĂ€hrend einer Iteration](#-modifizieren-eines-dictionarys-wĂ€hrend-einer-iteration) - [💡 ErklĂ€rung:](#-erklĂ€rung-31) - - [▶ Stubborn `del` operation](#-stubborn-del-operation) + - [▶ HartnĂ€ckige `del` Operation](#-hartnĂ€ckige-del-operation) - [💡 ErklĂ€rung:](#-erklĂ€rung-32) - - [▶ The out of scope variable](#-the-out-of-scope-variable) + - [▶ Die Variable aus dem Ă€ußeren Geltungsbereich](#-die-variable-aus-dem-Ă€ußeren-geltungsbereich) - [💡 ErklĂ€rung:](#-erklĂ€rung-33) - - [▶ Deleting a list item while iterating](#-deleting-a-list-item-while-iterating) + - [▶ Löschen eines Listenelements wĂ€hrend einer Iteration](#-löschen-eines-listenelements-wĂ€hrend-einer-iteration) - [💡 ErklĂ€rung:](#-erklĂ€rung-34) - - [▶ Lossy zip of iterators \*](#-lossy-zip-of-iterators-) + - [▶ Lossy Zips von Iteratoren \*](#-lossy-zips-von-iteratoren-) - [💡 ErklĂ€rung:](#-erklĂ€rung-35) - - [▶ Loop variables leaking out!](#-loop-variables-leaking-out) + - [▶ Schleifenvariablen, die auslaufen!](#-schleifenvariablen-die-auslaufen) - [💡 ErklĂ€rung:](#-erklĂ€rung-36) - - [▶ Beware of default mutable arguments!](#-beware-of-default-mutable-arguments) + - [▶ Vorsicht vor standardmĂ€ĂŸig verĂ€nderbaren Argumenten!](#-vorsicht-vor-standardmĂ€ĂŸig-verĂ€nderbaren-argumenten) - [💡 ErklĂ€rung:](#-erklĂ€rung-37) - - [▶ Catching the Exceptions](#-catching-the-exceptions) + - [▶ Fangen der Exceptions](#-fangen-der-exceptions) - [💡 ErklĂ€rung](#-erklĂ€rung-38) - - [▶ Same operands, different story!](#-same-operands-different-story) + - [▶ Gleiche Operanden, unterschiedliche Story!](#-gleiche-operanden-unterschiedliche-story) - [💡 ErklĂ€rung:](#-erklĂ€rung-39) - - [▶ Name resolution ignoring class scope](#-name-resolution-ignoring-class-scope) + - [▶ Namensauflösung ohne BerĂŒcksichtigung des Geltungsbereichs der Klasse](#-namensauflösung-ohne-berĂŒcksichtigung-des-geltungsbereichs-der-klasse) - [💡 ErklĂ€rung](#-erklĂ€rung-40) - - [▶ Rounding like a banker \*](#-rounding-like-a-banker-) + - [▶ Runden wie ein Bankier \*](#-runden-wie-ein-bankier-) - [💡 ErklĂ€rung:](#-erklĂ€rung-41) - - [▶ Needles in a Haystack \*](#-needles-in-a-haystack-) + - [▶ Nadeln im Heuhaufen \*](#-nadeln-im-heuhaufen-) - [💡 ErklĂ€rung:](#-erklĂ€rung-42) - [▶ Splitsies \*](#-splitsies-) - [💡 ErklĂ€rung:](#-erklĂ€rung-43) - - [▶ Wild imports \*](#-wild-imports-) + - [▶ Wilde Imports \*](#-wilde-imports-) - [💡 ErklĂ€rung:](#-erklĂ€rung-44) - - [▶ All sorted? \*](#-all-sorted-) + - [▶ Alles sortieren ? \*](#--alles-sortieren--) - [💡 ErklĂ€rung:](#-erklĂ€rung-45) - - [▶ Midnight time doesn't exist?](#-midnight-time-doesnt-exist) + - [▶ Mitternachtszeit gibt es nicht ?](#-mitternachtszeit-gibt-es-nicht-) - [💡 ErklĂ€rung:](#-erklĂ€rung-46) - - [Section: The Hidden treasures!](#section-the-hidden-treasures) - - [▶ Okay Python, Can you make me fly?](#-okay-python-can-you-make-me-fly) + - [Section: Die verborgenen SchĂ€tze!](#section-die-verborgenen-schĂ€tze) + - [▶ Okay Python, kannst du mich fliegen lassen?](#-okay-python-kannst-du-mich-fliegen-lassen) - [💡 ErklĂ€rung:](#-erklĂ€rung-47) - - [▶ `goto`, but why?](#-goto-but-why) + - [▶ `goto`, aber wieso?](#-goto-aber-wieso) - [💡 ErklĂ€rung:](#-erklĂ€rung-48) - - [▶ Brace yourself!](#-brace-yourself) + - [▶ Halte dich fest!](#-halte-dich-fest) - [💡 ErklĂ€rung:](#-erklĂ€rung-49) - [▶ Let's meet Friendly Language Uncle For Life](#-lets-meet-friendly-language-uncle-for-life) - [💡 ErklĂ€rung:](#-erklĂ€rung-50) - - [▶ Even Python understands that love is complicated](#-even-python-understands-that-love-is-complicated) + - [▶ Selbst Python versteht, dass Liebe kompliziert ist](#-selbst-python-versteht-dass-liebe-kompliziert-ist) - [💡 ErklĂ€rung:](#-erklĂ€rung-51) - - [▶ Yes, it exists!](#-yes-it-exists) + - [▶ Ja, es existiert!](#-ja-es-existiert) - [💡 ErklĂ€rung:](#-erklĂ€rung-52) - - [▶ Ellipsis \*](#-ellipsis-) + - [▶ Ellipsen \*](#-ellipsen-) - [💡 ErklĂ€rung](#-erklĂ€rung-53) - - [▶ Inpinity](#-inpinity) + - [▶ Einbindung](#-einbindung) - [💡 ErklĂ€rung:](#-erklĂ€rung-54) - - [▶ Let's mangle](#-lets-mangle) + - [▶ Lass uns demolieren](#-lass-uns-demolieren) - [💡 ErklĂ€rung:](#-erklĂ€rung-55) - - [Section: Appearances are deceptive!](#section-appearances-are-deceptive) - - [▶ Skipping lines?](#-skipping-lines) + - [Section: Der Schein trĂŒgt!](#section-der-schein-trĂŒgt) + - [▶ Zeilen ĂŒberspringen?](#-zeilen-ĂŒberspringen) - [💡 ErklĂ€rung](#-erklĂ€rung-56) - [▶ Teleportation](#-teleportation) - [💡 ErklĂ€rung:](#-erklĂ€rung-57) - - [▶ Well, something is fishy...](#-well-something-is-fishy) + - [▶ Da ist wohl irgendwas faul...](#-da-ist-wohl-irgendwas-faul) - [💡 ErklĂ€rung](#-erklĂ€rung-58) - - [Section: Miscellaneous](#section-miscellaneous) - - [▶ `+=` is faster](#--is-faster) + - [Section: Sonstiges](#section-sonstiges) + - [▶ `+=` ist schneller](#--ist-schneller) - [💡 ErklĂ€rung:](#-erklĂ€rung-59) - - [▶ Let's make a giant string!](#-lets-make-a-giant-string) + - [▶ Lass uns einen gigantischen String machen!](#-lass-uns-einen-gigantischen-string-machen) - [💡 ErklĂ€rung](#-erklĂ€rung-60) - - [▶ Slowing down `dict` lookups \*](#-slowing-down-dict-lookups-) + - [▶ Verlangsamen von `dict` Lookups \*](#-verlangsamen-von-dict-lookups-) - [💡 ErklĂ€rung:](#-erklĂ€rung-61) - - [▶ Bloating instance `dict`s \*](#-bloating-instance-dicts-) + - [▶ BlĂ€hende Instanz `dict`s \*](#-blĂ€hende-instanz-dicts-) - [💡 ErklĂ€rung:](#-erklĂ€rung-62) - - [▶ Minor Ones \*](#-minor-ones-) + - [▶ Kleinigkeiten \*](#-kleinigkeiten-) - [Contributing](#contributing) - [Anerkennung](#anerkennung) - [Ein paar nĂŒtzliche Links!](#ein-paar-nĂŒtzliche-links) @@ -591,9 +591,13 @@ Hier ist der Interpreter nicht schlau genug wĂ€hrend des AusfĂŒhrens von `y = 25 140640774013488 ``` -* When a and b are set to `257` in the same line, the Python interpreter creates a new object, then references the second variable at the same time. If you do it on separate lines, it doesn't "know" that there's already `257` as an object. +* Wenn a und b in derselben Zeile auf `257` gesetzt werden, erstellt der Python Interpreter ein neues Objekt, und referenziert die zweite Variable +zur selben Zeit. Wenn man es in verschiedenen Zeilen macht, dann weiß Python nicht, dass eine `257` als Objekt schon existiert. -* It's a compiler optimization and specifically applies to the interactive environment. When you enter two lines in a live interpreter, they're compiled separately, therefore optimized separately. If you were to try this example in a `.py` file, you would not see the same behavior, because the file is compiled all at once. This optimization is not limited to integers, it works for other immutable data types like strings (check the "Strings are tricky example") and floats as well, +* Es ist eine Compiler Optimierung, die speziell fĂŒr die interaktive Umgebung gilt. Wenn man zwei Zeilen in einem Live Interpreter eingibt, dann +werden sie getrennt kompiliert und auch getrennt optimiert. Wenn du dieses Beispiel in einer `.py` Datei ausprobierst, wĂŒrdest du nicht dasselbe +Verhalten beobachten, denn die Datei wird auf einmal kompiliert. Diese Optimierung ist nicht auf Integer beschrĂ€nkt, sie funktioniert auch fĂŒr +andere immutable Datentypen, wie z.B. Strings (siehe auch das Beispiel "Strings können manchmal schwierig sein") oder floats: ```py >>> a, b = 257.0, 257.0 @@ -601,7 +605,8 @@ Hier ist der Interpreter nicht schlau genug wĂ€hrend des AusfĂŒhrens von `y = 25 True ``` -* Why didn't this work for Python 3.7? The abstract reason is because such compiler optimizations are implementation specific (i.e. may change with version, OS, etc). I'm still figuring out what exact implementation change cause the issue, you can check out this [issue](https://github.com/satwikkansal/wtfpython/issues/100) for updates. +* Warum funktioniert das nicht in Python 3.7 ? Die abstrakte Antwort ist: Die Compiler Optimierungen sind von der Implementierung abhĂ€ngig (es verĂ€ndert sich mit der Version, dem Betriebssystem, etc.). Ich versuche noch herauszufinden, welche ImplementierungsĂ€nderung dieses Problem +verursacht. FĂŒr Updates, schaue dieses [Issue](https://github.com/satwikkansal/wtfpython/issues/100) an. --- @@ -621,7 +626,7 @@ some_dict[5] = "Python" ```py >>> some_dict[5.5] "JavaScript" ->>> some_dict[5.0] # "Python" destroyed the existence of "Ruby"? +>>> some_dict[5.0] # "Python" hat die Existenz von "Ruby" ausgelöscht ? "Python" >>> some_dict[5] "Python" @@ -633,7 +638,7 @@ complex "Python" ``` -So, why is Python all over the place? +Warum also ist Python ĂŒberall zu finden ? #### 💡 ErklĂ€rung @@ -672,7 +677,7 @@ So, why is Python all over the place? --- -### ▶ Deep down, we're all the same. +### ▶ Tief im Inneren sind wir alle gleich ```py class WTF: @@ -722,7 +727,7 @@ True --- -### ▶ Disorder within order * +### ▶ Unordnung in der Ordnung * ```py from collections import OrderedDict @@ -780,7 +785,7 @@ TypeError: unhashable type: 'dict' 2 ``` -What is going on here? +Was geht hier vor ? #### 💡 ErklĂ€rung: @@ -820,7 +825,7 @@ What is going on here? --- -### ▶ Keep trying... * +### ▶ Versuche es weiter... * ```py def some_func(): @@ -881,7 +886,7 @@ Iteration 0 --- -### ▶ For what? +### ▶ WofĂŒr? ```py some_string = "wtf" @@ -918,7 +923,7 @@ for i, some_dict[i] in enumerate(some_string): 3 ``` - Did you expect the loop to run just once? + Hast du erwartet, dass die Schleife nur einmal lĂ€uft ? **💡 ErklĂ€rung:** @@ -934,7 +939,7 @@ for i, some_dict[i] in enumerate(some_string): --- -### ▶ Evaluation time discrepancy +### ▶ Diskrepanz in der Auswertungszeit 1\. ```py @@ -1003,7 +1008,7 @@ array_4 = [400, 500, 600] --- -### ▶ `is not ...` is not `is (not ...)` +### ▶ `is not ...` ist nicht `is (not ...)` ```py >>> 'something' is not None @@ -1020,7 +1025,7 @@ False --- -### ▶ A tic-tac-toe where X wins in the first attempt! +### ▶ Ein tic-tac-toe wo X im ersten Versuch gewinnt! ```py @@ -1067,7 +1072,7 @@ We can avoid this scenario here by not using `row` variable to generate `board`. --- -### ▶ Schrödinger's variable * +### ▶ Schrödingers Variable * @@ -1143,7 +1148,7 @@ ClosureVars(nonlocals={}, globals={}, builtins={}, unbound=set()) --- -### ▶ The chicken-egg problem * +### ▶ Das Henne-Ei-Problem * 1\. ```py @@ -1193,7 +1198,7 @@ False --- -### ▶ Subclass relationships +### ▶ Beziehungen in Unterklassen **Ausgabe:** ```py @@ -1217,7 +1222,7 @@ The Subclass relationships were expected to be transitive, right? (i.e., if `A` --- -### ▶ Methods equality and identity +### ▶ Methodengleichheit und -identitĂ€t 1. @@ -1356,7 +1361,7 @@ Why's this True-False alteration? --- -### ▶ The surprising comma +### ▶ Das ĂŒberraschende Komma **Ausgabe (< 3.6):** @@ -1388,7 +1393,7 @@ SyntaxError: invalid syntax --- -### ▶ Strings and the backslashes +### ▶ Strings und die Backslashes **Ausgabe:** ```py @@ -1458,7 +1463,7 @@ SyntaxError: invalid syntax --- -### ▶ Half triple-quoted strings +### ▶ Halbe Zeichenketten in dreifachen AnfĂŒhrungszeichen **Ausgabe:** ```py @@ -1487,7 +1492,7 @@ SyntaxError: EOF while scanning triple-quoted string literal --- -### ▶ What's wrong with booleans? +### ▶ Was ist falsch an booleans? 1\. @@ -1577,7 +1582,7 @@ I have lost faith in truth! --- -### ▶ Class attributes and instance attributes +### ▶ Klassen- und Instanzattribute 1\. ```py @@ -1673,7 +1678,7 @@ def some_func(val): #### 💡 ErklĂ€rung: - This is a bug in CPython's handling of `yield` in generators and comprehensions. -- Source and ErklĂ€rung can be found here: https://stackoverflow.com/questions/32139885/yield-in-list-comprehensions-and-generator-expressions +- Quelle and ErklĂ€rung can be found here: https://stackoverflow.com/questions/32139885/yield-in-list-comprehensions-and-generator-expressions - Related bug report: https://bugs.python.org/issue10544 - Python 3.8+ no longer allows `yield` inside list comprehension and will throw a `SyntaxError`. @@ -1745,7 +1750,7 @@ The same result, this didn't work either. --- -### ▶ Nan-reflexivity * +### ▶ Nan-ReflexivitĂ€t * @@ -1821,7 +1826,7 @@ True --- -### ▶ Mutating the immutable! +### ▶ VerĂ€ndern des UnverĂ€nderlichen! @@ -1849,7 +1854,7 @@ But I thought tuples were immutable... #### 💡 ErklĂ€rung: -* Quoting from https://docs.python.org/3/reference/datamodel.html +* Zitat von https://docs.python.org/3/reference/datamodel.html > Immutable sequences An object of an immutable sequence type cannot change once it is created. (If the object contains references to other objects, these other objects may be mutable and may be modified; however, the collection of objects directly referenced by an immutable object cannot change.) @@ -1859,7 +1864,7 @@ But I thought tuples were immutable... --- -### ▶ The disappearing variable from outer scope +### ▶ Die verschwindende Variable aus dem Ă€ußeren GĂŒltigkeitsbereich ```py @@ -1884,7 +1889,7 @@ NameError: name 'e' is not defined #### 💡 ErklĂ€rung: -* Source: https://docs.python.org/3/reference/compound_stmts.html#except +* Quelle: https://docs.python.org/3/reference/compound_stmts.html#except When an exception has been assigned using `as` target, it is cleared at the end of the `except` clause. This is as if @@ -1941,7 +1946,7 @@ NameError: name 'e' is not defined --- -### ▶ The mysterious key type conversion +### ▶ Die mysteriöse key type Umwandlung ```py class SomeClass(str): @@ -1997,7 +2002,7 @@ str --- -### ▶ Let's see if you can guess this? +### ▶ Lass uns sehen, ob du dies errĂ€tst? ```py a, b = a[b] = {}, 5 @@ -2055,7 +2060,7 @@ a, b = a[b] = {}, 5 --- -### ▶ Exceeds the limit for integer string conversion +### ▶ Überschreitet den Grenzwert fĂŒr die Umwandlung von Integer-Strings ```py >>> # Python 3.10.6 >>> int("2" * 5432) @@ -2093,7 +2098,7 @@ Fortunately, you can increase the limit for the allowed number of digits when yo ## Section: Slippery Slopes -### ▶ Modifying a dictionary while iterating over it +### ▶ Modifizieren eines Dictionarys wĂ€hrend einer Iteration ```py x = {0: None} @@ -2129,7 +2134,7 @@ Yes, it runs for exactly **eight** times and stops. --- -### ▶ Stubborn `del` operation +### ▶ HartnĂ€ckige `del` Operation @@ -2174,7 +2179,7 @@ Okay, now it's deleted :confused: --- -### ▶ The out of scope variable +### ▶ Die Variable aus dem Ă€ußeren Geltungsbereich 1\. @@ -2254,7 +2259,7 @@ UnboundLocalError: local variable 'a' referenced before assignment --- -### ▶ Deleting a list item while iterating +### ▶ Löschen eines Listenelements wĂ€hrend einer Iteration ```py list_1 = [1, 2, 3, 4] @@ -2315,7 +2320,7 @@ Can you guess why the Ausgabe is `[2, 4]`? --- -### ▶ Lossy zip of iterators * +### ▶ Lossy Zips von Iteratoren * ```py @@ -2364,7 +2369,7 @@ Where did element `3` go from the `numbers` list? --- -### ▶ Loop variables leaking out! +### ▶ Schleifenvariablen, die auslaufen! 1\. ```py @@ -2428,7 +2433,7 @@ print(x, ': x in global') --- -### ▶ Beware of default mutable arguments! +### ▶ Vorsicht vor standardmĂ€ĂŸig verĂ€nderbaren Argumenten! ```py @@ -2486,7 +2491,7 @@ def some_func(default_arg=[]): --- -### ▶ Catching the Exceptions +### ▶ Fangen der Exceptions ```py some_list = [1, 2, 3] @@ -2561,7 +2566,7 @@ SyntaxError: invalid syntax --- -### ▶ Same operands, different story! +### ▶ Gleiche Operanden, unterschiedliche Story! 1\. ```py @@ -2603,7 +2608,7 @@ a += [5, 6, 7, 8] --- -### ▶ Name resolution ignoring class scope +### ▶ Namensauflösung ohne BerĂŒcksichtigung des Geltungsbereichs der Klasse 1\. ```py @@ -2646,7 +2651,7 @@ class SomeClass: --- -### ▶ Rounding like a banker * +### ▶ Runden wie ein Bankier * Let's implement a naive function to get the middle element of a list: ```py @@ -2696,7 +2701,7 @@ It seems as though Python rounded 2.5 to 2. --- -### ▶ Needles in a Haystack * +### ▶ Nadeln im Heuhaufen * @@ -2909,7 +2914,7 @@ def similar_recursive_func(a): --- -### ▶ Wild imports * +### ▶ Wilde Imports * @@ -2968,7 +2973,7 @@ NameError: name '_another_weird_name_func' is not defined --- -### ▶ All sorted? * +### ▶ Alles sortieren ? * @@ -3009,7 +3014,7 @@ False --- -### ▶ Midnight time doesn't exist? +### ▶ Mitternachtszeit gibt es nicht ? ```py from datetime import datetime @@ -3043,11 +3048,11 @@ Before Python 3.5, the boolean value for `datetime.time` object was considered t -## Section: The Hidden treasures! +## Section: Die verborgenen SchĂ€tze! This section contains a few lesser-known and interesting things about Python that most beginners like me are unaware of (well, not anymore). -### ▶ Okay Python, Can you make me fly? +### ▶ Okay Python, kannst du mich fliegen lassen? Well, here you go @@ -3065,7 +3070,7 @@ Sshh... It's a super-secret. --- -### ▶ `goto`, but why? +### ▶ `goto`, aber wieso? ```py @@ -3094,7 +3099,7 @@ Freedom! --- -### ▶ Brace yourself! +### ▶ Halte dich fest! If you are one of the people who doesn't like using whitespace in Python to denote scopes, you can use the C-style {} by importing, @@ -3150,7 +3155,7 @@ There we go. --- -### ▶ Even Python understands that love is complicated +### ▶ Selbst Python versteht, dass Liebe kompliziert ist ```py import this @@ -3207,7 +3212,7 @@ True --- -### ▶ Yes, it exists! +### ▶ Ja, es existiert! **The `else` clause for loops.** One typical example might be: @@ -3251,7 +3256,7 @@ Try block executed successfully... - `else` clause after a try block is also called "completion clause" as reaching the `else` clause in a `try` statement means that the try block actually completed successfully. --- -### ▶ Ellipsis * +### ▶ Ellipsen * ```py def some_func(): @@ -3311,7 +3316,7 @@ Ellipsis --- -### ▶ Inpinity +### ▶ Einbindung The spelling is intended. Please, don't submit a patch for this. @@ -3330,7 +3335,7 @@ The spelling is intended. Please, don't submit a patch for this. --- -### ▶ Let's mangle +### ▶ Lass uns demolieren 1\. ```py @@ -3406,9 +3411,9 @@ AttributeError: 'A' object has no attribute '__variable' --- --- -## Section: Appearances are deceptive! +## Section: Der Schein trĂŒgt! -### ▶ Skipping lines? +### ▶ Zeilen ĂŒberspringen? **Ausgabe:** ```py @@ -3477,7 +3482,7 @@ Where's the Nobel Prize? --- -### ▶ Well, something is fishy... +### ▶ Da ist wohl irgendwas faul... ```py def square(x): @@ -3518,10 +3523,10 @@ Shouldn't that be 100? --- --- -## Section: Miscellaneous +## Section: Sonstiges -### ▶ `+=` is faster +### ▶ `+=` ist schneller ```py @@ -3538,7 +3543,7 @@ Shouldn't that be 100? --- -### ▶ Let's make a giant string! +### ▶ Lass uns einen gigantischen String machen! ```py def add_string_with_plus(iters): @@ -3632,7 +3637,7 @@ Let's increase the number of iterations by a factor of 10. --- -### ▶ Slowing down `dict` lookups * +### ▶ Verlangsamen von `dict` Lookups * ```py some_dict = {str(i): 1 for i in range(1_000_000)} @@ -3665,7 +3670,7 @@ Why are same lookups becoming slower? + This process is not reversible for the particular `dict` instance, and the key doesn't even have to exist in the dictionary. That's why attempting a failed lookup has the same effect. -### ▶ Bloating instance `dict`s * +### ▶ BlĂ€hende Instanz `dict`s * ```py import sys @@ -3727,7 +3732,7 @@ What makes those dictionaries become bloated? And why are newly created objects + A small tip, if you aim to lower your program's memory footprint: don't delete instance attributes, and make sure to initialize all attributes in your `__init__`! -### ▶ Minor Ones * +### ▶ Kleinigkeiten * * `join()` is a string operation instead of list operation. (sort of counter-intuitive at first usage) From ec719a5787e37abd896ed75fa4eda5cfc585e62d Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Wed, 26 Apr 2023 21:51:54 +0200 Subject: [PATCH 05/20] #4 translation --- README.md | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c014157d..67d2f2f9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

What the f*ck Python! đŸ˜±

Entdecke und verstehe Python durch ĂŒberraschende Code-Schnipsel.

-Übersetzungen: [English](https://github.com/robertparley/wtfpython-cn) | +Übersetzungen: [English](https://github.com/satwikkansal/wtfpython) | Andere Modi: [Interaktiv](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) @@ -29,7 +29,7 @@ Also, los gehts... - [Sruktur der Beispiele](#sruktur-der-beispiele) - [Benutzung](#benutzung) - [👀 Beispiele](#-beispiele) - - [Kapitel: Strain your brain!](#kapitel-strain-your-brain) + - [Kapitel: Fordere dein Gehirn heraus!](#kapitel-fordere-dein-gehirn-heraus) - [▶ Das Wichtigste zuerst! \*](#-das-wichtigste-zuerst-) - [💡 ErklĂ€rung](#-erklĂ€rung) - [▶ Strings können manchmal schwierig sein](#-strings-können-manchmal-schwierig-sein) @@ -91,7 +91,7 @@ Also, los gehts... - [💡 ErklĂ€rung:](#-erklĂ€rung-29) - [▶ Überschreitet den Grenzwert fĂŒr die Umwandlung von Integer-Strings](#-ĂŒberschreitet-den-grenzwert-fĂŒr-die-umwandlung-von-integer-strings) - [💡 ErklĂ€rung:](#-erklĂ€rung-30) - - [Section: Slippery Slopes](#section-slippery-slopes) + - [Kapitel: Slippery Slopes](#kapitel-slippery-slopes) - [▶ Modifizieren eines Dictionarys wĂ€hrend einer Iteration](#-modifizieren-eines-dictionarys-wĂ€hrend-einer-iteration) - [💡 ErklĂ€rung:](#-erklĂ€rung-31) - [▶ HartnĂ€ckige `del` Operation](#-hartnĂ€ckige-del-operation) @@ -124,7 +124,7 @@ Also, los gehts... - [💡 ErklĂ€rung:](#-erklĂ€rung-45) - [▶ Mitternachtszeit gibt es nicht ?](#-mitternachtszeit-gibt-es-nicht-) - [💡 ErklĂ€rung:](#-erklĂ€rung-46) - - [Section: Die verborgenen SchĂ€tze!](#section-die-verborgenen-schĂ€tze) + - [Kapitel: Die verborgenen SchĂ€tze!](#kapitel-die-verborgenen-schĂ€tze) - [▶ Okay Python, kannst du mich fliegen lassen?](#-okay-python-kannst-du-mich-fliegen-lassen) - [💡 ErklĂ€rung:](#-erklĂ€rung-47) - [▶ `goto`, aber wieso?](#-goto-aber-wieso) @@ -143,14 +143,14 @@ Also, los gehts... - [💡 ErklĂ€rung:](#-erklĂ€rung-54) - [▶ Lass uns demolieren](#-lass-uns-demolieren) - [💡 ErklĂ€rung:](#-erklĂ€rung-55) - - [Section: Der Schein trĂŒgt!](#section-der-schein-trĂŒgt) + - [Kapitel: Der Schein trĂŒgt!](#kapitel-der-schein-trĂŒgt) - [▶ Zeilen ĂŒberspringen?](#-zeilen-ĂŒberspringen) - [💡 ErklĂ€rung](#-erklĂ€rung-56) - [▶ Teleportation](#-teleportation) - [💡 ErklĂ€rung:](#-erklĂ€rung-57) - [▶ Da ist wohl irgendwas faul...](#-da-ist-wohl-irgendwas-faul) - [💡 ErklĂ€rung](#-erklĂ€rung-58) - - [Section: Sonstiges](#section-sonstiges) + - [Kapitel: Sonstiges](#kapitel-sonstiges) - [▶ `+=` ist schneller](#--ist-schneller) - [💡 ErklĂ€rung:](#-erklĂ€rung-59) - [▶ Lass uns einen gigantischen String machen!](#-lass-uns-einen-gigantischen-string-machen) @@ -225,7 +225,7 @@ $ wtfpython # 👀 Beispiele -## Kapitel: Strain your brain! +## Kapitel: Fordere dein Gehirn heraus! ### ▶ Das Wichtigste zuerst! * @@ -411,17 +411,22 @@ False Ergibt Sinn, Oder? #### 💡 ErklĂ€rung: -+ The behavior in first and second snippets is due to a CPython optimization (called string interning) that tries to use existing immutable objects in some cases rather than creating a new object every time. -+ After being "interned," many variables may reference the same string object in memory (saving memory thereby). -+ In the snippets above, strings are implicitly interned. The decision of when to implicitly intern a string is implementation-dependent. There are some rules that can be used to guess if a string will be interned or not: - * All length 0 and length 1 strings are interned. - * Strings are interned at compile time (`'wtf'` will be interned but `''.join(['w', 't', 'f'])` will not be interned) - * Strings that are not composed of ASCII letters, digits or underscores, are not interned. This explains why `'wtf!'` was not interned due to `!`. CPython implementation of this rule can be found [here](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19) ++ Das Verhalten im ersten und zweiten Schnipsel erklĂ€rt sich durch eine CPython Optimierung (auch string interning genannt), die versucht, existierende +immutable Objekte zu nutzen anstatt jedes mal ein neues Objekt zu erstellen. ++ Nachdem "interned" (festgehalten) wurde, kann es sein, dass viele Variablen dasselbe String-Objekt im Speicher referenzieren (man spart also Speicher). + ++ In den Schnipseln oben werden Strings implizit festgehalten. Die Entscheidung, wann ein String implizit festgehalten wird, ist von der Implementierung +abhĂ€ngig. Es gibt einige Regeln, die benutzt werden können, um zu erahnen, ob ein String festgehalten wird oder nicht: + * Alle String der LĂ€nge 0 und 1 werden festgehalten. + * Strings werden wĂ€hrend der Compilezeit festgehalten (`'wtf'` wird festgehalten, aber `''.join(['w', 't', 'f'])` nicht) + * Strings, die nicht aus ASCII-Buchstaben, Ziffern oder Unterstrichen zusammengesetzt sind, werden nicht festgehalten. Das erklĂ€rt warum `'wtf!'` nicht festgehalten wurde (wegen `!`). + Die CPython-Implementierung dieser Regel kann [hier](https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19) gefunden werden ![image](/images/string-intern/string_intern.png) -+ When `a` and `b` are set to `"wtf!"` in the same line, the Python interpreter creates a new object, then references the second variable at the same time. If you do it on separate lines, it doesn't "know" that there's already `"wtf!"` as an object (because `"wtf!"` is not implicitly interned as per the facts mentioned above). It's a compile-time optimization. This optimization doesn't apply to 3.7.x versions of CPython (check this [issue](https://github.com/satwikkansal/wtfpython/issues/100) for more discussion). -+ A compile unit in an interactive environment like IPython consists of a single statement, whereas it consists of the entire module in case of modules. `a, b = "wtf!", "wtf!"` is single statement, whereas `a = "wtf!"; b = "wtf!"` are two statements in a single line. This explains why the identities are different in `a = "wtf!"; b = "wtf!"`, and also explain why they are same when invoked in `some_file.py` -+ The abrupt change in the Ausgabe of the fourth snippet is due to a [peephole optimization](https://en.wikipedia.org/wiki/Peephole_optimization) technique known as Constant folding. This means the expression `'a'*20` is replaced by `'aaaaaaaaaaaaaaaaaaaa'` during compilation to save a few clock cycles during runtime. Constant folding only occurs for strings having a length of less than 21. (Why? Imagine the size of `.pyc` file generated as a result of the expression `'a'*10**10`). [Here's](https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288) the implementation source for the same. -+ Note: In Python 3.7, Constant folding was moved out from peephole optimizer to the new AST optimizer with some change in logic as well, so the fourth snippet doesn't work for Python 3.7. You can read more about the change [here](https://bugs.python.org/issue11549). ++ Wenn `a` und `b` in derselben Zeile auf `"wtf!"` gesetzt werden, erzeugt der Python Interpreter ein neues Objekt, welches von der zweiten Variable zur selben Zeit referenziert wird. Wenn du es in zwei verschiedenen Zeilen deklarierst, dann "weiß" der Interpreter nicht, dass `"wtf!"` als Objekt schon existiert (weil `"wtf!"` nicht implizit festgehalten wird, siehe obige Auflistung). Es ist eine Compilezeit-Optimierung. Diese Optimierung gilt nicht fĂŒr 3.7.x Versionen von CPython (siehe dieses [Issue](https://github.com/satwikkansal/wtfpython/issues/100)). ++ Eine Compile-Unit ist eine interaktive Umgebung, wie z.B. IPython besteht aus einen einzigen Statement, wĂ€hrend es aus einem ganzen Modul im Falle von Modulen besteht. `a, b = "wtf!", "wtf!"` ist ein einziges Statement, wĂ€hrend `a = "wtf!"; b = "wtf!"` zwei Statements in einer Zeile sind. Das erklĂ€rt, warum die IdentitĂ€ten `a = "wtf!"; b = "wtf!"` verschieden sind. Es erklĂ€rt auch, warum sie dieselben sind, wenn sie in `some_file.py` aufgerufen werden. ++ Die abrupte VerĂ€nderung in der Ausgabe des 4.Schnipsel ist der [peephole Optimierung](https://en.wikipedia.org/wiki/Peephole_optimization) Technik +geschuldet, auch als Constant Folding bekannt. Das bedeutet, der Ausdruck `'a'*20` wird durch `'aaaaaaaaaaaaaaaaaaaa'` wĂ€hrend der Kompilierung ersetzt, um ein paar Taktzyklen wĂ€hrend der Laufzeit zu sparen. Constant Folding wird nur fĂŒr String mit einer kleineren LĂ€nge als 21 angewendet. (Wieso ? Stelle dir die GrĂ¶ĂŸe einer `.pyc` Datei vor, die durch den Ausdruck `'a'*10**10` generiert wurde). [Hier](https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288) ist die Quelle der Implementierung dafĂŒr. ++ Notiz: In Python 3.7, konstantes Folding wurde vom peephole-Optimierer zum neuen AST-Optimierer verschoben (mit ein paar VerĂ€nderungen in der Logik), d.h. das 4.Schnipsel funktioniert in Python 3.7 nicht. Du kannst [hier](https://bugs.python.org/issue11549) mehr darĂŒber erfahren. --- @@ -2096,7 +2101,7 @@ Fortunately, you can increase the limit for the allowed number of digits when yo --- -## Section: Slippery Slopes +## Kapitel: Slippery Slopes ### ▶ Modifizieren eines Dictionarys wĂ€hrend einer Iteration @@ -3048,7 +3053,7 @@ Before Python 3.5, the boolean value for `datetime.time` object was considered t -## Section: Die verborgenen SchĂ€tze! +## Kapitel: Die verborgenen SchĂ€tze! This section contains a few lesser-known and interesting things about Python that most beginners like me are unaware of (well, not anymore). @@ -3411,7 +3416,7 @@ AttributeError: 'A' object has no attribute '__variable' --- --- -## Section: Der Schein trĂŒgt! +## Kapitel: Der Schein trĂŒgt! ### ▶ Zeilen ĂŒberspringen? @@ -3523,7 +3528,7 @@ Shouldn't that be 100? --- --- -## Section: Sonstiges +## Kapitel: Sonstiges ### ▶ `+=` ist schneller From 2bd8616788f8b824ac7a2909300a20bad2b0bb0d Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Sun, 30 Apr 2023 20:53:26 +0200 Subject: [PATCH 06/20] added transl #5 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 67d2f2f9..6410b577 100644 --- a/README.md +++ b/README.md @@ -327,11 +327,11 @@ if a := irgendeine_funktion(): Das hat uns eine Zeile Code erspart. Zudem spart es einen zusĂ€tzlichen Aufruf der Funktion `irgendeine_funktion`. -- Unparenthesized "assignment expression" (use of walrus operator), is restricted at the top level, hence the `SyntaxError` in the `a := "wtf_walrus"` statement of the first snippet. Parenthesizing it worked as expected and assigned `a`. +- Nichtgeklammerte "Zuweisung Ausdruck" (Verwendung des Walrus-Operator), ist auf der obersten Ebene beschrĂ€nkt, daher der `Syntaxfehler` in der Anweisung `a := "wtf_walrus"` des erstes Schnipsels. Einklammeren hat funktioniert und wies `a` zu. -- As usual, parenthesizing of an expression containing `=` operator is not allowed. Hence the syntax error in `(a, b = 6, 9)`. +- Wie immer, Einklammerung eines Ausdrucks, welcher `=`- Operator enthĂ€lt, ist nicht erlaubt. Daher der Syntaxfehler in `(a, b = 6, 9)`. -- The syntax of the Walrus operator is of the form `NAME:= expr`, where `NAME` is a valid identifier, and `expr` is a valid expression. Hence, iterable packing and unpacking are not supported which means, +- Die Syntax des Walrus Operators lautet wie folgt: `NAME:= ausdruck`, wobei `NAME` ist ein gĂŒltiger Identifier, und `ausdruck` ist ein gĂŒltiger Ausdruck. Zudem werden iterierbares Verpacken und Entpacken nicht unterstĂŒtzt, d.h.: - `(a := 6, 9)` ist Ă€quivalent zu `((a := 6), 9)` und zu `(a, 9) ` (where `a`'s value is 6') @@ -678,7 +678,7 @@ Warum also ist Python ĂŒberall zu finden ? >>> hash(5) == hash(5.0) == hash(5 + 0j) True ``` - **Note:** The inverse is not necessarily true: Objects with equal hash values may themselves be unequal. (This causes what's known as a [hash collision](https://en.wikipedia.org/wiki/Collision_(computer_science)), and degrades the constant-time performance that hashing usually provides.) + **Note:** Das Inverse ist nicht unbedingt wahr: Objekte mit gleichem Hashwert können evtl. ungleich sein. (Das versursacht was auch als [hash collision](https://de.wikipedia.org/wiki/Kollisionsresistenz) bekannt ist), und und verschlechtert die zeitlich konstante Leistung, die Hashing normalerweise bietet. --- From 05106a53ff082f84ed3981ea8587650c4ed034c3 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Mon, 15 May 2023 20:17:15 +0200 Subject: [PATCH 07/20] #6 --- README.md | 164 +++++++++++++++++++++++++++--------------------------- 1 file changed, 83 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 6410b577..7222e0b6 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ Also, los gehts... - [▶ BlĂ€hende Instanz `dict`s \*](#-blĂ€hende-instanz-dicts-) - [💡 ErklĂ€rung:](#-erklĂ€rung-62) - [▶ Kleinigkeiten \*](#-kleinigkeiten-) + - [Das Verhalten ist darauf zurĂŒckzufĂŒhren, dass leere Teilstrings (`''`) mit Slices der LĂ€nge 0 in der ursprĂŒnglichen Zeichenkette ĂŒbereinstimmen](#das-verhalten-ist-darauf-zurĂŒckzufĂŒhren-dass-leere-teilstrings--mit-slices-der-lĂ€nge-0-in-der-ursprĂŒnglichen-zeichenkette-ĂŒbereinstimmen) - [Contributing](#contributing) - [Anerkennung](#anerkennung) - [Ein paar nĂŒtzliche Links!](#ein-paar-nĂŒtzliche-links) @@ -3055,23 +3056,23 @@ Before Python 3.5, the boolean value for `datetime.time` object was considered t ## Kapitel: Die verborgenen SchĂ€tze! -This section contains a few lesser-known and interesting things about Python that most beginners like me are unaware of (well, not anymore). +Dieser Abschnitt enthĂ€lt ein paar weniger bekannte und interessante Dinge ĂŒber Python, die den meisten AnfĂ€ngern wie mir nicht bekannt sind (nun aber schon). ### ▶ Okay Python, kannst du mich fliegen lassen? -Well, here you go +Nun hier wĂ€ren wir: ```py import antigravity ``` **Ausgabe:** -Sshh... It's a super-secret. +Sshh... Es ist supergeheim. #### 💡 ErklĂ€rung: -+ `antigravity` module is one of the few easter eggs released by Python developers. -+ `import antigravity` opens up a web browser pointing to the [classic XKCD comic](https://xkcd.com/353/) about Python. -+ Well, there's more to it. There's **another easter egg inside the easter egg**. If you look at the [code](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17), there's a function defined that purports to implement the [XKCD's geohashing algorithm](https://xkcd.com/426/). ++ Das `antigravity` Modul ist eines der wenigen easter eggs, die von Python Entwicklern veröffentlicht werden. ++ `import antigravity` öffnet deinen Webbrowser und zeigt zum [klassischen XKCD Comic](https://xkcd.com/353/). ++ Nun, es gibt noch mehr. Es gibt noch ein **easter egg im easter egg**. Wenn du dir den [code](https://github.com/python/cpython/blob/master/Lib/antigravity.py#L7-L17) anschaust, dann findest du eine Funktion, die die AusfĂŒhrung des [XKCDs Geohashing Algorithmus](https://xkcd.com/426/) beabsichtigt. --- @@ -3098,15 +3099,15 @@ Freedom! ``` #### 💡 ErklĂ€rung: -- A working version of `goto` in Python was [announced](https://mail.python.org/pipermail/python-announce-list/2004-April/002982.html) as an April Fool's joke on 1st April 2004. -- Current versions of Python do not have this module. -- Although it works, but please don't use it. Here's the [reason](https://docs.python.org/3/faq/design.html#why-is-there-no-goto) to why `goto` is not present in Python. +- Eine funktionierende Version von `goto` in Python wurde als Aprilscherz am 1. April 2004 [angekĂŒndigt](https://mail.python.org/pipermail/python-announce-list/2004-April/002982.html). +- Aktuelle Versionen von Python haben dieses Modul nicht. +- Auch wenn es funktioniert, benutze es bitte nicht. Hier ist die [Antwort](https://docs.python.org/3/faq/design.html#why-is-there-no-goto), warum `goto` in Python nicht verwendet wird. --- ### ▶ Halte dich fest! -If you are one of the people who doesn't like using whitespace in Python to denote scopes, you can use the C-style {} by importing, +Wenn du zu den Leuten gehörst, die keine Leerzeichen in Python verwenden wollen, um Bereiche zu kennzeichnen, kannst du den C-Stil {} verwenden, indem du folgendes importierst: ```py from __future__ import braces @@ -3119,13 +3120,13 @@ from __future__ import braces SyntaxError: not a chance ``` -Braces? No way! If you think that's disappointing, use Java. Okay, another surprising thing, can you find where's the `SyntaxError` raised in `__future__` module [code](https://github.com/python/cpython/blob/master/Lib/__future__.py)? +Klammern? Niemals! Wenn du enttĂ€uscht bist, nutze Java. Okay, eine weitere ĂŒberraschende Sache, kannst du herausfinden, wo `SyntaxError` im `__future__` Mmodul geworfen wird [code](https://github.com/python/cpython/blob/master/Lib/__future__.py)? #### 💡 ErklĂ€rung: -+ The `__future__` module is normally used to provide features from future versions of Python. The "future" in this specific context is however, ironic. -+ This is an easter egg concerned with the community's feelings on this issue. -+ The code is actually present [here](https://github.com/python/cpython/blob/025eb98dc0c1dc27404df6c544fc2944e0fa9f3a/Python/future.c#L49) in `future.c` file. -+ When the CPython compiler encounters a [future statement](https://docs.python.org/3.3/reference/simple_stmts.html#future-statements), it first runs the appropriate code in `future.c` before treating it as a normal import statement. ++ Das `__future__` Modul wird normalerweise benutzt, um Features von zukĂŒnftigen Python Versionen bereitzustellen. Das "future" is in diesem spezifischen Kontext ironisch gemeint. ++ Das ist ein easter egg die die GefĂŒhle der Community in dieser Frage wiederspiegeln. ++ Der Code ist tatsĂ€chlich [hier](https://github.com/python/cpython/blob/025eb98dc0c1dc27404df6c544fc2944e0fa9f3a/Python/future.c#L49) in der Datei `future.c` verfĂŒgbar. ++ Wenn der CPython Compiler auf ein [future Statement](https://docs.python.org/3.3/reference/simple_stmts.html#future-statements) trifft, wird zunĂ€chst der entsprechende Code in `future.c` ausgefĂŒhrt, bevor es als normale Importanweisung behandelt wird. --- @@ -3134,7 +3135,7 @@ Braces? No way! If you think that's disappointing, use Java. Okay, another surpr **Ausgabe (Python 3.x)** ```py >>> from __future__ import barry_as_FLUFL ->>> "Ruby" != "Python" # there's no doubt about it +>>> "Ruby" != "Python" # Hier bestehen keine Zweifel File "some_file.py", line 1 "Ruby" != "Python" ^ @@ -3144,11 +3145,11 @@ SyntaxError: invalid syntax True ``` -There we go. +Das wars schon. #### 💡 ErklĂ€rung: -- This is relevant to [PEP-401](https://www.python.org/dev/peps/pep-0401/) released on April 1, 2009 (now you know, what it means). -- Quoting from the PEP-401 +-Das ist relevant fĂŒr [PEP-401](https://www.python.org/dev/peps/pep-0401/), was am 1. April 2009 veröffentlicht wurde (nun weißt du, was das heißt). +- Zitat vom PEP-401 > Recognized that the != inequality operator in Python 3.0 was a horrible, finger-pain inducing mistake, the FLUFL reinstates the <> diamond operator as the sole spelling. - There were more things that Uncle Barry had to share in the PEP; you can read them [here](https://www.python.org/dev/peps/pep-0401/). @@ -3166,11 +3167,11 @@ There we go. import this ``` -Wait, what's **this**? `this` is love :heart: +Warte, was ist **this**? `this` ist love :heart: **Ausgabe:** ``` -The Zen of Python, by Tim Peters +Der Zen von Python, von Tim Peters Beautiful is better than ugly. Explicit is better than implicit. @@ -3193,7 +3194,7 @@ If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those! ``` -It's the Zen of Python! +Das ist der Zen von Python! ```py >>> love = this @@ -3219,7 +3220,7 @@ True ### ▶ Ja, es existiert! -**The `else` clause for loops.** One typical example might be: +**The `else` clause for loops.** Ein typisches Beispiel wĂ€re: ```py def does_exists_num(l, to_find): @@ -3240,7 +3241,7 @@ Exists! Does not exist ``` -**The `else` clause in exception handling.** An example, +**The `else` clause in exception handling.** Ein Beispiel: ```py try: @@ -3271,7 +3272,7 @@ def some_func(): **Ausgabe** ```py >>> some_func() -# No Ausgabe, No Error +# Keine Ausgabe, Kein Fehler >>> SomeRandomString Traceback (most recent call last): @@ -3283,7 +3284,7 @@ Ellipsis ``` #### 💡 ErklĂ€rung -- In Python, `Ellipsis` is a globally available built-in object which is equivalent to `...`. +- In Python, `Ellipsis` ist ein global verfĂŒgbares built-in Objekt, was Ă€quivalent ist zu `...`. ```py >>> ... Ellipsis @@ -3323,7 +3324,7 @@ Ellipsis ### ▶ Einbindung -The spelling is intended. Please, don't submit a patch for this. +Die Schreibweise ist beabsichtigt. Bitte schicke keinen Patch hierfĂŒr ab. **Ausgabe (Python 3.x):** ```py @@ -3364,7 +3365,7 @@ True ```py class Yo(object): def __init__(self): - # Let's try something symmetrical this time + # Versuchen wir es dieses Mal mit etwas Symmetrischem self.__honey__ = True self.bro = True ``` @@ -3380,7 +3381,7 @@ Traceback (most recent call last): AttributeError: 'Yo' object has no attribute '_Yo__honey__' ``` -Why did `Yo()._Yo__honey` work? +Warum hat `Yo()._Yo__honey` funktioniert? 3\. @@ -3389,7 +3390,7 @@ _A__variable = "Some value" class A(object): def some_func(self): - return __variable # not initialized anywhere yet + return __variable # noch nirgends initialisiert ``` **Ausgabe:** @@ -3406,7 +3407,7 @@ AttributeError: 'A' object has no attribute '__variable' #### 💡 ErklĂ€rung: -* [Name Mangling](https://en.wikipedia.org/wiki/Name_mangling) is used to avoid naming collisions between different namespaces. +* [Name Mangling](https://en.wikipedia.org/wiki/Name_mangling) wird verwendet, um Namenskollisionen zwischen verschiedenen namespaces zu vermeiden. * In Python, the interpreter modifies (mangles) the class member names starting with `__` (double underscore a.k.a "dunder") and not ending with more than one trailing underscore by adding `_NameOfTheClass` in front. * So, to access `__honey` attribute in the first snippet, we had to append `_Yo` to the front, which would prevent conflicts with the same name attribute defined in any other class. * But then why didn't it work in the second snippet? Because name mangling excludes the names ending with double underscores. @@ -3428,9 +3429,9 @@ AttributeError: 'A' object has no attribute '__variable' 11 ``` -Wut? +Was? -**Note:** The easiest way to reproduce this is to simply copy the statements from the above snippet and paste them into your file/shell. +**Note:** Um dies zu reproduzieren, kopiere einfach die Anweisungen aus dem obigen Ausschnitt und fĂŒge sie in deine Datei/Shell ein. #### 💡 ErklĂ€rung @@ -3459,15 +3460,15 @@ The built-in `ord()` function returns a character's Unicode [code point](https:/ ```py -# `pip install numpy` first. +# `pip install numpy` vorher. import numpy as np def energy_send(x): - # Initializing a numpy array + # Initialisiere ein numpy array np.array([float(x)]) def energy_receive(): - # Return an empty numpy array + # Gib ein leeres numpy array zurĂŒck return np.empty((), dtype=np.float).tolist() ``` @@ -3478,7 +3479,7 @@ def energy_receive(): 123.456 ``` -Where's the Nobel Prize? +Wo ist der Nobelpreis? #### 💡 ErklĂ€rung: @@ -3492,7 +3493,7 @@ Where's the Nobel Prize? ```py def square(x): """ - A simple function to calculate the square of a number by addition. + Eine einfahce FUnktion, um das Quadrat einer Zahl durch Addition zu bestimmen """ sum_so_far = 0 for counter in range(x): @@ -3507,9 +3508,9 @@ def square(x): 10 ``` -Shouldn't that be 100? +Sollte das nicht 100 sein? -**Note:** If you're not able to reproduce this, try running the file [mixed_tabs_and_spaces.py](/mixed_tabs_and_spaces.py) via the shell. +**Note:** Wenn du das Ergebnis nicht reproduzieren kannst, versuch die Datei [mixed_tabs_and_spaces.py](/mixed_tabs_and_spaces.py) via shell auszufĂŒhren. #### 💡 ErklĂ€rung @@ -3544,7 +3545,7 @@ Shouldn't that be 100? ``` #### 💡 ErklĂ€rung: -+ `+=` is faster than `+` for concatenating more than two strings because the first string (example, `s1` for `s1 += s2 + s3`) is not destroyed while calculating the complete string. ++ `+=` ist schneller als `+`, um mehr als zwei String zu konkatenieren, weil der erste String (Beispiel: `s1` fĂŒr `s1 += s2 + s3`), wĂ€hrend der Kalkulation des gesamten Strings, nicht zerstört wird. --- @@ -3636,9 +3637,9 @@ Let's increase the number of iterations by a factor of 10. >>> %timeit -n100 add_string_with_plus(10000) # Quadratic increase in execution time 9 ms ± 298 ”s per loop (mean ± std. dev. of 7 runs, 100 loops each) ``` -- So many ways to format and create a giant string are somewhat in contrast to the [Zen of Python](https://www.python.org/dev/peps/pep-0020/), according to which, +- So viele Möglichkeiten einen gigantischen String zu erzeugen und zu formatieren stehen irgendwie in Kontrast zum [Zen von Python](https://www.python.org/dev/peps/pep-0020/), nachdem gilt: - > There should be one-- and preferably only one --obvious way to do it. + > Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun. --- @@ -3666,11 +3667,11 @@ KeyError: 1 >>> %timeit another_dict['5'] 38.5 ns ± 0.0913 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) ``` -Why are same lookups becoming slower? +Wieso werden dieselben lookups immer langsamer? #### 💡 ErklĂ€rung: + CPython has a generic dictionary lookup function that handles all types of keys (`str`, `int`, any object ...), and a specialized one for the common case of dictionaries composed of `str`-only keys. -+ The specialized function (named `lookdict_unicode` in CPython's [source](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841)) knows all existing keys (including the looked-up key) are strings, and uses the faster & simpler string comparison to compare keys, instead of calling the `__eq__` method. ++ The specialized function (werden `lookdict_unicode` in CPythons [code](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841) genannt) knows all existing keys (including the looked-up key) are strings, and uses the faster & simpler string comparison to compare keys, instead of calling the `__eq__` method. + The first time a `dict` instance is accessed with a non-`str` key, it's modified so future lookups use the generic function. + This process is not reversible for the particular `dict` instance, and the key doesn't even have to exist in the dictionary. That's why attempting a failed lookup has the same effect. @@ -3693,7 +3694,7 @@ def dict_size(o): ``` -**Ausgabe:** (Python 3.8, other Python 3 versions may vary a little) +**Ausgabe:** (Python 3.8, oder Python 3 Versionen können ein bisschen variieren) ```py >>> o1 = SomeClass() >>> o2 = SomeClass() @@ -3709,7 +3710,7 @@ def dict_size(o): 232 ``` -Let's try again... In a new interpreter: +Versuchen wir es noch einmal... In einem neuen Interpreter: ```py >>> o1 = SomeClass() @@ -3739,16 +3740,16 @@ What makes those dictionaries become bloated? And why are newly created objects ### ▶ Kleinigkeiten * -* `join()` is a string operation instead of list operation. (sort of counter-intuitive at first usage) +* `join()` ist eine String-Operation anstatt einer List-Operation. (auf den ersten Blick nicht einfach zu verstehen) - **💡 ErklĂ€rung:** If `join()` is a method on a string, then it can operate on any iterable (list, tuple, iterators). If it were a method on a list, it'd have to be implemented separately by every type. Also, it doesn't make much sense to put a string-specific method on a generic `list` object API. + **💡 ErklĂ€rung:** Wenn `join()` eine Methode auf einem String ist, dann kann es auf irgendeinem Iterable operieren (Liste, Tuple, Iteratoren). WĂ€re es eine Methode auf einer Liste, mĂŒsste sie von jedem Typ separat implementiert werden. Außerdem macht es nicht viel Sinn, eine String-spezifische Methode auf eine generische API eines `listen`-Objektes anzuwenden -* Few weird looking but semantically correct statements: - + `[] = ()` is a semantically correct statement (unpacking an empty `tuple` into an empty `list`) - + `'a'[0][0][0][0][0]` is also semantically correct, because Python doesn't have a character data type like other languages branched from C. So selecting a single character from a string returns a single-character string. - + `3 --0-- 5 == 8` and `--5 == 5` are both semantically correct statements and evaluate to `True`. +* Ein paar komisch aussehende aber semantisch korrekte Statements: + + `[] = ()` ist ein semantisch korrektes Statement (entpacken eines leeren `Tuples` in eine leere `Liste`) + + `'a'[0][0][0][0][0]` ist auch semantisch korrect, weil Python keinen Char-Datentyp wie viele andere Sprachen, die auf C basieren, hat. Also ergibt das AuswĂ€hlen eines einzelnen Characters aus einem String einen Single-character String. + + `3 --0-- 5 == 8` und `--5 == 5` sind beides semantisch korrekte Statements und wird zu `True` ausgewertet. -* Given that `a` is a number, `++a` and `--a` are both valid Python statements but don't behave the same way as compared with similar statements in languages like C, C++, or Java. +* Sei `a` eine Zahl, `++a` und `--a` sind beides valide Python Statements aber sie verhaten sich nicht so wie vergleichbare Statements in Sprachen wie C, C++, oder Java. ```py >>> a = 5 >>> a @@ -3760,26 +3761,26 @@ What makes those dictionaries become bloated? And why are newly created objects ``` **💡 ErklĂ€rung:** - + There is no `++` operator in Python grammar. It is actually two `+` operators. - + `++a` parses as `+(+a)` which translates to `a`. Similarly, the Ausgabe of the statement `--a` can be justified. - + This StackOverflow [thread](https://stackoverflow.com/questions/3654830/why-are-there-no-and-operators-in-python) discusses the rationale behind the absence of increment and decrement operators in Python. + + Es gibt keinen `++` Operator in der Python Grammatik. Es handelt sich eigentlich um zwei `+` Operatoren. + + `++a` parst eigentlich `+(+a)` was ĂŒbersetzt wird zu `a`. In Ă€hnlicher Weise kann die Ausgabe des Statement `--a` begrĂŒndet werden. + + Dieser StackOverflow [Thread](https://stackoverflow.com/questions/3654830/why-are-there-no-and-operators-in-python) erörtert die GrĂŒnde fĂŒr das Fehlen von Inkrement- und Dekrementoperatoren in Python. -* You must be aware of the Walrus operator in Python. But have you ever heard about *the space-invader operator*? +* Der Walrus Operator in Python sollte dir bekannt sein. Aber hast du schon mal von dem *space-invader Operator* gehört? ```py >>> a = 42 >>> a -=- 1 >>> a 43 ``` - It is used as an alternative incrementation operator, together with another one + Er wird als alternativer Inkrementierungsoperator verwendet, zusammen mit einem anderen Operator ```py >>> a +=+ 1 >>> a >>> 44 ``` - **💡 ErklĂ€rung:** This prank comes from [Raymond Hettinger's tweet](https://twitter.com/raymondh/status/1131103570856632321?lang=en). The space invader operator is actually just a malformatted `a -= (-1)`. Which is equivalent to `a = a - (- 1)`. Similar for the `a += (+ 1)` case. + **💡 ErklĂ€rung:** Dieser Streich kommt von [Raymond Hettingers Tweet](https://twitter.com/raymondh/status/1131103570856632321?lang=en). Der Space Invader Operator ist tatsĂ€chlich nur ein schlecht formatiertes `a -= (-1)`, was Ă€quivalent zu `a = a - (- 1)` ist. Ähnliches gilt fĂŒr `a += (+ 1)`. -* Python has an undocumented [converse implication](https://en.wikipedia.org/wiki/Converse_implication) operator. +* Python hat einen undokumentierten [umgekehrten Implikations](https://en.wikipedia.org/wiki/Converse_implication) Operator. ```py >>> False ** False == True @@ -3792,9 +3793,9 @@ What makes those dictionaries become bloated? And why are newly created objects True ``` - **💡 ErklĂ€rung:** If you replace `False` and `True` by 0 and 1 and do the maths, the truth table is equivalent to a converse implication operator. ([Source](https://github.com/cosmologicon/pywat/blob/master/ErklĂ€rung.md#the-undocumented-converse-implication-operator)) + **💡 ErklĂ€rung:** If you replace `False` and `True` by 0 and 1 and do the maths, the truth table is equivalent to a converse implication operator. ([Quelle](https://github.com/cosmologicon/pywat/blob/master/ErklĂ€rung.md#the-undocumented-converse-implication-operator)) -* Since we are talking operators, there's also `@` operator for matrix multiplication (don't worry, this time it's for real). +* Weil wir ĂŒber Operatoren sprechen, erwĂ€hnen wir auch den `@` Ooperator, der fĂŒr Matrixmultiplikation benutzt wird (Keine Sorge, diese mal ist es ernst). ```py >>> import numpy as np @@ -3802,16 +3803,16 @@ What makes those dictionaries become bloated? And why are newly created objects 46 ``` - **💡 ErklĂ€rung:** The `@` operator was added in Python 3.5 keeping the scientific community in mind. Any object can overload `__matmul__` magic method to define behavior for this operator. + **💡 ErklĂ€rung:** Der `@` Operator wurde, mit der wissenschaftlichen Community im Hinterkopf, in Python 3.5 eingefĂŒhrt. Jedes Objekt kann die magische `__matmul__` Method ĂŒberladen, um ein bestimmtes Verhalten fĂŒr diesen Operator zu definieren. -* From Python 3.8 onwards you can use a typical f-string syntax like `f'{some_var=}` for quick debugging. Example, +* Ab Python 3.8 kannst du eine typische f-String-Syntax wie `f'{some_var=}` fĂŒr schnelles Debugging verwenden. Zum Beispiel: ```py >>> some_string = "wtfpython" >>> f'{some_string=}' "some_string='wtfpython'" ``` -* Python uses 2 bytes for local variable storage in functions. In theory, this means that only 65536 variables can be defined in a function. However, python has a handy solution built in that can be used to store more than 2^16 variable names. The following code demonstrates what happens in the stack when more than 65536 local variables are defined (Warning: This code prints around 2^18 lines of text, so be prepared!): +* Python nutzt 2 Bytes die Speicherung lokaler Variablen in Funktionen. Theoretisch heißt das, dass nur 65536 Variablen in einer Funktion gespeichert werden können. Allerdings hat Python eine praktische, eingebaute Lösung, die benutzt werden kann, um mehr als 2^16 Variablennamen zu speichern. Der folgende Code demonstriert, was im Stack passiert, wenn mehr als 65536 lokale Variablen definiert werden (Warnung: Dieser Code gibt ungefĂ€hr 2^18 Zeilen Text aus, also sei darauf vorbereitet!): ```py import dis @@ -3825,9 +3826,11 @@ What makes those dictionaries become bloated? And why are newly created objects print(dis.dis(f)) ``` -* Multiple Python threads won't run your *Python code* concurrently (yes, you heard it right!). It may seem intuitive to spawn several threads and let them execute your Python code concurrently, but, because of the [Global Interpreter Lock](https://wiki.python.org/moin/GlobalInterpreterLock) in Python, all you're doing is making your threads execute on the same core turn by turn. Python threads are good for IO-bound tasks, but to achieve actual parallelization in Python for CPU-bound tasks, you might want to use the Python [multiprocessing](https://docs.python.org/3/library/multiprocessing.html) module. +* Mehrere Python Threads werden deinen *Python code* nicht gleichzeitig laufen lassen (Ja, du hast richtig gehört!). +Es mag intuitiv erscheinen, mehrere Threads zu erzeugen, die dann deinen Python code gleichzeitig ausfĂŒhren, aber wegen dem [Global Interpreter Lock](https://wiki.python.org/moin/GlobalInterpreterLock) in Python, sorgst du nur dafĂŒr, dass die Threads abwechselnd auf demselben Kern ausgefĂŒhrt werden. +Python Threads sind gut fĂŒr IO-gebundene Aufgaben, aber um tatsĂ€chliche Parallelisierung fĂŒr CPU-gebundene Aufgaben in Python zu erreichen, solltest du lieber das Python [multiprocessing](https://docs.python.org/3/library/multiprocessing.html) Modul benutzen. -* Sometimes, the `print` method might not print values immediately. For example, +* Manchmal gibt die `print` Methode die Werte nicht sofort aus. Zum Beispiel: ```py # File some_file.py @@ -3837,35 +3840,35 @@ What makes those dictionaries become bloated? And why are newly created objects time.sleep(3) ``` - This will print the `wtfpython` after 3 seconds due to the `end` argument because the Ausgabe buffer is flushed either after encountering `\n` or when the program finishes execution. We can force the buffer to flush by passing `flush=True` argument. + Das wird `wtfpython` nach 3 Sekunden, aufgrund des `end` Argumentes ausgeben, wei der Ausgabe-Puffer, entweder nach `\n` oder wenn das Programm die AusfĂŒhrung beendet, geflusht wird. Mit dem Argument `flush=True` können wir den Puffer zum Flushen zwingen. -* List slicing with out of the bounds indices throws no errors +* List slicing mit Indices, die nicht innerhalb der Grenzen liegen, wirft keinen Fehler ```py >>> some_list = [1, 2, 3, 4, 5] >>> some_list[111:] [] ``` -* Slicing an iterable not always creates a new object. For example, +* Slicing eines Iterables erzeugt nicht immer ein neues Objekt. Zum Beispiel: ```py >>> some_str = "wtfpython" >>> some_list = ['w', 't', 'f', 'p', 'y', 't', 'h', 'o', 'n'] - >>> some_list is some_list[:] # False expected because a new object is created. + >>> some_list is some_list[:] # False erwartet, weil ein neues Objekt erzeugt wird. False - >>> some_str is some_str[:] # True because strings are immutable, so making a new object is of not much use. + >>> some_str is some_str[:] # True, weil Strings immutable sind, daher ist die Erstellung eines neuen Objektes sinnlos. True ``` -* `int('ÙĄÙąÙŁÙ€Ù„ÙŠÙ§ÙšÙ©')` returns `123456789` in Python 3. In Python, Decimal characters include digit characters, and all characters that can be used to form decimal-radix numbers, e.g. U+0660, ARABIC-INDIC DIGIT ZERO. Here's an [interesting story](https://chris.improbable.org/2014/8/25/adventures-in-unicode-digits/) related to this behavior of Python. +* `int('ÙĄÙąÙŁÙ€Ù„ÙŠÙ§ÙšÙ©')` gibt `123456789` in Python 3 zurĂŒck. In Python umfassen Dezimalzeichen auch Ziffernzeichen, und alle Zeichen, die zum Erstellen von Dezimal-Radix-Nummern benutzt werden können, z.B. U+0660, ARABIC-INDIC DIGIT ZERO. Hier ist eine [interessante Geschichte](https://chris.improbable.org/2014/8/25/adventures-in-unicode-digits/) im Zusammenhang mit diesem Verhalten in Python. -* You can separate numeric literals with underscores (for better readability) from Python 3 onwards. +* Du kannst numerische Literale mit Unterstrichen trennen, um die Lesbarkeit zu erhöhen (Python 3 spezifisch). ```py - >>> six_million = 6_000_000 - >>> six_million + >>> sechs_millionen = 6_000_000 + >>> sechs_millionen 6000000 - >>> hex_address = 0xF00D_CAFE - >>> hex_address + >>> sechs_millionen = 0xF00D_CAFE + >>> sechs_millionen 4027435774 ``` @@ -3877,8 +3880,7 @@ What makes those dictionaries become bloated? And why are newly created objects result += (s[i:i + len(sub)] == sub) return result ``` - The behavior is due to the matching of empty substring(`''`) with slices of length 0 in the original string. - + Das Verhalten ist darauf zurĂŒckzufĂŒhren, dass leere Teilstrings (`''`) mit Slices der LĂ€nge 0 in der ursprĂŒnglichen Zeichenkette ĂŒbereinstimmen --- --- From 77cd65c958bd41fa8a5f66b121ea34fc2f28feb7 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Wed, 19 Jul 2023 21:19:13 +0200 Subject: [PATCH 08/20] #7 --- README.md | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 7222e0b6..8408d1a2 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Also, los gehts... - [💡 ErklĂ€rung](#-erklĂ€rung-4) - [▶ Tief im Inneren sind wir alle gleich](#-tief-im-inneren-sind-wir-alle-gleich) - [💡 ErklĂ€rung:](#-erklĂ€rung-5) + - [Unterschied macht.](#unterschied-macht) - [▶ Unordnung in der Ordnung \*](#-unordnung-in-der-ordnung-) - [💡 ErklĂ€rung:](#-erklĂ€rung-6) - [▶ Versuche es weiter... \*](#-versuche-es-weiter-) @@ -435,11 +436,11 @@ geschuldet, auch als Constant Folding bekannt. Das bedeutet, der Ausdruck `'a'*2 ### ▶ Vorsicht bei verketteten Operationen ```py ->>> (False == False) in [False] # makes sense +>>> (False == False) in [False] # ergibt Sinn False ->>> False == (False in [False]) # makes sense +>>> False == (False in [False]) # ergibt Sinn False ->>> False == False in [False] # now what? +>>> False == False in [False] # Was nun? True >>> True is False == False @@ -692,11 +693,11 @@ class WTF: **Ausgabe:** ```py ->>> WTF() == WTF() # two different instances can't be equal +>>> WTF() == WTF() # zwei verschiedene Instanzen können nicht gleich sein False ->>> WTF() is WTF() # identities are also different +>>> WTF() is WTF() # IdetitĂ€ten sind ebenfalls unterschiedlich False ->>> hash(WTF()) == hash(WTF()) # hashes _should_ be different as well +>>> hash(WTF()) == hash(WTF()) # Hash-Werte _sollten_ ebenfalls verschieden sein True >>> id(WTF()) == id(WTF()) True @@ -729,8 +730,8 @@ True D True ``` - As you may observe, the order in which the objects are destroyed is what made all the difference here. - + Wie du villeicht beobachtest hast, ist die Reihenfolge, in der die Objekte zerstört werden, das, was hier den + Unterschied macht. --- ### ▶ Unordnung in der Ordnung * @@ -749,13 +750,13 @@ another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a'; class DictWithHash(dict): """ - A dict that also implements __hash__ magic. + Ein Dictionary auch __hash__ magic implementiert. """ __hash__ = lambda self: 0 class OrderedDictWithHash(OrderedDict): """ - An OrderedDict that also implements __hash__ magic. + Ein OrderedDict was auch __hash__ magic implementiert. """ __hash__ = lambda self: 0 ``` @@ -933,7 +934,9 @@ for i, some_dict[i] in enumerate(some_string): **💡 ErklĂ€rung:** - - The assignment statement `i = 10` never affects the iterations of the loop because of the way for loops work in Python. Before the beginning of every iteration, the next item provided by the iterator (`range(4)` in this case) is unpacked and assigned the target list variables (`i` in this case). + - Das Zuweisungs-Statement `i = 10` hat niemals einen Effekt auf die Schleife, aufgrund der Funktionsweise von + for-Schleifen in Python. Vor dem Beginn jeder Iteration, wird das nĂ€chste Objekt, was vom Iterator (in diesem + Fall `range(4)`) bereitgestellt wird, wird ausgepackt und der Zielliste zugewiesen (in diesem Fall `i`). * The `enumerate(some_string)` function yields a new value `i` (a counter going up) and a character from the `some_string` in each iteration. It then sets the (just assigned) `i` key of the dictionary `some_dict` to that character. The unrolling of the loop can be simplified as: ```py @@ -950,7 +953,7 @@ for i, some_dict[i] in enumerate(some_string): 1\. ```py array = [1, 8, 15] -# A typical generator expression +# Ein typischer Generator-Ausdruck gen = (x for x in array if array.count(x) > 0) array = [2, 8, 22] ``` @@ -958,7 +961,7 @@ array = [2, 8, 22] **Ausgabe:** ```py ->>> print(list(gen)) # Where did the other values go? +>>> print(list(gen)) # Wo sind die anderen Variablen hin? [8] ``` @@ -1035,9 +1038,9 @@ False ```py -# Let's initialize a row +# Lass uns eine Zeile initialisieren row = [""] * 3 #row i['', '', ''] -# Let's make a board +# Lass uns ein Brett bauen board = [row] * 3 ``` @@ -1055,11 +1058,11 @@ board = [row] * 3 [['X', '', ''], ['X', '', ''], ['X', '', '']] ``` -We didn't assign three `"X"`s, did we? +Wir haben nicht dreimal `"X"` zugewiesen, oder? #### 💡 ErklĂ€rung: -When we initialize `row` variable, this visualization explains what happens in the memory +Wenn wir die Variable `row` initialisieren, dann erklĂ€rt diese Visualisierung, was im Speicher passiert ![image](/images/tic-tac-toe/after_row_initialized.png) @@ -1067,7 +1070,7 @@ And when the `board` is initialized by multiplying the `row`, this is what happe ![image](/images/tic-tac-toe/after_board_initialized.png) -We can avoid this scenario here by not using `row` variable to generate `board`. (Asked in [this](https://github.com/satwikkansal/wtfpython/issues/68) issue). +Wir können dieses Szenario umfahren, indem wir nicht die `row` Variable zum generieren von `board` benutzen. (gefragt [hier](https://github.com/satwikkansal/wtfpython/issues/68)). ```py >>> board = [['']*3 for _ in range(3)] @@ -1089,7 +1092,7 @@ for x in range(7): def some_func(): return x funcs.append(some_func) - results.append(some_func()) # note the function call here + results.append(some_func()) # Beachte hier den Funktionsaufruf funcs_results = [func() for func in funcs] ``` @@ -1119,7 +1122,7 @@ The values of `x` were different in every iteration prior to appending `some_fun >>> inspect.getclosurevars(funcs[0]) ClosureVars(nonlocals={}, globals={'x': 6}, builtins={}, unbound=set()) ``` -Since `x` is a global value, we can change the value that the `funcs` will lookup and return by updating `x`: +Da `x` ein globaler Wert ist, können wir den Wert, den `funcs` nachschlĂ€gt und zurĂŒchgibt, verĂ€ndern, indem wir `x` updaten: ```py >>> x = 42 From 4c6b43f71e3585b94d5e2fe0ad73a2d10875e5e4 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Thu, 27 Jul 2023 19:13:36 +0200 Subject: [PATCH 09/20] #8 --- README.md | 66 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 8408d1a2..6dea8939 100644 --- a/README.md +++ b/README.md @@ -650,7 +650,8 @@ Warum also ist Python ĂŒberall zu finden ? #### 💡 ErklĂ€rung -* Uniqueness of keys in a Python dictionary is by *equivalence*, not identity. So even though `5`, `5.0`, and `5 + 0j` are distinct objects of different types, since they're equal, they can't both be in the same `dict` (or `set`). As soon as you insert any one of them, attempting to look up any distinct but equivalent key will succeed with the original mapped value (rather than failing with a `KeyError`): +* Einzigartigkeit der SchlĂŒssel in einem Python Dictionary wird durch *Äquivalenz*, nicht durch IdentitĂ€t festgestellt. Obwohl also `5`, `5.0`, und `5 + 0j` verschiedene Objekte unterschiedlichen Typs sind, können sie, da sie gleichwertig sind, nicht im gleichen `dict` (oder `set`) sein. +Sobald du einen von ihnen einfĂŒgst, wird der Versuch, nach einem anderen, aber gleichwertigen SchlĂŒssel zu suchen, mit dem ursprĂŒnglichen zugeordneten Wert erfolgreich sein (und nicht mit einem `KeyError` fehlschlagen): ```py >>> 5 == 5.0 == 5 + 0j True @@ -663,7 +664,9 @@ Warum also ist Python ĂŒberall zu finden ? >>> (5 in some_dict) and (5 + 0j in some_dict) True ``` -* This applies when setting an item as well. So when you do `some_dict[5] = "Python"`, Python finds the existing item with equivalent key `5.0 -> "Ruby"`, overwrites its value in place, and leaves the original key alone. +* Das gilt auch, wenn ein Item festgelegt wird. Wenn du also `some_dict[5] = "Python"` ausfĂŒhrst, findet Python +das existierende Item mit demselben Key `5.0 -> "Ruby"`, ĂŒberschreibt den Wert an dieser Stelle, und lĂ€sst den +originalen Wert unangetastet. ```py >>> some_dict {5.0: 'Ruby'} @@ -671,9 +674,10 @@ Warum also ist Python ĂŒberall zu finden ? >>> some_dict {5.0: 'Python'} ``` -* So how can we update the key to `5` (instead of `5.0`)? We can't actually do this update in place, but what we can do is first delete the key (`del some_dict[5.0]`), and then set it (`some_dict[5]`) to get the integer `5` as the key instead of floating `5.0`, though this should be needed in rare cases. +* Wie können wir also den Key zu `5` anstelle von `5.0` updaten? Wir können das tatsĂ€chlich nicht an dieser Stelle +tun, aber wir können den SchlĂŒssel zuerst löschen (`del some_dict[5.0]`), und ihn danach neu festzulegen (`some_dict[5]`), um den SchlĂŒssel `5` zu bekommen, anstelle des floats `5.0`. Das wird jedoch nur in seltenen FĂ€llen benötigt. -* How did Python find `5` in a dictionary containing `5.0`? Python does this in constant time without having to scan through every item by using hash functions. When Python looks up a key `foo` in a dict, it first computes `hash(foo)` (which runs in constant-time). Since in Python it is required that objects that compare equal also have the same hash value ([docs](https://docs.python.org/3/reference/datamodel.html#object.__hash__) here), `5`, `5.0`, and `5 + 0j` have the same hash value. +* Wie hat Python `5` in einem Dictionary gefunden, welches `5.0` enthĂ€lt? Python tut dies in konstanter Zeit, ohne jedes Item zu scannen, indem es Hash-Funktionen benutzt. Wenn Python den Key `foo` in einem Dictionary nachschlĂ€gt, dann verarbeitet es zuerst `hash(foo)` (was in konstanter Zeit lĂ€uft). Da es in Python notwendig ist, dass Objekte, die als gleich gelten auch den gleichen Hash-Wert haben ( siehe hier [docs](https://docs.python.org/3/reference/datamodel.html#object.__hash__)), haben `5`, `5.0`, und `5 + 0j` denselben Hash-Wert. ```py >>> 5 == 5.0 == 5 + 0j True @@ -1028,9 +1032,9 @@ False #### 💡 ErklĂ€rung -- `is not` is a single binary operator, and has behavior different than using `is` and `not` separated. -- `is not` evaluates to `False` if the variables on either side of the operator point to the same object and `True` otherwise. -- In the example, `(not None)` evaluates to `True` since the value `None` is `False` in a boolean context, so the expression becomes `'something' is True`. +- `is not` ist ein einzelner binĂ€rer Operator, der anderes Verhalten zeigt, als wenn man `is` und `not` einzeln benutzt. +- `is not` wird zu `False` ausgewertet wenn die Variablen auf beiden Seiten des Operators auf dasselbe Objekt verweisen, andernfalls zu `True`. +- Im Beispiel wird `(not None)` zu `True` ausgewertet, denn der Wert `None` ist `False` im booleschen Kontext, also wird der Ausdruck zu `'something' is True` ausgewertet. --- @@ -1040,7 +1044,7 @@ False ```py # Lass uns eine Zeile initialisieren row = [""] * 3 #row i['', '', ''] -# Lass uns ein Brett bauen +# Lass uns ein board bauen board = [row] * 3 ``` @@ -1066,7 +1070,7 @@ Wenn wir die Variable `row` initialisieren, dann erklĂ€rt diese Visualisierung, ![image](/images/tic-tac-toe/after_row_initialized.png) -And when the `board` is initialized by multiplying the `row`, this is what happens inside the memory (each of the elements `board[0]`, `board[1]` and `board[2]` is a reference to the same list referred by `row`) +Und wenn das `board` durch Multiplizieren der `row` initialisiert wird, dann passiert das hier innerhalb des Speichers (jedes der Elemente `board[0]`, `board[1]` und `board[2]` ist eine Referenz aud dieselbe Liste, aud die `row` verweist) ![image](/images/tic-tac-toe/after_board_initialized.png) @@ -1116,7 +1120,9 @@ The values of `x` were different in every iteration prior to appending `some_fun ``` #### 💡 ErklĂ€rung: -* When defining a function inside a loop that uses the loop variable in its body, the loop function's closure is bound to the *variable*, not its *value*. The function looks up `x` in the surrounding context, rather than using the value of `x` at the time the function is created. So all of the functions use the latest value assigned to the variable for computation. We can see that it's using the `x` from the surrounding context (i.e. *not* a local variable) with: +* Wenn wir eine Funktion innerhalb einer Schleife definieren, welche die Schleifenvariable in ihrem Körper benutzt, dann ist der Abschluss der Schleifenfunktion an die *Variable* gebunden, nicht an ihren *Wert*. +Die Funktion schlĂ€gt `x` in dem umgebenden Kontext nach, anstatt den Wert von `x` zum Zeitpunkt der Erstellung der Funktion zu benutzen. Also verwenden alle Funktionen den letzten Wert, der der Variable zugewiesen wurde, fĂŒr ihre Berechnungen. Wir können beobachten, dass `x` vom umgebenen Kontext verwendet wird (d.h. *keine* lokale Variable) mit: + ```py >>> import inspect >>> inspect.getclosurevars(funcs[0]) @@ -2055,12 +2061,12 @@ a, b = a[b] = {}, 5 ``` Similar is the case in our example (`a[b][0]` is the same object as `a`) -* So to sum it up, you can break the example down to +* Um zusammenzufassen, kannst du das Beispiel wie folgt aufgliedern ```py a, b = {}, 5 a[b] = a, b ``` - And the circular reference can be justified by the fact that `a[b][0]` is the same object as `a` + And the circular reference can be justified by the fact that `a[b][0]` ist dasselbe Objekt wie `a` ```py >>> a[b][0] is a True @@ -2092,15 +2098,15 @@ ValueError: Exceeds the limit (4300) for integer string conversion: ``` #### 💡 ErklĂ€rung: -This call to `int()` works fine in Python 3.10.6 and raises a ValueError in Python 3.10.8. Note that Python can still work with large integers. The error is only raised when converting between integers and strings. - -Fortunately, you can increase the limit for the allowed number of digits when you expect an operation to exceed it. To do this, you can use one of the following: -- The -X int_max_str_digits command-line flag -- The set_int_max_str_digits() function from the sys module -- The PYTHONINTMAXSTRDIGITS environment variable +Die Aufforderung `int()` funktioniert gut in Python 3.10.6 und gibt einen ValueError in Python 3.10.8 aus. Beachte, dass Python auch mit großen ganzen Zahlen arbeiten kann. Der Fehler tritt nur auf, wenn du zwischen Integern und Strings konvertiert wird. -[Check the documentation](https://docs.python.org/3/library/stdtypes.html#int-max-str-digits) for more details on changing the default limit if you expect your code to exceed this value. +GlĂŒcklicherweise kannst du den Grenzwert fĂŒr die zulĂ€ssige Anzahl von Ziffern erhöhen, wenn du erwartest, dass ein Vorgang diesen Grenzwert ĂŒberschreitet. Um das zu tun, kannst du folgendes benutzen: +- Das -X int_max_str_digits command-line flag +- Die set_int_max_str_digits() Funktion vom sys-modul +- Die PYTHONINTMAXSTRDIGITS Umgebungsvariable +[Check die Dokumentation](https://docs.python.org/3/library/stdtypes.html#int-max-str-digits) fĂŒr mehr Details +ĂŒber das VerĂ€ndern des Default-Limits, wenn du erwartest, dass dein Code diesen Wert ĂŒbersteigt. --- @@ -2131,11 +2137,11 @@ for i in x: 7 ``` -Yes, it runs for exactly **eight** times and stops. +Ja, es lĂ€uft exakt **acht** mal und stoppt dann. #### 💡 ErklĂ€rung: -* Iteration over a dictionary that you edit at the same time is not supported. +* Iteration ĂŒber ein Dictionary, welches du zur selben Zeit modifizierst, wird nicht unterstĂŒtzt. * It runs eight times because that's the point at which the dictionary resizes to hold more keys (we have eight deletion entries, so a resize is needed). This is actually an implementation detail. * How deleted keys are handled and when the resize occurs might be different for different Python implementations. * So for Python versions other than Python 2.7 - Python 3.5, the count might be different from 8 (but whatever the count is, it's going to be the same every time you run it). You can find some discussion around this [here](https://github.com/satwikkansal/wtfpython/issues/53) or in [this](https://stackoverflow.com/questions/44763802/bug-in-python-dict) StackOverflow thread. @@ -2158,22 +2164,22 @@ class SomeClass: ```py >>> x = SomeClass() >>> y = x ->>> del x # this should print "Deleted!" +>>> del x # das sollte "Deleted!" ausgeben >>> del y Deleted! ``` -Phew, deleted at last. You might have guessed what saved `__del__` from being called in our first attempt to delete `x`. Let's add more twists to the example. +Pha, deleted zuletzt. You might have guessed what saved `__del__` from being called in our first attempt to delete `x`. ErgĂ€nzen wir das Beispiel um weitere Aspekte 2\. ```py >>> x = SomeClass() >>> y = x >>> del x ->>> y # check if y exists +>>> y # check, ob y existiert <__main__.SomeClass instance at 0x7f98a1a67fc8> ->>> del y # Like previously, this should print "Deleted!" ->>> globals() # oh, it didn't. Let's check all our global variables and confirm +>>> del y # Wie vorher sollte das "Deleted!" ausgeben +>>> globals() # oh, das hat es nicht. Lass uns alle globalen Variablen checken und das bestĂ€tigen Deleted! {'__builtins__': , 'SomeClass': , '__package__': None, '__name__': '__main__', '__doc__': None} ``` @@ -2301,7 +2307,7 @@ for idx, item in enumerate(list_4): [2, 4] ``` -Can you guess why the Ausgabe is `[2, 4]`? +Kannst du erklĂ€ren, warum die Ausgabe `[2, 4]` ist? #### 💡 ErklĂ€rung: @@ -2311,7 +2317,7 @@ Can you guess why the Ausgabe is `[2, 4]`? >>> some_list = [1, 2, 3, 4] >>> id(some_list) 139798789457608 - >>> id(some_list[:]) # Notice that python creates new object for sliced list. + >>> id(some_list[:]) # Beachte, dass Python ein neues Objekt fĂŒr geslicte Listen baut. 139798779601192 ``` @@ -2323,8 +2329,8 @@ Can you guess why the Ausgabe is `[2, 4]`? **Why the Ausgabe is `[2, 4]`?** - The list iteration is done index by index, and when we remove `1` from `list_2` or `list_4`, the contents of the lists are now `[2, 3, 4]`. The remaining elements are shifted down, i.e., `2` is at index 0, and `3` is at index 1. Since the next iteration is going to look at index 1 (which is the `3`), the `2` gets skipped entirely. A similar thing will happen with every alternate element in the list sequence. -* Refer to this StackOverflow [thread](https://stackoverflow.com/questions/45946228/what-happens-when-you-try-to-delete-a-list-element-while-iterating-over-it) explaining the example -* See also this nice StackOverflow [thread](https://stackoverflow.com/questions/45877614/how-to-change-all-the-dictionary-keys-in-a-for-loop-with-d-items) for a similar example related to dictionaries in Python. +* Ich verweise auf diesen StackOverflow [thread](https://stackoverflow.com/questions/45946228/what-happens-when-you-try-to-delete-a-list-element-while-iterating-over-it), welches das Beispiel erklĂ€rt +* Siehe auch diesen schönen StackOverflow [thread](https://stackoverflow.com/questions/45877614/how-to-change-all-the-dictionary-keys-in-a-for-loop-with-d-items) fĂŒr ein Ă€hnliches Beispiel im Bezug auf Dictionaries in Python. --- From cad22b1c7dddfc726f10eb5372e6834994a2cb3d Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Thu, 27 Jul 2023 20:08:49 +0200 Subject: [PATCH 10/20] #9 --- README.md | 65 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 6dea8939..af073c09 100644 --- a/README.md +++ b/README.md @@ -709,10 +709,10 @@ True #### 💡 ErklĂ€rung: -* When `id` was called, Python created a `WTF` class object and passed it to the `id` function. The `id` function takes its `id` (its memory location), and throws away the object. The object is destroyed. -* When we do this twice in succession, Python allocates the same memory location to this second object as well. Since (in CPython) `id` uses the memory location as the object id, the id of the two objects is the same. -* So, the object's id is unique only for the lifetime of the object. After the object is destroyed, or before it is created, something else can have the same id. -* But why did the `is` operator evaluate to `False`? Let's see with this snippet. +* Wenn `id` genannt wurde, hat Python hat ein `WTF` class-Objekt gebaut und es der `id`-Funktion ĂŒbergeben. Die `id`-Funktion nimmt die `id` (den Speicherort), und wirft das Objekt weg. Das Objekt ist zerstört. +* When we do this twice in succession, Python allocates the same memory location to this second object as well. Da (in CPython) `id` denselben Speicherort wie die Objekt-Id benutzt, ist die id der beiden Objekte dieselbe. +* Also ist die Id des Objektes nur fĂŒr die Lebensdauer des Objektes einzigartig. Nachdem das Objekt zerstört wurde, oder bevor es gebaut wird, kann etwas anderes diese Id haben. +* Abe warum wurde der `is` zu `False` ausgewertet? Lass uns das anhand dieses Schnipsels betrachten. ```py class WTF(object): def __init__(self): print("I") @@ -767,23 +767,23 @@ class OrderedDictWithHash(OrderedDict): **Ausgabe** ```py ->>> dictionary == ordered_dict # If a == b +>>> dictionary == ordered_dict # Wenn a == b True ->>> dictionary == another_ordered_dict # and b == c +>>> dictionary == another_ordered_dict # und b == c True ->>> ordered_dict == another_ordered_dict # then why isn't c == a ?? +>>> ordered_dict == another_ordered_dict # warum ist dann c != a ?? False -# We all know that a set consists of only unique elements, -# let's try making a set of these dictionaries and see what happens... +# Wir wissen alle, dass ein Set nur aus einzigartigen Elementen besteht, +# Lass uns ein Set aus Dictionaries bauen und sehen, was passiert... >>> len({dictionary, ordered_dict, another_ordered_dict}) Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: 'dict' -# Makes sense since dict don't have __hash__ implemented, let's use -# our wrapper classes. +# Ergibt Sinn, denn ein Dictionary implementiert nicht __hash__, lass uns unsere +# Wrapper-Klasse benutzen. >>> dictionary = DictWithHash() >>> dictionary[1] = 'a'; dictionary[2] = 'b'; >>> ordered_dict = OrderedDictWithHash() @@ -792,7 +792,7 @@ TypeError: unhashable type: 'dict' >>> another_ordered_dict[2] = 'b'; another_ordered_dict[1] = 'a'; >>> len({dictionary, ordered_dict, another_ordered_dict}) 1 ->>> len({ordered_dict, another_ordered_dict, dictionary}) # changing the order +>>> len({ordered_dict, another_ordered_dict, dictionary}) # verĂ€ndere die Reihenfolge 2 ``` @@ -800,14 +800,15 @@ Was geht hier vor ? #### 💡 ErklĂ€rung: -- The reason why intransitive equality didn't hold among `dictionary`, `ordered_dict` and `another_ordered_dict` is because of the way `__eq__` method is implemented in `OrderedDict` class. From the [docs](https://docs.python.org/3/library/collections.html#ordereddict-objects) - - > Equality tests between OrderedDict objects are order-sensitive and are implemented as `list(od1.items())==list(od2.items())`. Equality tests between `OrderedDict` objects and other Mapping objects are order-insensitive like regular dictionaries. -- The reason for this equality in behavior is that it allows `OrderedDict` objects to be directly substituted anywhere a regular dictionary is used. -- Okay, so why did changing the order affect the length of the generated `set` object? The answer is the lack of intransitive equality only. Since sets are "unordered" collections of unique elements, the order in which elements are inserted shouldn't matter. But in this case, it does matter. Let's break it down a bit, +- Der Grund, warum die intransitive Gleichheit zwischen `dictionary`, `ordered_dict` und `another_ordered_dict` nicht gilt, liegt in der `__eq__` Methode und wie diese in der `OrderedDict`-Klasse implementiert ist. Aus der [Dokumentation](https://docs.python.org/3/library/collections.html#ordereddict-objects) + + > Gleichheitstests zwischen OrderedDict-Objekten sind ordnungsabhĂ€ngig und werden als `list(od1.items())==list(od2.items())` implementiert. Gleichheitstests zwischen `OrderedDict`-Objekten und anderen Mapping-Objekten sind nicht ordnungsabhĂ€ngig wie bei regulĂ€ren Dictionaries. + +- Der Grund fĂŒr diese Gleichheit im Verhalten ist, dass sie es ermöglicht, `OrderedDict`-Objekte direkt ĂŒberall dort zu ersetzen, wo ein regulĂ€res Wörterbuch verwendet wird. +- Okay, warum also hat die Änderung der Reihenfolge Auswirkungen auf die LĂ€nge des erzeugten `set`-Objekts? Die Antwort ist das Fehlen der intransitiven Gleichheit. Da Mengen "ungeordnete" Sammlungen von eindeutigen Elementen sind, sollte die Reihenfolge, in der die Elemente eingefĂŒgt werden, keine Rolle spielen. Aber in diesem Fall spielt sie doch eine Rolle. Lass uns das ein wenig aufschlĂŒsseln ```py >>> some_set = set() - >>> some_set.add(dictionary) # these are the mapping objects from the snippets above + >>> some_set.add(dictionary) # das sind die Mapping-Objekte von unseren Schnipseln oben >>> ordered_dict in some_set True >>> some_set.add(ordered_dict) @@ -832,7 +833,7 @@ Was geht hier vor ? >>> len(another_set) 2 ``` - So the inconsistency is due to `another_ordered_dict in another_set` being `False` because `ordered_dict` was already present in `another_set` and as observed before, `ordered_dict == another_ordered_dict` is `False`. + Die Inkonsistenz liegt bei `another_ordered_dict in another_set`, was `False` ist, weil `ordered_dict` bereits in `another_set` enthalten ist und wie schon vorher beobachtet, `ordered_dict == another_ordered_dict` ist `False`. --- @@ -852,13 +853,13 @@ def another_func(): finally: print("Finally!") -def one_more_func(): # A gotcha! +def one_more_func(): # Ein gotcha! try: for i in range(3): try: 1 / i except ZeroDivisionError: - # Let's throw it here and handle it outside for loop + # Lass es uns hier hin packen und es außerhalb des Loops behandeln raise ZeroDivisionError("A trivial divide by zero error") finally: print("Iteration", i) @@ -890,9 +891,12 @@ Iteration 0 #### 💡 ErklĂ€rung: -- When a `return`, `break` or `continue` statement is executed in the `try` suite of a "try
finally" statement, the `finally` clause is also executed on the way out. -- The return value of a function is determined by the last `return` statement executed. Since the `finally` clause always executes, a `return` statement executed in the `finally` clause will always be the last one executed. -- The caveat here is, if the finally clause executes a `return` or `break` statement, the temporarily saved exception is discarded. +- Wenn ein `return`-, `break`- oder `continue`-Anweisung in einem `try` ("try
finally") Anweisung ausgefĂŒhrt wird, +dann wird der `finally`-Abschnitt am Ende ebenfalls ausgefĂŒhrt. +- Der RĂŒckgabewert einer Funktion wird durch die letzte `return`-Anweisung bestimmt. Da der `finally`-Abschnitt +immer ausgefĂŒhrt wird, wird eine `return`-Anweisung im `finally`-Abschnitt immer die letzte sein, die ausgefĂŒhrt wird. +- Wenn also der `finally`-Abschnitt eine `return`- oder `break`-Anweisung ausfĂŒhrt, dann wird die kurzzeitige +Exception verworfen. --- @@ -908,18 +912,18 @@ for i, some_dict[i] in enumerate(some_string): **Ausgabe:** ```py ->>> some_dict # An indexed dict appears. +>>> some_dict # Ein indiziertes dictionary erscheint. {0: 'w', 1: 't', 2: 'f'} ``` #### 💡 ErklĂ€rung: -* A `for` statement is defined in the [Python grammar](https://docs.python.org/3/reference/grammar.html) as: +* Eine `for` Anweisung ist in [Python Syntax](https://docs.python.org/3/reference/grammar.html) wie folgt definiert: ``` for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] ``` - Where `exprlist` is the assignment target. This means that the equivalent of `{exprlist} = {next_value}` is **executed for each item** in the iterable. - An interesting example that illustrates this: + `exprlist` ist dabei das Zuweisungsziel. Das heißt, dass das Äquivalente von `{exprlist} = {next_value}` im Iterable **executed for each item** ist. + Ein interessantes Beispiel, was dies verdeutlicht: ```py for i in range(4): print(i) @@ -942,7 +946,10 @@ for i, some_dict[i] in enumerate(some_string): for-Schleifen in Python. Vor dem Beginn jeder Iteration, wird das nĂ€chste Objekt, was vom Iterator (in diesem Fall `range(4)`) bereitgestellt wird, wird ausgepackt und der Zielliste zugewiesen (in diesem Fall `i`). -* The `enumerate(some_string)` function yields a new value `i` (a counter going up) and a character from the `some_string` in each iteration. It then sets the (just assigned) `i` key of the dictionary `some_dict` to that character. The unrolling of the loop can be simplified as: +* Die `enumerate(some_string)` Funktion liefert ein neuen Wert `i` (ein ZĂ€hler, der aufwĂ€rts lĂ€uft) und ein +Character vom String `some_string` in jeder Iteration. Dann wird der gerade erzeugte Wert `i` des Dictionaries +`some_dict` als Key zu diesem Character gesetzt. Das Verhalten der Schleife kann wie folgt vereinfacht werden: + ```py >>> i, some_dict[i] = (0, 'w') >>> i, some_dict[i] = (1, 't') From 63c549f58672259c5bbe1069d62f101512997474 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Thu, 10 Aug 2023 11:46:03 +0200 Subject: [PATCH 11/20] #10 --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index af073c09..39940a56 100644 --- a/README.md +++ b/README.md @@ -1016,15 +1016,14 @@ array_4 = [400, 500, 600] #### 💡 ErklĂ€rung -- In a [generator](https://wiki.python.org/moin/Generators) expression, the `in` clause is evaluated at declaration time, but the conditional clause is evaluated at runtime. -- So before runtime, `array` is re-assigned to the list `[2, 8, 22]`, and since out of `1`, `8` and `15`, only the count of `8` is greater than `0`, the generator only yields `8`. -- The differences in the Ausgabe of `g1` and `g2` in the second part is due the way variables `array_1` and `array_2` are re-assigned values. -- In the first case, `array_1` is bound to the new object `[1,2,3,4,5]` and since the `in` clause is evaluated at the declaration time it still refers to the old object `[1,2,3,4]` (which is not destroyed). -- In the second case, the slice assignment to `array_2` updates the same old object `[1,2,3,4]` to `[1,2,3,4,5]`. Hence both the `g2` and `array_2` still have reference to the same object (which has now been updated to `[1,2,3,4,5]`). -- Okay, going by the logic discussed so far, shouldn't be the value of `list(gen)` in the third snippet be `[11, 21, 31, 12, 22, 32, 13, 23, 33]`? (because `array_3` and `array_4` are going to behave just like `array_1`). The reason why (only) `array_4` values got updated is explained in [PEP-289](https://www.python.org/dev/peps/pep-0289/#the-details) - - > Only the outermost for-expression is evaluated immediately, the other expressions are deferred until the generator is run. - +- In einem [Generator](https://wiki.python.org/moin/Generators)-Ausdruck wird die `in`-Klausel zur Deklarationszeit ausgewertet, wĂ€hrend die Bedingungsklausel zur Laufzeit ausgewertet wird. +- Vor der Laufzeit wird `array` wieder der Liste `[2, 8, 22]` zugewiesen, und da von `1`, `8` und `15`, nur die Anzahl von `8` grĂ¶ĂŸer als `0` ist, liefert der Generator nur `8`. +- Die Unterschiede in der Ausgabe von `g1` und `g2` im zweiten Teil sind auf die Art und Weise zurĂŒckzufĂŒhren, wie den Variablen `array_1` und `array_2` neue Werte zugewiesen werden. +- Im ersten Fall wird `array_1` zum neuen Objekt `[1,2,3,4,5]` gebunden und da die `in`-Klausel zur Deklarationszeit ausgewertet wird, bezieht es sich immer noch auf das alte Objekt `[1,2,3,4]` (was nicht zerstört wird). +- Im zweiten Fall updated die Slice-Anweisung an `array_2` das gleiche alte Objekt `[1,2,3,4]` zu `[1,2,3,4,5]`. Daher verweisen sowohl `g2` als auch `array_2` immer noch auf dasselbe Objekt (welches nun zu `[1,2,3,4,5]` geupdated wird). +- Okay, wenn wir die Logik anwenden, die wir bis jetzt kennengelernt haben, sollte dann der Wert von `list(gen)` im dritten Schnipsel nicht `[11, 21, 31, 12, 22, 32, 13, 23, 33]` sein? (weil `array_3` und `array_4` sich genauso wie `array_1` verhalten werden). Die Grund, warum (nur) die Werte von `array_4` geĂ€ndert werden, wird im [PEP-289](https://www.python.org/dev/peps/pep-0289/#the-details) erklĂ€rt. + + > Nur der Ă€ußerste for-Ausdruck wird direkt ausgewertet, die anderen AusdrĂŒcke werden zurĂŒckgestellt, bis der Generator ausgefĂŒhrt wird. --- From 9ab8b9388c0527b46cd68c33c9aaa32fe0a0e6c6 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Thu, 10 Aug 2023 14:13:55 +0200 Subject: [PATCH 12/20] #11 --- README.md | 82 ++++++++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 39940a56..1d89d19d 100644 --- a/README.md +++ b/README.md @@ -1142,7 +1142,7 @@ Da `x` ein globaler Wert ist, können wir den Wert, den `funcs` nachschlĂ€gt und [42, 42, 42, 42, 42, 42, 42] ``` -* To get the desired behavior you can pass in the loop variable as a named variable to the function. **Why does this work?** Because this will define the variable *inside* the function's scope. It will no longer go to the surrounding (global) scope to look up the variables value but will create a local variable that stores the value of `x` at that point in time. +* Um das entsprechende Verhalten zu bekommen, kannst du die Loop-Variable als named-Variable der Funktion ĂŒbergeben. **Warum funktioniert das?** Weil dies die Variable *innerhalb* des Scopes der Funktion definiert. Sie wird nicht lĂ€nger im umgebenden (globalen) Scope definiert, sondern es wird eine lokale Variable erzeugt, die den Wert von `x` zu diesem Zeitpunkt speichert. ```py funcs = [] @@ -1160,7 +1160,7 @@ for x in range(7): [0, 1, 2, 3, 4, 5, 6] ``` -It is not longer using the `x` in the global scope: +`x` wird nicht lĂ€nger im globalen Scope verwendet: ```py >>> inspect.getclosurevars(funcs[0]) @@ -1181,7 +1181,7 @@ True True ``` -So which is the "ultimate" base class? There's more to the confusion by the way, +Was ist also die ultimative Basisklasse? Die Verwirrung wird noch grĂ¶ĂŸer: 2\. @@ -1209,13 +1209,13 @@ False #### 💡 ErklĂ€rung -- `type` is a [metaclass](https://realpython.com/python-metaclasses/) in Python. -- **Everything** is an `object` in Python, which includes classes as well as their objects (instances). -- class `type` is the metaclass of class `object`, and every class (including `type`) has inherited directly or indirectly from `object`. -- There is no real base class among `object` and `type`. The confusion in the above snippets is arising because we're thinking about these relationships (`issubclass` and `isinstance`) in terms of Python classes. The relationship between `object` and `type` can't be reproduced in pure python. To be more precise the following relationships can't be reproduced in pure Python, - + class A is an instance of class B, and class B is an instance of class A. - + class A is an instance of itself. -- These relationships between `object` and `type` (both being instances of each other as well as themselves) exist in Python because of "cheating" at the implementation level. +- `type` ist eine [Metaklasse](https://realpython.com/python-metaclasses/) in Python. +- **Alles** ist ein `object` in Python, was Klassen und ihre Objekte (Instanzen) einschließt. +- Die Klasse `type` ist eine Metaklasse der Klasse `object`, und jede Klasse (einschließlich `type`) hat direkt oder indirekt von `object` geerbt. +- Es gibt keine echte Basisklasse zwischen `object` und `type`. Die Verwirrung im obigen Schnipsel ergibt sich weil wir ĂŒber diese Beziehungen (`issubclass` und `isinstance`) in Form von Python-Klassen denken. Die Beziehung zwischen `object` und `type` kann nicht in reinem Python reproduziert werden. Um prĂ€ziser zu sein, die folgenden Beziehungen können nicht in reinem Python reproduziert werden: + + Klasse A ist eine Instanz der Klasse B, und Klasse B ist eine Instanz von Klasse A. + + Klasse A ist eine Instanz von sich selbst. +- Diese Beziehungen zwischen `object` und `type` (beide sind Instanzen voneinander und von sich selbst) existieren in Python, weil auf dem Level der Implementierung "geschummelt" wird. --- @@ -1232,14 +1232,14 @@ True False ``` -The Subclass relationships were expected to be transitive, right? (i.e., if `A` is a subclass of `B`, and `B` is a subclass of `C`, the `A` _should_ a subclass of `C`) +Die Unterklassenbeziehungen sollten transitiv sein, nicht wahr? (d.h., wenn `A` eine Unterklasse von `B` ist, und `B` eine Unterklasse von `C`, dann _sollte_ `A` eine Unterklasse von `C` sein) #### 💡 ErklĂ€rung: -* Subclass relationships are not necessarily transitive in Python. Anyone is allowed to define their own, arbitrary `__subclasscheck__` in a metaclass. -* When `issubclass(cls, Hashable)` is called, it simply looks for non-Falsey "`__hash__`" method in `cls` or anything it inherits from. -* Since `object` is hashable, but `list` is non-hashable, it breaks the transitivity relation. -* More detailed ErklĂ€rung can be found [here](https://www.naftaliharris.com/blog/python-subclass-intransitivity/). +* Unterklassenbeziehungen in Python sind nicht notwendigerweise transitiv in Python. Jedem ist es erlaubt, seine eigene, beliebige `__subclasscheck__` in einer Metaklasse zu definieren. +* Wenn `issubclass(cls, Hashable)` aufgerufen wird, sucht es einfach nach nicht-Falsey "`__hash__`" Methoden in `cls` oderallem, von dem es erbt. +* Da `object` hashable ist, aber `list` nicht-hashable, bricht es die transitive Relation. +* Eine ausfĂŒhrlichere ErklĂ€rung kann [hier](https://www.naftaliharris.com/blog/python-subclass-intransitivity/) gefunden werden. --- @@ -1273,8 +1273,7 @@ True True ``` -Accessing `classm` twice, we get an equal object, but not the *same* one? Let's see what happens -with instances of `SomeClass`: +Wenn wir zweimal auf `classm` zugreifen, bekommen wir ein gleiches Objekt, aber nicht *dasselbe* oder? Lass uns sehen, was mit Instanzen von `SomeClass` passiert: 2. ```py @@ -1298,51 +1297,41 @@ True True ``` -Accessing` classm` or `method` twice, creates equal but not *same* objects for the same instance of `SomeClass`. +Der zweifache Zugriff auf `classm` oder `method`, erzeugt gleiche, aber nicht *gleiche* Objekte fĂŒr dieselbe Instanz von `SomeClass`. #### 💡 ErklĂ€rung -* Functions are [descriptors](https://docs.python.org/3/howto/descriptor.html). Whenever a function is accessed as an -attribute, the descriptor is invoked, creating a method object which "binds" the function with the object owning the -attribute. If called, the method calls the function, implicitly passing the bound object as the first argument -(this is how we get `self` as the first argument, despite not passing it explicitly). +* Funktionen sind [Deskriptoren](https://docs.python.org/3/howto/descriptor.html). Wann immer auf eine Funktion als Attribut zugegriffen wird, wird der Deskriptor aufgerufen, was ein Methodenobjekt erzeugt, das die Funktion mit dem Objekt "verbindet", welches das Attribut besitzt. Wenn aufgerufen, ruft die Methode die Funktion auf und ĂŒbergibt implizit das gebundene Objekt als erstes Argument (so erhalten wir `self` als erstes Argument, obwohl es nicht explizit ĂŒbergeben wird). ```py >>> o1.method > ``` -* Accessing the attribute multiple times creates a method object every time! Therefore `o1.method is o1.method` is -never truthy. Accessing functions as class attributes (as opposed to instance) does not create methods, however; so -`SomeClass.method is SomeClass.method` is truthy. +* Ein mehrfacher Zugriff auf das Attribut erzeugt jedes Mal ein Methodenobjekt! Daher ist `o1.method is o1.method` niemals wahr. +Der Zugriff auf Klassenattribute (im Gegensatz zu Instanzen) erzeugt jedoch keine Methoden; also ist +`SomeClass.method is SomeClass.method` wahr. ```py >>> SomeClass.method ``` -* `classmethod` transforms functions into class methods. Class methods are descriptors that, when accessed, create -a method object which binds the *class* (type) of the object, instead of the object itself. +* `classmethod` (Klassenmethoden) transformiert Funktionen in Klassenmethoden. Klassenmethoden sind Deskriptoren, die, wenn auf sie zugegriffen wird, ein Methodenobjekt erzeugen, welches die *Klasse* (Typ) des Objektes bindet, anstelle des Objektes selbst. ```py >>> o1.classm > ``` -* Unlike functions, `classmethod`s will create a method also when accessed as class attributes (in which case they -bind the class, not to the type of it). So `SomeClass.classm is SomeClass.classm` is falsy. +* Im Gegensatz zu Funktionen erzeugen Klassenmethoden auch dann eine Methode, wenn sie als Klassenattribute aufgerufen werden (in diesem Fall binden sie die Klasse, nicht den Typ der Klasse). Also ist `SomeClass.classm is SomeClass.classm` unwahr. ```py >>> SomeClass.classm > ``` -* A method object compares equal when both the functions are equal, and the bound objects are the same. So -`o1.method == o1.method` is truthy, although not the same object in memory. -* `staticmethod` transforms functions into a "no-op" descriptor, which returns the function as-is. No method -objects are ever created, so comparison with `is` is truthy. +* Ein Methodenobjekt ist gleich wenn beide Funktionen gleich sind, und die gebundenen Objekte gleich sind. Also ist `o1.method == o1.method` wahr, auch wenn sie nicht das gleiche Objekt im Speicher sind. +* `staticmethod` transformiert Funktionen in ein "no-op" Deskriptor, welches die Funktion so zurĂŒckgibt, wie sie ist. Es werden nie Methodenobjekte erzeugt, also ist der Vergleich mit `is` wahr. ```py >>> o1.staticm >>> SomeClass.staticm ``` -* Having to create new "method" objects every time Python calls instance methods and having to modify the arguments -every time in order to insert `self` affected performance badly. -CPython 3.7 [solved it](https://bugs.python.org/issue26110) by introducing new opcodes that deal with calling methods -without creating the temporary method objects. This is used only when the accessed function is actually called, so the -snippets here are not affected, and still generate methods :) +* Jedes Mal wenn Python Instanzmethoden aufruft, mĂŒssen neue "Methoden"-Objekte erstellt und die Argumente geĂ€ndert werden, um `self` einfĂŒgen zu können, was die Leistung negativ beeinflusst. +CPython 3.7 [löste dies](https://bugs.python.org/issue26110), indem neue Opcodes eingefĂŒhrt wurden, die den Aufruf von Methoden behandeln, ohne die temporĂ€ren Methodenobjekte zu erzeugen. Das wird nur genutzt, wenn die Funktion, auf die zugegriffen wird, tatsĂ€chlich aufgerufen wird, also sind die Schnipsel hier nicht betroffen. Sie erzeugen also immer noch Methoden :) ### ▶ All-true-ation * @@ -1362,11 +1351,11 @@ False True ``` -Why's this True-False alteration? +Warum ist diese Änderung True/False ? #### 💡 ErklĂ€rung: -- The implementation of `all` function is equivalent to +- Die Implementierung der `all` Funktion ist Ă€quivalent zu - ```py def all(iterable): @@ -1376,9 +1365,9 @@ Why's this True-False alteration? return True ``` -- `all([])` returns `True` since the iterable is empty. -- `all([[]])` returns `False` because the passed array has one element, `[]`, and in python, an empty list is falsy. -- `all([[[]]])` and higher recursive variants are always `True`. This is because the passed array's single element (`[[...]]`) is no longer empty, and lists with values are truthy. +- `all([])` gibt `True` zurĂŒck, da das Iterable leer ist. +- `all([[]])` gibt `False` zurĂŒck, weil das ĂŒbergebene Array ein Element hat, `[]`, und in Python, eine leere Liste `False` ist. +- `all([[[]]])` und höhere, rekursive Varianten sind immer `True`, weil das einzelne Element des ĂŒbergebenen Arrays (`[[...]]`) nicht lĂ€nger leer ist, und Listen mit Werten `True` sind. --- @@ -1408,9 +1397,10 @@ SyntaxError: invalid syntax #### 💡 ErklĂ€rung: -- Trailing comma is not always legal in formal parameters list of a Python function. -- In Python, the argument list is defined partially with leading commas and partially with trailing commas. This conflict causes situations where a comma is trapped in the middle, and no rule accepts it. -- **Note:** The trailing comma problem is [fixed in Python 3.6](https://bugs.python.org/issue9232). The remarks in [this](https://bugs.python.org/issue9232#msg248399) post discuss in brief different usages of trailing commas in Python. +- Ein Komma am Ende ist in der Liste der formalen Parameter einer Python-Funktion ist nicht immer zulĂ€ssig. +- In Python wird die Liste der Argumente teilweise mit fĂŒhrenden und teilweise mit abschließenden Kommas definiert. +Dieser Konflikt fĂŒhrt zu Situationen, in denen ein Komma in der Mitte gefangen ist, und keine Regel dies akzeptiert. +- **Hinweis:** Das abschließende-Komma-Problem wurde [in Python 3.6](https://bugs.python.org/issue9232) gelöst. Die Bemerkungen in [diesem](https://bugs.python.org/issue9232#msg248399) Post diskutieren in KĂŒrze die verschiedenen Verwendungen von abschließenden Kommas in Python. --- From 81b498ee3cc0c4ab8e8719d8cbadbca3485bc4ca Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Thu, 10 Aug 2023 16:47:01 +0200 Subject: [PATCH 13/20] #12 --- README.md | 124 ++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 1d89d19d..2b86170b 100644 --- a/README.md +++ b/README.md @@ -1426,12 +1426,12 @@ True #### 💡 ErklĂ€rung -- In a usual python string, the backslash is used to escape characters that may have a special meaning (like single-quote, double-quote, and the backslash itself). +- In einem normalen Python-String wird der Backslash zum Escapen von Charactern benutzt, die evtl. eine besondere Bedeutung haben (bspw. einfache AnfĂŒhrungszeichen, doppelte AnfĂŒhrungszeichen und der Backslash selbst). ```py >>> "wt\"f" 'wt"f' ``` -- In a raw string literal (as indicated by the prefix `r`), the backslashes pass themselves as is along with the behavior of escaping the following character. +- In einem raw-String-Literal (wie durch das PrĂ€fix `r` gekennzeichnet), werden die Backslashes so wie sie sind weitergegeben, zusammen mit den Verhalten, dass die folgenden Zeichen escaped werden. ```py >>> r'wt\"f' == 'wt\\"f' True @@ -1443,7 +1443,7 @@ True >>> print(r"\\n") '\\n' ``` -- This means when a parser encounters a backslash in a raw string, it expects another character following it. And in our case (`print(r"\")`), the backslash escaped the trailing quote, leaving the parser without a terminating quote (hence the `SyntaxError`). That's why backslashes don't work at the end of a raw string. +- Das heißt wenn ein Parser auf ein Backslash in einem raw-String trifft, dann erwartet es noch einen Character, der diesem Backslash folgt. Und in unserem Fall (`print(r"\")`) escaped der Backslash das abschließende AnfĂŒhrungszeichen, wodurch der Parser kein terminierendes AnfĂŒhrungszeichen bekommt (daher der `SyntaxError`). Deshalb funktionieren Backslashes am Ende eines raw-Strings nicht. --- @@ -1467,10 +1467,10 @@ SyntaxError: invalid syntax #### 💡 ErklĂ€rung: -* Operator precedence affects how an expression is evaluated, and `==` operator has higher precedence than `not` operator in Python. -* So `not x == y` is equivalent to `not (x == y)` which is equivalent to `not (True == False)` finally evaluating to `True`. -* But `x == not y` raises a `SyntaxError` because it can be thought of being equivalent to `(x == not) y` and not `x == (not y)` which you might have expected at first sight. -* The parser expected the `not` token to be a part of the `not in` operator (because both `==` and `not in` operators have the same precedence), but after not being able to find an `in` token following the `not` token, it raises a `SyntaxError`. +* Operator-Reihenfolge beeinflusst wie ein Ausdruck ausgewertet wird, und der `==` Operator hat eine höhere PrioritĂ€t als der `not`-Operator in Python. +* Also ist `not x == y` Ă€quivalent zu `not (x == y)`, was Ă€quivalent zu `not (True == False)` ist und schließlich zu `True` ausgewertet wird. +* Aber `x == not y` wirft einen `SyntaxError`, weil man es mit `(x == not) y` gleich setzen könnte und nicht `x == (not y)`, was man zuerst erwarten wĂŒrde. +* Der Parser erwartet das `not`-Token als Teil de `not in`-Operators (weil sowohl der `==`- als auch der `not in`-Operator die gleiche PrioritĂ€t haben), aber nachdem er kein `in`-Token, welches nach einem `not`-Token folgt, gefunden hat, wirft er einen `SyntaxError`. --- @@ -1482,7 +1482,7 @@ SyntaxError: invalid syntax wtfpython >>> print("wtfpython""") wtfpython ->>> # The following statements raise `SyntaxError` +>>> # Die folgende Anweisung wirft einen `SyntaxError` >>> # print('''wtfpython') >>> # print("""wtfpython") File "", line 3 @@ -1492,14 +1492,14 @@ SyntaxError: EOF while scanning triple-quoted string literal ``` #### 💡 ErklĂ€rung: -+ Python supports implicit [string literal concatenation](https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation), Example, ++ Python unterstĂŒtzt implizite [String-literal-Konkatenation](https://docs.python.org/3/reference/lexical_analysis.html#string-literal-concatenation), Beispiel: ``` >>> print("wtf" "python") wtfpython >>> print("wtf" "") # or "wtf""" wtf ``` -+ `'''` and `"""` are also string delimiters in Python which causes a SyntaxError because the Python interpreter was expecting a terminating triple quote as delimiter while scanning the currently encountered triple quoted string literal. ++ `'''` und `"""` sind auch String-Trennzeichen in Python, was einen SyntaxError hervorruft, weil der Python-Interpreter ein abschließendes dreifaches AnfĂŒhrungszeichen als Trennzeichen erwartet, wĂ€hrend er das momentane String-Literal mit dreifachen AnfĂŒhrungszeichen scannt. --- @@ -1508,8 +1508,8 @@ SyntaxError: EOF while scanning triple-quoted string literal 1\. ```py -# A simple example to count the number of booleans and -# integers in an iterable of mixed data types. +# Ein einfaches Beispiel, um die Anzahl der Booleans und +# der Integer in einem Iterable mit gemischten Datentypen zu zĂ€hlen. mixed_list = [False, 1.0, "some_string", 3, True, [], False] integers_found_so_far = 0 booleans_found_so_far = 0 @@ -1560,7 +1560,7 @@ I have lost faith in truth! #### 💡 ErklĂ€rung: -* `bool` is a subclass of `int` in Python +* `bool` ist eine Unterklasse von `int` in Python ```py >>> issubclass(bool, int) @@ -1569,7 +1569,7 @@ I have lost faith in truth! False ``` -* And thus, `True` and `False` are instances of `int` +* Zudem sind `True` und `False` Instanzen von `int` ```py >>> isinstance(True, int) True @@ -1577,7 +1577,7 @@ I have lost faith in truth! True ``` -* The integer value of `True` is `1` and that of `False` is `0`. +* Der Integer Wert von `True` ist `1` und der von `False` ist `0`. ```py >>> int(True) 1 @@ -1585,11 +1585,9 @@ I have lost faith in truth! 0 ``` -* See this StackOverflow [answer](https://stackoverflow.com/a/8169049/4354153) for the rationale behind it. - -* Initially, Python used to have no `bool` type (people used 0 for false and non-zero value like 1 for true). `True`, `False`, and a `bool` type was added in 2.x versions, but, for backward compatibility, `True` and `False` couldn't be made constants. They just were built-in variables, and it was possible to reassign them - -* Python 3 was backward-incompatible, the issue was finally fixed, and thus the last snippet won't work with Python 3.x! +* Siehe auch diese StackOverflow [Antwort](https://stackoverflow.com/a/8169049/4354153) fĂŒr die BegrĂŒndung dahinter. +* AnfĂ€nglich hatte Python keinen `bool` Typ (Leute benutzten 0 fĂŒr False und nicht-null Werte wie 1 fĂŒr True). `True`, `False`, und ein `bool` Typ wurden in den 2.x Versionen hinzugefĂŒgt, aber, fĂŒr RĂŒckwĂ€rtskompatibilitĂ€t, konnten `True` und `False` nicht zu Konstanten gemacht werden. Sie waren nur built-in Variablen, was es möglich machte, sie neu zuzuweisen. +* Python 3 war rĂŒckwĂ€rtskompatibel, das Problem wurde schließlich gelöst, und daher wird der letzte Schnipsel nicht mit Python 3.x funktionieren! --- @@ -1615,7 +1613,7 @@ class C(A): >>> A.x, B.x, C.x (1, 2, 1) >>> A.x = 3 ->>> A.x, B.x, C.x # C.x changed, but B.x didn't +>>> A.x, B.x, C.x # C.x wurde verĂ€ndert, aber B.x nicht (3, 2, 3) >>> a = A() >>> a.x, A.x @@ -1658,8 +1656,8 @@ True #### 💡 ErklĂ€rung: -* Class variables and variables in class instances are internally handled as dictionaries of a class object. If a variable name is not found in the dictionary of the current class, the parent classes are searched for it. -* The `+=` operator modifies the mutable object in-place without creating a new object. So changing the attribute of one instance affects the other instances and the class attribute as well. +* Klassenvariablen und Variablen in Klasseninstanzen werden intern als Dictionaries von einem Klassenobjekt behandelt. Wenn einen Variablenname nicht im Dictionary der momentanen Klasse gefunden wird, wird die Elternklasse durchsucht. +* Der `+=` Operator modifiziert das verĂ€nderbare Objekt in-place ohne ein neues Objekt zu erzeugen. Also beeinflusst das Ändern eines Attributtes von einer Instanz die anderen Instanzen und die Klassenattribute. --- @@ -1688,10 +1686,10 @@ def some_func(val): ``` #### 💡 ErklĂ€rung: -- This is a bug in CPython's handling of `yield` in generators and comprehensions. -- Quelle and ErklĂ€rung can be found here: https://stackoverflow.com/questions/32139885/yield-in-list-comprehensions-and-generator-expressions -- Related bug report: https://bugs.python.org/issue10544 -- Python 3.8+ no longer allows `yield` inside list comprehension and will throw a `SyntaxError`. +- Das ist ein Fehler in CPythons Handhabung von `yield` in Generatoren und Comprehensions. +- Die Quelle und eine ErklĂ€rung können hier gefunden werden: https://stackoverflow.com/questions/32139885/yield-in-list-comprehensions-and-generator-expressions +- Der zugehörige Fehlerbericht: https://bugs.python.org/issue10544 +- Python 3.8+ erlaubt kein `yield` in List-Comprehensions und wird einen `SyntaxError` werfen. --- @@ -1715,7 +1713,7 @@ def some_func(x): [] ``` -Where did the `"wtf"` go? Is it due to some special effect of `yield from`? Let's validate that, +Wo ist das `"wtf"` hin? Liegt es an einem besonderen Effekt von `yield from`? Lass uns das bestĂ€tigen: 2\. @@ -1735,17 +1733,15 @@ def some_func(x): [] ``` -The same result, this didn't work either. +Das gleiche Ergebnis; hat also auch nicht funktioniert. #### 💡 ErklĂ€rung: ++ Von Python 3.3 aus wurde es möglich, die `return`-Anweisung mit Werten innerhalb eines Generators zu benutzen (Siehe [PEP380](https://www.python.org/dev/peps/pep-0380/)). Die [offiziellen docs](https://www.python.org/dev/peps/pep-0380/#enhancements-to-stopiteration) sagen: -+ From Python 3.3 onwards, it became possible to use `return` statement with values inside generators (See [PEP380](https://www.python.org/dev/peps/pep-0380/)). The [official docs](https://www.python.org/dev/peps/pep-0380/#enhancements-to-stopiteration) say that, - -> "... `return expr` in a generator causes `StopIteration(expr)` to be raised upon exit from the generator." - -+ In the case of `some_func(3)`, `StopIteration` is raised at the beginning because of `return` statement. The `StopIteration` exception is automatically caught inside the `list(...)` wrapper and the `for` loop. Therefore, the above two snippets result in an empty list. +> "... `return expr` in einem Generator fĂŒhrt zu einem `StopIteration(expr)`, was beim Verlassen des Generators geworfen wird." -+ To get `["wtf"]` from the generator `some_func` we need to catch the `StopIteration` exception, ++ Im Fall von `some_func(3)` wird `StopIteration` am Beginn wegen der `return`-Anweisung geworfen. Die `StopIteration` Exception wird automatisch innerhalb des `list(...)`-Wrapppers und der `for`-Schleife abgefangen. Daher enden die beiden Schnipsel mit einer leeren Liste. ++ Um `["wtf"]` vom Generator `some_func` zu bekommen, mĂŒssen wir die `StopIteration` Exception auffangen: ```py try: @@ -1770,7 +1766,7 @@ The same result, this didn't work either. ```py a = float('inf') b = float('nan') -c = float('-iNf') # These strings are case-insensitive +c = float('-iNf') # Diese Strings sind case-insensitiv d = float('nan') ``` @@ -1804,11 +1800,11 @@ nan ```py >>> x = float('nan') >>> y = x / x ->>> y is y # identity holds +>>> y is y # IdentitĂ€t funktioniert True ->>> y == y # equality fails of y +>>> y == y # Gleichheit von y schlĂ€gt fehl False ->>> [y] == [y] # but the equality succeeds for the list containing y +>>> [y] == [y] # aber die Gleichheit fĂŒr die Liste, die y enthĂ€lt, gelingt True ``` @@ -1816,9 +1812,9 @@ True #### 💡 ErklĂ€rung: -- `'inf'` and `'nan'` are special strings (case-insensitive), which, when explicitly typecast-ed to `float` type, are used to represent mathematical "infinity" and "not a number" respectively. +- `'inf'` und `'nan'` sind spezielle Strings (case-insensitiv), die, wenn sie explizit zu `floats` getypcasted werden, benutzt werden, um die mathematische "Unendlichkeit" und "not a number" zu reprĂ€sentieren. -- Since according to IEEE standards ` NaN != NaN`, obeying this rule breaks the reflexivity assumption of a collection element in Python i.e. if `x` is a part of a collection like `list`, the implementations like comparison are based on the assumption that `x == x`. Because of this assumption, the identity is compared first (since it's faster) while comparing two elements, and the values are compared only when the identities mismatch. The following snippet will make things clearer, +- Da nach dem IEEE Standard ` NaN != NaN`, bircht die Befolgung dieser Regel die ReflexivitĂ€tsannahme eines Collection-Elements in Python, d.h. wenn `x` Teil einer Collection wie einer `list` ist, dann basieren die Implementierungen, wie zum Beispiel Vergleiche, auf der Annahme, dass `x == x`. Aufgrund dieser Annahme, wird die IdentitĂ€t zuerst verglichen (da dies schneller ist), wĂ€hrend die beiden Elemente verglichen werden, und die Werte werden nur verglichen, wenn die IdentitĂ€ten ungleich sind. Der folgende Schnipsel wird die Dinge klarer erscheinen lassen: ```py >>> x = float('nan') @@ -1831,9 +1827,9 @@ True (False, False) ``` - Since the identities of `x` and `y` are different, the values are considered, which are also different; hence the comparison returns `False` this time. + Da die IdentitĂ€ten von `x` und `y` unterschiedlich sind, werden die Werte betrachtet, die ebenfalls unterschiedlich sind; deshalb gibt der Vergleich dieses Mal `False` zurĂŒck. -- Interesting read: [Reflexivity, and other pillars of civilization](https://bertrandmeyer.com/2010/02/06/reflexivity-and-other-pillars-of-civilization/) +- Interessant zu lesen: [Reflexivity, and other pillars of civilization](https://bertrandmeyer.com/2010/02/06/reflexivity-and-other-pillars-of-civilization/) --- @@ -1841,7 +1837,7 @@ True -This might seem trivial if you know how references work in Python. +Das sieht vielleicht trivial aus, wenn du weißt wie Referenzen in Python funktionieren. ```py some_tuple = ("A", "tuple", "with", "values") @@ -1852,7 +1848,7 @@ another_tuple = ([1, 2], [3, 4], [5, 6]) ```py >>> some_tuple[2] = "change this" TypeError: 'tuple' object does not support item assignment ->>> another_tuple[2].append(1000) #This throws no error +>>> another_tuple[2].append(1000) #Das wirft keinen Fehler >>> another_tuple ([1, 2], [3, 4], [5, 6, 1000]) >>> another_tuple[2] += [99, 999] @@ -1861,17 +1857,17 @@ TypeError: 'tuple' object does not support item assignment ([1, 2], [3, 4], [5, 6, 1000, 99, 999]) ``` -But I thought tuples were immutable... +Aber ich dachte Tupel sind unverĂ€nderlich... #### 💡 ErklĂ€rung: * Zitat von https://docs.python.org/3/reference/datamodel.html - > Immutable sequences - An object of an immutable sequence type cannot change once it is created. (If the object contains references to other objects, these other objects may be mutable and may be modified; however, the collection of objects directly referenced by an immutable object cannot change.) + > UnverĂ€nderliche Sequenzen + Ein Objekt eines unverĂ€nderlichen Sequenztypen kann nicht nach der Erzeugung verĂ€ndert werden. (Wenn das Objekt Referenzen zu anderen Objekten enthĂ€lt, können die anderen Objekte verĂ€nderlich und modifizierbar sein; jedoch kann die Collection von Objekten, die von einem unverĂ€nderlichen Objekt referenziert werden, nicht geĂ€ndert werden.) -* `+=` operator changes the list in-place. The item assignment doesn't work, but when the exception occurs, the item has already been changed in place. -* There's also an ErklĂ€rung in [official Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works). +* Der `+=` Operator verĂ€ndert die Liste in-place. Die Element-Zuweisung funktioniert nicht, aber wenn die Exception auftritt, wurde das Element bereits an Ort und Stelle verĂ€ndert. +* Es gibt auch eine ErklĂ€rung im [offiziellen Python FAQ](https://docs.python.org/3/faq/programming.html#why-does-a-tuple-i-item-raise-an-exception-when-the-addition-works). --- @@ -1889,7 +1885,7 @@ except Exception as e: **Ausgabe (Python 2.x):** ```py >>> print(e) -# prints nothing +# gibt nichts aus ``` **Ausgabe (Python 3.x):** @@ -1902,14 +1898,14 @@ NameError: name 'e' is not defined * Quelle: https://docs.python.org/3/reference/compound_stmts.html#except - When an exception has been assigned using `as` target, it is cleared at the end of the `except` clause. This is as if + Wenn eine Exception mit dem `as`-Target zugewiesen wurde, wird sie am Ende der `except`-Klausel gelöscht. Das ist so, als ob ```py except E as N: foo ``` - was translated into + ĂŒbersetzt wurde in ```py except E as N: @@ -1919,9 +1915,9 @@ NameError: name 'e' is not defined del N ``` - This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because, with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs. + Das bedeutet, dass einer Exception ein anderer Name zugewiesen werden muss, wenn man es nach einer except-Klausel benutzen möchte. Exceptions werden gelöscht, weil sie mit dem angehĂ€ngten Traceback einen Referenzzyklus mit dem SatckFrame bilden, der alle Locals in diesem Frame am Leben erhĂ€lt, bis die nĂ€chste Garbage Collection stattfindet. -* The clauses are not scoped in Python. Everything in the example is present in the same scope, and the variable `e` got removed due to the execution of the `except` clause. The same is not the case with functions that have their separate inner-scopes. The example below illustrates this: +* Die Klauseln besitzen keinen Scope in Python. Alles im Beispiel liegt im selben Scope, und die Variable `e` wurde entfernt, da die except-Klausel ausgefĂŒhrt wurde. Das gleiche gilt nicht fĂŒr Funktionen, die ihren eigenen inneren Scope haben. Das Beispiel unten erlĂ€utert dies: ```py def f(x): @@ -1944,14 +1940,14 @@ NameError: name 'e' is not defined [5, 4, 3] ``` -* In Python 2.x, the variable name `e` gets assigned to `Exception()` instance, so when you try to print, it prints nothing. +* In Python 2.x wird der Variable `e` eine `Exception()`-Instanz zugewiesen, wenn du also versuchst, dies auszugeben, wird gar nichts ausgegeben. **Ausgabe (Python 2.x):** ```py >>> e Exception() >>> print e - # Nothing is printed! + # Nichts wird ausgegeben! ``` --- @@ -1972,7 +1968,7 @@ some_dict = {'s': 42} str >>> s = SomeClass('s') >>> some_dict[s] = 40 ->>> some_dict # expected: Two different keys-value pairs +>>> some_dict # erwartet: zwei verschiedene key-value-Paare {'s': 40} >>> type(list(some_dict.keys())[0]) str @@ -1980,10 +1976,10 @@ str #### 💡 ErklĂ€rung: -* Both the object `s` and the string `"s"` hash to the same value because `SomeClass` inherits the `__hash__` method of `str` class. -* `SomeClass("s") == "s"` evaluates to `True` because `SomeClass` also inherits `__eq__` method from `str` class. -* Since both the objects hash to the same value and are equal, they are represented by the same key in the dictionary. -* For the desired behavior, we can redefine the `__eq__` method in `SomeClass` +* Das Objekt `s` und der String `"s"` hashen auf denselben Wert, weil `SomeClass` erbt die `__hash__`-Methode von der `str`-Klasse. +* `SomeClass("s") == "s"` wird zu `True` ausgewertet, weil `SomeClass` auch die `__eq__`-Methode von der `str`-Klasse erbt. +* Da beide Objekte auf denselben Wert hashen und gleich sind, werden sie durch denselben Key im Dictionary reprĂ€sentiert. +* FĂŒr das gewĂŒnschte Verhalten, können wir die `__eq__`-Methode in `SomeClass` neu definieren: ```py class SomeClass(str): def __eq__(self, other): @@ -1993,8 +1989,8 @@ str and super().__eq__(other) ) - # When we define a custom __eq__, Python stops automatically inheriting the - # __hash__ method, so we need to define it as well + # Wenn wir ein benutzerdefiniertes __eq__ definieren, stoppt Python automatisch die Vererbung der + # __hash__ Methode, also mĂŒssen wir diese auch noch definieren __hash__ = str.__hash__ some_dict = {'s':42} From 36b73b7e78be844b37e9e99098eb07c6f8bfec85 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Fri, 11 Aug 2023 13:38:57 +0200 Subject: [PATCH 14/20] #13 --- README.md | 86 +++++++++++++++++++++++++++---------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 2b86170b..54b3a258 100644 --- a/README.md +++ b/README.md @@ -2023,23 +2023,23 @@ a, b = a[b] = {}, 5 #### 💡 ErklĂ€rung: -* According to [Python language reference](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements), assignment statements have the form +* Nach der [Python-Sprachreferenz](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements) haben Zuweisungsanweisungen die Form ``` (target_list "=")+ (expression_list | yield_expression) ``` - and - -> An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right. + und + +> Eine Zuweisungsanweisung wertet eine Liste von AusdrĂŒcken aus (denk daran, dass dies ein einzelner Ausdruck oder eine durch Komma getrennte Liste sein kann, wobei letzteres ein Tupel ergibt) und weist dem einzelnen resultierenden Objekt jeder der Ziellisten zu, von links nach rechts. -* The `+` in `(target_list "=")+` means there can be **one or more** target lists. In this case, target lists are `a, b` and `a[b]` (note the expression list is exactly one, which in our case is `{}, 5`). +* Das `+` in `(target_list "=")+` meint, dass es **eine oder mehrere** Ziellisten geben kann. In diesem Fall sind die Ziellisten `a, b` und `a[b]` (beachte, dass die Liste von AusdrĂŒcken exakt eine ist, was in unserem Fall `{}, 5` ist). -* After the expression list is evaluated, its value is unpacked to the target lists from **left to right**. So, in our case, first the `{}, 5` tuple is unpacked to `a, b` and we now have `a = {}` and `b = 5`. +* Nachdem die Liste der AusdrĂŒcke ausgewertet wurde, wird ihr Wert von **links nach rechts** in die Ziellisten entpackt. Also wird, in unserem Fall, zuerst das Tupel `{}, 5` zu `a, b` entpackt und wir haben nun `a = {}` und `b = 5`. -* `a` is now assigned to `{}`, which is a mutable object. +* `a` wird nun `{}` zugewiesen, was ein verĂ€nderliches Objekt ist. -* The second target list is `a[b]` (you may expect this to throw an error because both `a` and `b` have not been defined in the statements before. But remember, we just assigned `a` to `{}` and `b` to `5`). +* Die zweite Zielliste ist `a[b]` (vielleicht hĂ€ttest du erwartet, dass dies einen Fehler wirft, da sowohl `a` als auch `b` nicht in der Anweisung vorher definiert wurden. Aber denk daran, dass wir gerade `a` dem `{}` und `b` der `5` zugewiesen haben). -* Now, we are setting the key `5` in the dictionary to the tuple `({}, 5)` creating a circular reference (the `{...}` in the Ausgabe refers to the same object that `a` is already referencing). Another simpler example of circular reference could be +* Jetzt setzen wir den SchlĂŒssel `5` im Dictionary auf das Tupel `({}, 5)`, was einen Zirkelschluss erzeugt (das `{...}` in der Ausgabe bezieht sich auf dasselbe Objekt, was `a` bereits referenziert). Ein weiteres, einfacheres Beispiel einer zirkulĂ€ren Referenz: ```py >>> some_list = some_list[0] = [0] >>> some_list @@ -2051,14 +2051,14 @@ a, b = a[b] = {}, 5 >>> some_list[0][0][0][0][0][0] == some_list True ``` - Similar is the case in our example (`a[b][0]` is the same object as `a`) + Ähnlich verhĂ€lt es sich in unserem Beispiel (`a[b][0]` ist dasselbe Objekt wie `a`) * Um zusammenzufassen, kannst du das Beispiel wie folgt aufgliedern ```py a, b = {}, 5 a[b] = a, b ``` - And the circular reference can be justified by the fact that `a[b][0]` ist dasselbe Objekt wie `a` + Und der zirkulĂ€re Bezug lĂ€sst sich durch die Tatsache rechtfertigen, dass `a[b][0]` dasselbe Objekt ist wie `a` ```py >>> a[b][0] is a True @@ -2134,10 +2134,10 @@ Ja, es lĂ€uft exakt **acht** mal und stoppt dann. #### 💡 ErklĂ€rung: * Iteration ĂŒber ein Dictionary, welches du zur selben Zeit modifizierst, wird nicht unterstĂŒtzt. -* It runs eight times because that's the point at which the dictionary resizes to hold more keys (we have eight deletion entries, so a resize is needed). This is actually an implementation detail. -* How deleted keys are handled and when the resize occurs might be different for different Python implementations. -* So for Python versions other than Python 2.7 - Python 3.5, the count might be different from 8 (but whatever the count is, it's going to be the same every time you run it). You can find some discussion around this [here](https://github.com/satwikkansal/wtfpython/issues/53) or in [this](https://stackoverflow.com/questions/44763802/bug-in-python-dict) StackOverflow thread. -* Python 3.7.6 onwards, you'll see `RuntimeError: dictionary keys changed during iteration` exception if you try to do this. +* Es lĂ€uft acht Mal, weil sich die GrĂ¶ĂŸe des Dictionary an diesem Punkt Ă€ndert, um mehr SchlĂŒssel beherbergen zu können (wir haben acht LöscheintrĂ€ge, daher ist eine GrĂ¶ĂŸenĂ€nderung nötig). Das ist tatsĂ€chlich ein Implementierungsdetail. +* Wie gelöschte SchlĂŒssel gehandhabt werden und wann eine GrĂ¶ĂŸenĂ€nderung erfolgt, kann sich je nach Python-Implementierung unterscheiden. +* Daher mag sich die Anzahl fĂŒr andere Python-Versionen, als fĂŒr 2.7 - 3.5, von 8 unterscheiden (aber wie die Anzahl auch sein mag, sie wird bei jedem Programmdurchlauf gleich bleiben). Du kannst ein paar Diskussionen rund um das Thema [hier](https://github.com/satwikkansal/wtfpython/issues/53) oder in [diesem](https://stackoverflow.com/questions/44763802/bug-in-python-dict) StackOverflow thread finden. +* Ab Python 3.7.6 wirst du eine `RuntimeError: dictionary keys changed during iteration` Exception sehen, wenn du so etwas versuchst. --- @@ -2161,7 +2161,7 @@ class SomeClass: Deleted! ``` -Pha, deleted zuletzt. You might have guessed what saved `__del__` from being called in our first attempt to delete `x`. ErgĂ€nzen wir das Beispiel um weitere Aspekte +Endlich wird deleted ausgegeben. Vielleicht erahnst du schon schon, warum `__del__` nicht schon bei unserem ersten Versuch, `x` zu löschen, aufgerufen wurde. ErgĂ€nzen wir das Beispiel um weitere Aspekte 2\. ```py @@ -2176,13 +2176,13 @@ Deleted! {'__builtins__': , 'SomeClass': , '__package__': None, '__name__': '__main__', '__doc__': None} ``` -Okay, now it's deleted :confused: +Okay, jetzt ist es gelöscht :confused: #### 💡 ErklĂ€rung: -+ `del x` doesn’t directly call `x.__del__()`. -+ When `del x` is encountered, Python deletes the name `x` from current scope and decrements by 1 the reference count of the object `x` referenced. `__del__()` is called only when the object's reference count reaches zero. -+ In the second Ausgabe snippet, `__del__()` was not called because the previous statement (`>>> y`) in the interactive interpreter created another reference to the same object (specifically, the `_` magic variable which references the result value of the last non `None` expression on the REPL), thus preventing the reference count from reaching zero when `del y` was encountered. -+ Calling `globals` (or really, executing anything that will have a non `None` result) caused `_` to reference the new result, dropping the existing reference. Now the reference count reached 0 and we can see "Deleted!" being printed (finally!). ++ `del x` ruft nicht direkt `x.__del__()` auf. ++ Wenn auf `del x` gestoßen wird, dann löscht Python den Namen `x` vom momentanen Scope und dekrementiert den Referenz-Counter des Objektes, welches `x` referenziert, um 1. `__del__()` wird nur aufgerufen, wenn der Referenz-Counter des Objektes 0 erreicht. ++ Im zweiten Ausgabe-Schnipsel wurde `__del__()` nicht aufgerufen, weil die vorherige Anweisung (`>>> y`) im interaktiven Interpreter eine neue Referenz zum selben Objekt erzeugt hat (spezifisch die magische Variable `_`, welche das Ergebnis des letzten, nicht-`None` Ausdrucks der REPL referenziert), und daher den Referenz-Counter davon abhĂ€lt, die 0 zu erreichen, wenn `del y` gelesen wurde. ++ Mit dem Aufruf von `globals` (oder irgendetwas, dass kein Ergebnis hat, dass `None` ist) wurde `_` angewiesen, dass neue Ergebnis zu referenzieren, wodurch die bestehende Referenz fallen gelassen wurde. Nun hat der Referenz-Counter 0 erreicht und wir können sehen, dass "Deleted!" ausgegeben wurde (Endlich!) --- @@ -2230,8 +2230,8 @@ UnboundLocalError: local variable 'a' referenced before assignment ``` #### 💡 ErklĂ€rung: -* When you make an assignment to a variable in scope, it becomes local to that scope. So `a` becomes local to the scope of `another_func`, but it has not been initialized previously in the same scope, which throws an error. -* To modify the outer scope variable `a` in `another_func`, we have to use the `global` keyword. +* Wenn du eine einer Variablen in einem Scope etwas zuweist, dann wird das fĂŒr diesen Scope lokal. Also wird `a` lokal fĂŒr den Scope von `another_func`, aber es wurde vorher nicht im selben Scope initialisiert, was einen Fehler wirft. +* Um die Outer-Scope-Variable `a` in `another_func` zu modifizieren, mĂŒssen wir das `global` SchlĂŒsselwort verwenden. ```py def another_func() global a @@ -2244,8 +2244,8 @@ UnboundLocalError: local variable 'a' referenced before assignment >>> another_func() 2 ``` -* In `another_closure_func`, `a` becomes local to the scope of `another_inner_func`, but it has not been initialized previously in the same scope, which is why it throws an error. -* To modify the outer scope variable `a` in `another_inner_func`, use the `nonlocal` keyword. The nonlocal statement is used to refer to variables defined in the nearest outer (excluding the global) scope. +* In `another_closure_func` wird `a` fĂŒr den Scope von `another_inner_func` lokal, aber es wurde vorher nicht im selben Scope initialisiert, was der Grund fĂŒr den Fehler ist. +* Um die Outer-Scope-Variable `a` in `another_inner_func` zu modifizieren, brauchen wir das `nonlocal` SchlĂŒsselwort. Die nonlocal-Anweisung bezieht sich auf Variablen, die im nĂ€chstgelegenen Ă€ußeren Scope (globaler exkludiert) definiert wurden. ```py def another_func(): a = 1 @@ -2261,8 +2261,8 @@ UnboundLocalError: local variable 'a' referenced before assignment >>> another_func() 2 ``` -* The keywords `global` and `nonlocal` tell the python interpreter to not declare new variables and look them up in the corresponding outer scopes. -* Read [this](https://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html) short but an awesome guide to learn more about how namespaces and scope resolution works in Python. +* Die SchlĂŒsselwörter `global` und `nonlocal` teilen dem Python Interpreter mit, keine neuen Variablen zu deklarieren und diese im entsprechenden Ă€ußeren Scope nachzuschlagen. +* Lies [diesen](https://sebastianraschka.com/Articles/2014_python_scope_and_namespaces.html) kurzen, aber tollen Artikel durch, der ein super Leitfaden ist, um mehr ĂŒber Namespaces und Scope-Auflösung in Python zu lernen. --- @@ -2303,7 +2303,7 @@ Kannst du erklĂ€ren, warum die Ausgabe `[2, 4]` ist? #### 💡 ErklĂ€rung: -* It's never a good idea to change the object you're iterating over. The correct way to do so is to iterate over a copy of the object instead, and `list_3[:]` does just that. +* Es ist nie eine gute Idee ein Objekt zu verĂ€ndern, worĂŒber du gerade iterierst. Korrekt wĂ€re es stattdessen ĂŒber eine Kopie des Objektes zu iterieren, und `list_3[:]` tut genau das. ```py >>> some_list = [1, 2, 3, 4] @@ -2313,13 +2313,13 @@ Kannst du erklĂ€ren, warum die Ausgabe `[2, 4]` ist? 139798779601192 ``` -**Difference between `del`, `remove`, and `pop`:** -* `del var_name` just removes the binding of the `var_name` from the local or global namespace (That's why the `list_1` is unaffected). -* `remove` removes the first matching value, not a specific index, raises `ValueError` if the value is not found. -* `pop` removes the element at a specific index and returns it, raises `IndexError` if an invalid index is specified. +**Unterschied zwischen `del`, `remove`, und `pop`:** +* `del var_name` entfernt nur die Bindung von `var_name` vom lokalen oder globalen Namespace (Deshalb ist `list_1` davon nicht betroffen). +* `remove` entfernt den ersten Wert, der ĂŒbereinstimmt, keinen spezifischen Index, und wirft einen `ValueError`, wenn der Wert nicht gefunden werden konnte. +* `pop` entfernt ein Element am angegebenen Index und gibt dieses zurĂŒck und wirft einen `IndexError`, wenn ein falscher Index angegeben wurde. -**Why the Ausgabe is `[2, 4]`?** -- The list iteration is done index by index, and when we remove `1` from `list_2` or `list_4`, the contents of the lists are now `[2, 3, 4]`. The remaining elements are shifted down, i.e., `2` is at index 0, and `3` is at index 1. Since the next iteration is going to look at index 1 (which is the `3`), the `2` gets skipped entirely. A similar thing will happen with every alternate element in the list sequence. +**Warum ist die Ausgabe `[2, 4]`?** +- Die Listeniteration wird ĂŒber den Index ausgefĂŒhrt und wenn wir `1` von `list_2` oder `list_4` entfernen, ist der Inhalt der Listen nun `[2, 3, 4]`. Die verbliebenen Elemente werden heruntergeschoben, d.h.., `2` ist am Index 0, und `3` ist am Index 1. Da die nĂ€chste Iteration an Index 1 nachsehen wird (wo `3` steht), wird die `2` komplett ĂŒbersprungen. Ähnliches wird anderen Element in einer Listensequenz passieren. * Ich verweise auf diesen StackOverflow [thread](https://stackoverflow.com/questions/45946228/what-happens-when-you-try-to-delete-a-list-element-while-iterating-over-it), welches das Beispiel erklĂ€rt * Siehe auch diesen schönen StackOverflow [thread](https://stackoverflow.com/questions/45877614/how-to-change-all-the-dictionary-keys-in-a-for-loop-with-d-items) fĂŒr ein Ă€hnliches Beispiel im Bezug auf Dictionaries in Python. @@ -2340,15 +2340,15 @@ Kannst du erklĂ€ren, warum die Ausgabe `[2, 4]` ist? >>> numbers_iter = iter(numbers) >>> list(zip(numbers_iter, first_three)) [(0, 0), (1, 1), (2, 2)] -# so far so good, let's zip the remaining +# so weit, so gut, lass uns den Rest zippen >>> list(zip(numbers_iter, remaining)) [(4, 3), (5, 4), (6, 5)] ``` -Where did element `3` go from the `numbers` list? +Wo ist das Element `3` von der Liste `numbers` hin? #### 💡 ErklĂ€rung: -- From Python [docs](https://docs.python.org/3.3/library/functions.html#zip), here's an approximate implementation of zip function, +- Von der Python-[Dokumentation](https://docs.python.org/3.3/library/functions.html#zip), hier ist eine ungefĂ€hre Implementierung der zip-Funktion: ```py def zip(*iterables): sentinel = object() @@ -2361,9 +2361,9 @@ Where did element `3` go from the `numbers` list? result.append(elem) yield tuple(result) ``` -- So the function takes in arbitrary number of iterable objects, adds each of their items to the `result` list by calling the `next` function on them, and stops whenever any of the iterable is exhausted. -- The caveat here is when any iterable is exhausted, the existing elements in the `result` list are discarded. That's what happened with `3` in the `numbers_iter`. -- The correct way to do the above using `zip` would be, +- Die Funktion nimmt also beliebige Zahlen von Iterable-Objekten, fĂŒgt jedes ihrer Elemente der Liste `result` hinzu, indem es die Funktion `next` auf ihnen aufruft, und stoppt immer dann, wenn einer der Iterables aufgebraucht ist. +- Die EinschrĂ€nkung liegt hier darin, dass wenn ein Iterable aufgebraucht ist, die verbleibenden Elemente in der `result` Liste verworfen werden. Das ist mit der `3` in `numbers_iter` passiert. +- Die korrekte Vorgehensweise mit `zip` fĂŒr das obige sĂ€he wie folgt aus: ```py >>> numbers = list(range(7)) >>> numbers_iter = iter(numbers) @@ -2372,7 +2372,7 @@ Where did element `3` go from the `numbers` list? >>> list(zip(remaining, numbers_iter)) [(3, 3), (4, 4), (5, 5), (6, 6)] ``` - The first argument of zip should be the one with fewest elements. + Das erste Argument von zip sollte das mit der geringsten Anzahl an Elementen sein. --- @@ -2392,11 +2392,11 @@ print(x, ': x in global') 6 : x in global ``` -But `x` was never defined outside the scope of for loop... +Aber `x` wurde nie außerhalb des Scopes der for-Schleife definiert... 2\. ```py -# This time let's initialize x first +# Las uns dieses Mal x zuerst initialisieren x = -1 for x in range(7): if x == 6: From 244f96fc60549c5c513146b7fcc093e404e704c9 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Fri, 11 Aug 2023 14:50:18 +0200 Subject: [PATCH 15/20] #14 --- README.md | 66 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 54b3a258..3d948272 100644 --- a/README.md +++ b/README.md @@ -2432,11 +2432,11 @@ print(x, ': x in global') #### 💡 ErklĂ€rung: -- In Python, for-loops use the scope they exist in and leave their defined loop-variable behind. This also applies if we explicitly defined the for-loop variable in the global namespace before. In this case, it will rebind the existing variable. +- In Python benutzen for-Schleifen den Scope, in dem sie existieren und lassen ihre definierte Schleifenvariable zurĂŒck. Das passiert auch, wenn wir diese Variable vorher im globalen Namespace definieren. In diesem Fall wird die bestehende Variable neu gebunden. -- The differences in the Ausgabe of Python 2.x and Python 3.x interpreters for list comprehension example can be explained by following change documented in [What’s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) changelog: +- Die Unterschiede in der Ausgabe des Python 2.x und Python 3.x Interpreters fĂŒr List-Comprehensions können durch die folgende Änderung erklĂ€rt werden, welche im [What’s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) Changelog dokumentiert wurde: - > "List comprehensions no longer support the syntactic form `[... for var in item1, item2, ...]`. Use `[... for var in (item1, item2, ...)]` instead. Also, note that list comprehensions have different semantics: they are closer to syntactic sugar for a generator expression inside a `list()` constructor, and in particular, the loop control variables are no longer leaked into the surrounding scope." + > "List-Comprehensions unterstĂŒtzen nicht lĂ€nger die syntaktische Form `[... for var in item1, item2, ...]`. Benutze `[... for var in (item1, item2, ...)]` stattdessen. Beachte zudem, dass List-Comprehensions eine andere Semantik haben: sie sind eher syntaktischer Zucker fĂŒr einen Generator-Ausdruck innerhalb eines `list()`-Konstruktors und insbesondere werden die Steuervariablen der Schleife nicht mehr in den umgebenden Scope geleakt." --- @@ -2463,7 +2463,7 @@ def some_func(default_arg=[]): #### 💡 ErklĂ€rung: -- The default mutable arguments of functions in Python aren't really initialized every time you call the function. Instead, the recently assigned value to them is used as the default value. When we explicitly passed `[]` to `some_func` as the argument, the default value of the `default_arg` variable was not used, so the function returned as expected. +- Die vorgegebenen verĂ€nderbaren Argumente von Funktionen in Python werden nicht wirklich jedes Mal, wenn du die Funktion aufrufst, initialisiert. Stattdessen wird der zuletzt zugewiesene Wert als default genommen. Als wir explizit `[]` an `some_func` als Argument ĂŒbergeben haben, dann wurde der default-Wert der `default_arg`-Variable nicht benutzt, also hat die Funktion das zurĂŒckgegeben, was wir erwartet hatten. ```py def some_func(default_arg=[]): @@ -2473,7 +2473,7 @@ def some_func(default_arg=[]): **Ausgabe:** ```py - >>> some_func.__defaults__ #This will show the default argument values for the function + >>> some_func.__defaults__ #Das zeigt die default-Werte der Argumente fĂŒr die Funktion ([],) >>> some_func() >>> some_func.__defaults__ @@ -2486,7 +2486,7 @@ def some_func(default_arg=[]): (['some_string', 'some_string'],) ``` -- A common practice to avoid bugs due to mutable arguments is to assign `None` as the default value and later check if any value is passed to the function corresponding to that argument. Example: +- Eine typische Vorgehensweise um Fehler, ausgelöst durch verĂ€nderbare Argumente, zu verhindern ist es, `None` dem default-Wert zuzuweisen und spĂ€ter zu ĂŒberprĂŒfen, ob irgendein Wert an die Funktion ĂŒbergeben wird, der diesem Argument entspricht. Beispiel: ```py def some_func(default_arg=None): @@ -2503,13 +2503,13 @@ def some_func(default_arg=[]): ```py some_list = [1, 2, 3] try: - # This should raise an ``IndexError`` + # Das sollte einen ``IndexError`` werfen print(some_list[4]) except IndexError, ValueError: print("Caught!") try: - # This should raise a ``ValueError`` + # Das sollte einen ``ValueError`` werfen some_list.remove(4) except IndexError, ValueError: print("Caught again!") @@ -2532,11 +2532,12 @@ SyntaxError: invalid syntax #### 💡 ErklĂ€rung -* To add multiple Exceptions to the except clause, you need to pass them as parenthesized tuple as the first argument. The second argument is an optional name, which when supplied will bind the Exception instance that has been raised. Example, +* Um mehrere Exceptions der except-Klausel hinzuzufĂŒgen, musst du diese als Tupel mit Klammern und als erstes Argument ĂŒbergeben. Das zweite Argument ist ein optionaler Name, der, wenn angegeben, die Exception-Instanz bindet, die geworfen wurde. Beispiel: + ```py some_list = [1, 2, 3] try: - # This should raise a ``ValueError`` + # Das sollte einen ``ValueError`` werfen some_list.remove(4) except (IndexError, ValueError), e: print("Caught again!") @@ -2555,7 +2556,7 @@ SyntaxError: invalid syntax IndentationError: unindent does not match any outer indentation level ``` -* Separating the exception from the variable with a comma is deprecated and does not work in Python 3; the correct way is to use `as`. Example, +* Die Exceptions und die Variable mit einem Komma zu trennen ist veraltet und funktioniert in Python 3 nicht mehr; der korrekte Weg wĂ€re `as` zu benutzen. Beispiel: ```py some_list = [1, 2, 3] try: @@ -2607,11 +2608,11 @@ a += [5, 6, 7, 8] #### 💡 ErklĂ€rung: -* `a += b` doesn't always behave the same way as `a = a + b`. Classes *may* implement the *`op=`* operators differently, and lists do this. +* `a += b` verhĂ€lt sich nicht immer wie `a = a + b`. Klassen *können* die *`op=`* Operatoren unterschiedlich implementieren und Listen tun das. -* The expression `a = a + [5,6,7,8]` generates a new list and sets `a`'s reference to that new list, leaving `b` unchanged. +* Der Ausdruck `a = a + [5,6,7,8]` generiert eine neue Liste und setzt `a`s Referenz auf diese neue Liste, wodurch `b` unverĂ€ndert bleibt. -* The expression `a += [5,6,7,8]` is actually mapped to an "extend" function that operates on the list such that `a` and `b` still point to the same list that has been modified in-place. +* Der Ausdruck `a += [5,6,7,8]` wird tatsĂ€chlich zu einer "extend"-Funktion gemapped wird, die auf der Liste arbeitet, sodass `a` und `b` immer noch auf dieselbe Liste zeigen, die in-place modifiziert wurde. --- @@ -2652,15 +2653,16 @@ class SomeClass: ``` #### 💡 ErklĂ€rung -- Scopes nested inside class definition ignore names bound at the class level. -- A generator expression has its own scope. -- Starting from Python 3.X, list comprehensions also have their own scope. + +- Innerhalb der Klassendefinition verschachtelte Scopes ignorieren die auf Klassenebene gebundenen Namen. +- Ein Generator-Ausdruck hat seinen eigenen Scope. +- Ausgehend von Python 3.X haben List Comprehensions auch ihren eigenen Scope. --- ### ▶ Runden wie ein Bankier * -Let's implement a naive function to get the middle element of a list: +Lass uns eine naive Funktion implementieren, um das mittlere Element einer Liste zu bekommen: ```py def get_middle(some_list): mid_index = round(len(some_list) / 2) @@ -2669,22 +2671,22 @@ def get_middle(some_list): **Python 3.x:** ```py ->>> get_middle([1]) # looks good +>>> get_middle([1]) # sieht gut aus 1 ->>> get_middle([1,2,3]) # looks good +>>> get_middle([1,2,3]) # sieht gut aus 2 >>> get_middle([1,2,3,4,5]) # huh? 2 ->>> len([1,2,3,4,5]) / 2 # good +>>> len([1,2,3,4,5]) / 2 # gut 2.5 ->>> round(len([1,2,3,4,5]) / 2) # why? +>>> round(len([1,2,3,4,5]) / 2) # Warum? 2 ``` -It seems as though Python rounded 2.5 to 2. +Sieht so aus, als ob Python 2.5 zu 2 rundet. #### 💡 ErklĂ€rung: -- This is not a float precision error, in fact, this behavior is intentional. Since Python 3.0, `round()` uses [banker's rounding](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even) where .5 fractions are rounded to the nearest **even** number: +- Das ist kein Gleitkommafehler, denn faktisch ist dieses Verhalten Absicht. Seit Python 3.0 benutzt `round()` [banker's rounding](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even), wodurch 0,5er-BrĂŒche auf die nĂ€chste **gerade** Zahl gerundet werden: ```py >>> round(0.5) @@ -2693,7 +2695,7 @@ It seems as though Python rounded 2.5 to 2. 2 >>> round(2.5) 2 ->>> import numpy # numpy does the same +>>> import numpy # numpy tut dasselbe >>> numpy.round(0.5) 0.0 >>> numpy.round(1.5) @@ -2702,9 +2704,9 @@ It seems as though Python rounded 2.5 to 2. 2.0 ``` -- This is the recommended way to round .5 fractions as described in [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754#Rounding_rules). However, the other way (round away from zero) is taught in school most of the time, so banker's rounding is likely not that well known. Furthermore, some of the most popular programming languages (for example: JavaScript, Java, C/C++, Ruby, Rust) do not use banker's rounding either. Therefore, this is still quite special to Python and may result in confusion when rounding fractions. -- See the [round() docs](https://docs.python.org/3/library/functions.html#round) or [this stackoverflow thread](https://stackoverflow.com/questions/10825926/python-3-x-rounding-behavior) for more information. -- Note that `get_middle([1])` only returned 1 because the index was `round(0.5) - 1 = 0 - 1 = -1`, returning the last element in the list. +- Das ist der empfohlene Weg um 0,5er-BrĂŒche zu runden, wie es auch in [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754#Rounding_rules) beschrieben wurde. Allerdings wird in der Schule meist die andere Methode (von Null abrunden) gelehrt, so dass banker's rounding wahrscheinlich nicht so bekannt ist. Außerdem benutzen manche der populĂ€rsten Programmiersprachen (zum Beispiel: JavaScript, Java, C/C++, Ruby, Rust) nicht das banker's rounding. Daher ist das ziemlich besonders fĂŒr Python und kann zu Verwirrung beim runden von BrĂŒchen fĂŒhren. +- Sieh dir die [round() docs](https://docs.python.org/3/library/functions.html#round) oder [diesen stackoverflow thread](https://stackoverflow.com/questions/10825926/python-3-x-rounding-behavior), um mehr Informationen zu bekommen. +- Beachte, dass `get_middle([1])` nur 1 zurĂŒckgegeben hat, weil der Index `round(0.5) - 1 = 0 - 1 = -1` war, wodurch das letzte Element in der Liste zurĂŒckgibt. --- @@ -2712,7 +2714,7 @@ It seems as though Python rounded 2.5 to 2. -I haven't met even a single experience Pythonist till date who has not come across one or more of the following scenarios, +Ich habe bis heute keinen einzigen erfahrenen Pythonisten getroffen, der nicht auf eines oder mehrere der folgenden Szenarien gestoßen ist: 1\. @@ -2723,7 +2725,7 @@ x, y = (0, 1) if True else None, None **Ausgabe:** ```py ->>> x, y # expected (0, 1) +>>> x, y # erwartet: (0, 1) ((0, 1), None) ``` @@ -2787,9 +2789,9 @@ b = "javascript" **Ausgabe:** ```py -# An assert statement with an assertion failure message. +# Eine assert-Anweisung mit einer assertion-Fehlermeldung. >>> assert(a == b, "Both languages are different") -# No AssertionError is raised +# Kein AssertionError wurde geworfen ``` 5\. From 51231fdd22bb8958f23a76fc9040f78cec9861bd Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Fri, 11 Aug 2023 15:31:41 +0200 Subject: [PATCH 16/20] #15 --- README.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 3d948272..e9c09a77 100644 --- a/README.md +++ b/README.md @@ -2846,20 +2846,20 @@ def similar_recursive_func(a): #### 💡 ErklĂ€rung: -* For 1, the correct statement for expected behavior is `x, y = (0, 1) if True else (None, None)`. +* FĂŒr 1 wĂ€re die korrekte Anweisung fĂŒr das erwartete Verhalten `x, y = (0, 1) if True else (None, None)`. -* For 2, the correct statement for expected behavior is `t = ('one',)` or `t = 'one',` (missing comma) otherwise the interpreter considers `t` to be a `str` and iterates over it character by character. +* FĂŒr 2 wĂ€re die korrekte Anweisung fĂŒr das erwartete Verhalten `t = ('one',)` oder `t = 'one',` (fehlendes Komma) andernfalls wird der Interpreter `t` als ein `str` betrachten und iteriert Character fĂŒr Character ĂŒber es. -* `()` is a special token and denotes empty `tuple`. +* `()` ist ein spezielles Token und bezeichnet ein leeres `tuple`. -* In 3, as you might have already figured out, there's a missing comma after 5th element (`"that"`) in the list. So by implicit string literal concatenation, +* In 3, wie du vielleicht schon mitbekommen hast, fehlt ein Komma nach dem fĂŒnften Element (`"that"`) in der Liste. Also bei implizierter String-Literal-Konkatenation: ```py >>> ten_words_list ['some', 'very', 'big', 'list', 'thatconsists', 'of', 'exactly', 'ten', 'words'] ``` -* No `AssertionError` was raised in 4th snippet because instead of asserting the individual expression `a == b`, we're asserting entire tuple. The following snippet will clear things up, +* Es wurde kein `AssertionError` im 4.ten Schnipsel geworfen, weil wir statt den individuellen Ausdruck `a == b` zu asserten, das ganze Tupel asserten. Der folgende Schnipsel wird die Dinge klarer werden lassen: ```py >>> a = "python" @@ -2878,11 +2878,11 @@ def similar_recursive_func(a): AssertionError: Values are not equal ``` -* As for the fifth snippet, most methods that modify the items of sequence/mapping objects like `list.append`, `dict.update`, `list.sort`, etc. modify the objects in-place and return `None`. The rationale behind this is to improve performance by avoiding making a copy of the object if the operation can be done in-place (Referred from [here](https://docs.python.org/3/faq/design.html#why-doesn-t-list-sort-return-the-sorted-list)). +* Was den fĂŒnften Schnipsel betrifft, so modifizieren die meisten Methoden, die die Elemente von Sequenzen/Mapping-Objekten modifizieren, wie `list.append`, `dict.update`, `list.sort`, die Objekte in-place und geben `None` zurĂŒck. Der Grund dafĂŒr ist eine Leistungsverbesserung, indem die Erstellung einer Kopie vermieden wird, wenn die Operation in-place ausgefĂŒhrt werden kann (Verweis nach [hier](https://docs.python.org/3/faq/design.html#why-doesn-t-list-sort-return-the-sorted-list)). -* Last one should be fairly obvious, mutable object (like `list`) can be altered in the function, and the reassignment of an immutable (`a -= 1`) is not an alteration of the value. +* Das letzte sollte ziemlich offensichtlich sein. Ein verĂ€nderliches Objekt (wie `list`) kann in der Funktion geĂ€ndert werden und die Neuzuweisung eines unverĂ€nderlichen Wertes (`a -= 1`) ist keine Änderung des WErtes -* Being aware of these nitpicks can save you hours of debugging effort in the long run. +* Wenn du dir dieser Kleinigkeiten bewusst bist, dann kannst du dir auf lange Sicht stundenlanges Debugging sparen. --- @@ -2893,25 +2893,25 @@ def similar_recursive_func(a): >>> 'a'.split() ['a'] -# is same as +# ist dasselbe wie >>> 'a'.split(' ') ['a'] -# but +# aber >>> len(''.split()) 0 -# isn't the same as +# ist nicht dasselbe wie >>> len(''.split(' ')) 1 ``` #### 💡 ErklĂ€rung: -- It might appear at first that the default separator for split is a single space `' '`, but as per the [docs](https://docs.python.org/3/library/stdtypes.html#str.split) - > If sep is not specified or is `None`, a different splitting algorithm is applied: runs of consecutive whitespace are regarded as a single separator, and the result will contain no empty strings at the start or end if the string has leading or trailing whitespace. Consequently, splitting an empty string or a string consisting of just whitespace with a None separator returns `[]`. - > If sep is given, consecutive delimiters are not grouped together and are deemed to delimit empty strings (for example, `'1,,2'.split(',')` returns `['1', '', '2']`). Splitting an empty string with a specified separator returns `['']`. -- Noticing how the leading and trailing whitespaces are handled in the following snippet will make things clear, +- Auf den ersten Blick sieht es so aus, als wĂ€re das Standardtrennzeichen fĂŒr split ein einzelnes Leerzeichen `' '`, aber der [Dokumentation](https://docs.python.org/3/library/stdtypes.html#str.split) zufolge + > Wenn ein Separator nicht angegeben oder `None` ist, dann wird ein anderer Splitting-Algorithmus angewendet: aufeinanderfolgende Leerzeichen werden als ein einziges Trennzeichen betrachtet, und das Ergebnis enthĂ€lt keine leeren Strings am Anfang oder Ende, wenn der String fĂŒhrende oder nachfolgende Leerzeichen enthĂ€lt. Folglich gibt das Splitten eines leeren Strings oder eines Strings, der nur ein Leerzeichen enthĂ€lt, mit einen None-Separator `[]` zurĂŒck. + > Wenn ein Separator gegeben ist,Aufeinanderfolgende Begrenzungszeichen werden nicht zusammengefasst und gelten als Begrenzung leerer Strings. (zum Beispiel, `'1,,2'.split(',')` gibt `['1', '', '2']` zurĂŒck). Einen leeren String mit einem angegebenen Separator zu splitten gibt `['']` zurĂŒck. +- Wenn du dir ansiehst, wie die fĂŒhrenden und nachfolgenden Leerzeichen im folgenden Schnipsel gehandhabt werden, wird die Sache klarer: ```py >>> ' a '.split(' ') ['', 'a', ''] @@ -2928,7 +2928,7 @@ def similar_recursive_func(a): ```py -# File: module.py +# Datei: module.py def some_weird_name_func_(): print("works!") @@ -2952,14 +2952,14 @@ NameError: name '_another_weird_name_func' is not defined #### 💡 ErklĂ€rung: -- It is often advisable to not use wildcard imports. The first obvious reason for this is, in wildcard imports, the names with a leading underscore don't get imported. This may lead to errors during runtime. -- Had we used `from ... import a, b, c` syntax, the above `NameError` wouldn't have occurred. +- Es ist oft ratsam, keine Wildcard-Importe zu verwenden. Der erste offensichtliche Grund dafĂŒr ist, dass bei Wildcard-Importen die Namen mit einem fĂŒhrenden Unterstrich nicht importiert werden. Das kann zu Fehlern wĂ€hrend der Laufzeit fĂŒhren. +- HĂ€tten wir diese `from ... import a, b, c` Syntax benutzt, wĂ€re der obige `NameError` nicht aufgetreten. ```py >>> from module import some_weird_name_func_, _another_weird_name_func >>> _another_weird_name_func() works! ``` -- If you really want to use wildcard imports, then you'd have to define the list `__all__` in your module that will contain a list of public objects that'll be available when we do wildcard imports. +- Wenn du wirklich Wildcard-Importe verwenden willst, musst du in deinem Modul die Liste `__all__` definieren, die eine Liste der öffentlichen Objekte enthĂ€lt, die bei Wildcard-Importen zur VerfĂŒgung stehen werden. ```py __all__ = ['_another_weird_name_func'] @@ -3000,7 +3000,7 @@ False #### 💡 ErklĂ€rung: -- The `sorted` method always returns a list, and comparing lists and tuples always returns `False` in Python. +- Die `sorted` Methode gibt immer eine Liste zurĂŒck, und das Vergleichen von Listen und Tupeln gibt in Python immer `False` zurĂŒck. - ```py >>> [] == tuple() @@ -3010,9 +3010,9 @@ False (tuple, list) ``` -- Unlike `sorted`, the `reversed` method returns an iterator. Why? Because sorting requires the iterator to be either modified in-place or use an extra container (a list), whereas reversing can simply work by iterating from the last index to the first. +- Im Gegensatz zu `sorted`, gibt die `reversed` Methode einen Iterator zurĂŒck. Warum? Weil Sortieren vorraussetzt, dass der Iterator entweder in-place modifiziert wird oder einen extra Container (eine Liste) benutzt, wĂ€hrend die Umkehrung einfach durch Iteration vom letzten Index zum ersten funktionieren kann. -- So during comparison `sorted(y) == sorted(y)`, the first call to `sorted()` will consume the iterator `y`, and the next call will just return an empty list. +- Also wĂ€hrend des Vergleichs `sorted(y) == sorted(y)`, wird der erste Aufruf von `sorted()` den Iterator `y` konsumieren, und der nĂ€chste Aufruf wird nur eine leere Liste zurĂŒckgeben. ```py >>> x = 7, 8, 9 @@ -3050,7 +3050,7 @@ The midnight time is not printed. #### 💡 ErklĂ€rung: -Before Python 3.5, the boolean value for `datetime.time` object was considered to be `False` if it represented midnight in UTC. It is error-prone when using the `if obj:` syntax to check if the `obj` is null or some equivalent of "empty." +Vor Python 3.5, wurde der boolesche Wert fĂŒr das `datetime.time`-Objekt als `False` betrachtet, wenn wenn es Mitternacht in UTC dargestellt hĂ€tte. Es ist fehleranfĂ€llig, wenn die `if obj:`-Syntax verwendet wird, um zu prĂŒfen, ob `obj` null oder ein Äquivalent von "leer" ist. --- --- From 2cb98c041e0b67b7f0967fa95d02c2d14db4f090 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Fri, 11 Aug 2023 16:24:48 +0200 Subject: [PATCH 17/20] #16 --- README.md | 90 +++++++++++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index e9c09a77..c1eefc49 100644 --- a/README.md +++ b/README.md @@ -3070,7 +3070,7 @@ import antigravity ``` **Ausgabe:** -Sshh... Es ist supergeheim. +Sshh... It's a super-secret. #### 💡 ErklĂ€rung: + Das `antigravity` Modul ist eines der wenigen easter eggs, die von Python Entwicklern veröffentlicht werden. @@ -3089,7 +3089,7 @@ for i in range(9): for k in range(9): print("I am trapped, please rescue!") if k == 2: - goto .breakout # breaking out from a deeply nested loop + goto .breakout # Ausbrechen aus einer tief verschachtelten Schleife label .breakout print("Freedom!") ``` @@ -3153,10 +3153,10 @@ Das wars schon. #### 💡 ErklĂ€rung: -Das ist relevant fĂŒr [PEP-401](https://www.python.org/dev/peps/pep-0401/), was am 1. April 2009 veröffentlicht wurde (nun weißt du, was das heißt). - Zitat vom PEP-401 - - > Recognized that the != inequality operator in Python 3.0 was a horrible, finger-pain inducing mistake, the FLUFL reinstates the <> diamond operator as the sole spelling. -- There were more things that Uncle Barry had to share in the PEP; you can read them [here](https://www.python.org/dev/peps/pep-0401/). -- It works well in an interactive environment, but it will raise a `SyntaxError` when you run via python file (see this [issue](https://github.com/satwikkansal/wtfpython/issues/94)). However, you can wrap the statement inside an `eval` or `compile` to get it working, + + > Die FLUFL hat erkannt, dass der Ungleichheitsoperator != in Python 3.0 ein schrecklicher, fingerschmerzverursachender Fehler war, und fĂŒhrt den <> Diamantoperator als einzige Schreibweise wieder ein. +- Es gab mehrere Dinge, die Onkel Barry im PEP teilte; du kannst das [hier](https://www.python.org/dev/peps/pep-0401/) nachlesen. +- Es funktioniert gut in einem Interactive Environment, aber es wirft einen `SyntaxError`, wenn du es in einer Python-Datei ausfĂŒhrst (siehe auch dieses [issue](https://github.com/satwikkansal/wtfpython/issues/94)). Du kannst jedoch die Anweisung innerhalb einer `eval` oder `compile` verpacken, um es zum Laufen zu bekommen: ```py from __future__ import barry_as_FLUFL print(eval('"Ruby" <> "Python"')) @@ -3209,15 +3209,15 @@ False False >>> love is not True or False True ->>> love is not True or False; love is love # Love is complicated +>>> love is not True or False; love is love # Liebe ist kompliziert True ``` #### 💡 ErklĂ€rung: -* `this` module in Python is an easter egg for The Zen Of Python ([PEP 20](https://www.python.org/dev/peps/pep-0020)). -* And if you think that's already interesting enough, check out the implementation of [this.py](https://hg.python.org/cpython/file/c3896275c0f6/Lib/this.py). Interestingly, **the code for the Zen violates itself** (and that's probably the only place where this happens). -* Regarding the statement `love is not True or False; love is love`, ironic but it's self-explanatory (if not, please see the examples related to `is` and `is not` operators). +* Das `this` Modul in Python ist ein Easter Egg fĂŒr den Zen von Python ([PEP 20](https://www.python.org/dev/peps/pep-0020)). +* Und wenn du denkst, dass das schon interessant genug ist, sieh dir die Implementierung von [this.py](https://hg.python.org/cpython/file/c3896275c0f6/Lib/this.py) an. Interessanterweise **verstĂ¶ĂŸt der Code fĂŒr das Zen gegen sich selbst** (und das ist wahrscheinlich der einzige Ort, an dem dies geschieht). +* Die Aussage `love is not True or False; love is love` ist ironisch, aber selbsterklĂ€rend (wenn nicht, sieh dir die Beispiele zu den `is` und `is not` Operatoren an). --- @@ -3244,7 +3244,7 @@ Exists! Does not exist ``` -**The `else` clause in exception handling.** Ein Beispiel: +**Die `else`-Klausel in der Behandlung von Exceptions.** Ein Beispiel: ```py try: @@ -3261,8 +3261,8 @@ Try block executed successfully... ``` #### 💡 ErklĂ€rung: -- The `else` clause after a loop is executed only when there's no explicit `break` after all the iterations. You can think of it as a "nobreak" clause. -- `else` clause after a try block is also called "completion clause" as reaching the `else` clause in a `try` statement means that the try block actually completed successfully. +- Die `else`-Klausel nach einer Schleife wird nur dann ausgefĂŒhrt, wenn es kein explizites `break` nach allen Iterationen gibt. Du kannst es dir als eine "nobreak"-Klausel vorstellen. +- Eine `else`-Klausel nach einem try-Block wird auch "completion clause" genannt, da wenn die `else`-Klausel in einer `try`-Anweisung erreicht wird, dies bedeutet, dass der try-Block tatsĂ€chlich komplett erfolgreich durchlief. --- ### ▶ Ellipsen * @@ -3287,14 +3287,14 @@ Ellipsis ``` #### 💡 ErklĂ€rung -- In Python, `Ellipsis` ist ein global verfĂŒgbares built-in Objekt, was Ă€quivalent ist zu `...`. +- In Python ist `Ellipsis` ein global verfĂŒgbares built-in Objekt, was Ă€quivalent zu `...` ist. ```py >>> ... Ellipsis ``` -- Ellipsis can be used for several purposes, - + As a placeholder for code that hasn't been written yet (just like `pass` statement) - + In slicing syntax to represent the full slices in remaining direction +- Ellipsen können fĂŒr verschiedene Dinge eingesetzt werden, + + Als ein Platzhalter fĂŒr Code, der noch nicht geschrieben wurde (wie auch die `pass`-Anweisung) + + In Slicing-Syntax, um die vollen Slices in der ĂŒbrigen Richtung zu reprĂ€sentieren ```py >>> import numpy as np >>> three_dimensional_array = np.arange(8).reshape(2, 2, 2) @@ -3310,18 +3310,18 @@ Ellipsis ] ]) ``` - So our `three_dimensional_array` is an array of array of arrays. Let's say we want to print the second element (index `1`) of all the innermost arrays, we can use Ellipsis to bypass all the preceding dimensions + Also ist unser `three_dimensional_array` ein Array von Arrays von Arrays. Angenommen, wir wollen das zweite Element (index `1`) aller innersten Arrays ausgeben, dann können wir Ellipsis verwenden, um alle vorhergehenden Dimensionen zu umgehen ```py >>> three_dimensional_array[:,:,1] array([[1, 3], [5, 7]]) - >>> three_dimensional_array[..., 1] # using Ellipsis. + >>> three_dimensional_array[..., 1] # Benutzen der Ellipsis. array([[1, 3], [5, 7]]) ``` - Note: this will work for any number of dimensions. You can even select slice in first and last dimension and ignore the middle ones this way (`n_dimensional_array[firs_dim_slice, ..., last_dim_slice]`) - + In [type hinting](https://docs.python.org/3/library/typing.html) to indicate only a part of the type (like `(Callable[..., int]` or `Tuple[str, ...]`)) - + You may also use Ellipsis as a default function argument (in the cases when you want to differentiate between the "no argument passed" and "None value passed" scenarios). + Beachte: dies funktioniert fĂŒr eine beliebige Anzahl von Dimensionen. Auf diese Weise kannst du sogar die erste und letzte Dimension auswĂ€hlen und die mittleren ignorieren. (`n_dimensional_array[firs_dim_slice, ..., last_dim_slice]`) + + In [type hinting](https://docs.python.org/3/library/typing.html) um nur einen Teil des Typs anzugeben (wie `(Callable[..., int]` oder `Tuple[str, ...]`)) + + Du kannst Ellipsis auch als default-Argument einer Funktion verwenden (in den FĂ€llen, wo du zwischen den Szenarien "no argument passed" und "None value passed" unterscheiden willst). --- @@ -3339,8 +3339,8 @@ Die Schreibweise ist beabsichtigt. Bitte schicke keinen Patch hierfĂŒr ab. ``` #### 💡 ErklĂ€rung: -- Hash of infinity is 10⁔ x π. -- Interestingly, the hash of `float('-inf')` is "-10⁔ x π" in Python 3, whereas "-10⁔ x e" in Python 2. +- Der Hash von infinity ist 10⁔ x π. +- Interessanterweise ist der Hash von `float('-inf')` "-10⁔ x π" in Python 3, wĂ€hrend er in Python 2 "-10⁔ x e" ist. --- @@ -3410,12 +3410,12 @@ AttributeError: 'A' object has no attribute '__variable' #### 💡 ErklĂ€rung: -* [Name Mangling](https://en.wikipedia.org/wiki/Name_mangling) wird verwendet, um Namenskollisionen zwischen verschiedenen namespaces zu vermeiden. -* In Python, the interpreter modifies (mangles) the class member names starting with `__` (double underscore a.k.a "dunder") and not ending with more than one trailing underscore by adding `_NameOfTheClass` in front. -* So, to access `__honey` attribute in the first snippet, we had to append `_Yo` to the front, which would prevent conflicts with the same name attribute defined in any other class. -* But then why didn't it work in the second snippet? Because name mangling excludes the names ending with double underscores. -* The third snippet was also a consequence of name mangling. The name `__variable` in the statement `return __variable` was mangled to `_A__variable`, which also happens to be the name of the variable we declared in the outer scope. -* Also, if the mangled name is longer than 255 characters, truncation will happen. +* [Name Mangling](https://en.wikipedia.org/wiki/Name_mangling) wird verwendet, um Namenskollisionen zwischen verschiedenen Namespaces zu vermeiden. +* In Python modifiziert (lies: demoliert) der Interpreter die Namen der Klassenattribute, die mit `__` (doppelter Unterstrich a.k.a "dunder") anfangen und nicht mit mehr als einem Unterstrich am Ende enden, indem er `_NameOfTheClass` voranstellt. +* Um also auf das `__honey`-Attribut im ersten Schnipsel zugreifen zu können, mĂŒssten wir `_Yo` vorne anhĂ€ngen, was Konflikte mit demselben Attributsnamen, das in einer anderen Klasse definiert ist, verhindern wĂŒrde. +* Aber warum hat es dann im zweiten Schnipsel nicht geklappt? Weil Name Mangling die Namen ausschließt, die mit doppelten Unterstrichen enden. +* Der dritte Schnipsel war auch eine Konsequenz des Name Manglings. Der Name `__variable` in der Anweisung `return __variable` wurde zu `_A__variable`, was zufĂ€llig auch der Name der Variablen ist, die wir im Ă€ußeren Scope deklariert haben. +* Wenn der demolierte Name lĂ€nger als 255 Zeichen ist, wird er außerdem abgeschnitten. --- --- @@ -3434,27 +3434,27 @@ AttributeError: 'A' object has no attribute '__variable' Was? -**Note:** Um dies zu reproduzieren, kopiere einfach die Anweisungen aus dem obigen Ausschnitt und fĂŒge sie in deine Datei/Shell ein. +**Beachte:** Um dies zu reproduzieren, kopiere einfach die Anweisungen aus dem obigen Ausschnitt und fĂŒge sie in deine Datei/Shell ein. #### 💡 ErklĂ€rung -Some non-Western characters look identical to letters in the English alphabet but are considered distinct by the interpreter. +Einige nicht-westliche Schriftzeichen sehen genauso aus wie die Buchstaben des englischen Alphabets, werden aber von Interpreter als unterschiedlich angesehen. ```py ->>> ord('Đ”') # cyrillic 'e' (Ye) +>>> ord('Đ”') # kyrillisches 'e' (Ye) 1077 ->>> ord('e') # latin 'e', as used in English and typed using standard keyboard +>>> ord('e') # lateinisches 'e', wie es in Englisch benutzt wird und auch auf einer Standard-Tastatur vorkommt 101 >>> 'Đ”' == 'e' False ->>> value = 42 # latin e ->>> valuĐ” = 23 # cyrillic 'e', Python 2.x interpreter would raise a `SyntaxError` here +>>> value = 42 # lateinisches e +>>> valuĐ” = 23 # kyrillisches 'e', der Python 2.x Interpreter wĂŒrde hier einen `SyntaxError` werfen >>> value 42 ``` -The built-in `ord()` function returns a character's Unicode [code point](https://en.wikipedia.org/wiki/Code_point), and different code positions of Cyrillic 'e' and Latin 'e' justify the behavior of the above example. +Die built-in `ord()`-Funktion gibt den Unicode eines Characters zurĂŒck [code point](https://en.wikipedia.org/wiki/Code_point), und unterschiedliche Codepositionen des kyrillischen "e" und des lateinischen "e" begrĂŒnden das Verhalten des obigen Beispiels. --- @@ -3486,8 +3486,8 @@ Wo ist der Nobelpreis? #### 💡 ErklĂ€rung: -* Notice that the numpy array created in the `energy_send` function is not returned, so that memory space is free to reallocate. -* `numpy.empty()` returns the next free memory slot without reinitializing it. This memory spot just happens to be the same one that was just freed (usually, but not always). +* Beachte, dass das numpy array, was in der Funktion `energy_send` erzeugt wurde, nicht zurĂŒckgegeben wird, so dass Speicherplatz fĂŒr die Neuzuweisung frei ist. +* `numpy.empty()` gibt den nĂ€chsten freien Speicherplatz zurĂŒck, ohne ihn neu zu initialisieren. Dieser Speicherplatz ist zufĂ€llig der gleiche, der gerade freigegeben wurde (normalerweise, aber nicht immer). --- @@ -3496,7 +3496,7 @@ Wo ist der Nobelpreis? ```py def square(x): """ - Eine einfahce FUnktion, um das Quadrat einer Zahl durch Addition zu bestimmen + Eine einfahce Funktion, um das Quadrat einer Zahl durch Addition zu bestimmen """ sum_so_far = 0 for counter in range(x): @@ -3517,12 +3517,12 @@ Sollte das nicht 100 sein? #### 💡 ErklĂ€rung -* **Don't mix tabs and spaces!** The character just preceding return is a "tab", and the code is indented by multiple of "4 spaces" elsewhere in the example. -* This is how Python handles tabs: +* **Vermische keine Leerzeichen und Tabs!** Das Zeichen unmittelbar vor dem Return ist ein "Tab", und der Code ist an anderer Stelle im Beispiel um ein Vielfaches von "4 Leerzeichen" eingerĂŒckt. +* So geht Python mit Tabs um: - > First, tabs are replaced (from left to right) by one to eight spaces such that the total number of characters up to and including the replacement is a multiple of eight <...> -* So the "tab" at the last line of `square` function is replaced with eight spaces, and it gets into the loop. -* Python 3 is kind enough to throw an error for such cases automatically. + > Als erstes werden Tabs (von links nach rechts) durch ein bis acht Leerzeichen ersetzt, so dass die Gesamtzahl der Zeichen bis einschließlich der Ersetzung ein Vielfaches von acht ist <...> +* So wird "tab" in der letzten Zeile der Funktion `square` durch acht Leerzeichen ersetzt und gelangt in die Schleife. +* Python 3 ist so freundlich, in solchen FĂ€llen automatisch einen Fehler zu melden. **Ausgabe (Python 3.x):** ```py From 60698ba8594073fc3e1b5afc2601422ea4e99f15 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Fri, 11 Aug 2023 16:48:29 +0200 Subject: [PATCH 18/20] #17 --- README.md | 62 +++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index c1eefc49..6e257a73 100644 --- a/README.md +++ b/README.md @@ -3539,16 +3539,16 @@ Sollte das nicht 100 sein? ```py -# using "+", three strings: +# Benutzen von "+" mit drei Strings: >>> timeit.timeit("s1 = s1 + s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100) 0.25748300552368164 -# using "+=", three strings: +# Benutzen von "+=" mit drei Strings: >>> timeit.timeit("s1 += s2 + s3", setup="s1 = ' ' * 100000; s2 = ' ' * 100000; s3 = ' ' * 100000", number=100) 0.012188911437988281 ``` #### 💡 ErklĂ€rung: -+ `+=` ist schneller als `+`, um mehr als zwei String zu konkatenieren, weil der erste String (Beispiel: `s1` fĂŒr `s1 += s2 + s3`), wĂ€hrend der Kalkulation des gesamten Strings, nicht zerstört wird. ++ `+=` ist schneller als `+`, um mehr als zwei String zu konkatenieren, weil der erste String (Beispiel: `s1` fĂŒr `s1 += s2 + s3`), wĂ€hrend der Berechnung des gesamten Strings, nicht zerstört wird. --- @@ -3587,8 +3587,8 @@ def convert_list_to_string(l, iters): **Ausgabe:** ```py -# Executed in ipython shell using %timeit for better readability of results. -# You can also use the timeit module in normal python shell/scriptm=, example usage below +# AusgefĂŒhrt in der ipython-Shell unter Verwendung von %timeit fĂŒr eine bessere Lesbarkeit der Ergebnisse. +# Du kannst das timeit-Modul auch in der normalen Python-Shell/scriptm= verwenden, Beispielverwendung unten # timeit.timeit('add_string_with_plus(10000)', number=1000, globals=globals()) >>> NUM_ITERS = 1000 @@ -3605,29 +3605,29 @@ def convert_list_to_string(l, iters): 10.1 ”s ± 1.06 ”s per loop (mean ± std. dev. of 7 runs, 1000 loops each) ``` -Let's increase the number of iterations by a factor of 10. +Erhöhen wir die Anzahl der Iterationen um den Faktor 10. ```py >>> NUM_ITERS = 10000 ->>> %timeit -n1000 add_string_with_plus(NUM_ITERS) # Linear increase in execution time +>>> %timeit -n1000 add_string_with_plus(NUM_ITERS) # Linearer Anstieg der AusfĂŒhrungszeit 1.26 ms ± 76.8 ”s per loop (mean ± std. dev. of 7 runs, 1000 loops each) ->>> %timeit -n1000 add_bytes_with_plus(NUM_ITERS) # Quadratic increase +>>> %timeit -n1000 add_bytes_with_plus(NUM_ITERS) # Quadratische Anstieg 6.82 ms ± 134 ”s per loop (mean ± std. dev. of 7 runs, 1000 loops each) ->>> %timeit -n1000 add_string_with_format(NUM_ITERS) # Linear increase +>>> %timeit -n1000 add_string_with_format(NUM_ITERS) # Linearer Anstieg 645 ”s ± 24.5 ”s per loop (mean ± std. dev. of 7 runs, 1000 loops each) ->>> %timeit -n1000 add_string_with_join(NUM_ITERS) # Linear increase +>>> %timeit -n1000 add_string_with_join(NUM_ITERS) # Linearer Anstieg 1.17 ms ± 7.25 ”s per loop (mean ± std. dev. of 7 runs, 1000 loops each) >>> l = ["xyz"]*NUM_ITERS ->>> %timeit -n1000 convert_list_to_string(l, NUM_ITERS) # Linear increase +>>> %timeit -n1000 convert_list_to_string(l, NUM_ITERS) # Linearer Anstieg 86.3 ”s ± 2 ”s per loop (mean ± std. dev. of 7 runs, 1000 loops each) ``` #### 💡 ErklĂ€rung -- You can read more about [timeit](https://docs.python.org/3/library/timeit.html) or [%timeit](https://ipython.org/ipython-doc/dev/interactive/magics.html#magic-timeit) on these links. They are used to measure the execution time of code pieces. -- Don't use `+` for generating long strings — In Python, `str` is immutable, so the left and right strings have to be copied into the new string for every pair of concatenations. If you concatenate four strings of length 10, you'll be copying (10+10) + ((10+10)+10) + (((10+10)+10)+10) = 90 characters instead of just 40 characters. Things get quadratically worse as the number and size of the string increases (justified with the execution times of `add_bytes_with_plus` function) -- Therefore, it's advised to use `.format.` or `%` syntax (however, they are slightly slower than `+` for very short strings). -- Or better, if already you've contents available in the form of an iterable object, then use `''.join(iterable_object)` which is much faster. -- Unlike `add_bytes_with_plus` because of the `+=` optimizations discussed in the previous example, `add_string_with_plus` didn't show a quadratic increase in execution time. Had the statement been `s = s + "x" + "y" + "z"` instead of `s += "xyz"`, the increase would have been quadratic. +- Du kannst mehr ĂŒber timeit hier [timeit](https://docs.python.org/3/library/timeit.html) oder hier [%timeit](https://ipython.org/ipython-doc/dev/interactive/magics.html#magic-timeit) lesen. Sie werden verwendet, um die AusfĂŒhrungszeit von CodestĂŒcken zu messen. +- Benutze `+` nicht, um lange Strings zu generieren — In Python ist `str` unverĂ€nderlich, daher mĂŒssen der linke und der rechte String fĂŒr jedes Paar von Verkettungen in den neuen String kopiert werden. Wenn du 4 String mit LĂ€nge 10 konkatenierst, dann kopierst du (10+10) + ((10+10)+10) + (((10+10)+10)+10) = 90 Characters anstatt nur 40 Characters. Die Situation verschlechtert sich quadratisch mit zunehmender Anzahl und GrĂ¶ĂŸe der Zeichenketten (mit den AusfĂŒhrungszeiten der Funktion `add_bytes_with_plus` begrĂŒndet) +- Daher ist es ratsam, die Syntax `.format.` oder `%` zu verwenden. (sie sind jedoch bei sehr kurzen Zeichenfolgen etwas langsamer als `x`). +- Oder besser, wenn du bereits Inhalte in Form eines iterierbaren Objekts zur VerfĂŒgung hast, dann verwende `''.join(iterable_object)`, was viel schneller ist. +- Im Gegensatz zu `add_bytes_with_plus` zeigte `add_string_with_plus` aufgrund der im vorherigen Beispiel besprochenen `+=`-Optimierungen keinen quadratischen Anstieg der AusfĂŒhrungszeit. WĂ€re die Anweisung `s = s + "x" + "y" + "z"` statt `s += "xyz"` gewesen, wĂ€re der Anstieg quadratisch gewesen. ```py def add_string_with_plus(iters): s = "" @@ -3637,7 +3637,7 @@ Let's increase the number of iterations by a factor of 10. >>> %timeit -n100 add_string_with_plus(1000) 388 ”s ± 22.4 ”s per loop (mean ± std. dev. of 7 runs, 1000 loops each) - >>> %timeit -n100 add_string_with_plus(10000) # Quadratic increase in execution time + >>> %timeit -n100 add_string_with_plus(10000) # Quadratischer Anstieg der AusfĂŒhrungszeit 9 ms ± 298 ”s per loop (mean ± std. dev. of 7 runs, 100 loops each) ``` - So viele Möglichkeiten einen gigantischen String zu erzeugen und zu formatieren stehen irgendwie in Kontrast zum [Zen von Python](https://www.python.org/dev/peps/pep-0020/), nachdem gilt: @@ -3663,7 +3663,7 @@ another_dict = {str(i): 1 for i in range(1_000_000)} >>> %timeit another_dict['5'] 28.5 ns ± 0.142 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each) ->>> another_dict[1] # Trying to access a key that doesn't exist +>>> another_dict[1] # Versuch, auf einen SchlĂŒssel zuzugreifen, der nicht existiert Traceback (most recent call last): File "", line 1, in KeyError: 1 @@ -3673,11 +3673,10 @@ KeyError: 1 Wieso werden dieselben lookups immer langsamer? #### 💡 ErklĂ€rung: -+ CPython has a generic dictionary lookup function that handles all types of keys (`str`, `int`, any object ...), and a specialized one for the common case of dictionaries composed of `str`-only keys. -+ The specialized function (werden `lookdict_unicode` in CPythons [code](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841) genannt) knows all existing keys (including the looked-up key) are strings, and uses the faster & simpler string comparison to compare keys, instead of calling the `__eq__` method. -+ The first time a `dict` instance is accessed with a non-`str` key, it's modified so future lookups use the generic function. -+ This process is not reversible for the particular `dict` instance, and the key doesn't even have to exist in the dictionary. That's why attempting a failed lookup has the same effect. - ++ CPython hat eine generische Funktion zum Nachschlagen in Dictionaries, die alle Arten von SchlĂŒsseln (`str`, `int`, beliebige Objekte ...) behandelt, und eine spezialisierte Funktion fĂŒr den hĂ€ufigen Fall von Dictionaries, die nur aus `str`-SchlĂŒsseln bestehen. ++ Die spezialisierte Funktion (wird `lookdict_unicode` in CPythons [code](https://github.com/python/cpython/blob/522691c46e2ae51faaad5bbbce7d959dd61770df/Objects/dictobject.c#L841) genannt) weiß, dass alle vorhandenen SchlĂŒssel (einschließlich des nachgeschlagenen SchlĂŒssels) Strings sind, und verwendet den schnelleren und einfacheren Stringvergleich, um SchlĂŒssel zu vergleichen, anstatt die Methode `__eq__` aufzurufen. ++ Das erste Mal, wenn auf eine `dict`-Instanz mit einem Nicht-`str`-SchlĂŒssel zugegriffen wird, wird sie so geĂ€ndert, dass zukĂŒnftige SuchvorgĂ€nge die generische Funktion verwenden. ++ Dieser Prozess ist fĂŒr die jeweilige `dict`-Instanz nicht umkehrbar, und der SchlĂŒssel muss nicht einmal im Dictionary vorhanden sein. Deshalb hat der Versuch eines fehlgeschlagenen Nachschlagevorgangs denselben Effekt. ### ▶ BlĂ€hende Instanz `dict`s * @@ -3713,13 +3712,13 @@ def dict_size(o): 232 ``` -Versuchen wir es noch einmal... In einem neuen Interpreter: +Versuchen wir es noch einmal... in einem neuen Interpreter: ```py >>> o1 = SomeClass() >>> o2 = SomeClass() >>> dict_size(o1) -104 # as expected +104 # wie erwartet >>> o1.some_attr5 = 5 >>> o1.some_attr6 = 6 >>> dict_size(o1) @@ -3731,15 +3730,14 @@ Versuchen wir es noch einmal... In einem neuen Interpreter: 232 ``` -What makes those dictionaries become bloated? And why are newly created objects bloated as well? +Was fĂŒhrt dazu, dass diese Dictionaries aufgeblĂ€ht werden? Und warum werden neu erstellte Objekte ebenfalls aufgeblĂ€ht? #### 💡 ErklĂ€rung: -+ CPython is able to reuse the same "keys" object in multiple dictionaries. This was added in [PEP 412](https://www.python.org/dev/peps/pep-0412/) with the motivation to reduce memory usage, specifically in dictionaries of instances - where keys (instance attributes) tend to be common to all instances. -+ This optimization is entirely seamless for instance dictionaries, but it is disabled if certain assumptions are broken. -+ Key-sharing dictionaries do not support deletion; if an instance attribute is deleted, the dictionary is "unshared", and key-sharing is disabled for all future instances of the same class. -+ Additionaly, if the dictionary keys have been resized (because new keys are inserted), they are kept shared *only* if they are used by a exactly single dictionary (this allows adding many attributes in the `__init__` of the very first created instance, without causing an "unshare"). If multiple instances exist when a resize happens, key-sharing is disabled for all future instances of the same class: CPython can't tell if your instances are using the same set of attributes anymore, and decides to bail out on attempting to share their keys. -+ A small tip, if you aim to lower your program's memory footprint: don't delete instance attributes, and make sure to initialize all attributes in your `__init__`! - ++ CPython ist in der Lage, das gleiche "keys"-Objekt in mehreren Dictionaries wiederzuverwenden. Dies wurde in [PEP 412](https://www.python.org/dev/peps/pep-0412/) mit der Motivation hinzugefĂŒgt, die Speichernutzung zu reduzieren, insbesondere in Dictionaries von Instanzen - wo SchlĂŒssel (Instanzattribute) tendenziell fĂŒr alle Instanzen gleich sind. ++ Diese Optimierung ist fĂŒr Instanz-Dictionaries völlig nahtlos, wird aber deaktiviert, wenn bestimmte Annahmen nicht eingehalten werden. ++ Key-Sharing-Dictionaries unterstĂŒtzen keine Löschung; wird ein Instanzattribut gelöscht, ist das Wörterbuch "unshared" und Key-Sharing ist fĂŒr alle zukĂŒnftigen Instanzen derselben Klasse deaktiviert. ++ Wenn die GrĂ¶ĂŸe der Dictionary-SchlĂŒssel geĂ€ndert wurde (weil neue SchlĂŒssel eingefĂŒgt wurden), werden sie außerdem *nur* dann gemeinsam genutzt, wenn sie von genau einem einzigen Dictionary verwendet werden (dies ermöglicht das HinzufĂŒgen vieler Attribute in der `__init__` der allerersten erstellten Instanz, ohne ein "unshare" zu verursachen). Wenn mehrere Instanzen existieren, wenn eine GrĂ¶ĂŸenĂ€nderung stattfindet, wird das Key-Sharing fĂŒr alle zukĂŒnftigen Instanzen der gleichen Klasse deaktiviert: CPython kann nicht mehr feststellen, ob die Instanzen den gleichen Satz von Attributen verwenden und entscheidet sich, den Versuch, ihre SchlĂŒssel zu teilen, abzubrechen. ++ Ein kleiner Tipp, wenn du den Speicherbedarf deines Programms verringern willst: lösche keine Instanzattribute und stelle sicher, dass alle Attribute in `__init__` initialisiert werden! ### ▶ Kleinigkeiten * From 1a208d32ad6f5330b6d18cc1e01d72cba0caac06 Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Fri, 11 Aug 2023 16:53:52 +0200 Subject: [PATCH 19/20] #18 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6e257a73..8c98ffba 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Übersetzungen: [English](https://github.com/satwikkansal/wtfpython) | -Andere Modi: [Interaktiv](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) +Andere Modi: [Interaktive Website](https://wtfpython-interactive.vercel.app) | [Interaktives Notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) Python, bekannt als gut designte High-Level und Interpreter-basierte Programmiersprache, stellt viele Features zur VerfĂŒgung, um dem Programmierer das Leben zu erleichtern. Allerdings kann es vorkommen, dass ein Python-Schnipsel ein unerwartetes Verhalten zeigt. @@ -3794,7 +3794,7 @@ Was fĂŒhrt dazu, dass diese Dictionaries aufgeblĂ€ht werden? Und warum werden ne True ``` - **💡 ErklĂ€rung:** If you replace `False` and `True` by 0 and 1 and do the maths, the truth table is equivalent to a converse implication operator. ([Quelle](https://github.com/cosmologicon/pywat/blob/master/ErklĂ€rung.md#the-undocumented-converse-implication-operator)) + **💡 ErklĂ€rung:** Wenn du `False` und `True` durch 0 und 1 ersetzt und dann rechnest, dann ist die Wahrheitstabelle Ă€quivalent zu einem Operator der umgekehrten Implikation. ([Quelle](https://github.com/cosmologicon/pywat/blob/master/ErklĂ€rung.md#the-undocumented-converse-implication-operator)) * Weil wir ĂŒber Operatoren sprechen, erwĂ€hnen wir auch den `@` Ooperator, der fĂŒr Matrixmultiplikation benutzt wird (Keine Sorge, diese mal ist es ernst). @@ -3834,7 +3834,7 @@ Python Threads sind gut fĂŒr IO-gebundene Aufgaben, aber um tatsĂ€chliche Parall * Manchmal gibt die `print` Methode die Werte nicht sofort aus. Zum Beispiel: ```py - # File some_file.py + # Datei some_file.py import time print("wtfpython", end="_") @@ -3873,7 +3873,7 @@ Python Threads sind gut fĂŒr IO-gebundene Aufgaben, aber um tatsĂ€chliche Parall 4027435774 ``` -* `'abc'.count('') == 4`. Here's an approximate implementation of `count` method, which would make the things more clear +* `'abc'.count('') == 4`. Hier ist eine ungefĂ€hre Implementierung der Methode `count`, die die Dinge klarer machen wĂŒrde ```py def count(s, sub): result = 0 From 04d0295b0ecad05d1f044d9db02870fb96351dbf Mon Sep 17 00:00:00 2001 From: BenSt099 Date: Sun, 7 Jan 2024 15:52:09 +0100 Subject: [PATCH 20/20] updated readme to include newest changes --- README.md | 5 +++-- images/logo-dark.png | Bin 0 -> 13052 bytes 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 images/logo-dark.png diff --git a/README.md b/README.md index 8c98ffba..73cd5635 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -

+

What the f*ck Python! đŸ˜±

Entdecke und verstehe Python durch ĂŒberraschende Code-Schnipsel.

-Übersetzungen: [English](https://github.com/satwikkansal/wtfpython) | +Übersetzungen: [English](https://github.com/satwikkansal/wtfpython) | [Chinesisch äž­æ–‡](https://github.com/robertparley/wtfpython-cn) | [Vietnamesisch Tiáșżng Việt](https://github.com/vuduclyunitn/wtfptyhon-vi) | [Spanisch Español](https://web.archive.org/web/20220511161045/https://github.com/JoseDeFreitas/wtfpython-es) | [Koreanisch 한ꔭ얎](https://github.com/buttercrab/wtfpython-ko) | [Russisch РуссĐșĐžĐč](https://github.com/frontdevops/wtfpython) | [Übersetzung hinzufĂŒgen](https://github.com/satwikkansal/wtfpython/issues/new?title=Add%20translation%20for%20[LANGUAGE]&body=Expected%20time%20to%20finish:%20[X]%20weeks.%20I%27ll%20start%20working%20on%20it%20from%20[Y].) Andere Modi: [Interaktive Website](https://wtfpython-interactive.vercel.app) | [Interaktives Notebook](https://colab.research.google.com/github/satwikkansal/wtfpython/blob/master/irrelevant/wtf.ipynb) | [CLI](https://pypi.python.org/pypi/wtfpython) @@ -1224,6 +1224,7 @@ False **Ausgabe:** ```py >>> from collections import Hashable +>>> from collections.abc import Hashable >>> issubclass(list, object) True >>> issubclass(object, Hashable) diff --git a/images/logo-dark.png b/images/logo-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..9d7791f3a30ae76158b3f33d84cdf0f31de2e3c2 GIT binary patch literal 13052 zcmbWe1z4QR(jbhxyJxTjcNqrv!5sz<4DK>mfZ!Se6Eq>X6A13^5)w2C!8K@Lf+Rq& z9nQV??C!T`cmIERnC6}Cdb^~ns=KO-1YK=aLOeP=6ciLfHL#LC3JNM5`QgFALiQZB zejh;o!Sw>0`l6uVlRtb=QL=MrP*5;_IU7P?5G_p*)YF~M#?I5$o-fed3ki*aA|)H> zWdn7!hXHKu9i2U-SrDDQEC6RaX%-VvEdebrMSCY_@G~EKgJ;@?&}Xht2|E^98GuwE z2swefJ3ksBG`Dc5BoCj?0GYH9tA;~!~pcmErOFHG4V z$;Q70@{iEIhCyET{QCC3o_;=1du4wlnXC`oc!3ms>}_D4K8Bv2ZvR;<-T#mb5EA7R z0B~s8K%G4vnBe>$Ua?oQf!Ry5Jggh9pa8FcsG*=32>B}_$}Io{2?+cPRLj%O*&*m3 zL4hDaf&U2;NkIaPlWvPw=c8zKsqoVq^IH_ep`%! z!uwuLN!~DU@hI0lo^8H;?Y_Iy>b+_4aWij7E!zI-Hx&!=&ftWQVnBoCVYLhny-uyI z+o;MLD+V0qf_>cQ{qwQ=gs*8la`s==pY@N-rBTj&w-xSw8dlHZsr4f`7i`gjJ)lrG z@SBF^25X7@P^CdcGMD%lL$0vs7ipuFUsm^zD5UvUERD)1CGO9prX;2~wH}j`DBv*5 zOZ2k@<6+>R8XQdIz&|#H;mCo1YM3b=u>DgLjfNcf$3|BUIq**n2_ACb zzc&BK!e4Ct6AOR!#lJP+i5%iUccSSvADQ}{KIPW<4TsseP~?p!1aC&4vaoKu`SB=C zpI4$2glWw{5MvZeAQj5di>R-_Wu}1tXk=rVPEEG)6|R_~D?$!@CNsOrpV%shQzNC7DzveO_6>F$rgrCH zM%Mz{e#@L|jjJ(8f^R-FM8#|{ulLILf`bhyB(RWSDY=IxX>wVd7s0k?r=W#7KIl$J z1Os!#&kxmNx0nq{=_Zs=JExd2&C>agdp0v_}=ju!H6P$1$kh1k3(a3 z2|hW`Ezr%pDU@ydhE2<|rWT#iwX#%h8;6-ThI=NZ9FMWiBQRc-ypNYOlPLU*lY)56 zuNI9XfkvSkUK4MXo03hUfX}w9*U8Iz?#eVUL#c=BOR+{VQ4lfco&L(=1tFu9wPD3_ z#2wY%EDMq{1@aU=BJ3O^k`+8X;PRYD+;ly@GGQ|QhtxH9lq`j=c^O#vE!`to=565K zKsGNEqoULYugE<`376TKNp2>4lnE3M#d5*=?TUB-!j0|TMX~DC2pl!S6HIa+SM%c@?eQB5g(uQ-9L z(+WwYz^OH-pi$8mtTPu1pT^mQ6`F@(FTZ^`<|&a#RIu94qBkWx?yy$O|mFB52~!K zXnMZ+sTuCoGJUL{eU#t>Op^=?De*8>j&qv{YY#PL)t&+(x{b%yhkfXjF44>)nAMqhcZcCfuZTO5Sn%pfdEOi`5$Rl5QuwWi?)~T? z^vcCyjwv3i)XXeJ|Dh6+XSr9|usUQP-5-n63_VXM}|+HK&Iy`OeR+9zSJ^rUKUp znz)&eZ2ATd;0k=QClNLln=h7^(*$!X`L`^1%2;j$&El} zFwfu{=dTHS9e+jw)+h>H>P<-%P{&yrp(3(lC!t8=2&$DsL@xeqN6y+evLM}y z_&cvn94L^ldIfFyj4MYux)^85hTeFz497T4>jl!Q6j+~P+=uX#>#SakU$qza zG4)ey-;v_ws@`(ioT&RygF_C==Ap*}8#~MCtTmH&5jBqnDq6W07ZQ|(I4~Xdry{r& z5eTLyVhy6X^As@l9S^-n$|9E)v}?6AtR1h7Xf)}6_Hjtof&_IIK3lA9@X`Oerdc)y z_$QK~>&g7#(0_(OnIc%E^~hSRno5K2yfhwhl!-IaQuUD=Y@L07^4cSI?w#j6VV1pN+P}ziS1>e*0`erTyAZHo<2pPhZR)*m$o3pn&6iJbGng z^<;w%lIc5dOEc3_c&6_M&mj)VnGVV-6mRz_2F+l>3f4~dEYc`4Iz|D5*(cXLu6neYt{*!Q`=TrZmE4TN|$s>auoHV!Cp+p(9=p7^J5jys< z!1kDOUc_NNeR=rM_YttIVf9Ump2@k;d1Svoo(fbg{TIr!awYNLn&f%UCvN_+%@Qgn zx6lu^@i*?+Ar>p05{|bXG@F8O$C=2XM+?i;UyDBlHE zvPSrjmL<<4$w)*E8YF5f4Urf~LHhztAN<+uNh*qRVuT3EJ<9+d)rEJ}d+5?gs7Qgy zd;t7oM`n{Adbu~%E57$SW`H0jN^Hva4G^k}b)FIW@fkrSJHX2wyx}c)xWJKeeFfdo zfUWm5noZPn|If^LB@;T;Y$!d$Z5pt?)bewma~B24DOIS%vuTOO4sh7hoZ_%lrQF5> zXc9x8uAGmg{%Kmi>UTvt8sjmVg{2#Hn~3XT#~HMmtH3n@%&2U-^Bw!9a8AH0|IKCs z3rBqI=@lycZMqz`m=efq=P7!iRPgj|C+Alifzt)jV9QaOxOvkz=mmO8RPP!-U(-5o zQNRh_cB%>Bc^xN;bnu-=R;a6hq=G-(CM^u1FlZeWf}Y~58U%l1%B?GsE!CWB2%l_v znqJ{oVDhu7Uyo+Ks`}a{b`cMgEh>q;+M*M6cp`JeC^Po!m{+?vd?m)p3YU=ES0*J< zk9cKZS{Zx|xw*UO9lg8j*}b<4{bkg3wewc>?ruGbcyk5uJmA}}(16$qcYu^h8oT{G z%8Ch6!)ZToIK3{Q)F*s8U{W~ul2}-`M>GX1M`^Xb;Cpp+5%a}UGfYJWOA~>C5LZG4 zQk>ztJDHwe?>!5bj%=l@y5ePjMiBQk@IW$SUQqLIN+W`F(x;pN?%tx&j_;L92t5il zQ4{*n^c2W0Vue{T-j+7ucMDEhmaGwOvjdtjhWMQ%=1aF|#~iQqzgB)KKfgJfDxTY4 zpUjmU?Fn#qKZ@?Ye{z4`+ zh1J`1cmAPd1yw4dY!N)CRdR;#icpJrton{8qP*-C7(@@J^b zg)XSY+{X=!y_8;j(2#DJ%uT;AcCuw30Ri_~cldu4HBRg4GqDb(w7xwsIVmI#b$S;l z^*g3F@My3~{IUEnI*Lr!GwA8Y7kUF#_|^%H_0#SG$CPeHGI|y=ToOfIA0h01gwTEti&O?)Qzu73^H_Xp{ zgM|8hr=;UlnSwB^uNUWkF1pqR^&sZ%e^1?S+}?^$@jUA>WkEyfz57*r@=O}-Cl21zO`9c2P{X!MNg%e zbn!?`=CYsI*3}gsx1-mH@sK7H9J3;U$)=89l3EacX`_nqSc9?lyNxr1wq7RI;6Q=+ z#S|IdN5u0B$&h2;{K4WBnZ*42o81VR>&t6|v<;pbg>n4&gU)<5(AlUTWg5ii?}86C zF2&^iEFk0hy^w1lS5)mKfKl>M_0gN~Ciu(Gi(8zP23ynt4fozz>}7T+OH&`3}tmQ*KlfbJ0i9C{t^$s-Y&R z$&L7=Lj}S*fn5qM5nGOCmT`?@CH$<_c@RP8{haRV6m9M56zQQR`L9I@1hQ-#DCJECUmCo5;WmMD@cTuRT5+H%s9auc29FQ%DZ^#GT~)mcF`K?Y^=faiau|XO8-LttRM9n z$P?J7cS)C>LPfX+N``KIBPW#xAEw(I=zN;Usfe3Dd5rqyN^cMPWweF2SwdcB(95a? z7k1yxZlwg?uEgPU#rm#Cu;GCD z&Mw7@u#tbhcdG%uICdPXS2@57C|8dUoyjwsIS$DDGHy`5Mz|jK$@`u2J~UEjWCL~_ zdUY%|+nXVT$rkrRoqV{ez4PjUuQ14NL3Q&gBW}=(L5|9D##P$(i>*gqOcOuYOY$PLag8FCy**Ot2x|xcuYE zBAI{{%;K^W>KR|*(eN&Mv`7$6Eqj4r;<&w)#Q(L7E&1rpB_%OR-`&uhx_V#Cml$m| z5t75=0pud8C2AEn8nVpBP2L(tziM41U*-xABzWb;CD;4jU#|O4cUkK{ zmMrQ_ogISTTEr&P`hR;lj2*SN%3`ZgE|H$-JTc`e(R)EiN~EFUXOGfq2g_2OfaaXX z`&psZuU?!!dP}8bv5AUOzH0nz?hql^QAaV~4*+4Zm9orcB{!mtW)xS$JH0k(gNk@I zXTtNusy6|QcB8*CC6)!@<93@GICnSJ*4G(iDQ&e^#GVW{BZmkXONiLOQqMxt7xzXn zJ-OMT7FZrSaPC>_hTFmCtSzwt>+U=ZqrG%KsvNny24*IL*Q)W7Sf}Fi_gD74`C44! zU*3d0?afKuJlycAt{I?13WHp78b3Y#i#OrqVgzaqVAT>>^WFgq;YkRZ^i}3b@gq&9 z8fJYqnJ4`Mn<;P|PMZ29SPd!9fsJJo#;+WB;KgskTnDiyt**AOVC!wq|DYVJVOwZj zNsDd_iSg{&#ru&CGUwbbyr^qcg&dMmv3M~Iao-2yfuB+tFIANP5|Prt!+GtaWaap zO37 z+*{DH6l_#IZLgn+i2E+|PH}hEWqb{58uhdRCytC9e>qW1FS4Uf{Yk1IT5_X|%+G^+%uVZRha%nFN{q<8`aL8hSWcU5?)|%@@sa%Q39fCTc}>3Rbk*K&yYyGN#++Ct7yCL8s4bV%E)}58H)tOs6;38izVr zcf-B+Dfe!>_c_=6J8Q&|cw_tI*lA?CpoH;l8TD_n92rEq*$kS;TT0Gh`q@A7Il7Ms zb9lRn);%>!$7{XAXYSC`?$29#&u*-*B!d?1F*=VUo%(Sgu&}L$cO}J{a{&>qs zy%|pV>Z=G-)t*LtZRPTCijV3NlNq9APnAB<;O^=s1{-kB88th}yl-@z+AMx_>!h!2 z5~s~+7jcsEZ9_ppf$Z@FUv*084=6DBx0`->YoTQ;1u~5?q|D_bN{TloBJ--!!A6|w!dx8OdV@>1}r;wlh*eBa*I*(0ZJDc)&$V5N9ofg_7 z1@)(^?h4ujoN0GvFcJ_S*#;Ip=k~I$Yif!XcAR80b+ZSaq=>;{F_EcwHUY&w%JDZ) zD{*6*1@GP4i^gdpe zkUAM6SEDwkewG-FX@O2DNl-+diq>=Uo&O=A!j`>6?K#Uute4B)I;{%10|cl-`3VfQ=Xr*y1BWn$I0F>AFuW1Uy4efPb&s~ z&oJ>i_`FP%REMDyI_h38$5&4~gbxKom%KJ8*S2wX#*OMn=|%E)@~bwC@!>R1-d&~> zvPu3TUiDjbKW@QNH7^B;&ujMR-eCH14r19Gfu8eH{tfEhOU#zm){}*)=TykRaS7T> zlrKrFqDDEHodRmZ1~;HHP{|)u40sPW!6T)#*h16Q*)6&PNvZj*hE`XZ@sqJvDGKxf!0l9qwgj3n?g>e(-URL1aTUUc4!(MZ7rkxqnfu1Bpwm4&k_tc#AV~C zDK5rkyUhwLYJ7?_0{Jj10_B5RnDM||)yX}E=X^Kq?{;jcC%KkIol$tbJof+$PiEOd zH)p8(P0)n{A#AJ+vW+!-Q&zY-*vYO0(~?a3y2vA0@#z@>sWo4f>#UO-DQ{wY80x+p z0$*t0{8Pfn&)@BH&rUpFF5y2{HDCOk$o%+B+jq@dy4Q7NUB~o1R8dpx3I`c)H8NAy zrpd)DiKys!T$6^QLR)^;itifwheoVu+*3|3`_+#cQX)SsRO)%xH-*LB6K8=No1 zju2u*ozcHpo~>H$e=e?Lx+vjwA9!Qj%Qn^RnA7_6Ft!aYU}5NB@}+IS38+`i zI}Sclk5FkjOE+Nfvo*#xkyN>)LzNuE8(4r$Q1AuE>S~fx`B@+Qi5n?!zy6 z2_EAZg5ne11_(YZ`Ti9H)humO4<}`a;!rZYYdWhqb6vE87LG2F-6R+P$hhFbE*YfD zG=e3?g%c<`nz@cMxv8G&=`rq#3Cd8T6T_$)@OCHEg)f*j$?a6JnNQEjH0tYl44g=N zZlAaRh;Wri9Kg}`>fv>t)*kme8t|qx=K#+d;DLYY-H@EU=g>iaD?v@F&w#qG_=NhX z{Kub~#5UgDTX`?4%rG%KJDXu12EXXHJRWmx`CaXeBVHD!7NR*}BP>kC>CaGW!1VO2 zqry!bfKh|k)xFABa=V7|m*bnKTr7$L8ur2Mz>-jbX zqsbk?lEGe&m(O1fimFq<_ub??`QJK<6`EiNkXnwc1M5ob#aN_N(Hk9uUwVr;*iRhd zfDn{19KZ<{IgE&F0(YJVa@vnNJv z+-}C|-upzs(%Scp;a(q3(FZdMjn`Hl3h+9}hHGaIU z8t6S8EE~&=ecV(;U5@Lt(;er-^sittG-zVPcN_cuK|BMhthdbP9~J$=g6hXUw|s4< zd95dxEMtMckLSXRBkiT&qy-IDI`jK_>_uu zUhqhoLGI%y7K6C=&JsSRlCL@Fpy`uB2mA305vSZ^CjhHo9fYQY97lF3+&A{`;PeMsAhWKunZDN zgkDH1f`z07!z(oztnFlnbFI)f9viSlvrXa5@CBA)lA&u%U*nZz;I$PbJ=`A|Rq%8& z`cFSx@Z%~xN_LHZv4z8IN0fLlpf4OlN86_T_Dec^Sx@ou`eqs}AwsAj-yn`8H57IH zMqz*j4~z}7BvnXd{o($Oe9I8^kp=cDtsE{h8&P!^4tRzK&XmL18BF`mNozw(NR@#e|#jIWnuw$c}em%PREfgc0V zUv|D^DEaDNPagU6^{;83{9}q2j&@zi1Sg!QO6Zg(jqpJrbpV^DI5`SCm7-lm?gr?m z`1=MPMtMb*4cHaKF^4O#3%`_8hE?$?7T@9HTC_%j+>>D86mc*ra_4))8`Qn22*jGk z?~4_}s|{}~ztI=PD6_w@On6E7WGp8u*?*x<%EvWAPmTkitStI7o0#+)*~}g-qMMts zu+!H`y^&S2F5 za}cOCkVkD-KC%&aJvH7_y7*!`IxqTZAqqJGjgk&Or9e0nWhju3yq8KrM@b1+?a``m zinS3} z52aCBx8tK2fyeo0I8@(y`EplDUN}naDd?!b&O(K)OMEgcoF@|9hA5*xF%*c;vobF6 zu5I8@fLhXBm(o--C{MpS=QY7z#Ps5gb~PjOrd9ep!+B^EJaS8*)Yo06={a`qY5NBw zMg&r8*`D7MZ&{e;Jd37=#)`MzdZPkCx%P&@mk{Dl#)TFsH_ zvtKix!fMu3tCUKv(cU?NaXWah;hl|IH0icg*0W>EkY3)R-Z#^szlY5ZSR8RloFlg1 z`t2um@FY%yqWB^^mA)1_x>m-xXK*q;)lr#wNuxUAIxSqVX-j?9xzklm`;jD`Y13Og zJH1p>^;F80B4xpg&a*>+{Q8IyT6o@{G5LHC+9PsASkL2M+E}$-r=fRb;Y7Pzc|{>I z@#{yV_G@H;!@Po+uMe*V?ME|jD|y%n9shxT4K#@AqYyG%>&yCG=H}DrBQ^oh1dEna z?=Pu=x!A2UEm!TeUx?RV(iA| zCbpf;<7G^V$yUq}77V8qnwXWyb3D=F%@-@OK6@2yglXp~{G^$G#CvM6b}X8miLmks zMT$fLJ~v}=gIHH9NA7Uhj9zLnjMR-KGP@y&`@8+S$ZyW1DequI7XqP+@6CvPEEsDC zy)FH0+m0#sZX76x@xYJuDn%E4{c+?a$5~7tv0f7M@eiJa5f{wApokF#dgtNZ)FPZd z^r^nzpt1Rr9PGCj6A?Vx6qDB!Q!#J)x)VcawH^g#!~SB8@TG${by7@QJ1=AABUC-_ z7^)nInk8u1mzjXb?P>whY!_p$@1PF5aOkRKF7lci4e*C@mGhEH*EAM|+htPjL+J36 z+deZ1`(@eLGQ7ZwjInaw0sHZYjH*I{Cslo}2;7gp2lb99+4ZWWiM#)%r&9NQfL~8%4;R;Aa{f$UmCz zr-;znmqW%NhD)}%1eUDRdXpcjj^<7qyuM-X&ij=)5Qzzdoq{vOhSd9PkHfFO&Y_J1 zTz&--&#*f!!RM=Zj#&pR(~36^fM3>91}T_+o#|p!a2(=1o_03ec|T~RxV)7o(Z+-3 z6QLD}mMSV%vXwXst5Fz5X#;Xud@N`uD~x4U_cE0fuxd38@gyvA1J*RV3g)-s^D&f! z+oiJ){zzH0B%5z}Z`UyfIqkf1NlYZmCQaP(;Gw@@%8IELb8sD8vsF<*RkI(Y?O(Hf zCona?IVNr-LMW(5rAZh!H$*HT-FfUkvLv^>sV82Y%k-WIS@VDkZ4T1?swB5}_(^4V z5uR`UTBd(M=sDBIPc!NZ1eBOr{lj7<-2hE%Agqso5PA2Tw$0^T1{~+#`P$GolYl}= z%&dsOgN1-?Vt1QfI z`;|bwv_EU|UB|2$gXGwqvfX} z+|heY?r1y9CZ0W9oYyw&FAG+@7^L*%giIGy!IOU99W+#;EG)ncDwNs`Q;|eNDP>)) zo6LOfmDlcGR8*L3tR?P@vFg?7suP`5f~CNz9|jOQd;Z+bs;O8JCA(l^NTWqa5|t&nuk$z+0na0^h=FwwTGzC z=NM)X@^ZfL;_fk<*5}e&&9{4kne$W*ql%e@2EWbunBRrdtHlsO0UPj)H`++DW`UOn zFMvOIe=_iWbs2HqI zxE?X9;e7AtXnHEm1noEs#MJ%~RW-v2sB}Y7wDVmfY(`#na7VKZ#o~;0xvRdXmXQ5^ zKjCFD@v%=1Rqcr5dCmsjhub+d{fhL%UFyqZWceAg$}$D(Pz;mp{Wh~2^Lvt13JqJv zYChe7BTh7>lX%j}f$Wq#2GhJR_4wUBd2pcf(|S=_s&l5Z#}h(;qCj0aeT_UcUrV3? z$6-h{n_`j|O!?1Zq%q-}C}jDjTzcu8`}ghV{==yUk&hZ)XInPf3ZEhOUc7TG zg9k@_u+N%Xxj5KRP1mFVPHI|jt4Ch^JioTbouv4a$v}~Uu_0m=X6H8?G#%X3r&SK_ zLe^Q0*~pi(pA@km^rG4ic|dqzD&63mR(S0G_BH9^TlHHCcy*z_9QObZ zyV*k_D;T_OGc56*L;=hu5HIsqCZ{h*?>DKgaKp2ZbL8;YP4$@TOr+oZItEXcDJBkc zV*&mIeTGvVDuQt`5s=3#K=n{`i?KtMqpYs{sjAqP+5Ka$IRmo%Pal{_1TM1zKz_wRZ>(O@SbXhuvT;y>IF@2;gu)SYX0zG*CqGpVsp=&fKeHn@@KH~s1 zj{jlWZTj#~e~0mOJp^QttBrFKEf0&6p#kP&UEniEPouq2Ak}Z4!+WTCRVX8R;