+++
title = "Python Class structure basics"
subtitle = "A crash course in Python classes"
draft = false
archived = true
tags = [
"python",
"ruby",
"classes"
]
date = "2013-10-01"
categories = ["programming"]
+++
Handy links:
* [special class methods like _ _getattr_ _ and _ _new_ _](http://www.diveintopython.net/object_oriented_framework/special_class_methods2.html)
* [dive into python - native datatypes](http://www.diveintopython3.net/native-datatypes.html#tuples)
* [Inside story on new style classes](http://python-history.blogspot.be/2010/06/inside-story-on-new-style-classes.html) - ter info: Python3 heeft **enkel** "newstyle" classes!
### Method overriding
Is **niet mogelijk**. Gebruik default values!
```python
def func(i, j = 2, k 3):
return i + j + k
func(1) # 6
func(1, 1) # 5
func(1, 1, 1) # 3
```
Wat wel gaat, evt met decorators, zie [Five-minute multimethods in Python](http://www.artima.com/weblogs/viewpost.jsp?thread=101605) - is `__call__` implementeren en dan met metaprogrammeren te loopen over alle methods en te kijken of de argumenten overeen komen met het type dat required is. Fancypancy!
##### Opgelet met pitfalls
**Nummer 1**: default variables worden herbruikt:
> When Python executes a “def” statement, it takes some ready-made pieces (including the compiled code for the function body and the current namespace), and creates a new function object. When it does this, it also evaluates the default values. [...] Another way to reset the defaults is to simply re-execute the same “def” statement. Python will then create a new binding to the code object, evaluate the defaults, and assign the function object to the same variable as before. But again, only do that if you know exactly what you’re doing.
Default als `arr = []` Gaat de array muteren. Heel handig voor memoization, heel verwarrend anders. Oplossing? `arr None` en dan `arr = [] if arr is None`.
Zie ook [Default parameter values in Python](http://effbot.org/zone/default-values.htm) voor in-depth uitleg.
**Nummer 2**: *Python’s nested scopes bind to variables, not object values*.
```python
for i in range(10):
def callback():
print "clicked button", i
UI.Button("button %s" % i, callback)
```
variabele `i` gaat altijd 9 zijn - wordt niet op value gebind. Oplossing is explicit binding door de functie definitie van `callback():` te veranderen naar `callback(i=i):`.
### Fields dynamisch definiëren
`Thing(a=1, b2)` kan op een paar manieren gedefiniëerd worden.
##### fields expliciet declareren
```python
class Thing:
def __init__(self, a, b):
self.a, self.b = a, b
```
##### dynamisch uw eigen dictionary updaten
```python
class Thing:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
```
:exclamation: Dit is uiteraard heel gevaarlijk aangezien het al uw method bodies kan vervangen door een param value. BOEM.
`* *name`(zonder spatie, wiki markup, nvdr) geeft alle argumenten in een [dict](http://docs.python.org/2/library/stdtypes.html#typesmapping) terug. `*name` gaat ook, geeft u een lijst van argumenten terug. Combinatie gaat ook, één ster moet voor de tweede komen. Zoiets is dus mogelijk: `def _ _init_ _(self, arg1, arg2, *allargs, * *allargsasdict)`.
##### Alles als een message passing systeem zien
In Ruby is er een andere manier om `def name block end` te schrijven, hoe het geïnterpreteerd wordt: `self.class.send(:name, args) { block }`
```ruby
def opt_to_s opt={}
opt.empty? ? '' : ' ' + opt.map {|e,v| "#{e}=
"#{v}
""}.join(', ')
end
[:html, :body, :h1].each do |el|
start="<#{el}"
fin="#{el}>"
self.class.send(:define_method, el) {|options={}, &blk| start + opt_to_s(options) + '>' + blk.call + fin}
end
# Now, we can neatly nest tags and content
html do
body do
h1 :class=>"bold-h1", :id>"h1_99" do
"header"
end
end
end
=> "