amitu.com
Descriptors In
Python
Excerpt from Python For Programmers
available on amitu.com/python/
amitu.com Descriptors In Python
This is an excerpt of my upcoming python book
amitu.com/python/
amitu.com Descriptors In Python
Lets take a look at property in Python
amitu.com Descriptors In Python
Or with a @property syntax sugar
amitu.com Descriptors In Python
So what exactly is the property() returning?
amitu.com Descriptors In Python
And why don't we get what property() returns
when we access .first_name?
student.first_name appears to be simple
string object!
amitu.com Descriptors In Python
And assigning to a property is even weirder.
It doesn't seem to be overwriting anything,
as normally assignment does.
It calls a function! The setter.
What were you smoking Guido?!?
amitu.com Descriptors In Python
We know that properties are useful, no
complaints here.
The real question is…
… is this some compiler/interpreter magic?
or
is it application of some simple feature
available to us?
amitu.com Descriptors In Python
We know the @ syntax is just a syntax
sugar, we love it, we create decorators
using them.
Out of @property()…
Which leaves us with property()
function or decorator.
Is property() special, or can we write it ourselves?
amitu.com Descriptors In Python
… and the answer is YES!
The name of the feature is descriptor.
Django’s ORM uses it extensively
for example…
amitu.com Descriptors In Python
Lets recap what happens when Python sees
attribute access:
[of course we are simplifying thins, no __mro__, no
__call__ etc etc]
amitu.com Descriptors In Python
… but the picture is closer to:
(we are reusing the function defined in previous slide)
amitu.com Descriptors In Python
… or in English:
If on an object, say o, when you do an attribute
lookup, say o.x, if Python finds an object at o.x
that has o.x.__get__ attribute, then instead of
returning o.x, it returns whatever
o.x.__get__(o, o.__class__) returns.
amitu.com Descriptors In Python
… when doing setting an attribute, (o.x = 10),
o.x__set__(o, 10) is looked up and called …
And this is not only for reading an attribute…
… and when you call del o.x,
o.x.__delete__(obj, o.__class__) is called if
present.
amitu.com Descriptors In Python
With that in mind, lets implement @property:
Doesn’t look that hard, does it?
amitu.com Descriptors In Python
Lets use our MyProperty:
Works like a charm!
amitu.com Descriptors In Python
When better_lookup() sees .first_name, it
finds instance of our class, and our class
instances do have .__get__(), so Python calls
it, which calls ._getter(), that was passed to
MyProperty() constructor (.__init__())
because we used it as a decorator!
amitu.com Descriptors In Python
Please note:
MyProperty class instance is created when
Student class is being constructed (as against
when student instance is being initialised).
amitu.com Descriptors In Python
Lets try setter:
amitu.com Descriptors In Python
Using the setter:
amitu.com Descriptors In Python
How we implemented @name.setter is by
realising that name now points to an
instance of our MyProperty class, and that
instance happened to have .setter()
method, which happens to take a function
as argument, so name.setter can be used
as a decorator too.
amitu.com Descriptors In Python
Cool, so we can implement @property
using descriptors.
Next question is:
When to use descriptor over property?
amitu.com Descriptors In Python
The deciding factor:
The implementation of the property lives
inside the class that is using the property.
The descriptor on the other hand is a
separate class altogether.
Let me clarify…
amitu.com Descriptors In Python
Say we want to implement .name on a
bunch of classes.
1. It must convert assigned names to
UPPER case.
2. It must validate that name is composed
of two words.
3. Name must be maximum of 100 chars
long.
amitu.com Descriptors In Python
Say we want .name on Student, Parent and
Teacher classes, and they have nothing else
in common.
amitu.com Descriptors In Python
One solution is we implement a NamedObject,
and subclass each of Student, Parent and
Teacher from NamedObject:
and so on for Parent and Teacher
amitu.com Descriptors In Python
The property based solution works, but it
does not “scale”.
What if we don't just have .name, but
also .spouse_name on Student?
What if along with .name
and .spouse_name, we also want different
length validations on each name, .name
must be 100 chars, but .spouse_name upto
80 chars?
amitu.com Descriptors In Python
A property based solution would
require us to keep track
of ._name, ._spouse_name, ._nam
e_length and ._spouse_length on
Student object.
amitu.com Descriptors In Python
Lets see how to implemented this using descriptors?
amitu.com Descriptors In Python
As you can see descriptor scales pretty well,
encapsulates better.
We can even subclass Name descriptor to add
more features to it, and we wont have to touch
the Student class etc.
amitu.com Descriptors In Python
A note on descriptors as class attributes:
If we try to access a descriptor using the class instead
of instance, e.g. Student.name instead of
student.name (where student = Student()), .__get__()
is still called with obj set to None.
amitu.com Descriptors In Python
… and at class level .__set__()
and .__delete__() calls are not allowed.
amitu.com Descriptors In Python
Thats it for now!
You have seen a section in my Python for
Developers book. This covers python
material for people who're already
developers, even python developers.
Check it out: amitu.com/python/

