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) met...
py - basic building blocks
1. expressions
a + b!
2. functions - program logic, objects which can be "executed()"
lambda a,...
everything is an object
x = None
def add(a,b): return a+b
class Person(object): …
!
for o in (1 , x, "", None, True, add,
...
object types
• two kinds: mutable and immutable
• builtin immutable:
int long float complex
str/unicode bytes
tuple frozen...
immutable
• immutable can not be changed :) - check functional paradigm
• important is to understand - "change" of variabl...
mutable
• supports changing the object in place
!
>>> a, b = ["test"], ["test"]
>>> c = a
>>> id(a),id(b),id(c)
(454813057...
global and local
• every context has its own global and local variables - use functions globals(), locals()
• global varia...
custom classes
• custom classes are mutable
• all standard types can be inherited
• for immutable types we can add methods...
custom classes
• it is much more interesting to inherit mutable objects - e.g.
!
class JavascriptDict(dict):
def __getattr...
collections.*
• from collections import OrderedDict!
• records the order the items are added
• from collections import Cou...
collections.namedtuple
>>> Person = namedtuple('Person',
['age', 'gender']) # returns class!
>>> p = Person(20, "m")
>>> p...
misc std classes
• ABC - handy for isinstance():
numbers.Number, basestring
• currency type -> decimal.Decimal
• UserDict,...
class, object and
constructor
>>> type(int)
<type 'type'>
!
>>> callable(int)
True
!
# class/type is a "function" which re...
module loading & objects creation
• execution on loading of a module - white is not executed
import sys
global_var = 3 # 2...
multiple inheritance & mixins
• one class inherits more than one class
• Mixin - popular usage of MI:
mixin is a class whi...
MRO
• method resolution order - which method will be called in the case of "method overloading"?
!
class FormMixin(object)...
obj/cls.__dict__
• useful in some cases - not the same as result of dir(obj/cls)
• object.__dict__ - holds object attribut...
dynamic class creation
• how to dynamically create an class, add attributes, methods … - runtime "code generator"
!
def ge...
class decorator
• function which gets class object and returns (changed or different) class object
!
def add_age_method(cl...
metaclasses
• The most complex but also the most powerfull to manage class creation
• django uses by implementing django.d...
@property
• property - very frequently used in other languages - Java, C#
• getter i setter - methods which "mimic" readin...
descriptors
• generalization of @property decorator - to have one single place for the same type of property data
• must b...
context managers
• generalization of prepare and cleanup of objects using with command + __enter__ & __exit__
methods
• ca...
__methods__
• there is a huge number of reserved __methods__ - only some interesting/practical will be listed
• operators,...
obj. => __getattr__, ..
• "." operator
• implementation using __getattr__, __setattr__, __delattr__
• much powerful altern...
"for obj in" => __iter__
• iteration -> implemenation of __iter__ method
• usually returns generator (yield), but can be i...
obj[i] => __getitem__, ..
• [] operator - list or dictionary or …
• implementing using __getitem__, __setitem__, __delitem...
summary
• python (IMHO)
• has an object model which suites all common
use cases and lot of special ones
• hits a sweet spo...
aand … that's all folks!
Thanks for the patience!
Questions?
Anyone?
!
robert.lujo@gmail.com
@trebor74hr
Upcoming SlideShare
Loading in …5
×

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

2,498 views

Published on

Python object model - advanced and some not so advanced features, lot of code examples:

building blocks, objects, classes, functions, mutable and immutable, everything is an object, variables, global context, "executing" the module, standard types inheritance, multiple inheritance, mixins and mro, dynamic classes, metaclasses, property function and descriptors context managers & with, useful __methods__

Published in: Software, Technology

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

  1. 1. object.__class__.__dict__ ! (python object model and friends) ! Robert Lujo, 2014
  2. 2. about me • software • professionally 17 y. • python since 2.0, django since 0.96 • freelancer • more info -> linkedin
  3. 3. 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
  4. 4. 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:
  5. 5. 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
  6. 6. 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
  7. 7. 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)
  8. 8. 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
  9. 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. 10. 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
  11. 11. 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
  12. 12. 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
  13. 13. collections.namedtuple >>> Person = namedtuple('Person', ['age', 'gender']) # returns class! >>> p = Person(20, "m") >>> p.age,p.gender -> 20, "m" >>> age, gender = p
  14. 14. misc std classes • ABC - handy for isinstance(): numbers.Number, basestring • currency type -> decimal.Decimal • UserDict, UserList - mutable dict and list - for inheritance
  15. 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. 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. 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. 18. 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
  19. 19. 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>}
  20. 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. 21. 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
  22. 22. 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
  23. 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. 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. 25. 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"
  26. 26. __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__,... >,[:]… ...
  27. 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. 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. 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. 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. 31. aand … that's all folks! Thanks for the patience! Questions? Anyone? ! robert.lujo@gmail.com @trebor74hr

×