diff --git a/python-operators-expressions/README.md b/python-operators-expressions/README.md new file mode 100644 index 0000000000..8fd0886dcd --- /dev/null +++ b/python-operators-expressions/README.md @@ -0,0 +1,46 @@ +# Operators and Expressions in Python + +This folder provides the code examples for the Real Python tutorial [Operators and Expressions in Python](https://realpython.com/python-operators-expressions/). + +## Running the Examples + +The tutorial presents its examples in the interactive REPL. Here, each section +of the tutorial has its own self-contained script that runs the same code in +the same order and prints the results. The examples only use the standard +library, so there's nothing to install. Run any of them with Python 3.14 or +later: + +```sh +$ python arithmetic.py +``` + +| File | Tutorial section | +| ------------------------------ | --------------------------------------------------- | +| `getting_started.py` | Getting Started With Operators and Expressions | +| `assignment.py` | The Assignment Operator and Statements | +| `arithmetic.py` | Arithmetic Operators and Expressions in Python | +| `comparison.py` | Comparison Operators and Expressions in Python | +| `comparison_integers.py` | Comparison of Integer Values | +| `comparison_floats.py` | Comparison of Floating-Point Values | +| `comparison_strings.py` | Comparison of Strings | +| `comparison_sequences.py` | Comparison of Lists and Tuples | +| `boolean_operands.py` | Boolean Expressions Involving Boolean Operands | +| `boolean_context.py` | Evaluation of Regular Objects in a Boolean Context | +| `boolean_other_operands.py` | Boolean Expressions Involving Other Types of Operands | +| `short_circuit.py` | Compound Logical Expressions and Short-Circuit Evaluation | +| `short_circuit_idioms.py` | Idioms That Exploit Short-Circuit Evaluation | +| `chained_comparisons.py` | Compound vs Chained Expressions | +| `conditional_expressions.py` | Conditional Expressions or the Ternary Operator | +| `identity.py` | Identity Operators and Expressions in Python | +| `membership.py` | Membership Operators and Expressions in Python | +| `concatenation_repetition.py` | Concatenation and Repetition Operators and Expressions | +| `walrus.py` | The Walrus Operator and Assignment Expressions | +| `bitwise.py` | Bitwise Operators and Expressions in Python | +| `precedence.py` | Operator Precedence in Python | +| `augmented_assignment.py` | Augmented Assignment Operators and Expressions | + +A few of the tutorial's snippets can't live in a script: the bare `-`, `==`, +and `or` operators are a `SyntaxError`, and several snippets are syntax +sketches with placeholder names. Those are noted in comments where they +belong. Where the tutorial shows a traceback, the script catches the +exception and prints its message so that you can still see the error. diff --git a/python-operators-expressions/arithmetic.py b/python-operators-expressions/arithmetic.py new file mode 100644 index 0000000000..a76184b3e0 --- /dev/null +++ b/python-operators-expressions/arithmetic.py @@ -0,0 +1,26 @@ +a = 5 +b = 2 + +print(+a) +print(-b) +print(a + b) +print(a - b) +print(a * b) +print(a / b) +print(a % b) +print(a // b) +print(a**b) + +# The division operator always returns a floating-point number +print(10 / 5) +print(10.0 / 5) + +# With complex numbers, division returns a complex number +print(10 / 5j) + +# Floor division always rounds down +print(10 // 4) +print(-10 // -4) + +print(10 // -4) +print(-10 // 4) diff --git a/python-operators-expressions/assignment.py b/python-operators-expressions/assignment.py new file mode 100644 index 0000000000..0e54b24e94 --- /dev/null +++ b/python-operators-expressions/assignment.py @@ -0,0 +1,9 @@ +number = 42 +day = "Friday" +digits = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) +letters = ["a", "b", "c"] + +print(number) +print(day) +print(digits) +print(letters) diff --git a/python-operators-expressions/augmented_assignment.py b/python-operators-expressions/augmented_assignment.py new file mode 100644 index 0000000000..de7a2518c2 --- /dev/null +++ b/python-operators-expressions/augmented_assignment.py @@ -0,0 +1,14 @@ +total = 10 +total = total + 5 +print(total) + +# Accumulating into an undefined variable raises a NameError +try: + count = count + 1 +except NameError as error: + print(error) + +# The augmented addition operator does the same job +total = 10 +total += 5 +print(total) diff --git a/python-operators-expressions/bitwise.py b/python-operators-expressions/bitwise.py new file mode 100644 index 0000000000..9e8655344c --- /dev/null +++ b/python-operators-expressions/bitwise.py @@ -0,0 +1,15 @@ +# Bitwise AND +# 0b1100 12 +# & 0b1010 10 +# -------- +# = 0b1000 8 +print(bin(0b1100 & 0b1010)) +print(12 & 10) + +# Bitwise OR +# 0b1100 12 +# | 0b1010 10 +# -------- +# = 0b1110 14 +print(bin(0b1100 | 0b1010)) +print(12 | 10) diff --git a/python-operators-expressions/boolean_context.py b/python-operators-expressions/boolean_context.py new file mode 100644 index 0000000000..02f801cf75 --- /dev/null +++ b/python-operators-expressions/boolean_context.py @@ -0,0 +1,21 @@ +# Numeric values: zero is falsy, everything else is truthy +print(bool(0), bool(0.0), bool(0.0 + 0j)) +print(bool(-3), bool(3.14159), bool(1.0 + 1j)) + +# Strings: the empty string is falsy +print(bool("")) +print(bool(" ")) +print(bool("Hello")) + +# Containers: empty containers are falsy +print(bool([])) +print(bool([1, 2, 3])) + +print(bool(())) +print(bool(("John", 25, "Python Dev"))) + +print(bool(set())) +print(bool({"square", "circle", "triangle"})) + +print(bool({})) +print(bool({"name": "John", "age": 25, "job": "Python Dev"})) diff --git a/python-operators-expressions/boolean_operands.py b/python-operators-expressions/boolean_operands.py new file mode 100644 index 0000000000..d7bb568002 --- /dev/null +++ b/python-operators-expressions/boolean_operands.py @@ -0,0 +1,34 @@ +age = 20 + +is_adult = age > 18 +print(is_adult) + +print(type(is_adult)) + +number = 42 + +validation_conditions = ( + isinstance(number, int), + number % 2 == 0, +) + +print(all(validation_conditions)) + +print(callable(number)) +print(callable(print)) + +# The and operator with Boolean operands +print(5 < 7 and 3 == 3) +print(5 < 7 and 3 != 3) +print(5 > 7 and 3 == 3) +print(5 > 7 and 3 != 3) + +# The or operator with Boolean operands +print(5 < 7 or 3 == 3) +print(5 < 7 or 3 != 3) +print(5 > 7 or 3 == 3) +print(5 > 7 or 3 != 3) + +# The not operator with a Boolean operand +print(5 < 7) +print(not 5 < 7) diff --git a/python-operators-expressions/boolean_other_operands.py b/python-operators-expressions/boolean_other_operands.py new file mode 100644 index 0000000000..1da0e9d6ad --- /dev/null +++ b/python-operators-expressions/boolean_other_operands.py @@ -0,0 +1,16 @@ +# The and operator returns one of its operands +print(3 and 4) +print(0 and 4) +print(3 and 0) + +# The or operator also returns one of its operands +print(3 or 4) +print(0 or 4) +print(3 or 0) + +# When both operands are falsy, or returns the right-hand one +print(0 or []) + +# The not operator always returns a Boolean value +print(not 3) +print(not 0) diff --git a/python-operators-expressions/chained_comparisons.py b/python-operators-expressions/chained_comparisons.py new file mode 100644 index 0000000000..bc994fc974 --- /dev/null +++ b/python-operators-expressions/chained_comparisons.py @@ -0,0 +1,10 @@ +# A compound expression joined with the and operator +number = 5 +print(number >= 0 and number <= 10) + +number = 42 +print(number >= 0 and number <= 10) + +# The equivalent chained comparison +number = 5 +print(0 <= number <= 10) diff --git a/python-operators-expressions/comparison.py b/python-operators-expressions/comparison.py new file mode 100644 index 0000000000..2f517d057a --- /dev/null +++ b/python-operators-expressions/comparison.py @@ -0,0 +1,8 @@ +# Comparing objects of different types for equality +print(2 == "2") + +# Non-equality comparisons between different types raise a TypeError +try: + print(5 < "7") +except TypeError as error: + print(error) diff --git a/python-operators-expressions/comparison_floats.py b/python-operators-expressions/comparison_floats.py new file mode 100644 index 0000000000..6f5eae31b5 --- /dev/null +++ b/python-operators-expressions/comparison_floats.py @@ -0,0 +1,9 @@ +from math import isclose + +x = 1.1 + 2.2 + +print(x == 3.3) +print(1.1 + 2.2) + +# Compare floating-point values for approximate equality instead +print(isclose(x, 3.3)) diff --git a/python-operators-expressions/comparison_integers.py b/python-operators-expressions/comparison_integers.py new file mode 100644 index 0000000000..d093291cf0 --- /dev/null +++ b/python-operators-expressions/comparison_integers.py @@ -0,0 +1,19 @@ +a = 10 +b = 20 + +print(a == b) +print(a != b) +print(a < b) +print(a <= b) +print(a > b) +print(a >= b) + +x = 30 +y = 30 + +print(x == y) +print(x != y) +print(x < y) +print(x <= y) +print(x > y) +print(x >= y) diff --git a/python-operators-expressions/comparison_sequences.py b/python-operators-expressions/comparison_sequences.py new file mode 100644 index 0000000000..b3f9ca4ad4 --- /dev/null +++ b/python-operators-expressions/comparison_sequences.py @@ -0,0 +1,33 @@ +print([2, 3] == [2, 3]) +print((2, 3) == (2, 3)) + +print([5, 6, 7] < [7, 5, 6]) +print((5, 6, 7) < (7, 5, 6)) + +print([4, 3, 2] < [4, 3, 2]) +print((4, 3, 2) < (4, 3, 2)) + +# You can compare lists to tuples for equality... +print([2, 3] == (2, 3)) +print([2, 3] != (2, 3)) + +# ...but the order comparisons raise a TypeError +try: + print([2, 3] > (2, 3)) +except TypeError as error: + print(error) + +try: + print([2, 3] <= (2, 3)) +except TypeError as error: + print(error) + +# Sequences of different lengths +print([5, 6, 7] < [8]) +print((5, 6, 7) < (8,)) + +print([5, 6, 7] == [5]) +print((5, 6, 7) == (5,)) + +print([5, 6, 7] > [5]) +print((5, 6, 7) > (5,)) diff --git a/python-operators-expressions/comparison_strings.py b/python-operators-expressions/comparison_strings.py new file mode 100644 index 0000000000..0309344bde --- /dev/null +++ b/python-operators-expressions/comparison_strings.py @@ -0,0 +1,15 @@ +print(ord("A")) +print(ord("a")) + +print("A" == "a") +print("A" > "a") +print("A" < "a") + +# Lexicographical ordering, character by character +print("Hello" > "HellO") + +print(ord("o")) +print(ord("O")) + +# Strings of different lengths +print("Hello" > "Hello, World!") diff --git a/python-operators-expressions/concatenation_repetition.py b/python-operators-expressions/concatenation_repetition.py new file mode 100644 index 0000000000..6fc4408d21 --- /dev/null +++ b/python-operators-expressions/concatenation_repetition.py @@ -0,0 +1,11 @@ +# The concatenation operator +print("Hello, " + "World!") +print(("A", "B", "C") + ("D", "E", "F")) +print([0, 1, 2, 3] + [4, 5, 6]) + +# The repetition operator +print("Hello" * 3) +print(3 * "World!") + +print(("A", "B", "C") * 3) +print(3 * [1, 2, 3]) diff --git a/python-operators-expressions/conditional_expressions.py b/python-operators-expressions/conditional_expressions.py new file mode 100644 index 0000000000..ad9617166b --- /dev/null +++ b/python-operators-expressions/conditional_expressions.py @@ -0,0 +1,7 @@ +day = "Sunday" +open_time = "11AM" if day == "Sunday" else "9AM" +print(open_time) + +day = "Monday" +open_time = "11AM" if day == "Sunday" else "9AM" +print(open_time) diff --git a/python-operators-expressions/getting_started.py b/python-operators-expressions/getting_started.py new file mode 100644 index 0000000000..ecdd4c43be --- /dev/null +++ b/python-operators-expressions/getting_started.py @@ -0,0 +1,19 @@ +# The minus sign as a unary and as a binary operator +print(-273.15) +print(5 - 2) + +# The equality operator +print(42 == 42) + +# Operators by themselves aren't valid syntax. The tutorial's bare `-`, `==`, +# and `or` examples raise a SyntaxError, so they only work in the REPL. + +# Expressions built with operators +print(7 + 5) +print(42 / 2) +print(5 == 5) + +# Expressions that don't need an operator +print(abs(-7)) +print(pow(2, 8)) +print("Hello, World!") diff --git a/python-operators-expressions/identity.py b/python-operators-expressions/identity.py new file mode 100644 index 0000000000..224b2a3466 --- /dev/null +++ b/python-operators-expressions/identity.py @@ -0,0 +1,33 @@ +# Heads-up: the tutorial runs these examples in the REPL, where each +# statement is compiled on its own, so the two 1001 literals below become two +# separate objects and x is y is False. In a script, Python compiles the whole +# module at once and reuses a single 1001 object for both names, so this file +# prints True where the tutorial prints False. The equality results and the +# string examples are the same either way. + +x = 1001 +y = 1001 + +print(x == y) +print(x is y) + +# The id() numbers differ on every machine and every run +print(id(x)) +print(id(y)) + +a = "Hello, Pythonista!" +b = a + +print(id(a)) +print(id(b)) + +print(a is b) + +# The is not operator is the opposite of is +x = 1001 +y = 1001 +print(x is not y) + +a = "Hello, Pythonista!" +b = a +print(a is not b) diff --git a/python-operators-expressions/membership.py b/python-operators-expressions/membership.py new file mode 100644 index 0000000000..19b8a2099b --- /dev/null +++ b/python-operators-expressions/membership.py @@ -0,0 +1,7 @@ +# The in operator +print(5 in [2, 3, 5, 9, 7]) +print(8 in [2, 3, 5, 9, 7]) + +# The not in operator +print(5 not in [2, 3, 5, 9, 7]) +print(8 not in [2, 3, 5, 9, 7]) diff --git a/python-operators-expressions/precedence.py b/python-operators-expressions/precedence.py new file mode 100644 index 0000000000..21d6382c03 --- /dev/null +++ b/python-operators-expressions/precedence.py @@ -0,0 +1,13 @@ +print(20 + 4 * 10) + +print(2 * 3**4 * 5) + +# Parentheses override the default operator precedence +print((20 + 4) * 10) + +print(2 * 3 ** (4 * 5)) + +# The tutorial closes with a readability example that uses placeholder +# names, so it isn't runnable on its own: +# (a < 10) and (b > 30) +# a < 10 and b > 30 diff --git a/python-operators-expressions/short_circuit.py b/python-operators-expressions/short_circuit.py new file mode 100644 index 0000000000..b4cb46f2fc --- /dev/null +++ b/python-operators-expressions/short_circuit.py @@ -0,0 +1,19 @@ +def f(arg): + print(f"-> f({arg}) = {arg}") + return arg + + +print(f(0)) +print(f(False)) +print(f(1.5)) + +# Short-circuit evaluation in a compound or expression +print(f(0) or f(False) or f(1) or f(2) or f(3)) + +# Short-circuit evaluation in a compound and expression +print(f(1) and f(False) and f(2) and f(3)) +print(f(1) and f(0.0) and f(2) and f(3)) + +# When every operand is truthy, and returns the rightmost one +print(f(1) and f(2.2) and f("Hello")) +print(f(1) and f(2.2) and f(0)) diff --git a/python-operators-expressions/short_circuit_idioms.py b/python-operators-expressions/short_circuit_idioms.py new file mode 100644 index 0000000000..951e5c76ea --- /dev/null +++ b/python-operators-expressions/short_circuit_idioms.py @@ -0,0 +1,34 @@ +# Avoiding an exception +a = 3 +b = 1 + +print((b / a) > 0) + +a = 0 +b = 1 + +try: + print((b / a) > 0) +except ZeroDivisionError as error: + print(error) + +print(a != 0 and (b / a) > 0) + + +def is_divisible(a, b): + return b != 0 and a % b == 0 + + +# Providing a default value +country = "Canada" +default_country = "United States" + +print(country or default_country) + +country = "" +print(country or default_country) + +# Skipping a costly operation. The tutorial shows these two idioms as +# sketches with placeholder names, so they aren't runnable as they stand: +# data_is_clean or clean_data(data) +# data_is_updated and process_data(data) diff --git a/python-operators-expressions/walrus.py b/python-operators-expressions/walrus.py new file mode 100644 index 0000000000..eb875f99ff --- /dev/null +++ b/python-operators-expressions/walrus.py @@ -0,0 +1,9 @@ +def validate_length(string): + if (n := len(string)) < 8: + print(f"Length {n} is too short, needs at least 8") + else: + print(f"Length {n} is okay!") + + +validate_length("Pythonista") +validate_length("Python")