object.__class__.__dict__
!
(python object model and friends)
!
Robert Lujo, 2014
about me
• software
• professionally 17 y.
• python since 2.0, django since 0.96
• freelancer
• more info -> linkedin
OOP
object oriented programming is a programming
paradigm
concept of "objects"
a) "attributes" - data fields (state)
b) methods - associated functions (logic)
objects are instances of classes
https://en.wikipedia.org/wiki/Object-oriented_programming
py - basic building blocks
1. expressions
a + b!
2. functions - program logic, objects which can be "executed()"
lambda a,b: a+b
3. objects (classes)
Person()
4. "variables" - pointer to object
per = Person()
add = lambda a,b: a+b
5. commands
for per in person_list:
everything is an object
x = None
def add(a,b): return a+b
class Person(object): …
!
for o in (1 , x, "", None, True, add,
Person,Person(), Person().get_name ):
print type(o),id(o),isinstance(o,object)
!
<type 'int'> 140699668384744 True
<type 'NoneType'> 4546336056 True
<type 'str'> 4546876680 True
<type 'NoneType'> 4546336056 True
<type 'bool'> 4546257024 True
<type 'function'> 4548133304 True
<type 'type'> 140699671469632 True
<class '__main__.Person'> 4547839824 True
<type 'instancemethod'> 4547596112 True
!
# https://docs.python.org/2.7/reference/datamodel.html
object types
• two kinds: mutable and immutable
• builtin immutable:
int long float complex
str/unicode bytes
tuple frozenset
• builtin mutable:
list dict
set byte-array
immutable
• immutable can not be changed :) - check functional paradigm
• important is to understand - "change" of variable is pointing to a new object
!
>>> a = "test"
>>> b = "test"
>>> c = a
>>> id("test"), id("test")==id(a)==id(b)==id(c)
(4547809072, True)
>>> a += "ing" # is this changing an object?
>>> id(a), id(a)==id(b) # not really
(4547808736, False)
mutable
• supports changing the object in place
!
>>> a, b = ["test"], ["test"]
>>> c = a
>>> id(a),id(b),id(c)
(4548130576, 4547733192, 4548130576)
>>> a.append(3) # promjena in-place
>>> id(a),id(b),id(c)
(4548130576, 4547733192, 4548130576)
!
BUT - first member of both objects is immutable object and everywhere is the same!
>>> id(a[0])==id(b[0])==id(c[0])
True
global and local
• every context has its own global and local variables - use functions globals(), locals()
• global variables are read-only, but again there is a difference between mutable and immutable
• global keyword
!
>>> g1, g2, g3 = 3, [3], 3
>>> id(g1), id(g2), id(g3)
2084115824 2523984 2084115824
!
def fun():
# print g1 # produces: SyntaxWarning: name 'g1' is used prior to global declaration
global g1
print g1, g2, g3
# g3 = 4 # if this is enabled then previous "print g3" and raises an Error
print "fg1:", id(g1), id(g2), id(g3)
g1 = 4 # change of global variable to new object
g2.append(4) # although g2 variable is read-only, the object is NOT!
print "fg2:", id(g1), id(g2), id(g3) # g1 has changed id locally and globally
!
>>> fun()
3 [3] 3
fg1: 2084115824 2523984 2084115824
fg2: 2084115812 2523984 2084115824
>>> print g1, g2, g3
4 [3, 4] 3 # change on g1 and g2 can be seen in object values
>>> print id(g1), id(g2), id(g3) # the same as fg2: - function has changed global g1
2084115812 2523984 2084115824
custom classes
• custom classes are mutable
• all standard types can be inherited
• for immutable types we can add methods and attribues, but we can't
change internal object state (e.g. change value of int object "3" to have value
4)
class Int(int):
def add2(self):
self.last = 2
return self+2
>>> x = Int(3) ; x.add2() ; x.last
5 2
custom classes
• it is much more interesting to inherit mutable objects - e.g.
!
class JavascriptDict(dict):
def __getattr__(self, aname):
if aname in self:
return self[aname]
raise AttributeError("Attr %s not found. Use %s" % (
aname, ",".join(self.keys())))
!
>>> d = JavascriptDict({"a" : 1, "b" : 2})
>>> d.a # calls d.__getattr__ - more details later …
1
>>> d.c
AttributeError: Attr c not found. Use a,b
collections.*
• from collections import OrderedDict!
• records the order the items are added
• from collections import Counter !
>>> p = Counter(blue=2, red=3)
>>> p["green"]+=1
>>> p.most_common()
[('red', 3), ('blue', 2), ('green', 1)]
• from collections import defaultdict
collections.namedtuple
>>> Person = namedtuple('Person',
['age', 'gender']) # returns class!
>>> p = Person(20, "m")
>>> p.age,p.gender -> 20, "m"
>>> age, gender = p
misc std classes
• ABC - handy for isinstance():
numbers.Number, basestring
• currency type -> decimal.Decimal
• UserDict, UserList - mutable dict and
list - for inheritance
class, object and
constructor
>>> type(int)
<type 'type'>
!
>>> callable(int)
True
!
# class/type is a "function" which returns a new object
>>> x = int(); print x, id(x)
0 14069966838468
!
# when and how was object "3" created?
>>> int(3) == int.__call__(3) == 3
True
!
>>> id(int(3)) == id(int.__call__(3)) == id(3)
True
module loading & objects creation
• execution on loading of a module - white is not executed
import sys
global_var = 3 # 2. maybe now object "3" is created? not IMHO.
def get_add_nr(nr): # 3. create a function object - add2 not created
def add2(a):
return a+nr
return add2
class Person(object): # 4. class object is getting created
CLS_ATTR = 22
class Age(object): # 4.2 inner class object is getting created
def get_age(self): # 4.2.1 creating function/object i.e. method
raise NotImplementedError()
def __init__(self,age,gender): # 4.3. creating function/object i.e. method
self.age, self.gender = age,gender
# dir() -> ['Person', 'get_add_nr', 'global_var', 'sys', '__file__', '__name__',…]
multiple inheritance & mixins
• one class inherits more than one class
• Mixin - popular usage of MI:
mixin is a class which contains a combination of methods from other classes, …
encourages code reuse
!
class FormMixin(object):
def init_fields(self):
for i, (fname, field) in enumerate(self.fields.iteritems()):
field.widget.attrs["placeholder"] = field.help_text
!
class LoginForm(forms.Form, FormMixin):
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.init_fields()
MRO
• method resolution order - which method will be called in the case of "method overloading"?
!
class FormMixin(object):
def init_fields(self): … # 3. mixin method
!
class Form(object):
def init_fields(self): … # 2. parent method
!
class LoginForm(forms.Form, FormMixin):
def init_fields(self): … # 1. own method
def __init__(self, *args, **kwargs):
self.init_fields() # 1. own method - by default
super(LoginForm, self).init_fields() # 2. parent method
FormMixin.init_fields(self) # 3. mixing method
obj/cls.__dict__
• useful in some cases - not the same as result of dir(obj/cls)
• object.__dict__ - holds object attributes
• class.__dict__ - holds class attributes and methods
!
class Person(object):
def __init__(self, name, dob):
self.dob, self.name = dob, name
!
>>> per = Person("Bero", date(2000,1,1))
>>> per.__dict__ # object content
{'dob': datetime.date(2000, 1, 1), 'name': 'Bero'}
>>> per.__class__.__dict__ # class / same as: Person.__dict__
{'__dict__': …, '__module__': '__main__', '__weakref__': …, '__doc__': None,
'__init__': <function __init__ at 0x1051ea230>}
dynamic class creation
• how to dynamically create an class, add attributes, methods … - runtime "code generator"
!
def get_method(say):
def meth1(self): print "%ss" % say # the last "s" is not an error
return meth1
!
Cat = type('Cat', (object,), # it looks a bit like Js?
{'meow': get_method('meow'),
'eat': get_method('eat')})
!
>>> c = Cat()
>>> "Cat %s and %s" % (c.meow(), c.eat())
Cat meows and eats
class decorator
• function which gets class object and returns (changed or different) class object
!
def add_age_method(cls):
def age_method(self): return date.today().year - self.dob.year
cls.age = age_method
return cos
!
@add_age_method # is equal as: Person = add_age_method(Person)
class Person(object):
def __init__(self, dob):
self.dob = dob
>>> Person(date(2000,1,1)).age()
14
metaclasses
• The most complex but also the most powerfull to manage class creation
• django uses by implementing django.db.models.Model!
!
class AddAgeMethodMeta(type):
def __new__(cls, name, bases, attrs):
def age_method(self): return date.today().year - self.dob.year
attrs["age"] = age_method
return super(AddAgeMethodMeta, cls).__new__(cls, name, bases, attrs)
!
class Person(object):
__metaclass__ = AddAgeMethodMeta # python 2 way
def __init__(self, dob): self.dob = dob
!
>>> Person(date(2000,1,1)).age()
14
@property
• property - very frequently used in other languages - Java, C#
• getter i setter - methods which "mimic" reading and changing an attribute
• python @property decorator / function - example given is using explicit function call:
class Person(object):
def __init__(self, dob): self.dob = dob
def get_age(self): return date.today().year - self.dob.year
def set_age(self, new_age):
self.dob = self.dob.replace(year=date.today().year - new_age)
def del_age(self): raise AttributeError("Age can not be deleted")
age = property(get_age, set_age, del_age,
"pydoc - Age in years - based on diff d.o.b. - today")
>>> p = Person(date(2000,1,1))
>>> p.age -> 14 # calls p.get_age()
>>> p.age = 15 # calls p.set_age(15)
>>> p.dob -> datetime.date(1999, 1, 1)
descriptors
• generalization of @property decorator - to have one single place for the same type of property data
• must be defined on class level!
• used for: methods, django related, django deferred … This example is simple - descriptors are more
powerful:
!
class AgeProperty(object):
def __get__(self,obj,objtype):
return date.today().year - obj.dob.year
!
class Person(object):
age = AgeProperty() # must be defined on class level
def __init__(self, dob):
self.dob = dob
!
>>> print Person(date(2000,1,1)).age # .age zone o.__class__.age.__get__(personobj)
14
context managers
• generalization of prepare and cleanup of objects using with command + __enter__ & __exit__
methods
• can be done with @contextlib.contextmanager decorator:
class Person(object):
DATA = {20 : dict(name="Katarina"), 23 : dict(name="Bero") }
def __init__(self, name): self.name = name
!
@contextlib.contextmanager
def per_load_and_save(id):
person = Person(**Person.DATA[id]) # load, on __enter__
yield person # send object in with blok (generator)
Person.DATA[id] = dict(name=person.name) # save, on __exit__
with per_load_and_save(id=23) as person:
print person.name
person.name = "Jo"
__methods__
• there is a huge number of reserved __methods__ - only some interesting/practical will be listed
• operators, commands and standard functions
"." __getattr__,__setattr__...
"for .. in" __iter__
[i] __getitem__,__setitem__...
"if .. in" __contains__
len() __len__
int()… __int__,...
"if "/bool() __nonzero__
+… __add__,...
|… __and__,...
>,[:]… ...
obj. => __getattr__, ..
• "." operator
• implementation using __getattr__, __setattr__, __delattr__
• much powerful alternative are __getattribute__ …. (doesn't check __dict__, "." recursion)
!
class Person(object):
def __init__(self, dob): self.dob = dob
def __getattr__(self, aname):
if aname=="age": return date.today().year - self.dob.year
raise AttributeError("Attribute '%s' not found" % aname)
!
>>> Person(date(2000,1,1)).age
14
!
"for obj in" => __iter__
• iteration -> implemenation of __iter__ method
• usually returns generator (yield), but can be implemented with an iterator too (__iter__ + next)
!
class Person(object):
def __init__(self, name): self.name = name
!
class PersonList(object):
def __init__(self, data): self.data = data
def __iter__(self): # yield -> function is a generator
for d in self.data:
yield Person(**d)
>>> for person in PersonList([dict(name="Katarina"), dict(name="Bero")]):
... print person.name,
Bero Katarina
!
obj[i] => __getitem__, ..
• [] operator - list or dictionary or …
• implementing using __getitem__, __setitem__, __delitem__
!
class Person(object):
def __init__(self, name): self.name = name
!
class PersonList(object):
def __init__(self, data):
self.data = {d["name"] : Person(**d) for d in data}
def __getitem__(self, name):
return self.data[name]
!
>>> per_list = PersonList([dict(name="Katarina"), dict(name="Bero")])
>>> print per_list["Bero"].name
Bero
summary
• python (IMHO)
• has an object model which suites all common
use cases and lot of special ones
• hits a sweet spot when combining object and
functional paradigm
• encourages creating a nice API, readable
code and maintainable program structure
aand … that's all folks!
Thanks for the patience!
Questions?
Anyone?
!
robert.lujo@gmail.com
@trebor74hr

Object.__class__.__dict__ - python object model and friends - with examples

  • 1.
    object.__class__.__dict__ ! (python object modeland friends) ! Robert Lujo, 2014
  • 2.
    about me • software •professionally 17 y. • python since 2.0, django since 0.96 • freelancer • more info -> linkedin
  • 3.
    OOP object oriented programmingis a programming paradigm concept of "objects" a) "attributes" - data fields (state) b) methods - associated functions (logic) objects are instances of classes https://en.wikipedia.org/wiki/Object-oriented_programming
  • 4.
    py - basicbuilding blocks 1. expressions a + b! 2. functions - program logic, objects which can be "executed()" lambda a,b: a+b 3. objects (classes) Person() 4. "variables" - pointer to object per = Person() add = lambda a,b: a+b 5. commands for per in person_list:
  • 5.
    everything is anobject x = None def add(a,b): return a+b class Person(object): … ! for o in (1 , x, "", None, True, add, Person,Person(), Person().get_name ): print type(o),id(o),isinstance(o,object) ! <type 'int'> 140699668384744 True <type 'NoneType'> 4546336056 True <type 'str'> 4546876680 True <type 'NoneType'> 4546336056 True <type 'bool'> 4546257024 True <type 'function'> 4548133304 True <type 'type'> 140699671469632 True <class '__main__.Person'> 4547839824 True <type 'instancemethod'> 4547596112 True ! # https://docs.python.org/2.7/reference/datamodel.html
  • 6.
    object types • twokinds: mutable and immutable • builtin immutable: int long float complex str/unicode bytes tuple frozenset • builtin mutable: list dict set byte-array
  • 7.
    immutable • immutable cannot be changed :) - check functional paradigm • important is to understand - "change" of variable is pointing to a new object ! >>> a = "test" >>> b = "test" >>> c = a >>> id("test"), id("test")==id(a)==id(b)==id(c) (4547809072, True) >>> a += "ing" # is this changing an object? >>> id(a), id(a)==id(b) # not really (4547808736, False)
  • 8.
    mutable • supports changingthe object in place ! >>> a, b = ["test"], ["test"] >>> c = a >>> id(a),id(b),id(c) (4548130576, 4547733192, 4548130576) >>> a.append(3) # promjena in-place >>> id(a),id(b),id(c) (4548130576, 4547733192, 4548130576) ! BUT - first member of both objects is immutable object and everywhere is the same! >>> id(a[0])==id(b[0])==id(c[0]) True
  • 9.
    global and local •every context has its own global and local variables - use functions globals(), locals() • global variables are read-only, but again there is a difference between mutable and immutable • global keyword ! >>> g1, g2, g3 = 3, [3], 3 >>> id(g1), id(g2), id(g3) 2084115824 2523984 2084115824 ! def fun(): # print g1 # produces: SyntaxWarning: name 'g1' is used prior to global declaration global g1 print g1, g2, g3 # g3 = 4 # if this is enabled then previous "print g3" and raises an Error print "fg1:", id(g1), id(g2), id(g3) g1 = 4 # change of global variable to new object g2.append(4) # although g2 variable is read-only, the object is NOT! print "fg2:", id(g1), id(g2), id(g3) # g1 has changed id locally and globally ! >>> fun() 3 [3] 3 fg1: 2084115824 2523984 2084115824 fg2: 2084115812 2523984 2084115824 >>> print g1, g2, g3 4 [3, 4] 3 # change on g1 and g2 can be seen in object values >>> print id(g1), id(g2), id(g3) # the same as fg2: - function has changed global g1 2084115812 2523984 2084115824
  • 10.
    custom classes • customclasses are mutable • all standard types can be inherited • for immutable types we can add methods and attribues, but we can't change internal object state (e.g. change value of int object "3" to have value 4) class Int(int): def add2(self): self.last = 2 return self+2 >>> x = Int(3) ; x.add2() ; x.last 5 2
  • 11.
    custom classes • itis much more interesting to inherit mutable objects - e.g. ! class JavascriptDict(dict): def __getattr__(self, aname): if aname in self: return self[aname] raise AttributeError("Attr %s not found. Use %s" % ( aname, ",".join(self.keys()))) ! >>> d = JavascriptDict({"a" : 1, "b" : 2}) >>> d.a # calls d.__getattr__ - more details later … 1 >>> d.c AttributeError: Attr c not found. Use a,b
  • 12.
    collections.* • from collectionsimport OrderedDict! • records the order the items are added • from collections import Counter ! >>> p = Counter(blue=2, red=3) >>> p["green"]+=1 >>> p.most_common() [('red', 3), ('blue', 2), ('green', 1)] • from collections import defaultdict
  • 13.
    collections.namedtuple >>> Person =namedtuple('Person', ['age', 'gender']) # returns class! >>> p = Person(20, "m") >>> p.age,p.gender -> 20, "m" >>> age, gender = p
  • 14.
    misc std classes •ABC - handy for isinstance(): numbers.Number, basestring • currency type -> decimal.Decimal • UserDict, UserList - mutable dict and list - for inheritance
  • 15.
    class, object and constructor >>>type(int) <type 'type'> ! >>> callable(int) True ! # class/type is a "function" which returns a new object >>> x = int(); print x, id(x) 0 14069966838468 ! # when and how was object "3" created? >>> int(3) == int.__call__(3) == 3 True ! >>> id(int(3)) == id(int.__call__(3)) == id(3) True
  • 16.
    module loading &objects creation • execution on loading of a module - white is not executed import sys global_var = 3 # 2. maybe now object "3" is created? not IMHO. def get_add_nr(nr): # 3. create a function object - add2 not created def add2(a): return a+nr return add2 class Person(object): # 4. class object is getting created CLS_ATTR = 22 class Age(object): # 4.2 inner class object is getting created def get_age(self): # 4.2.1 creating function/object i.e. method raise NotImplementedError() def __init__(self,age,gender): # 4.3. creating function/object i.e. method self.age, self.gender = age,gender # dir() -> ['Person', 'get_add_nr', 'global_var', 'sys', '__file__', '__name__',…]
  • 17.
    multiple inheritance &mixins • one class inherits more than one class • Mixin - popular usage of MI: mixin is a class which contains a combination of methods from other classes, … encourages code reuse ! class FormMixin(object): def init_fields(self): for i, (fname, field) in enumerate(self.fields.iteritems()): field.widget.attrs["placeholder"] = field.help_text ! class LoginForm(forms.Form, FormMixin): def __init__(self, *args, **kwargs): super(LoginForm, self).__init__(*args, **kwargs) self.init_fields()
  • 18.
    MRO • method resolutionorder - which method will be called in the case of "method overloading"? ! class FormMixin(object): def init_fields(self): … # 3. mixin method ! class Form(object): def init_fields(self): … # 2. parent method ! class LoginForm(forms.Form, FormMixin): def init_fields(self): … # 1. own method def __init__(self, *args, **kwargs): self.init_fields() # 1. own method - by default super(LoginForm, self).init_fields() # 2. parent method FormMixin.init_fields(self) # 3. mixing method
  • 19.
    obj/cls.__dict__ • useful insome cases - not the same as result of dir(obj/cls) • object.__dict__ - holds object attributes • class.__dict__ - holds class attributes and methods ! class Person(object): def __init__(self, name, dob): self.dob, self.name = dob, name ! >>> per = Person("Bero", date(2000,1,1)) >>> per.__dict__ # object content {'dob': datetime.date(2000, 1, 1), 'name': 'Bero'} >>> per.__class__.__dict__ # class / same as: Person.__dict__ {'__dict__': …, '__module__': '__main__', '__weakref__': …, '__doc__': None, '__init__': <function __init__ at 0x1051ea230>}
  • 20.
    dynamic class creation •how to dynamically create an class, add attributes, methods … - runtime "code generator" ! def get_method(say): def meth1(self): print "%ss" % say # the last "s" is not an error return meth1 ! Cat = type('Cat', (object,), # it looks a bit like Js? {'meow': get_method('meow'), 'eat': get_method('eat')}) ! >>> c = Cat() >>> "Cat %s and %s" % (c.meow(), c.eat()) Cat meows and eats
  • 21.
    class decorator • functionwhich gets class object and returns (changed or different) class object ! def add_age_method(cls): def age_method(self): return date.today().year - self.dob.year cls.age = age_method return cos ! @add_age_method # is equal as: Person = add_age_method(Person) class Person(object): def __init__(self, dob): self.dob = dob >>> Person(date(2000,1,1)).age() 14
  • 22.
    metaclasses • The mostcomplex but also the most powerfull to manage class creation • django uses by implementing django.db.models.Model! ! class AddAgeMethodMeta(type): def __new__(cls, name, bases, attrs): def age_method(self): return date.today().year - self.dob.year attrs["age"] = age_method return super(AddAgeMethodMeta, cls).__new__(cls, name, bases, attrs) ! class Person(object): __metaclass__ = AddAgeMethodMeta # python 2 way def __init__(self, dob): self.dob = dob ! >>> Person(date(2000,1,1)).age() 14
  • 23.
    @property • property -very frequently used in other languages - Java, C# • getter i setter - methods which "mimic" reading and changing an attribute • python @property decorator / function - example given is using explicit function call: class Person(object): def __init__(self, dob): self.dob = dob def get_age(self): return date.today().year - self.dob.year def set_age(self, new_age): self.dob = self.dob.replace(year=date.today().year - new_age) def del_age(self): raise AttributeError("Age can not be deleted") age = property(get_age, set_age, del_age, "pydoc - Age in years - based on diff d.o.b. - today") >>> p = Person(date(2000,1,1)) >>> p.age -> 14 # calls p.get_age() >>> p.age = 15 # calls p.set_age(15) >>> p.dob -> datetime.date(1999, 1, 1)
  • 24.
    descriptors • generalization of@property decorator - to have one single place for the same type of property data • must be defined on class level! • used for: methods, django related, django deferred … This example is simple - descriptors are more powerful: ! class AgeProperty(object): def __get__(self,obj,objtype): return date.today().year - obj.dob.year ! class Person(object): age = AgeProperty() # must be defined on class level def __init__(self, dob): self.dob = dob ! >>> print Person(date(2000,1,1)).age # .age zone o.__class__.age.__get__(personobj) 14
  • 25.
    context managers • generalizationof prepare and cleanup of objects using with command + __enter__ & __exit__ methods • can be done with @contextlib.contextmanager decorator: class Person(object): DATA = {20 : dict(name="Katarina"), 23 : dict(name="Bero") } def __init__(self, name): self.name = name ! @contextlib.contextmanager def per_load_and_save(id): person = Person(**Person.DATA[id]) # load, on __enter__ yield person # send object in with blok (generator) Person.DATA[id] = dict(name=person.name) # save, on __exit__ with per_load_and_save(id=23) as person: print person.name person.name = "Jo"
  • 26.
    __methods__ • there isa huge number of reserved __methods__ - only some interesting/practical will be listed • operators, commands and standard functions "." __getattr__,__setattr__... "for .. in" __iter__ [i] __getitem__,__setitem__... "if .. in" __contains__ len() __len__ int()… __int__,... "if "/bool() __nonzero__ +… __add__,... |… __and__,... >,[:]… ...
  • 27.
    obj. => __getattr__,.. • "." operator • implementation using __getattr__, __setattr__, __delattr__ • much powerful alternative are __getattribute__ …. (doesn't check __dict__, "." recursion) ! class Person(object): def __init__(self, dob): self.dob = dob def __getattr__(self, aname): if aname=="age": return date.today().year - self.dob.year raise AttributeError("Attribute '%s' not found" % aname) ! >>> Person(date(2000,1,1)).age 14 !
  • 28.
    "for obj in"=> __iter__ • iteration -> implemenation of __iter__ method • usually returns generator (yield), but can be implemented with an iterator too (__iter__ + next) ! class Person(object): def __init__(self, name): self.name = name ! class PersonList(object): def __init__(self, data): self.data = data def __iter__(self): # yield -> function is a generator for d in self.data: yield Person(**d) >>> for person in PersonList([dict(name="Katarina"), dict(name="Bero")]): ... print person.name, Bero Katarina !
  • 29.
    obj[i] => __getitem__,.. • [] operator - list or dictionary or … • implementing using __getitem__, __setitem__, __delitem__ ! class Person(object): def __init__(self, name): self.name = name ! class PersonList(object): def __init__(self, data): self.data = {d["name"] : Person(**d) for d in data} def __getitem__(self, name): return self.data[name] ! >>> per_list = PersonList([dict(name="Katarina"), dict(name="Bero")]) >>> print per_list["Bero"].name Bero
  • 30.
    summary • python (IMHO) •has an object model which suites all common use cases and lot of special ones • hits a sweet spot when combining object and functional paradigm • encourages creating a nice API, readable code and maintainable program structure
  • 31.
    aand … that'sall folks! Thanks for the patience! Questions? Anyone? ! robert.lujo@gmail.com @trebor74hr