execution model and other must-know's
DESCRIPTION
Session in Python Bcn Meetup, Beginners session >> Contents: - Python execution model - Everything is an object - Everything is a pointer (or a reference) - Mutable vs. immutable objects - Common errors >> Code examples: https://github.com/pablito56/pybcn-beginnersTRANSCRIPT
{Execution model and
other must-‐‑know’s “event”: “Python BCN Meetup – Beginners session” “author”: “Pablo Enfedaque” “twi5er”: “@pablitoev56”
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> Today we are going to see:
> Python execution model
> Everything is an object
> Everything is a pointer (or a reference)
> Mutable vs. immutable objects
Welcome to Python!
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s start with a simple module
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
a_simple_module.py
#-*- coding: utf-8 -*-"pybcn basic module example" # Module docstringfrom random import randint # An importclass MyClass(object): # A class declaration def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2def random_instance(): # A function declaration "Create an instance of MyClass with random values" attr1_val = randint(0, 10) attr2_val = randint(0, 10) return MyClass(attr1_val, attr2_val)# We execute some statementsinst = random_instance()print "Instance:", inst, inst.attr1, inst.attr2
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> Modules can contain any kind and any number of valid Python statements > Classes declaration > Functions declaration
> Logical control constructions (if, for, while...)
> Function calls > Assignments and instantiations
> Etc.
Python modules
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s execute this module
me@myhost:~/wspace/beginners$ python a_simple_module.pyInstance: <__main__.MyClass object at 0x10210b390> 2 5me@myhost:~/wspace/beginners$ python a_simple_module.pyInstance: <__main__.MyClass object at 0x10104c390> 6 3me@myhost:~/wspace/beginners$ python a_simple_module.pyInstance: <__main__.MyClass object at 0x11004a390> 9 4
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s import this module
me@myhost:~/wspace/beginners$ pythonPython 2.7.5 (default, Aug 25 2013, 00:04:04)[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwinType "help", "copyright", "credits" or "license" for more ...>>> from a_simple_module import random_instanceInstance: <a_simple_module.MyClass object at 0x10083b490> 0 4>>> from a_simple_module import random_instance>>> another_inst = random_instance()>>> print another_inst, another_inst.attr1, another_inst.attr2<a_simple_module.MyClass object at 0x10083b510> 5 8
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> Modules are the basic unit of code reusability
> We can reuse the content of modules with import
Python modules
import module_namefrom package import module_namefrom package.module_name import namefrom module_name import name as another_name
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s import again the module
me@myhost:~/wspace/beginners$ pythonPython 2.7.5 (default, Aug 25 2013, 00:04:04)[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwinType "help", "copyright", "credits" or "license" for more ...>>> from a_simple_module import random_instanceInstance: <a_simple_module.MyClass object at 0x10083b490> 0 4>>> from a_simple_module import random_instance>>> another_inst = random_instance()>>> print another_inst, another_inst.attr1, another_inst.attr2<a_simple_module.MyClass object at 0x10083b510> 5 8me@myhost:~/wspace/beginners$ pythonPython 2.7.5 (default, Aug 25 2013, 00:04:04)[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwinType "help", "copyright", "credits" or "license" for more ...>>> from a_simple_module import instInstance: <a_simple_module.MyClass object at 0x10d305490> 6 3
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> When a module is imported for first time Python interprets (executes) all its content > Classes declaration > Functions declaration
> Logical control constructions (if, for, while...)
> Function calls > Assignments and instantiations
> Etc.
Python execution model
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s modify our simple module
#-*- coding: utf-8 -*-"pybcn basic module example”from random import randintclass MyClass(object): def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2def random_instance(): "Create an instance of MyClass with random values" attr1_val = randint(0, 10) attr2_val = randint(0, 10) return MyClass(attr1_val, attr2_val)# We execute some statementsinst = random_instance()print "Instance:", inst, inst.attr1, inst.attr2
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
a_main_module.py
#-*- coding: utf-8 -*-"pybcn main module example”from random import randintclass MyClass(object): def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2def random_instance(): "Create an instance of MyClass with random values" attr1_val = randint(0, 10) attr2_val = randint(0, 10) return MyClass(attr1_val, attr2_val)if __name__ == "__main__": # Only run when module is executed inst = random_instance() print "Instance:", inst, inst.attr1, inst.attr2
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s import the new module
me@myhost:~/wspace/beginners$ pythonPython 2.7.5 (default, Aug 25 2013, 00:04:04)[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwinType "help", "copyright", "credits" or "license" for more ...>>> from a_main_module import random_instance>>> another_inst = random_instance()>>> print another_inst, another_inst.attr1, another_inst.attr2<a_main_module.MyClass object at 0x1082191d0> 4 4me@myhost:~/wspace/beginners$ pythonPython 2.7.5 (default, Aug 25 2013, 00:04:04)[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwinType "help", "copyright", "credits" or "license" for more ...>>> from a_main_module import instTraceback (most recent call last): File "<stdin>", line 1, in <module>ImportError: cannot import name inst
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> When a module is imported for first time Python interprets (executes) all its content
> Check the name of the module in __name__ > This global module a5ribute has value __main__ when
a module is directly executed (instead of imported)
Python execution model
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
All code is interpreted, also the if
#-*- coding: utf-8 -*-"pybcn main module example”from random import randintclass MyClass(object): def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2def random_instance(): "Create an instance of MyClass with random values" attr1_val = randint(0, 10) attr2_val = randint(0, 10) return MyClass(attr1_val, attr2_val)if __name__ == "__main__": # Only run when module is executed inst = random_instance() print "Instance:", inst, inst.attr1, inst.attr2
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
another_module.py
#-*- coding: utf-8 -*-"pybcn another main module example”from random import randintclass MyClass(object): def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2def random_instance(): "Create an instance of MyClass with random values" attr1_val = randint(0, 10) attr2_val = randint(0, 10) return MyClass(attr1_val, attr2_val)if False: # Never interpreted!! inst = random_instance() print "Instance:", inst, inst.attr1, inst.attr2
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s use this module
me@myhost:~/wspace/beginners$ python another_module.pyme@myhost:~/wspace/beginners$ python another_module.pyme@myhost:~/wspace/beginners$ pythonPython 2.7.5 (default, Aug 25 2013, 00:04:04)[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwinType "help", "copyright", "credits" or "license" for more ...>>> from another_module import random_instance>>> another_inst = random_instance()>>> print another_inst, another_inst.attr1, another_inst.attr2<another_module.MyClass object at 0x10d6e4510> 10 10>>> from another_module import instTraceback (most recent call last): File "<stdin>", line 1, in <module>ImportError: cannot import name inst
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Ok, but… why everything is interpreted?
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s use the interpreter
me@myhost:~/wspace/beginners$ pythonPython 2.7.5 (default, Aug 25 2013, 00:04:04)[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwinType "help", "copyright", "credits" or "license" for more ...>>> def a_func(arg):... "This is a function"... return arg + arg...>>> a_func(2)4>>> print a_func.func_docThis is a function>>> print a_func.func_namea_func>>> print type(a_func), isinstance(a_func, object)<type 'function'> True
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> In Python everything is an object
> For Python there is no difference between… > An instantiation calls the class constructor and the
result is a new instance (object) of that class
> The def keyword and all its statements are interpreted and the result is a new function object
> The class keyword and all its statements are interpreted and the result is a new class object
Python execution model
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Everything is an object
#-*- coding: utf-8 -*-"pybcn main module example”from random import randintclass MyClass(object): def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2def random_instance(): "Create an instance of MyClass with random values" attr1_val = randint(0, 10) attr2_val = randint(0, 10) return MyClass(attr1_val, attr2_val)if __name__ == "__main__": # Only run when module is executed inst = random_instance() print "Instance:", inst, inst.attr1, inst.attr2
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Everything is an object
#-*- coding: utf-8 -*-"pybcn main module example”from random import randintclass MyClass(object): def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2def random_instance(): "Create an instance of MyClass with random values" attr1_val = randint(0, 10) attr2_val = randint(0, 10) return MyClass(attr1_val, attr2_val)if __name__ == "__main__": # Only run when module is executed inst = random_instance() print "Instance:", inst, inst.attr1, inst.attr2
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s copy an object
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
id_function_is_example.py
#-*- coding: utf-8 -*-"pybcn 'id' function and 'is' example"class MyClass(object): def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2inst1 = MyClass(1, 1)inst2 = MyClass(2, 2)inst3 = inst1 # Copy# 'id' function returns the unique identity of an objectprint "Instance 1:", id(inst1), inst1.attr1, inst1.attr2print "Instance 2:", id(inst2), inst2.attr1, inst2.attr2print "Instance 3:", id(inst3), inst3.attr1, inst3.attr2print inst1 is inst3 # 'is' compares the identity
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Did we copy the object?
#-*- coding: utf-8 -*-"pybcn 'id' function and 'is' example"class MyClass(object): def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2inst1 = MyClass(1, 1)inst2 = MyClass(2, 2)inst3 = inst1 # Copy?# 'id' function returns the unique identity of an objectprint "Instance 1:", id(inst1), inst1.attr1, inst1.attr2print "Instance 2:", id(inst2), inst2.attr1, inst2.attr2print "Instance 3:", id(inst3), inst3.attr1, inst3.attr2print inst1 is inst3 # 'is' compares the identityme@myhost:~/wspace/beginners$ python id_function_is_example.pyInstance 1: 4424626832 1 1Instance 2: 4424626896 2 2Instance 3: 4424626832 1 1True
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
No, we just copied the reference
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> Every object has an unchangeable identity
> In Python names are references bound to an object
> Assignments only copy the reference to an object > Shallow copy is the default behaviour in Python > Otherwise, use copy.deepcopy method
> Function calls only pass the reference to the arguments > You access the same object outside and inside a call > The same applies for return values
Python execution model
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
everything_is_a_pointer.py
#-*- coding: utf-8 -*-"pybcn 'everything is a pointer' example"class MyClass(object): def __init__(self, attr1, attr2): self.attr1 = attr1 self.attr2 = attr2def print_id_and_return(attr): print "Attr id:", id(attr) return attrinst = MyClass(3, 4)print "Instance:", id(inst)ret_val = print_id_and_return(inst)print inst is ret_valme@myhost:~/wspace/beginners$ python everything_is_a_pointer.pyInstance: 4306146128Attr id: 4306146128True
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
h5p://pythontutor.com/visualize.html
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Let’s modify some objects value
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
modify_objects_value.py
#-*- coding: utf-8 -*-"pybcn modify objects value example”txt1 = "This is text"print id(txt1), txt1txt2 = txt1 + " and more text" # Which object is txt2?print id(txt2), txt2print "-" * 5int1 = 7print id(int1), int1int1 += 11 # Which object is int1?print id(int1), int1print "-" * 5list1 = ["a", "b", "c"]print id(list1), list1list1.extend([0, 1, 2]) # In place modificationlist1[0] = "XXX"print id(list1), list1
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Assignment copies the ref. to an object!
#-*- coding: utf-8 -*-"pybcn modify objects value example”txt1 = "This is text"print id(txt1), txt1txt2 = txt1 + " and more text" # Which object is txt2?print id(txt2), txt2print "-" * 5int1 = 7print id(int1), int1int1 += 11 # Which object is int1?print id(int1), int1print "-" * 5list1 = ["a", "b", "c"]print id(list1), list1list1.extend([0, 1, 2]) # In place modificationlist1[0] = "XXX"print id(list1), list1
$ python modify_objects_value.py4335119080 This is text4335161776 This is text and more text-----140435402066344 7140435402066080 18-----4335009736 ['a', 'b', 'c']4335009736 ['XXX', 'b', 'c', 0, 1, 2]
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> Objects whose value can change are mutable > dicts, lists, sets > They allow in-‐‑place modifications (append in a list,
pop in a dictionary...)
> They can not be hashed (used as dict keys)
> Objects whose value is unchangeable once they are created are called immutable > numbers, strings, tuples, NoneType, boolean
Mutables vs. immutables
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Ignorance can lead to bugs...
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
mutables_vs_immutables_1.py
#-*- coding: utf-8 -*-"pybcn mutables assignment bug example”list1 = ["a", "b", "c"]print "list1", list1, "@", id(list1)print "-" * 5list3 = list2 = list1list2.append("x")print "list1", list1, "@", id(list1)print "list2", list2, "@", id(list2)print "list3", list3, "@", id(list3)print "-" * 5mtrx1 = [[1, 1, 1], [2, 2, 2]]print "mtrx1", mtrx1, "@", id(mtrx1)print "-" * 5mtrx2 = list(mtrx1)mtrx2[0].append("a")print "mtrx1", mtrx1, "@", id(mtrx1)print "mtrx2", mtrx2, "@", id(mtrx2)print "-" * 5print "mtrx1[0]", mtrx1[0], "@", id(mtrx1[0])print "mtrx2[0]", mtrx2[0], "@", id(mtrx2[0])
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Shallow copy uses ref. to same object
#-*- coding: utf-8 -*-"pybcn mutables assignment bug example”list1 = ["a", "b", "c"]print "list1", list1, "@", id(list1)print "-" * 5list3 = list2 = list1list2.append("x")print "list1", list1, "@", id(list1)print "list2", list2, "@", id(list2)print "list3", list3, "@", id(list3)print "-" * 5mtrx1 = [[1, 1, 1], [2, 2, 2]]print "mtrx1", mtrx1, "@", id(mtrx1)print "-" * 5mtrx2 = list(mtrx1)mtrx2[0].append("a")print "mtrx1", mtrx1, "@", id(mtrx1)print "mtrx2", mtrx2, "@", id(mtrx2)print "-" * 5print "mtrx1[0]", mtrx1[0], "@", id(mtrx1[0])print "mtrx2[0]", mtrx2[0], "@", id(mtrx2[0])
$ python mutables_vs_immutables_1.pylist1 ['a', 'b', 'c'] @ 4536893384-----list1 ['a', 'b', 'c', 'x'] @ 4536893384list2 ['a', 'b', 'c', 'x'] @ 4536893384list3 ['a', 'b', 'c', 'x'] @ 4536893384-----mtrx1 [[1, 1, 1], [2, 2, 2]] @ 4537042920-----mtrx1 [[1, 1, 1, 'a'], [2, 2, 2]] @ 4537042920mtrx2 [[1, 1, 1, 'a'], [2, 2, 2]] @ 4537043928-----mtrx1[0] [1, 1, 1, 'a'] @ 4536943320mtrx2[0] [1, 1, 1, 'a'] @ 4536943320
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
mutables_vs_immutables_2.py
#-*- coding: utf-8 -*-"pybcn class attributes bug example"class ExampleClass(object): list_attr = [] int_attr = 0instA = ExampleClass()instB = ExampleClass()instA.int_attr += 1instA.list_attr.extend([5, 7, 9])print "instA.int_attr:", instA.int_attrprint "instA.list_attr:", instA.list_attrprint "-" * 5print "instB.int_attr:", instB.int_attrprint "instB.list_attr:", instB.list_attrprint "-" * 5print instA.list_attr is instB.list_attrprint ExampleClass.list_attr
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Class a5ributes remain in the class
#-*- coding: utf-8 -*-"pybcn class attributes bug example"class ExampleClass(object): list_attr = [] int_attr = 0instA = ExampleClass()instB = ExampleClass()instA.int_attr += 1instA.list_attr.extend([5, 7, 9])print "instA.int_attr:", instA.int_attrprint "instA.list_attr:", instA.list_attrprint "-" * 5print "instB.int_attr:", instB.int_attrprint "instB.list_attr:", instB.list_attrprint "-" * 5print instA.list_attr is instB.list_attrprint ExampleClass.list_attr
$ python mutables_vs_immutables_2.pyinstA.int_attr: 1instA.list_attr: [5, 7, 9]-----instB.int_attr: 0instB.list_attr: [5, 7, 9]-----True[5, 7, 9]
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
mutables_vs_immutables_3.py
#-*- coding: utf-8 -*-"pybcn function default attribute bug example"def add_power_to_list(item, powers_lst=[]): powers_lst.append(item ** 2) return powers_lstprint "default:", add_power_to_list.func_defaultsprint "-" * 5result1 = add_power_to_list(2)print "result1:", result1print "-" * 5result2 = add_power_to_list(3)print "result1:", result1, 'vs', "result2", result2print result1 is result2print "-" * 5print "default:", add_power_to_list.func_defaults
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Functions default values remain in the function
#-*- coding: utf-8 -*-"pybcn function default attribute bug example"def add_power_to_list(item, powers_lst=[]): powers_lst.append(item ** 2) return powers_lstprint "default:", add_power_to_list.func_defaultsprint "-" * 5result1 = add_power_to_list(2)print "result1:", result1print "-" * 5result2 = add_power_to_list(3)print "result1:", result1, 'vs', "result2", result2print result1 is result2print "-" * 5print "default:", add_power_to_list.func_defaults
$ python mutables_vs_immutables_3.pydefault: ([],)-----result1: [4]-----result1: [4, 9] vs result2 [4, 9]True-----default: ([4, 9],)
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> Shallow copy uses the reference to the object > Assignment, constructor by copy, arguments in function calls > Be aware of it
> Class a5ributes remain in the class > Create instance mutable aPributes in __init__
> Functions default values remain in the function > Create mutable default values inside the function
Mutables vs. immutables bugs
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
> Modules can contain anything > All lines of code are interpreted
> Check __name__
> Everything is an object
> Names are pointers bound to objects
> Mutable and immutable objects > Take care with common bugs
Conclusions
{ “event”: “Python BCN Meetup”, “author”: “Pablo Enfedaque”, “twi5er”: “@pablitoev56”}
Q&A
Thanks for coming!
Slides:
h5ps://speakerdeck.com/pablito56/execution-‐‑model-‐‑and-‐‑other-‐‑must-‐‑knows
Code: h5ps://github.com/pablito56/pybcn-‐‑
beginners