Python Fundamentals

Anatomy of your very simple first script


In [10]:
#!/usr/bin/env python

def main():
    print("Hello World!")

if __name__ == '__main__':
    main()


Hello World!
  1. Shebang: /usr/bin/python2 or /usr/bin/python3
  2. main function
  3. What the heck is __name__ or __file__ ? Snake charmers

Adding parameters to your script ... Your first imports and function parameters: *args, **kwargs

$ python hello_montoya.py "Hello" "My name is Iñigo Montoya" "You killed my father" "Prepare to Die"

Encoding

Check out How to unicode

Brief history

ASCII (American Standard Code for Information Interexchange) 1968. English alphabet took the conversion of a letter to a digit, between 0-127. Mid 1980's computers -> 8-bit (0-255) But what happens to accents? cyrilic alphabets? French (Latin1 or ISO-8859-1) Russian (KOI8)? UNICODE Standarization with 16-bit (2^16 = 65.535 distinct values)

Definitions

Character: smallest component of text ("A", "É")

Unicode: code points: integer value usually denoted in base 16

Unicode string: Serie of code points from 0 to 0x010ffff.

Unicode scapes:

  • \xhh -> \xf1 == ñ
  • \uhhhh ->
  • \Uhhhhhhhh

Encoding: translates a unicode string sequence of bytes

Comment -- X: Y -- (inspired by Emacs, PEP 263)

# -*- coding: latin-1 -*-

In Python 3 the default encoding: UTF-8

All strings → python3 -c 'print("buenos dias" "hyvää huomenta" """おはようございます""")' are unicode

IMPORTS

Official Docs

Namespace is designed to overcome this difficulty and is used to differentiate functions, classes, variables etc. with the same name, available in different modules.

A Python module is simply a Python source file, which can expose classes, functions and global variables. When imported from another Python source file, the file name is sometimes treated as a namespace.

__main__ is the name of the scope in which top-level code executes.

A module’s __name__ variable is set to __main__ when read from standard input, a script, or from an interactive prompt.

#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":

    settings_module = "settings.local"
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings_module)

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

A Python package is simply a directory of Python module(s). __init__.py.

The __init__.py file is the first thing that gets executed when a package is loaded.

rocklab/ ...
spacelab/
    __init__.py
    manage.py
    utils/
        __init__.py
        physics.py
        multidimensional/
            __init__.py
            laws.py
    rockets/
        __init__.py
        engine.py  
        base.py  # Defines a rocket model that exposes all its functionality

Relative imports specific location of the modules to be imported are relative to the current package.

laws.py

from ..phsycis import gravity

base.py

from ..mutidimensional.laws import InterDimensionalTravel
from .engine import (Motor, turn_on_engine, turn_off_engine,
                     Bolt)
# Avoid the use of \ for linebreaks and use parenthesis. Lisp people will be happy
from .engine import Motor, turn_on_engine, turn_off_engine, \
                    Bolt

Absolute imports an import where you fully specify the location of the entities being imported.

base.py

from utils.multidimensional.laws import Infinity
from rockets.engine import Motor

Circular imports happen when you create two modules that import each other.

rockets.engine.py

from .base import bad_design_decision
# D'ouh

def inside_the_function(*params):
    # avoid circular import, or ci. Is good to mention (IMAO)
    from rockets.base import bad_design_decision
    bad_design_decision(params)

Here comes the future

Official Docs

Note for absolute imports:

from __future__ import absolute_import

Keep Reading

About imports in Python

About future imports


In [38]:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

def main(*args, **kwargs):
    """Simple main function that prints stuff"""
    print(args)  # args is a tuple of positional params
    print(kwargs) # kwargs is a dict with keyword params
    ## The names are just a mere convention

if __name__ == '__main__':
    main(sys.argv)  # input params from the command line


(['/home/miguel/.virtualenvs/pcc/lib/python2.7/site-packages/ipykernel_launcher.py', '-f', '/run/user/1000/jupyter/kernel-5e33a56d-0aa6-465a-85a6-55f9c11ae881.json'],)
{}

Programming Types

Boolean: True, False

NoneType: None

Mutable / Immutable Objects

Some immutable types:

int, float, long, complex
str
bytes
tuple
frozen set

Some mutable types:

byte array
list
set
dict

In [11]:
# Immutable Objects

age = 60 # int
weight = 77.8  # float
infinite = float('inf')
name = "Rick" # basestring/str
nick_names = ("Sanchez", "Grandpa") # tuple

jobs = frozenset(("scientist", "inventor", "arms salesman", "store owner"))

# Mutable Objects
interests = ['interdimensional travel', 'nihilism', 'alcohol']
info = {
    "name": name,
    "last_names": last_names,
    "age": age
}
redundant = set(interests)

In [12]:
# Information from objects
type(age) # int
isinstance(age, int)  # True 
type(infinite)
type(name)
isinstance(name, basestring)
# typve vs isinstance: type doesnt check for object subclasses
# we will discuss the type constructor later on


Out[12]:
True

Why immutable objects?


In [14]:
# integers
print(id(age))
age += 10
print(id(age))
age -= 10
print(id(age))


94363336246216
94363336245976
94363336246216

In [31]:
# Strings
print(name + ": Wubba lubba dub-dub!!")
print(name.replace("R", "r"))
print(name.upper(), name.lower())


Rick: Wubba lubba dub-dub!!
rick
('RICK', 'rick')

In [33]:
# Tuples
operations = "test",  # note the comma as it makes it a tuple!!! | tuple.count/index
print(id(operations))
operations += ('build', 'deploy')
print(operations, id(operations))


140378617825616
(('test', 'build', 'deploy'), 140378260466176)

In [30]:
## Tuple assignment

def say(*args):
    print(args)
    
say(range(8))

# Packing 
test, build, deploy = "Always passing", "A better world", "Your mind"

# OK but use parenthesis :)

(test, build, deploy) = ("Always passing", "A better world", "Your mind")


print("Test: ", test)
print("Build: " + build)
print("Deploy: " + deploy)


140378334218192
(('test', 'build', 'deploy'), 140378260466256)
([0, 1, 2, 3, 4, 5, 6, 7],)
('Test: ', 'Always passing')
Build: A better world
Deploy: Your mind
('test', 'build', 'deploy')

In [ ]:
# Unpacking
test, build, deploy = operations
print(test, build, deploy)

# You are warned:  # ERROR -- too many values to unpack
# https://docs.python.org/3.6/tutorial/controlflow.html#unpacking-argument-lists

In [ ]:
# lists

Operators

Official Docs

Arithmetic Operators: + - / // * ** %


In [40]:
print(1 + 3)
print(2 ** 10)
print(5 % 3)


4
1024
2

In [49]:
print(10 / 4) 2

from __future__ import division

print(10 / 4) 2.5  # float division

10 // 4  # in python 3 to get integer division


2.5
2.5

In [39]:
import operator

operator.add(2, 4)
operator.gt(10, 5)


Out[39]:
6