Descriptors In Python

  • 1.
    amitu.com Descriptors In Python Excerpt fromPython For Programmers available on amitu.com/python/
  • 2.
    amitu.com Descriptors InPython This is an excerpt of my upcoming python book amitu.com/python/
  • 3.
    amitu.com Descriptors InPython Lets take a look at property in Python
  • 4.
    amitu.com Descriptors InPython Or with a @property syntax sugar
  • 5.
    amitu.com Descriptors InPython So what exactly is the property() returning?
  • 6.
    amitu.com Descriptors InPython And why don't we get what property() returns when we access .first_name? student.first_name appears to be simple string object!
  • 7.
    amitu.com Descriptors InPython And assigning to a property is even weirder. It doesn't seem to be overwriting anything, as normally assignment does. It calls a function! The setter. What were you smoking Guido?!?
  • 8.
    amitu.com Descriptors InPython We know that properties are useful, no complaints here. The real question is… … is this some compiler/interpreter magic? or is it application of some simple feature available to us?
  • 9.
    amitu.com Descriptors InPython We know the @ syntax is just a syntax sugar, we love it, we create decorators using them. Out of @property()… Which leaves us with property() function or decorator. Is property() special, or can we write it ourselves?
  • 10.
    amitu.com Descriptors InPython … and the answer is YES! The name of the feature is descriptor. Django’s ORM uses it extensively for example…
  • 11.
    amitu.com Descriptors InPython Lets recap what happens when Python sees attribute access: [of course we are simplifying thins, no __mro__, no __call__ etc etc]
  • 12.
    amitu.com Descriptors InPython … but the picture is closer to: (we are reusing the function defined in previous slide)
  • 13.
    amitu.com Descriptors InPython … or in English: If on an object, say o, when you do an attribute lookup, say o.x, if Python finds an object at o.x that has o.x.__get__ attribute, then instead of returning o.x, it returns whatever o.x.__get__(o, o.__class__) returns.
  • 14.
    amitu.com Descriptors InPython … when doing setting an attribute, (o.x = 10), o.x__set__(o, 10) is looked up and called … And this is not only for reading an attribute… … and when you call del o.x, o.x.__delete__(obj, o.__class__) is called if present.
  • 15.
    amitu.com Descriptors InPython With that in mind, lets implement @property: Doesn’t look that hard, does it?
  • 16.
    amitu.com Descriptors InPython Lets use our MyProperty: Works like a charm!
  • 17.
    amitu.com Descriptors InPython When better_lookup() sees .first_name, it finds instance of our class, and our class instances do have .__get__(), so Python calls it, which calls ._getter(), that was passed to MyProperty() constructor (.__init__()) because we used it as a decorator!
  • 18.
    amitu.com Descriptors InPython Please note: MyProperty class instance is created when Student class is being constructed (as against when student instance is being initialised).
  • 19.
    amitu.com Descriptors InPython Lets try setter:
  • 20.
    amitu.com Descriptors InPython Using the setter:
  • 21.
    amitu.com Descriptors InPython How we implemented @name.setter is by realising that name now points to an instance of our MyProperty class, and that instance happened to have .setter() method, which happens to take a function as argument, so name.setter can be used as a decorator too.
  • 22.
    amitu.com Descriptors InPython Cool, so we can implement @property using descriptors. Next question is: When to use descriptor over property?
  • 23.
    amitu.com Descriptors InPython The deciding factor: The implementation of the property lives inside the class that is using the property. The descriptor on the other hand is a separate class altogether. Let me clarify…
  • 24.
    amitu.com Descriptors InPython Say we want to implement .name on a bunch of classes. 1. It must convert assigned names to UPPER case. 2. It must validate that name is composed of two words. 3. Name must be maximum of 100 chars long.
  • 25.
    amitu.com Descriptors InPython Say we want .name on Student, Parent and Teacher classes, and they have nothing else in common.
  • 26.
    amitu.com Descriptors InPython One solution is we implement a NamedObject, and subclass each of Student, Parent and Teacher from NamedObject: and so on for Parent and Teacher
  • 27.
    amitu.com Descriptors InPython The property based solution works, but it does not “scale”. What if we don't just have .name, but also .spouse_name on Student? What if along with .name and .spouse_name, we also want different length validations on each name, .name must be 100 chars, but .spouse_name upto 80 chars?
  • 28.
    amitu.com Descriptors InPython A property based solution would require us to keep track of ._name, ._spouse_name, ._nam e_length and ._spouse_length on Student object.
  • 29.
    amitu.com Descriptors InPython Lets see how to implemented this using descriptors?
  • 30.
    amitu.com Descriptors InPython As you can see descriptor scales pretty well, encapsulates better. We can even subclass Name descriptor to add more features to it, and we wont have to touch the Student class etc.
  • 31.
    amitu.com Descriptors InPython A note on descriptors as class attributes: If we try to access a descriptor using the class instead of instance, e.g. Student.name instead of student.name (where student = Student()), .__get__() is still called with obj set to None.
  • 32.
    amitu.com Descriptors InPython … and at class level .__set__() and .__delete__() calls are not allowed.
  • 33.
    amitu.com Descriptors InPython Thats it for now! You have seen a section in my Python for Developers book. This covers python material for people who're already developers, even python developers. Check it out: amitu.com/python/