Python for Java Developers
🧑 Mario Kahlhofer
📧 mario.kahlhofer@dynatrace.com
🌎 github.com/blu3r4y/python-for-java-developers
Agenda
- What is Python?
- Installation
- Syntax Primer
- Data Types
- Collections
- Input and Output
- Examples
- Functions
- Classes
- Code Organization
- Libraries
- Zen of Python
Literature
Books and Resources
- 📚 Sarda, Deepak. Python for the Busy Java
Developer. Apress, 2017.
DOI: 10.1007/978-1-4842-3234-7 (sadly, uses the deprecated Python 2 syntax) - 🌍 Real Python Tutorials. realpython.com
Official Documentation
- "How can I achieve X?" ... docs.python.org/3/faq/programming.html
- "Why is Y different in Python?" ... docs.python.org/3/faq/design.html
- "What does the standard library offer?" ... docs.python.org/3/library
- "What does term X mean?" ... docs.python.org/3/glossary.html
Cheat Sheets
🐍 What is Python?
Python is a mature, general-purpose, object-oriented, dynamically-typed programming language.
- released in 1991, four years before Java
- dominant in machine learning, statistics, and data analytics
- popular alternative to MATLAB or Octave
- gaining in popularity year after year
Comparison to Java
Similarities
- general-purpose, both having a large standard library
- object-oriented
- garbage-collected
Differences
- dynamically-typed, and not strongly-typed
("type checks will only happen at runtime") - interpreted with CPython, and not
just-in-time compiled with a JVM
("more flexibility, but slower execution times") - interactive mode provided out of the box
("i will show you that soon")
🐍 Installation
Go to python.org and install the 64-bit version of Python 3.8 or newer.
🚫 Do NOT use Python 2.7 or older anymore!
Usage
pythoncan be used from the command line directlypipis the most popular package manager for Python, pulling packages from pypi.org
The most popular IDEs are IntelliJ PyCharm or Visual Studio Code.
What is Anaconda?
If you intend to use lots of scientific packages, you can install Anaconda or Miniconda as
an alternative. numpy / scipy /
sympy / tensorflow / ... usually work out of
the box with Anaconda, especially on Windows.
condais the package manager used by Anaconda, pulling packages from anaconda.org
Jupyter Notebooks
Notebooks let you mix code and documentation, usually for prototyping or documentation purposes.
Installation
Jupyter Notebooks are the "classic" notebooks and Jupyter Labs is the new IDE-like successor of them.
pip install jupyter jupyterlab
# or, if that doesn't work
python -m pip install jupyter jupyterlabUsage
You may want to open *.ipynb notebook files directly
within VS
Code or PyCharm.
Alternatively, you can start a stand-alone instance in the browser from
the command line.
python -m juypter notebook [--notebook-dir <path>]
python -m jupyter lab [--notebook-dir <path>]Try it now
📜 ./python/m02_jupyter_introduction.ipynb
🐍 Syntax Primer
// ./java/M03_MaximumValue.java#L5-L15
List<Integer> numbers = Arrays.asList(1, -10, 0, -5, -1000, 100, 7);
int maximum = numbers.get(0);
for (int number : numbers) {
if (number > maximum) {
maximum = number;
}
}
System.out.println("The maximum value is " + maximum);# ./python/m03_maximum_value.py
numbers = [1, -10, 0, -5, -1000, 100, 7]
maximum = numbers[0]
for number in numbers:
if number > maximum:
maximum = number
print("The maximum value is", maximum)What do we notice here?
- There are no semicolons
; - There are no types
- There are no braces
{ }but blocks that are started by a colon: - There are no parentheses
( )around the expressions - A list - one of many built-in
types in Python - is initialized with square brackets
[ ]
... actually, there are no arrays in Python - The
forandifsyntax is slightly different - Comments are written with the hashtag symbol
#
🐍 Data Types
We will only look into a few non-container data types of Python,
which Java would call primitive
types. *
Find all "built-in types" at docs.python.org/3/library/stdtypes.html
- Numeric Types
- Text Types
- Boolean Types
💡 In Python, you do not specify types explicitly! Although, you can have type hints.
* You can think of a variable in Python as a "tag" or "name" that is attached to some object, and NOT as the "container" that holds some value. All types in Python are essentially objects, even the numeric, text, and boolean ones. However, don't wrap your head around this too much - as you will see, things turn out to behave quite similar to Java.
Python is dynamically-typed
Unlike Java, you can re-assign values of different types to the same variable as you wish. **
x = 1416787301
x = "is"
x = True** Speaking in the notion of "tags" and "names", this means that you can freely re-assign the "tag" or "name" to point to a different location.
Numeric Types 1/4
There are only exist the three numeric types float /
int / complex in Python.
floattypes in Python ➡ are equal todoubletypes in Java *- There are NO
short/int/long/ "float" /doubletypes in Python
my_int = 5
my_float = 3.141
my_complex = 1 + 2j
# there are also some useful ways to write numbers
speed_of_light = 299_792_458
us_national_debt = 28.9e+12
ascii_symbol = 0x3f
input_bitmask = 0b1011_1001* "Floating point numbers are usually implemented using
double in C; information about the precision and internal
representation of floating point numbers for the machine on which your
program is running is available in sys.float_info" - see docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex
Numeric Types 2/4: Arbitrary Precision Integers
Integers in Python allow computations beyond usual integer limits without loss of precision.
# ./python/m04_arbitrary_precision_integers.py
lightyear_to_meter = 9_460_730_472_580_800
min_milky_way_diameter = 170_000 * lightyear_to_meter
min_milky_way_diameter_plus_one = min_milky_way_diameter + 1
print("Woooooow, the milky way is at least", min_milky_way_diameter, "meters in diameter!")
print("Adding one meter on that, we are at", min_milky_way_diameter_plus_one, "meters.")
# > Woooooow, the milky way is at least 1608324180338736000000 meters in diameter!
# > Adding one meter on that, we are at 1608324180338736000001 meters.Numeric Types 3/4: Mathematical Expressions
Find them all at docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex
# ./python/m04_mathematical_expressions.py
x = 10.5
y = -3
print("x + y =", x + y) # addition
print("x - y =", x - y) # subtraction
print("x * y =", x * y) # multiplication
print("x / y =", x / y) # normal division
print("x // y =", x // y) # integer division
print("x % y =", x % y) # modulo
print("abs(y) =", abs(y))
print("int(x) =", int(x)) # convert to integer
print("float(y) =", float(y)) # convert to float
print("complex(x, y) =", complex(x, y)) # convert to complex
print("pow(x, 3) =", pow(x, 3)) # exponentiation
print("x ** 3 =", x ** 3) # exponentiation (alternative syntax)Numeric Types 4/4: Mathematical Functions
Find them all at docs.python.org/3/library/math.html
# ./python/m04_mathematical_functions.py
# we use function from this built-in package
import math
print("sqrt(16) =", math.sqrt(16))
print("5! =", math.factorial(5))
print("log(e) =", math.log(math.e))
print("sin(pi / 2) =", math.sin(math.pi / 2))Text Types
Strings in Python are immutable* - just like in Java. When you modify strings, new memory is allocated.
first_string = "Hello World"
second_string = 'Hello Python'
multi_line_strings = """This can even
hold line breaks
now"""* Immutable, i.e., unchangeable, objects can not be modified after their creation.
String Conversion
Many types in Python can be converted to a string with
str() - similar to .toString() in Java.
As seen in the example, if you concatenate a string with a non-string,
you even have to. **
// ./java/M04_StringConversion.java#L3-L4
int num = 42;
System.out.println("The number is " + num);# ./python/m04_string_conversion.py
num = 42
print("The number is " + str(num))
# alternative, which ONLY works for print()
print("The number is", num)
# print("The number is " + num)
# 💥 TypeError: can only concatenate str (not "int") to strString Concatenation
Use str.join() in Python to concatenate a large number
of strings. *
// ./java/M04_StringConcatenation.java#L3-L8
String a = "How";
String b = "to";
String c = "concatenate";
String d = "strings";
String result = String.join(" ", a, b, c, d);# ./python/m04_string_concatenation.py#L1-L7
a = "How"
b = "to"
c = "concatenate"
d = "strings"
# we learn more about lists in the next modules ...
result = " ".join([a, b, c, d])* The equivalent of a StringBuilder
in Java would be io.StringIO
in Python.
Boolean Types
# ./python/m04_boolean_expressions.py
x = True
y = False
print("x or y =", x or y) # logical or
print("x and y =", x and y) # logical and
print("not x =", not x) # logical notBitwise Expressions
You can also perform binary computations with bitwise
operators.
Find them all at docs.python.org/3/library/stdtypes.html#bitwise-operations-on-integer-types
# ./python/m04_bitwise_expressions.py
port = 0b1011_1011
bitmask = 0b0010_0000
is_bit_set = port & (bitmask >> 1)
# we learn more about formatting in the next module ...
print("dec:", is_bit_set)
print(f"bin: {is_bit_set:08b}")
# > dec: 16
# > bin: 00010000🐍 Collections
We will only look into a few collection types of Python.
Find them all at docs.python.org/3/library/stdtypes.html
- Lists and arrays in Java ➡ are just
listin Python (but, there is alsotuple) - Maps in Java ➡ are
dictin Python - Sets in Java ➡ are also
setin Python
Lists 1/2
Lists hold multiple elements in a specific order. Unlike arrays, they can change in size at any time.
# ./python/m05_list_operations.py#L1-L15
numbers = [1, 2, 3, 4, 5]
names = ["Janine", "Ali", "Alice"]
mixed = [1, 2, "Max", 3.141]
names[0] # get element by index
names[0] = "Peter" # set element at index
names[-1] # use negative indexes to count from the end
names.append(-5) # add element to the end of the list
names.insert(1, "Bob") # add element at specific index
names.remove(-5) # remove the first occurrence from the list
del names[0] # remove by indexWhat do we notice here?
- Collections in Python are allowed to contain mixed types of data
Lists 2/2: More list operations
Learn about all list operations at docs.python.org/3/tutorial/datastructures.html#more-on-lists.
# ./python/m05_list_operations.py#L18-L26
"Alice" in names # check for existence
"Mario" not in names # ... and non-existence
numbers.count(1) # the number of times this item is in the list
len(numbers) # total number of elements in the list
# merge two lists into one
merged = [1, 2, 3] + [4, 5, 6]Tuples 1/2
Tuples hold two or more objects together in an efficient manner. They have NO direct equivalent in Java. Use them to group together small number of elements, e.g., when returning multiple values from a method.
pair = ("Jonas", 12) # create a tuple
pair[0] # get element by index, similar to lists💡 Tuples are always immutable!
You can NOT modify, append, or delete anything from them after you created one.
# pair[1] = 13
# 💥 TypeError: 'tuple' object does not support item assignment
# pair.append(123)
# 💥 AttributeError: 'tuple' object has no attribute 'append'However, you can convert tuples to lists.
numbers = (10, 11, 12)
list(numbers)
# and back again ...
letters = ["A", "B", "C"]
tuple(letters)Tuples 2/2: Collection Destructuring
Destructuring helps you to quickly retrieve elements from list-like types in Python.
# ./python/m05_destructuring.py
x, y = 1, 2
print(x, y)
# > 1 2
numbers = [1, 2, 3]
x, y, z = numbers
print(x, y, z)
# > 1 2 3
pair = ("Jonas", 12)
name, age = pair
print(name, age)
# > Jonas 12What do we notice here?
- Actually, whenever you use a comma
,in such contexts, atupleis used implicitly.
Dictionaries
Dictionaries map keys to values.
# ./python/m05_dict_operations.py
grades = {
"math": 2,
"programming": 1,
"literature": 3
}
# alternative syntax
grades = dict(math=2, programming=1, literature=3)
grades["math"] # get elements by key
grades["math"] = 5 # set elements by key
grades["electronics"] = 4 # add a new element
# remove an element (will raise an error if the key does not exist)
if "math" in grades:
del grades["math"]
grades.keys() # get all the keys as a list
grades.values() # get all the values as a listSets 1/2
Sets hold multiple elements, without duplicates, but also without order.
# ./python/m05_set_operations.py#L1-L10
numbers = {1, 1, 2, 3, 5} # notice how the '1' is only appended once after all
numbers.add(7) # add new elements
numbers.add(1) # add elements that already exist (no effect)
1 in numbers # check for existence (much faster than with lists)
# remove elements (will raise an error if the element does not exist)
if 2 in numbers:
numbers.remove(2)💡 You can NOT retrieve elements by index from a set!
# numbers[0]
# 💥 TypeError: 'set' object is not subscriptableYou must iterate over them or convert the set to a list with
list(elements)
# ./python/m05_set_operations.py#L12-L14
# iterate over set elements
for val in numbers:
print(val)Sets 2/2: Set Arithmetic
Sets are handy when you want to apply operations from set theory.
# ./python/m05_set_arithmetic.py
a = {1, 2, 3, 4, 5}
b = {4, 5, 6, 7, 8}
print("a | b =", a | b) # union
print("a & b =", a & b) # intersection
print("a - b =", a - b) # difference
# > a | b = {1, 2, 3, 4, 5, 6, 7, 8}
# > a & b = {4, 5}
# > a - b = {1, 2, 3}🐍 Input and Output
Input
You can read input from the command line with
input()
# ./python/m06_input.py#L1-L2
name = input("Please enter your name: ")
print("Your name is", name)💡 Don't forget data type conversions!
# ./python/m06_input.py#L4-L11
# this function will always give you a string
number = input("Please enter a number: ")
as_int = int(number)
as_float = float(number)
print(as_int, as_float)Output 1/2
You output something to the command line with
print()
# ./python/m06_output.py#L1-L14
pi = 3.141
print(pi)
print()
print("The value of pi is", pi)
# > 3.141
# >
# > The value of pi is 3.141
print("I hate: ", end="")
print("line breaks")
# > I hate: line breaksAmong many alternatives, format strings are the recommended way to format output.
# ./python/m06_output.py#L17-L19
print(f"The value of pi is {pi} and the value of tau is {2 * pi}")
# > The value of pi is 3.141 and the value of tau is 6.282Output 2/2: Number Formatting
Look them up when you need it at gto76.github.io/python-cheatsheet/#format
# ./python/m06_number_formatting.py
pi = 3.14159265359
print(pi)
# > 3.14159265359
print(f"{pi:.0f}") # no decimal places
print(f"{pi:.2f}") # two decimal places
print(f"{pi:.3e}") # scientific notation
# > 3
# > 3.14
# > 3.142e+00
ratio = 0.25
print(f"{ratio:.1%}") # percentage
# > 25.0%Reading and Writing Files
Among many, here is one way to read and write a file in Python.
Learn more at docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files.
# ./python/m06_file_io.py#L3-L11
filename = "m06_file_io.txt"
with open(filename, "w+") as f:
f.write("Hello\n")
f.write("File!\n")
with open(filename, "r") as f:
for line in f.read().splitlines():
print(line)🐍 Examples
Basic Control Flow
// ./java/M07_BasicControlFlow.java#L3-L17
int x = 0;
switch (x) {
case 0:
System.out.println("The value is 0");
break;
case 1:
System.out.println("The value is 1");
break;
case 2:
System.out.println("The value is 2");
break;
default:
System.out.println("The value is something else");
}# ./python/m07_basic_control_flow.py
x = 0
if x == 0:
print("The value is 0")
elif x == 1:
print("The value is 1")
elif x == 2:
print("The value is 2")
else:
print("The value is something else")What do we notice here?
- Python has no
switchexpression, you have to make a cascade ofif/elif/elsestatements *
* Actually, if you are using Python 3.10 or
newer, there are the new match and case
statements now.
Sum of all Digits
// ./java/M07_SumOfAllDigits.java#L6-L18
Scanner scanner = new Scanner(System.in);
System.out.print("Enter a number: ");
int n = scanner.nextInt();
scanner.close();
int digitSum = 0;
while (n > 0) {
digitSum += n % 10;
n = n / 10;
}
System.out.println("The digit sum is " + digitSum);# ./python/m07_sum_of_all_digits.py
n = int(input('Enter a number: '))
digit_sum = 0
while n > 0:
digit_sum += n % 10
n = n // 10
print("The digit sum is ", digit_sum)What do we notice here?
- Reading from user input is done with
input()and can also output a prompt - The
whileloop also exists in Python - We use an explicit integer division
//in Python, but use a normal division/in Java
# unlike Java, a division will alwasy give you a float data type
assert 5 / 2 == 2.5
# unless you want an explicit integer division
assert 5 // 2 == 2* assert will raise an
AssertionError if the condition is False - use
it to check assumptions in your code.
Iterating over Elements 1/2: By Value
// ./java/M07_IteratingElementsByValue.java#L3-L7
String[] names = {"Lisa", "John", "Susan", "Alex"};
for (String name : names) {
System.out.println(name);
}# ./python/m07_iterating_elements_by_value.py
names = ["Lisa", "John", "Susan", "Alex"]
for name in names:
print(name)What do we notice here?
- Iteration over a list of elements is quite similar in Java and python
Iterating over Elements 2/2: By Index
// ./java/M07_IteratingElementsByIndex.java#L3-L7
int[] numbers = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
for (int i = 5; i < 8; i++) {
System.out.println(numbers[i]);
}# ./python/m07_iterating_elements_by_index.py
numbers = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
for i in range(5, 8):
print(numbers[i])What do we notice here?
- Python only supports the
x in ysyntax with aforloop - To replicate the behavior you might know, you have to use
range(start, stop),
which will give you numbers fromstarttostop - 1
💡 Actually, range() will give you an iterator!
If you really want the numbers in a list, you have to convert the result.
# iterators only allow getting the next element with next()
range(5, 8)
# lists allow arbitrary access by index
list(range(5, 8))🐍 Advanced Operations on Sequences
Sequence Slicing 1/2
Examples like the one before are usually solved by slicing list-like
collections.
This is also very useful for mathematical applications, e.g. when
working with a lot of arrays and matrices.
# ./python/m07_sequence_slicing.py#L1-L5
numbers = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
numbers[5:8] # give me a new COPY of the list, starting at index 5, and ending at index 7
# > [15, 16, 17]The following variants are supported:
a[start:stop:step]a[start:stop]a[start:]a[:stop]a[:]
The stop index is always exclusive,
i.e. the element at index stop is not part of the resulting
slice.
Sequence Slicing 2/2: Examples
numbers = [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]# ./python/m07_sequence_slicing.py#L7-L14
numbers[1:] # all except the 1st item > [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
numbers[:3] # the first three items > [10, 11, 12]
numbers[:-1] # all except the last item > [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
numbers[-2:] # the last two items > [19, 20]
numbers[::2] # every 2nd item > [10, 12, 14, 16, 18, 20]
numbers[1::2] # every 2nd, but start at 2 > [11, 13, 15, 17, 19]This also works with strings because they are just a list of characters.
# ./python/m07_sequence_slicing.py#L17-L20
name = "Hello World"
name[1:-1]
# > 'ello Worl'Sequence Reversing
- Use
reversed(a)to iterate over the sequence in reverse order - Use
a.reverse()on the object to reverse the items in-place - Slice out a reversed copy of the elements with
a[::-1]
# ./python/m07_sequence_reversing.py
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# iterator that iterates the list in reverse order
reversed(numbers)
# reverse the list in-place
numbers.reverse()
# slice a reversed copy of the elements
numbers[::-1]Sequence Sorting
- Use
sorted(a)to get a sorted list of the elements - Use
a.sort()to sort the sequence in-place - Use the
reverse=Truekeyword argument to reverse the sorting order
# ./python/m07_sequence_sorting.py
numbers = [1, -10, 20, 11, 19, 0, -5, -1000, 100, 7]
# get a sorted list of the elements
sorted(numbers)
sorted(numbers, reverse=True)
# sort the list in-place
numbers.sort()
numbers.sort(reverse=True)Enumerating over Elements
// ./java/M07_EnumeratingOverElements.java#L3-L9
String[] names = {"Lisa", "John", "Susan", "Alex"};
int i = 0;
while (i < names.length) {
System.out.println(i + " " + names[i]);
i++;
}# ./python/m07_enumerating_over_elements.py
names = ["Lisa", "John", "Susan", "Alex"]
for i, name in enumerate(names):
print(i, name)What do we notice here?
- Our loop iterates over two values now -
enumerate()creates tuples for us here
Price Tax Computation
// ./java/M07_PriceTax.java#L5-L16
List<Double> prices = Arrays.asList(12.3, 5.2, 8.7, 1.2, 8.0);
List<Double> gross = new ArrayList<Double>();
for (double price : prices) {
if (price > 8) {
gross.add(price * 1.2);
}
}
for (double price : gross) {
System.out.println(price);
}# ./python/m07_price_tax.py#L1-L8
prices = [12.3, 5.2, 8.7, 1.2, 8.0]
gross = []
for price in prices:
if price > 8:
gross.append(price * 1.2)
print(gross)💡 List Comprehension
List comprehensions map each value in a list to a new value and thus create a new list. *
[x for x in sequence]
# ./python/m07_price_tax.py#L11-L12
prices = [12.3, 5.2, 8.7, 1.2, 8.0]
gross = [price * 1.2 for price in prices if price > 8]* Python offers a lot of features for functional programming,
like map
/ filter
/ reduce
/ zip
/ all
/ any
/ ...
🐍 Functions
// ./java/M08_RectangleFunctions.java#L2-L16
static double area(double a, double b) {
return a * b;
}
static boolean isSquare(double a, double b) {
return a == b;
}
public static void main(String[] args) {
System.out.println("area(1, 5) = " + area(1, 5));
System.out.println("area(1.5, 2.3) = " + area(1.5, 2.3));
System.out.println("isSquare(1, 5) = " + isSquare(1, 5));
System.out.println("isSquare(5, 5) = " + isSquare(5, 5));
}# ./python/m08_rectangle_functions.py#L1-L13
def area(a, b):
return a * b
def is_square(a, b):
return a == b
print("area(1, 5) =", area(1, 5))
print("area(1.5, 2.3) =", area(1.5, 2.3))
print("is_square(1, 5) =", is_square(1, 5))
print("is_square(5, 5) =", is_square(5, 5))What do we notice here?
- Functions are defined with
def - Python does not have any access modifiers nor the
statickeyword - You don't have to specify any types on the function parameters - this is called duck-typing
Pass by "Object Reference" / "Assignment"
In a nutshell, Python has the same passing behavior as Java - although, Python lacks primitive types.
// ./java/M08_PassByObjectReference.java#L4-L20
static void replace(List<Integer> numbers) {
numbers = Arrays.asList(42, 43, 44);
}
static void append(List<Integer> numbers) {
numbers.add(42);
}
public static void main(String[] args) {
List<Integer> oneTwoThree = new LinkedList<>(Arrays.asList(1, 2, 3));
replace(oneTwoThree);
System.out.println(Arrays.toString(oneTwoThree.toArray()));
append(oneTwoThree);
System.out.println(Arrays.toString(oneTwoThree.toArray()));
}# ./python/m08_pass_by_object_reference.py
def replace(numbers):
numbers = [42, 43, 44]
def append(numbers):
numbers.append(42)
one_two_three = [1, 2, 3]
replace(one_two_three)
print(one_two_three) # > [1, 2, 3]
append(one_two_three)
print(one_two_three) # > [1, 2, 3, 42]What else is different with Python functions? 1/3
You can specify argument names explicitly - and even change their order.
# ./python/m08_rectangle_functions.py#L17-L18
area(a=2, b=5)
area(b=5, a=2)You can specify default values for arguments.
# ./python/m08_function_differences.py#L1-L12
def function_with_default_args(x, y, name="Unknown User", factor=1.2):
result = x * y * factor
print(f"Hello {name}, your result is {result}")
function_with_default_args(1, 2)
function_with_default_args(1, 2, name="Mario")
function_with_default_args(1, 2, factor=10)
# > Hello Unknown User, your result is 2.4
# > Hello Mario, your result is 2.4
# > Hello Unknown User, your result is 20What else is different with Python functions? 2/3
You can return multiple results with tuples and destructuring.
# ./python/m08_function_differences.py#L15-L30
def function_with_two_return_values(radius):
pi = 3.14159
circumference = 2 * pi * radius
area = pi * radius ** 2
return circumference, area
c, a = function_with_two_return_values(5)
print("circumference", c)
print("area", a)
# > circumference 31.4159
# > area 78.53975What else is different with Python functions? 3/3
- You can declare functions inside functions
- You can declare anonymous functions, called lambda expressions
- You can overwrite and change functions on-the-fly, just like
variables
("functions are first-class-citizens in Python") - You can use
*argsand**kwargsto work with almost arbitrary input parameters, which you already did use in theprint()function for example
Learn more about funtions at docs.python.org/3/tutorial/controlflow.html#more-on-defining-functions.
🐍 Classes
Python is object-oriented, but follows a more lean approach towards classes.
// ./java/M09_PassengersProgram.java#L3-L40
class Passenger {
final String firstName;
final String lastName;
Passenger(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
void display() {
System.out.printf("%s %s %n", firstName, lastName);
}
static Passenger fromInput() {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter first name: ");
String firstName = scanner.nextLine();
System.out.print("Enter last name: ");
String lastName = scanner.nextLine();
scanner.close();
return new Passenger(firstName, lastName);
}
}
class PassengersProgram {
public static void main(String[] args) {
Passenger lisa = new Passenger("Lisa", "Ha");
Passenger user = Passenger.fromInput();
lisa.display();
user.display();
}
}# ./python/m09_passengers_program.py
class Passenger:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def display(self):
print(f"Passenger: {self.first_name} {self.last_name}")
@staticmethod
def from_input():
first_name = input("Enter first name: ")
last_name = input("Enter last name: ")
return Passenger(first_name, last_name)
if __name__ == "__main__":
lisa = Passenger("Lisa", "Ha")
user = Passenger.from_input()
lisa.display()
user.display()What do we notice here?
Constructors
- There is only one constructor that is called
__init__with a mandatoryselfparameter - Python does not support constructor overloading or method overloading
- We don't explicitly define the class properties
first_nameandlast_name,
but you create them on-the-fly in the constructor or elsewhere
Functions and methods
- What makes a function a method is only governed by the explicit
selfparameter - You must always use
self.if you want to access class properties - There are no access modifiers and there is also no
finalin Python
Static methods
- A static method needs the
@staticmethoddecorator and omits theselfparameter - A static method just means that it won't access any class properties
Instantiation
- Creating a new object works similar, but you omit the
newkeyword - The
mainmethod in Python is actually a condition - we will learn more in the next modules
Informal Interfaces
// ./java/M09_ShapesProgram.java
interface Shape {
double area();
}
class Circle implements Shape {
final double radius;
Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return 3.14159 * radius * radius;
}
}
class Square implements Shape {
final double length;
Square(double length) {
this.length = length;
}
@Override
public double area() {
return length * length;
}
}
class ShapesProgram {
public static void main(String[] args) {
Shape[] shapes = { new Circle(5), new Square(10) };
for (Shape shape : shapes) {
System.out.println(shape.area());
}
}
}# ./python/m09_shapes_program.py
class Shape:
def area(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius * self.radius
class Square(Shape):
def __init__(self, length):
self.length = length
def area(self):
return self.length * self.length
shapes = [Circle(5), Square(10)]
for shape in shapes:
print(shape.area())What do we notice here?
- There is no
interfacetype in Python, instead we use a normalclassand inhert from it - Methods are overridden without an explicit annotation - they are always replaced
- No type checks are enforced by Python, try removing
Shapeor renaming thearea()method ...
Duck-Typing
Since there is NO type-checking at compile-time, we may also solely
rely on duck-typing.
An AttributeError is thrown at runtime, if the method you
are calling wouldn't exist. *
# ./python/m09_shapes_duck_typing.py
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius * self.radius
class Square:
def __init__(self, length):
self.length = length
def area(self):
return self.length * self.length
shapes = [Circle(5), Square(10)]
for shape in shapes:
print(shape.area())* Look into type hints to have better type-checking at runtime and even before you run your code.
🐍 Code Organization
Let's take a quick interactive look at how one would create a Python project consisting of multiple files.
Running Python Scripts
📜 ./python/m10_multiple_scripts
Packages and Modules
📜 ./python/m10_demo_project
Learn about more best practices at docs.python-guide.org/writing/structure
Running Python Scripts
Your code is always executed from top to bottom.
The Main "Function"
The __main__ condition that you write, will only
evaluate to True when that script is executed directly.
# ./python/m10_multiple_scripts/main.py#L5-L6
if __name__ == "__main__":
print("This will only run if you specifically started the interpretor on this file.")With that, you mainly differentiate if a script is run directly, or
being imported.
Upon import, the __main__ condition of the importee will
evaluate to False.
# ./python/m10_multiple_scripts/imports.py
import main
# you might also want to try out these:
# import script
# from main import test_variable
if __name__ == "__main__":
print("The value of the test variable is:", main.test_variable)Packages and Modules
You should structure your code into packages ("directories") and modules ("Python files").
.
├── README.md <-- brief description
├── requirements.txt <-- list of dependencies (list package names and versions)
├── graphics
│ ├── __init__.py
│ └── parabola.py
└── user <-- a package named 'user'
├── __init__.py <-- will be executed when you 'import user'
└── app.py <-- a module named 'app'
Dependencies are usually listed in a requirements.txt
file and are installed with pip. *
python -m pip install -r requirements.txtRunning Python Modules
You run modules when your code consists of multiple files.
When you run a module, your root package is loaded into the import
path of the interpreter.
Thus, on each import statement you write, packages and
modules will be found and imported.
* Note that pip is a package by itself and that
we use the module mode to run it. Many modules are also added to your
system path upon installation, which allows you to run them directly
from the command line, e.g. with pip instead of
python -m pip.
🐍 Libraries
Don't re-invent the wheel for various tasks, have a look at what packages exist already.
Recommended Packages
numpy&scipy- high-performance numerical computations, multi-dimensional arraysmatplotlib&seaborn&plotly&bokeh- graphical visualization for mathematicianspandas- work with tabular datasympy- symbolic mathematicsnetworkx- graphs and networksrequests- network requests, download filestkinter&pyqt- graphical user interfaces
💡 Install new packages with pip
python -m pip install <package-name>Library Usage
Compute
and show a parabola with numpy and
matplotlib
# ./python/m11_numpy_demo.py
import matplotlib.pyplot as plt
import numpy as np
# get 1000 numbers between -5 and 5
xs = np.linspace(-5, 5, 1000)
# apply a function on this numpy array
ys = xs ** 2 - 1
# show a figure
plt.plot(xs, ys)
plt.show()Read a tabular dataset with
pandas
# ./python/m11_pandas_demo.py
import pandas as pd
# quickly read a csv file
df = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data")
print(df)🐍 Zen of Python
If you ever need help, type help - use the resources mentioned in the beginning - or, ask
Google.
help(sorted)
# > Help on built-in function sorted in module builtins:
# >
# > sorted(iterable, /, *, key=None, reverse=False)
# > Return a new list containing all items from the iterable in ascending order.
# >
# > A custom key function can be supplied to customize the sort order, and the
# > reverse flag can be set to request the result in descending order.And also try out this one.