Python for programmers (part 1)

Python is a weird language when coming from a C-style language (i.e. almost all the popular languages out there). But I say weird in a good way. No curly braces, no variable definitions, not a lot of parenthesis.

And it's quite readable. It's so readable and easy-to-use actually that I got around writing several smallish programs in Python without properly learning the language. By properly I don't mean any official course/certification or something, rather just reading a complete tutorial. I just Googled my way around until I got to the desired outcome.

But this approach has its limitations. So I decided to finally give Python the time it deserves and read the official language tour. This is a summary, a cheatsheet, for anyone else in a similar situation. I plan to split the entire language tour in 3-4 parts. This part covers (3) An Informal Introduction to Python and (4) More Flow Control Tools.

I repeat that this is targeted for people that already know a modern C-style programming language (e.g. Java, Kotlin, Dart, etc) and want to learn Python. Also, this will not cover every feature of the language. I aim to learn about the existance of the most common and basic features at least.  

Basic data types

Numbers

Integer numbers (e.g. 1, 2 ,3) have type int.
Numbers with fractional part (e.g. 1.0, 2.0, 3.0) have type float.

>>> 10 / 2  # division always returns a float
5.0

>>> 10 // 2  # floor division discards the fractional part
5

>>> 5 ** 2  # 5 squared
25

>>> 2 * 2.5 #  mixed type operations will have floating point result
5.0

Strings

Immutable.
Single quotes ('...') or double quotes ("..."), makes not difference.
Span multiple lines using triple-quotes: """...""" or '''...'''.

>>> 'Py' 'thon' # String literals next to each other are concatenated
'Python'

>>> 3 * 'h' + 'ello' # Concatenated with the +, and repeated with *
'hhhello'

>>> len('Hello') # Built-in function returning the length of a string
5

Characters in a String can be indexed and sliced.
Remember that Strings are immutable, every time you make a change a new instance is created.

>>> word = 'Python'

>>> word[0] # Character in position 0
'P'

>>> word[-1] # Last character
'n'

>>> word[0:2] # Characters from position 0 (included) to 2 (excluded)
'Py'

>>> word[:2] # Character from the beginning to position 2 (excluded)
'Py'

>>> word[4:] # Characters from position 4 (included) to the end
'on'

>>> word[-2:] # Characters from the second-last (included) to the end
'on'

Lists

Mutable.
Might contain items of different types, but usually the items all have the same.
Can be indexed and sliced similarly to a String (described above).
Since mutable, every operation changes the original object.

>>> a_list = [1, 4, 9, 16, 25]

>>> a_list + [36, 49, 64, 81, 100] # Concat lists
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

>>> a_list.append(216)  # Append to a list
[1, 4, 9, 16, 25, 216]

Flow control

If

Keyword ‘elif’ is short for else if.
Substitute for the switch or case statements found in other languages.

if x < 0:
    print('Negative')
elif x == 0:
    print('Zero')
else:
    print('Positive')

For

Iterates over the items of any sequence (a list or a string), in the order that they appear.

words = ['ab', 'cd', 'ef']

# Iterate over words
for w in words: 
    print(w, len(w))

# Iterate from 0 to 4
for i in range(5):
    print(i)

# `Else` in `For` statements
for x in range(5):
    if x == 2:
        print('equals 2')
        break
else:
    # Runs when no break occurs
    print('should not happen')

Since there are not indexes, if you need to modify the collection you are iterating through you need do something like this:

# Iterate over a copy
for user, status in users.copy().items():
    if status == 'inactive':
        del users[user]

# Create a new collection
active_users = {}
for user, status in users.items():
    if status == 'active':
        active_users[user] = status

Functions

def hey(n):
    """This is the method documentation."""
    print('Hello world')

Pass

Can be used is as a placeholder for a function or conditional body.

def do_something():
    pass   # Remember to implement this!

Default values

def optionaly_greet(should_greet, greeting='Hey there!'):
    if should_greet:
        print(greeting)
        
optionaly_greet(True)

Default values are evaluated at the point of function definition and only once.

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))

# This will print:
# [1]
# [1, 2]
# [1, 2, 3]

Keyword arguments

Call methods with arguments in keyword=value format.

def optionaly_greet(should_greet, greeting='Hey there!'):
    if should_greet:
        print(greeting)
        
# All these calls have the same result
optionaly_greet(True, 'Hello!')
optionaly_greet(True, greeting='Hello!')
optionaly_greet(greeting='Hello!', should_greet=True)

Special arguments

A parameter of the form *name receives a tuple containing the positional arguments beyond the formal parameter list. A parameter **name receives a dictionary (explained later) containing all keyword arguments except for those corresponding to a formal parameter.

def special_one(formal_parameter, *arguments_tuple, **keywords_map):
    print(formal_parameter)
    for arg in arguments_tuple:
        print(arg)
    print("-" * 40)
    for kw in keywords_map:
        print(kw, ":", keywords_map[kw])

special_one("Hello", "World", not_fomral_paramter="!!")

# Hello
# World
# ----------------------------------------
# not_formal_parameter : !!

Type of arguments

There is a way to define how the parameters should be passed: Positional-or-Keyword Arguments, Positional-Only Parameters, Keyword-Only Arguments.

Arguments unpacking

Call with the *-operator to unpack the arguments out of a list or tuple.

>>> args = [3, 6]
>>> list(range(*args)) # Same as range(3, 6)
[3, 4, 5]

Lambda

Syntactically restricted to a single expression.

pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
pairs.sort(key=lambda pair: pair[1])

Documentation

First line should always be a short, concise summary of the object’s purpose.
Second line should be blank.
Following lines should be one or more paragraphs describing the object’s calling conventions, its side effects, etc.

def my_function():
    """Do nothing, but document it.

        No, really, it doesn't do anything.
    """
    pass

Coding style

There is a single popular coding style called PEP 8 (summary).

Continue to part 2...