Download Software Tool Seminar WS1516

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Software Tool Seminar WS1516 - Taming the Snake
November 4, 2015
1
Taming the Snake
1.1
Understanding how Python works in N simple steps
(with N still growing)
1.2
Step 0. What this talk is about (and what it isn’t)
Four basic things you need to learn to become a good programmer:
1.
2.
3.
4.
Learn
Learn
Learn
Learn
how to express algorithms in a computer programming language
how to design programs
how your tool (the programming language) works and what it can offer you
what others already have built for you
I will only teach you how Python works.
(And this is only the first part of it.)
1.3
Step 1. Everything is an object
In Python, everything is an object.
Examples:
42, 4.3, ’Hello world’, True, False, None, [0, 1, 2, 3], {’key’: ’value’, ’other key’: ’other value’}
(’This’, ’is’, ’a’, ’tuple’), np.eye(10)
Really everything!
math.sin, lambda x: x, class C, math, func.__code__
To understand Python, we should first understand what objects are!
1.4
Step 2. The three properties of an object
Objects have:
1. Identity
2. State
3. Methods
1
1.5
Step 3. The Identity of an object
In [1]: a = [0, 1, 2]
b = [0, 1, 2]
a == b
Out[1]: True
In [2]: a is b
Out[2]: False
In [3]: id(a)
Out[3]: 140008350782240
In [4]: id(b)
Out[4]: 140008350781880
In [5]: (a is b) == (id(a) == id(b))
Out[5]: True
In [6]: x = 6
y = 6
x is y
Out[6]: True
In [7]: x = 666
y = 666
x is y
Out[7]: False
In [8]: id(a) is id(a)
Out[8]: False
Do not use is unless you have a good reason!
Reasonable exceptions:
x is True
x is False
x is None
This works because True, False, None are signletons in Python, i.e. there is only one object True, etc.,
in the whole Python universe.
2
1.6
Step 4. Understand assignment
In [9]: import numpy as np
a = np.ones(10)
b = np.zeros(10)
print(a)
print(b)
[ 1.
[ 0.
1.
0.
1.
0.
1.
0.
1.
0.
1.
0.
1.
0.
1.
0.
1.
0.
1.]
0.]
0.
0.
0.
0.
0.
0.
0.
0.
0.
0.
0.]
0.]
0.
0.
0.
0.
0.
0.
0.
0.
0.
0.
0.]
0.]
In [10]: a is b
Out[10]: False
In [11]: a = b
print(a)
print(b)
[ 0.
[ 0.
0.
0.
0.
0.
0.
0.
In [12]: a[0] = 1
print(a)
print(b)
[ 1.
[ 1.
0.
0.
0.
0.
0.
0.
In [13]: a is b
Out[13]: True
1.6.1
Definition of assignment
a = b
means
assign the name a to the object with name b
1.6.2
Let’s repeat!
1.6.3
Definition of assignment
a = b
means
assign the name a to the object with name b
3
1.7
Step 5. The state of an object
Objects have state (data) associated to them, which can change over the lifetime of an object.
The state is stored in the objects attributes.
In [14]: from email.mime.text import MIMEText
m = MIMEText(’Hi, this is an email!’)
m
Out[14]: <email.mime.text.MIMEText instance at 0x7f563c04cf38>
In [15]: print(m.as_string())
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Hi, this is an email!
In [16]: m._payload
m._headers
Out[16]: [(’Content-Type’, ’text/plain; charset="us-ascii"’),
(’MIME-Version’, ’1.0’),
(’Content-Transfer-Encoding’, ’7bit’)]
The underscore means, payload and headers are private attributes.
You, the user, should not mess around with them.
Methods can change attributes:
In [17]: m.add_header(’From’, ’[email protected]’)
m.add_header(’To’, ’[email protected]’)
m.add_header(’Subject’, ’World domination’)
print(m.as_string())
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
From: [email protected]
To: [email protected]
Subject: World domination
Hi, this is an email!
In [18]: m._headers
Out[18]: [(’Content-Type’, ’text/plain; charset="us-ascii"’),
(’MIME-Version’, ’1.0’),
(’Content-Transfer-Encoding’, ’7bit’),
(’From’, ’[email protected]’),
(’To’, ’[email protected]’),
(’Subject’, ’World domination’)]
We can also change attributes, even private ones:
(Do not try this at home!)
In [19]: m._payload = ’We need to talk!’
print(m.as_string())
4
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
From: [email protected]
To: [email protected]
Subject: World domination
We need to talk!
In [20]: m.my_attribute = 666
m.my_attribute
Out[20]: 666
1.7.1
Step 6. Understand the basics of attribute lookup
So where do all these attributes come from?
In [21]: m.__dict__
Out[21]: {’ charset’: us-ascii,
’ default type’: ’text/plain’,
’ headers’: [(’Content-Type’, ’text/plain; charset="us-ascii"’),
(’MIME-Version’, ’1.0’),
(’Content-Transfer-Encoding’, ’7bit’),
(’From’, ’[email protected]’),
(’To’, ’[email protected]’),
(’Subject’, ’World domination’)],
’ payload’: ’We need to talk!’,
’ unixfrom’: None,
’defects’: [],
’epilogue’: None,
’my attribute’: 666,
’preamble’: None}
In [22]: m.__dict__[’favourite_song’] = ’Hotel california’
m.__dict__[’_payload’] = ’WE NEED TO TALK!!!’
In [23]: m.favourite_song
Out[23]: ’Hotel california’
In [24]: print(m.as_string())
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
From: [email protected]
To: [email protected]
Subject: World domination
WE NEED TO TALK!!!
5
1.7.2
Attribute lookup
a.b
means
a.__dict__[’b’]
In [25]: a = np.eye(10)
a.secret_answer = 42
Writing out traceback for vim ...
--------------------------------------------------------------------------AttributeError
Traceback (most recent call last)
<ipython-input-25-9d909bc47556> in <module>()
1 a = np.eye(10)
----> 2 a.secret answer = 42
AttributeError: ’numpy.ndarray’ object has no attribute ’secret answer’
In [26]: a.__dict__
Writing out traceback for vim ...
--------------------------------------------------------------------------AttributeError
Traceback (most recent call last)
<ipython-input-26-87da7e691200> in <module>()
----> 1 a. dict
AttributeError: ’numpy.ndarray’ object has no attribute ’ dict ’
In [27]: (42).__dict__
Writing out traceback for vim ...
--------------------------------------------------------------------------AttributeError
Traceback (most recent call last)
<ipython-input-27-f22e1a648ac9> in <module>()
----> 1 (42). dict
AttributeError: ’int’ object has no attribute ’ dict ’
6
In [28]: [0, 1, 2].__dict__
Writing out traceback for vim ...
--------------------------------------------------------------------------AttributeError
Traceback (most recent call last)
<ipython-input-28-cb92ad523bf5> in <module>()
----> 1 [0, 1, 2]. dict
AttributeError: ’list’ object has no attribute ’ dict ’
1.7.3
Attribute lookup
If a has a dict,
a.b
means
a.__dict__[’b’]
This is not the case for builtin types or C extension types.
In [29]: class C(object):
pass
c = C()
c.__dict__
Out[29]: {}
In [30]: c.secret_answer = 42
c.__dict__
Out[30]: {’secret answer’: 42}
In [31]: class C(object):
secret_answer = 42
c = C()
c.secret_answer
Out[31]: 42
In [32]: c.__dict__
Out[32]: {}
In [33]: c.__class__
Out[33]:
main .C
In [34]: c.__class__.__dict__
Out[34]: <dictproxy {’ dict ’: <attribute ’ dict ’ of ’C’ objects>,
’ doc ’: None,
’ module ’: ’ main ’,
’ weakref ’: <attribute ’ weakref ’ of ’C’ objects>,
’secret answer’: 42}>
7
1.7.4
Attribute lookup (simplified)
If a has a dict,
a.b
means
if ’b’ in a.__dict__:
return a.__dict__[’b’]
elif ’b’ in a.__class__.__dict__:
return a.__class__.__dict__[’b’]
elif ’b’ in ’base class dicts’:
return base_class.__dict__[’b’]
else:
raise AttributeError
This is not the case for builtin types or C extension types.
1.7.5
Step 7. Be careful with class attributes
In [35]: class C(object):
great_list_of_awesomeness = []
c1 = C()
c2 = C()
In [36]: c1.great_list_of_awesomeness.append(42)
c1.great_list_of_awesomeness
Out[36]: [42]
In [37]: c2.great_list_of_awesomeness
Out[37]: [42]
This might not be what you want!
1.7.6
Step 8. Understand methods
Methods are functions defined in class definitions as follows:
In [38]: class C(object):
def __init__(self, x):
self.x = x
def f(self, y):
return self.x + y
c = C(11)
c.f(31)
Out[38]: 42
8
c.f(31)
translates to
C.f(c, 31)
i.e. calling a method on an object c magically inserts c as first argument of the method.
This also explains this strange error:
In [39]: c.f()
Writing out traceback for vim ...
--------------------------------------------------------------------------TypeError
Traceback (most recent call last)
<ipython-input-39-69c69864e152> in <module>()
----> 1 c.f()
TypeError: f() takes exactly 2 arguments (1 given)
init is one of Python’s many special methods.
It is called, after a new object has been created.
Thus
c = C(11)
translates to
c = newly_created_C_instance
c.__init__(c, 11)
We can add new methods to the class at any time:
In [40]: def g(ego, y):
return ego.x * y
C.mult = g
c.mult(2)
Out[40]: 22
Note that self as first argument name is pure convention.
You should really stick to it!
Adding functions directly to objects does not work:
In [41]: def h(self, y):
return self.x - y
c.h = h
c.h(-31)
Writing out traceback for vim ...
9
--------------------------------------------------------------------------TypeError
Traceback (most recent call last)
<ipython-input-41-f498a20a0d9d> in <module>()
3
4 c.h = h
----> 5 c.h(-31)
TypeError: h() takes exactly 2 arguments (1 given)
Oh no, the magic is not working!
In [42]: import types
c.h = types.MethodType(h, c)
c.h(-31)
Out[42]: 42
1.7.7
Step 9. Understand immutable objects
Numbers, strings and tuples are immutable in Python:
In [43]: t = (0, 1, 2)
t[1] = 2
Writing out traceback for vim ...
--------------------------------------------------------------------------TypeError
Traceback (most recent call last)
<ipython-input-43-4ca911cddf58> in <module>()
1 t = (0, 1, 2)
----> 2 t[1] = 2
TypeError: ’tuple’ object does not support item assignment
There is absolutely no way to modify them!
So what about here:
In [44]: x = 41
y = x
x += 1
In [45]: y
Out[45]: 41
10
In [46]: x is y
Out[46]: False
In [47]: x
Out[47]: 42
So, x refers to a new int object with value 42.
Think what would have happend, if the object had stayed the same!
This is, how inplace addition works:
In [48]: class MyNumber(object):
def __init__(self, value):
self.value = value
def __iadd__(self, other):
return MyNumber(self.value + other)
In [49]: n = MyNumber(12)
print(n.value)
print(id(n))
n += 7
print(n.value)
print(id(n))
12
140008016975120
19
140008149531472
n += 7
is really the same as
n = n.__iadd__(7)
What happens here?
In [50]: class C(object):
value = 42
c1 = C()
c2 = C()
c1.value = 666
In [51]: c1.value
Out[51]: 666
In [52]: c2.value
Out[52]: 42
In [53]: print(c1.__dict__)
print(c2.__dict__)
print(C.__dict__)
{’value’: 666}
{}
{’ dict ’: <attribute ’ dict ’ of ’C’ objects>, ’ module ’: ’ main ’, ’ weakref ’: <attribute ’ wea
11
1.7.8
Step 10. Be careful with default arguments:
Default arguments are attributes of the function object:
In [54]: def f(x, more_values=[]):
more_values.append(x)
print(more_values)
In [55]: f.__defaults__
Out[55]: ([],)
In [56]: print(dir(f))
[’ call ’, ’ class ’, ’ closure ’, ’ code ’, ’ defaults ’, ’ delattr ’, ’ dict ’, ’ doc ’, ’ for
In [57]: def f(x, more_values=[]):
more_values.append(x)
print(more_values)
In [58]: f(1)
[1]
In [59]: f(42, [4, 8, 15, 16, 23, 42])
[4, 8, 15, 16, 23, 42, 42]
In [60]: f(1)
f(1)
[1, 1]
[1, 1, 1]
In [61]: f.__defaults__
Out[61]: ([1, 1, 1],)
In [62]: f.__defaults__ = ([],)
f(1)
[1]
12