🐍 Python for Java Developers

🧑 Mario Kahlhofer
📧 mario.kahlhofer@dynatrace.com
🌎 github.com/blu3r4y/python-for-java-developers

xkcd Comic

(c) https://xkcd.com/353


Agenda


Literature

Books and Resources

Official Documentation

Cheat Sheets

🐍 What is Python?

Python Logo

Python is a mature, general-purpose, object-oriented, dynamically-typed programming language.

Python Popularity


Comparison to Java

Similarities

Differences

🐍 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

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.


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 jupyterlab

Usage

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?

🐍 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

💡 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.

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 str

String 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 not

Bitwise 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 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 index

What do we notice here?


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 12

What do we notice here?


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 list

Sets 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 subscriptable

You 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 breaks

Among 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.282

Output 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)

What do we notice here?

* Read about possible modes at gto76.github.io/python-cheatsheet/#open.

🐍 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?

* 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?

# 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?


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?

💡 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:

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

# ./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

# ./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?


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?


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]

Arguments are ALWAYS passed by-value, in Java and also in Python.
When your argument is an object, the reference to that object is passed.

* From here on, things get complicated. Learn more about the technical details by Robert Heaton. 2014. "Is Python pass-by-reference or pass-by-value?"
and Sreejith Kesavan. 2012. "Understanding Python Variables and Memory Management".


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 20

What 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.53975

What else is different with Python functions? 3/3

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

Functions and methods

Static methods

Instantiation


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?


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())

But, how can I have a "real" interfaces and inheritance in Python?

* 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.

python script.py

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.txt

Running Python Modules

You run modules when your code consists of multiple files.

python -m user.app

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.

💡 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.

Never forget the Zen of Python.

import this

And also try out this one.

import antigravity