descriptors in python

33
amitu.com Descriptors In Python Excerpt from Python For Programmers available on amitu.com/python/

Upload: amit-upadhyay

Post on 12-Apr-2017

94 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Descriptors In Python

amitu.com

Descriptors In Python

Excerpt from Python For Programmers available on amitu.com/python/

Page 2: Descriptors In Python

amitu.com Descriptors In Python

This is an excerpt of my upcoming python book

amitu.com/python/

Page 3: Descriptors In Python

amitu.com Descriptors In Python

Lets take a look at property in Python

Page 4: Descriptors In Python

amitu.com Descriptors In Python

Or with a @property syntax sugar

Page 5: Descriptors In Python

amitu.com Descriptors In Python

So what exactly is the property() returning?

Page 6: Descriptors In Python

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!

Page 7: Descriptors In Python

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?!?

Page 8: Descriptors In Python

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?

Page 9: Descriptors In Python

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?

Page 10: Descriptors In Python

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…

Page 11: Descriptors In Python

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]

Page 12: Descriptors In Python

amitu.com Descriptors In Python

… but the picture is closer to:

(we are reusing the function defined in previous slide)

Page 13: Descriptors In Python

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.

Page 14: Descriptors In Python

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.

Page 15: Descriptors In Python

amitu.com Descriptors In Python

With that in mind, lets implement @property:

Doesn’t look that hard, does it?

Page 16: Descriptors In Python

amitu.com Descriptors In Python

Lets use our MyProperty:

Works like a charm!

Page 17: Descriptors In Python

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!

Page 18: Descriptors In Python

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).

Page 19: Descriptors In Python

amitu.com Descriptors In Python

Lets try setter:

Page 20: Descriptors In Python

amitu.com Descriptors In Python

Using the setter:

Page 21: Descriptors In Python

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.

Page 22: Descriptors In Python

amitu.com Descriptors In Python

Cool, so we can implement @property using descriptors.

Next question is:When to use descriptor over property?

Page 23: Descriptors In Python

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…

Page 24: Descriptors In Python

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.

Page 25: Descriptors In Python

amitu.com Descriptors In Python

Say we want .name on Student, Parent and Teacher classes, and they have nothing else

in common.

Page 26: Descriptors In Python

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

Page 27: Descriptors In Python

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?

Page 28: Descriptors In Python

amitu.com Descriptors In Python

A property based solution would require us to keep track

of ._name, ._spouse_name, ._name_length and ._spouse_length on

Student object.

Page 29: Descriptors In Python

amitu.com Descriptors In Python

Lets see how to implemented this using descriptors?

Page 30: Descriptors In Python

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.

Page 31: Descriptors In Python

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.

Page 32: Descriptors In Python

amitu.com Descriptors In Python

… and at class level .__set__() and .__delete__() calls are not allowed.

Page 33: Descriptors In Python

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/