print((2 ** 63) % 13)
import math
print(math.pi ** math.e > math.e ** math.pi)
d = float(input("diameter ? "))
area = math.pi * d**2 / 4.0
circumference = math.pi * d
print("the circle has area", area, "and circumference", circumference)
import this
This is a list of core principles the Python language follows and also serves as a recommendation for Python developers.
Although that way may not be obvious at first unless you're Dutch
is a reference to Guido van Rossum, the inventor of Python who is dutch and developed the first version of Python when being bored over christmas.
Close to Readability counts.
the sentence you read code more often than you write it
if often cited within the Python community making a clear point that readable code is important.
In the face of ambiguity, refuse the temptation to guess.
together with Errors should never pass silently.
implicate that your code should not try to correct invalid input, usually it is better to report an error back to the user.
p = float(input("p = ? "))
q = float(input("q = ? "))
d = math.sqrt(p**2 / 4.0 - q)
x1 = - p / 2.0 + d
x2 = - p / 2.0 - d
print(x1, x2)
import cmath
p = float(input("p = ? "))
q = float(input("q = ? "))
d = cmath.sqrt(p**2 / 4.0 - q)
x1 = - p / 2.0 + d
x2 = - p / 2.0 - d
print(x1, x2)
import math
x = 1e300
print(math.hypot(x, x))
print(math.sqrt(x ** 2 + x ** 2))
The "manual" implementation overflows when computing the intermediate value x ** 2
although the result is still in the available range for float
values:
print(x ** 2)
If you rewrite $\sqrt{a^2 + b^2}$ as $a \sqrt{1 + \frac{b}{a}^2}$ under the assumption $b < a$ the value in the square root is between $0$ and $2$. (If $b>a$ just swap $a$ and $b$).
In our case we have $a = b = x$:
print(x * math.sqrt(1 + 1))
Take home message: Equivalent mathematical formulas can behave differently when implemented for a computer. This affects:
the .rstrip(..)
method removes charachters from the right side of a string. Without an argument it removes so called "white spaces" which are "symbols" you actually don't see as characters in the output. Thus this include spaces, tabs and line breaks:
print("abcd \n\t ".rstrip() + "!")
Or if you provide an argument as follows the characters from the argument are stripped:
"abcdedee".rstrip("de")
Python has also lstrip
for stripping from the left side, and strip
for both sides:
" abcde ".strip() + "!"
import math
def area_and_circumference(d):
area = math.pi * d**2 / 4.0
circumference = math.pi * d
return area, circumference
d = 1.0
area, circumference = area_and_circumference(d)
print("the circle with diameter {d:.2f} has area {a:.4f} and circumference {c:.4f}"
.format(d=d, a=area, c=circumference))
def product(a, b=1, c=1):
return a * b * c
print(product(2))
print(product(2, 3))
print(product(2, 3, 4))
avg_at_1_2
is an example, that you also can pass functions to functions. This can be used to implement a function which determines zeros or maxima of a given function.
compose
is a function which takes two functions and returns a new function. The returend function evaluates an argument x
as f(g(x))
.
Such functions opearting on functions and maybe returning functions are also called "higher level functions".
Another example:
def double_result(f):
def modified_function(x):
return 2 * f(x)
return modified_function
def inc(x):
return x + 1
double_inc = double_result(inc)
# double_inc is now the "modified_function" using f=inc which is
# created within "double_result"
# calling double_inc(x) is the same as modified_function(x)
# thus it will return 2 * inc(1)
print(double_inc(1))
def double_if_even(n):
if n % 2 == 0:
return 2 * n
return n
print(double_if_even(4))
print(double_if_even(2))
def check_number(n):
if n % 3 == 0 and n % 4 == 0:
print("{} is a multiple of 3 and 4".format(n))
elif n % 3 == 0:
print("{} is a multiple of 3 but not of 4".format(n))
elif n % 4 == 0:
print("{} is a multiple of 4 but not of 4".format(n))
else:
print("{} is a neither a multiple of 3 nor of 4".format(n))
check_number(12)
check_number(8)
check_number(6)
check_number(7)
Recursion: compute
computes the product of the first n
natural numbers, 1 * 2 * ... * n
.
For adding, we here also introduce a one line version of "if/else":
def sumup(n):
assert n>=0, "only works for arguments >= 0"
return 0 if n == 0 else n + sumup(n - 1)
sumup(3)
sumup(-1)
def average(numbers):
if len(numbers) == 0:
return None # average of empty list is not defined
sum_ = 0.0
for number in numbers:
sum_ += number
# an empty list would trigger a "DivisionByZero" error:
return sum_ / len(numbers)
print(average([]))
print(average([1, 2, 3]))
Btw: there is a builtin function sum
:
def average(numbers):
if len(numbers) == 0:
return None # average of empty list is not defined
return sum(numbers) / len(numbers)
print(average([]))
print(average([1, 2, 3]))
def average_of_even_numbers(numbers):
count = 0
sum_ = 0.0
for number in numbers:
if number % 2 == 0:
count += 1
sum_ += number
if count > 0:
return sum_ / count
return None # averag of empty list is not defined
print(average_of_even_numbers([]))
print(average_of_even_numbers([1, 2, 3, 4, 5, 6]))
import random
def number_guessing_game(upper_limit=100):
secret = random.randint(0, upper_limit)
while True:
guess = int(input("your guess ? "))
if guess == secret:
print("you got it")
break
elif guess > secret:
print("your guess is too high")
else:
print("your guess is too low")
number_guessing_game()
def is_prime(n):
i = 2
while i * i <= n:
if n % i == 0:
return False
i += 1
return True
print(is_prime(49))
print(is_prime(79))
def squares_of_odd_numbers(numbers):
result = []
for number in numbers:
if number % 2 == 1:
result.append(number ** 2)
return result
print(squares_of_odd_numbers([1, 2, 3, 4, 5]))
def fib(n):
if n == 1:
return [1]
result = [1, 1]
while len(result) < n:
result.append(result[-1] + result[-2])
return result
print(fib(1))
print(fib(11))
num_to_square = {}
for i in range(1, 101): # usually iteration starts with 0, upper limits are always exclusive
num_to_square[i] = i * i
print(num_to_square)
def invert_unique(d):
inverted = {}
for k in d.keys():
v = d[k]
inverted[v] = k
return inverted
print(invert_unique({1:2, 3:4}))
def invert_general(d):
inverted = {}
for k in d.keys():
v = d[k]
if v not in inverted.keys():
inverted[v] = []
inverted[v].append(k)
return inverted
print invert_general({1:2, 3:4, 4: 4})
An alternative is to used the defaultdict
from the collections
module. Such a defaultdict
behaves like an ordinary dictionary, but you can specify a function to create default values if you access unknown keys:
from collections import defaultdict
# this creates an empty list in dd if you access unknown keys:
dd = defaultdict(list)
dd[2].append(1)
print(dd)
from collections import defaultdict
def invert_general(d):
"""alternative solution using setdefault"""
inverted = defaultdict(list)
for k in d.keys():
v = d[k]
inverted[v].append(k)
return inverted
print(invert_general({1:2, 3:4, 4: 4}))
with open("numbers.txt", "w") as fp:
for i in range(1, 11):
print(i * i, file=fp)
sum_ = 0
with open("numbers.txt", "r") as fp:
for line in fp:
sum_ += int(line.strip()) ** 2
print(sum_)
We use list comprehensions here, which are explained later in the script:
import csv
with open("table.csv", "w") as fh:
csv_fh = csv.writer(fh, delimiter=";")
for row_idx in range(1, 11):
row = [row_idx * col_idx for col_idx in range(1, 11)]
csv_fh.writerow(row) # entries in row can have arbitrary type, here: ints !
#show output of table.csv
sum_ = 0
with open("table.csv", "r") as fh:
csv_fh = csv.reader(fh, delimiter=";")
for row in csv_fh:
for cell in row:
sum_ += int(cell) # when reading the row is always a list of strings !
print(sum_)
numbers = [2, 3, 5, 7, 11]
print([n **2 for n in numbers if n < 7])
def my_key(s):
return s.upper()
data = ["ab", "ABc", "abC", "AB"]
print("regular sort:", sorted(data))
print("special sorg:", sorted(data, key=my_key))
def detect_type(value):
for t in [float, int, str]:
try:
t(value)
return t
except ValueError:
pass
return None
for d in ["1.23", "123", "abc"]:
print(d, detect_type(d))
class InvalidTerm(ValueError):
pass
def to_float(s):
try:
return float(s)
except ValueError:
raise InvalidTerm("'{}' is not a number".format(s))
def add(x, y):
return x + y
def sub(x, y):
return x - y
def mul(x, y):
return x * y
def div(x, y):
return x / y
def evaluate(term):
parts = term.split(" ")
if len(parts) != 3:
raise InvalidTerm("term '{}' does not have form N1 op N2".format(term))
# unpack list of length 3:
v1, op, v2 = parts
v1 = to_float(v1)
v2 = to_float(v2)
operations = {"+" : add,
"-" : sub,
"*" : mul,
"/" : div,
"**": pow} # pow is builtin function
if op not in operations.keys():
raise InvalidTerm("op '{}' not known".format(op))
return operations[op](v1, v2)
for term in ["2 + 3",
"2 - 3",
"2 * 3",
"2 / 3",
"2 ** 3",
"2+3",
"a + 1",
"1 + a",
"1 x 2"
]:
try:
value = evaluate(term)
print("value of", term, "is", value)
except InvalidTerm as e:
print("evaluating", term, "resulted in error", str(e))
def merge(*dicts, **kwargs):
if not dicts: # an empty dict is evaluated as 'False' !
return kwargs
result = dicts[0]
for d in dicts[1:]:
result.update(d) # dicts have an update method
# don't forget to merge the kwargs:
result.update(kwargs)
return result
print(merge(a=3, b=4))
print(merge({"a":7}, {"c": 5}, a=3, b=4))
def chain(*iterators):
for iterator in iterators:
for value in iterator:
yield value
print(list(chain(range(3), range(3), range(2))))
# even shorter, not in the script
def chain(*iterators):
for iterator in iterators:
yield from iterator
print(list(chain(range(3), range(3), range(2))))
data = ["ab", "AB", "abc", "ABc", "ABC"]
print(sorted(data))
print(sorted(data, key=lambda s:s.upper()))
def double(fun):
def wrapped(*a, **kw): # this captures all use cases how fun can be called
return 2 * fun(*a, **kw)
return wrapped
@double
def inc(x):
return x + 1
print(inc(6))
# copy pasted from the script, then modified to solve the exercise:
import math
class Point2D:
def __init__(self, x0, y0):
self.x = x0
self.y = y0
def length(self):
return math.hypot(self.x, self.y)
def __str__(self):
return "Point2D(x=%s, y=%s, lenght=%s)" % (self.x, self.y, self.length()) # attribute and method access here !
class Vector2D(Point2D):
def __str__(self):
""" overrides __str__ from Vector2D """
return "Vector2D(x=%s, y=%s)" % (self.x, self.y)
def __add__(self, other):
""" is called when you execute self + other """
return Vector2D(self.x + other.x, self.y + other.y)
# here come the new methods from the exercise:
def scale(self, factor):
""" scales vector self by factor fac """
assert isinstance(factor, (float, int)) # checks if factor is int or float
self.x *= factor
self.y *= factor
def __mul__(self, other):
""" is called when you execute self * other """
return self.x * other.x + self.y * other.y
v1 = Vector2D(1, 2)
v2 = Vector2D(2, 2)
v1.scale(2)
print(v1)
print(v1 * v2)
class ComplexNumber(Vector2D):
def __str__(self):
if self.y == 0:
return str(self.x)
elif self.x == 0:
return "{} i".format(self.y)
elif self.y > 0:
return "{} + {} i".format(self.x, self.y)
else:
return "{} - {} i".format(self.x, -self.y)
def __mul__(self, other):
re = self.x * other.x - self.y * other.y
im = self.x * other.y + self.y * other.x
return ComplexNumber(re, im)
c1 = ComplexNumber(1, 1)
c2 = ComplexNumber(1, -1)
c3 = ComplexNumber(2, 0)
print(c1)
print(c2)
print(c3)
print(c1 * c1)
print(c1 * c2)
print(c1 * c3)
# but we did not override __add__; so the result is Vector2D again.
print(c1 + c1)