python descriptors demystified

25
Descriptors Python's most obscure language feature demystified. In 5 minutes . Chris Beaumont @BeaumontChris graduate student, astrophysics Harvard University / University of Hawaii

Upload: chris-beaumont

Post on 30-Jun-2015

738 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: Python Descriptors Demystified

DescriptorsPython's most obscure language feature demystified.

In 5 minutes.

Chris Beaumont @BeaumontChris

graduate student, astrophysicsHarvard University / University of Hawaii

Page 2: Python Descriptors Demystified

Learning about descriptors creates an appreciation for the elegance of Python's design.

-Raymond Hettinger

Page 3: Python Descriptors Demystified

Learning about descriptors creates an appreciation for the elegance of Python's design.

-Raymond Hettinger

I DON'T

GET IT

Page 4: Python Descriptors Demystified

class Email(object):

def __init__(self, sender, subject, message): self.sender_widget = QLineEdit(sender) self.subject_widget = QLineEdit(subject) self.message_widget = QLineEdit(message)

How does other codeinteract with email data?

Page 5: Python Descriptors Demystified

class Email(object): ...

def get_subject(self): return self.subject_widget.text()

def set_subject(self, subject): self.subject_widget.setText(subject) ...

e = Email()e.set_subject('Hi there')sub = e.get_subject()

Page 6: Python Descriptors Demystified

class Email(object): ...

def get_subject(self): return self.subject_widget.text()

def set_subject(self, subject): self.subject_widget.setText(subject) ...

e = Email()e.set_subject('Hi there')sub = e.get_subject()

Gross

Page 7: Python Descriptors Demystified

PropertiesDisguise methods

as attributes

http://www.flickr.com/photos/mkapple/741018101/

Page 8: Python Descriptors Demystified

class Email(object): ...

@property def subject(self): return self.subject_widget.text()

@subject.setter def subject(self, subject): self.subject_widget.setText(subject) ...

Page 9: Python Descriptors Demystified

e = Email()sub = e.subjecte.subject = 'hi there'

class Email(object): ...

@property def subject(self): return self.subject_widget.text()

@subject.setter def subject(self, subject): self.subject_widget.setText(subject) ...

Page 10: Python Descriptors Demystified

e = Email()sub = e.subjecte.subject = 'hi there'

class Email(object): ...

@property def subject(self): return self.subject_widget.text()

@subject.setter def subject(self, subject): self.subject_widget.setText(subject) ...

Nice.

Page 11: Python Descriptors Demystified

class Email(object):

def __init__(self, sender, subject, message): self._sender_widget = QLineEdit(sender) self._subject_widget = QLineEdit(subject) self._message_widget = QLineEdit(message)

@property def sender(self): return self._sender_widget.text()

@sender.setter def sender(self, sender): self._sender_widget.setText(sender)

@property def subject(self): return self._subject_widget.text()

@subject.setter def subject(self, subject): self._subject_widget.setText(subject)

@property def message(self): return self._message_widget.text()

@message.setter def message(self, message): self._message_widget.setText(message)

Page 12: Python Descriptors Demystified

class Email(object):

def __init__(self, sender, subject, message): self._sender_widget = QLineEdit(sender) self._subject_widget = QLineEdit(subject) self._message_widget = QLineEdit(message)

@property def sender(self): return self._sender_widget.text()

@sender.setter def sender(self, sender): self._sender_widget.setText(sender)

@property def subject(self): return self._subject_widget.text()

@subject.setter def subject(self, subject): self._subject_widget.setText(subject)

@property def message(self): return self._message_widget.text()

@message.setter def message(self, message): self._message_widget.setText(message)

Gross

Page 13: Python Descriptors Demystified

DescriptorsReusable Properties

http://www.freeimageslive.co.uk/files/images005/locust_leaf.JPG

Page 14: Python Descriptors Demystified

class TextWrapper(object):

def __init__(self, widget_name): self.widget_name = widget_name

def __get__(self, object): widget = getattr(object, self.widget_name) return widget.text()

def __set__(self, object, value): widget = getattr(object, self.widget_name) widget.setText(value)

class Email(object): sender = TextWrapper('sender_widget') subject = TextWrapper('subject_widget') message = TextWrapper('message_widget')

def __init__(self, sender, subject, message): self.sender_widget = QLineEdit(sender) self.subject_widget = QLineEdit(subject) self.message_widget = QLineEdit(message)

...

...

Page 15: Python Descriptors Demystified

class TextWrapper(object):

def __init__(self, widget_name): self.widget_name = widget_name

def __get__(self, object): widget = getattr(object, self.widget_name) return widget.text()

def __set__(self, object, value): widget = getattr(object, self.widget_name) widget.setText(value)

class Email(object): sender = TextWrapper('sender_widget') subject = TextWrapper('subject_widget') message = TextWrapper('message_widget')

def __init__(self, sender, subject, message): self.sender_widget = QLineEdit(sender) self.subject_widget = QLineEdit(subject) self.message_widget = QLineEdit(message)

e = Email()

sender = e.sender

e.sender = 'foo'

...

...

Page 16: Python Descriptors Demystified

e = Email()

sender = e.sender

e.sender = 'foo'...

class TextWrapper(object):

def __init__(self, widget_name): self.widget_name = widget_name

def __get__(self, object): widget = getattr(object, self.widget_name) return widget.text()

def __set__(self, object, value): widget = getattr(object, self.widget_name) widget.setText(value)

class Email(object): sender = TextWrapper('sender_widget') subject = TextWrapper('subject_widget') message = TextWrapper('message_widget')

def __init__(self, sender, subject, message): self.sender_widget = QLineEdit(sender) self.subject_widget = QLineEdit(subject) self.message_widget = QLineEdit(message)

Page 17: Python Descriptors Demystified

e = Email()

sender = e.sender

e.sender = 'foo'

class TextWrapper(object):

def __init__(self, widget_name): self.widget_name = widget_name

def __get__(self, object): widget = getattr(object, self.widget_name) return widget.text()

def __set__(self, object, value): widget = getattr(object, self.widget_name) widget.setText(value)

class Email(object): sender = TextWrapper('sender_widget') subject = TextWrapper('subject_widget') message = TextWrapper('message_widget')

def __init__(self, sender, subject, message): self.sender_widget = QLineEdit(sender) self.subject_widget = QLineEdit(subject) self.message_widget = QLineEdit(message)

Page 18: Python Descriptors Demystified

e = Email()

sender = e.sender

e.sender = 'foo'

Nice.

class TextWrapper(object):

def __init__(self, widget_name): self.widget_name = widget_name

def __get__(self, object): widget = getattr(object, self.widget_name) return widget.text()

def __set__(self, object, value): widget = getattr(object, self.widget_name) widget.setText(value)

class Email(object): sender = TextWrapper('sender_widget') subject = TextWrapper('subject_widget') message = TextWrapper('message_widget')

def __init__(self, sender, subject, message): self.sender_widget = QLineEdit(sender) self.subject_widget = QLineEdit(subject) self.message_widget = QLineEdit(message)

Page 19: Python Descriptors Demystified

e = Email()

sender = e.sender

e.sender = 'foo'

Nice.

Nice.

class TextWrapper(object):

def __init__(self, widget_name): self.widget_name = widget_name

def __get__(self, object): widget = getattr(object, self.widget_name) return widget.text()

def __set__(self, object, value): widget = getattr(object, self.widget_name) widget.setText(value)

class Email(object): sender = TextWrapper('sender_widget') subject = TextWrapper('subject_widget') message = TextWrapper('message_widget')

def __init__(self, sender, subject, message): self.sender_widget = QLineEdit(sender) self.subject_widget = QLineEdit(subject) self.message_widget = QLineEdit(message)

Page 20: Python Descriptors Demystified

e = Email()

sender = e.sender

e.sender = 'foo'

Nice.

Nice.

Meh?class TextWrapper(object):

def __init__(self, widget_name): self.widget_name = widget_name

def __get__(self, object): widget = getattr(object, self.widget_name) return widget.text()

def __set__(self, object, value): widget = getattr(object, self.widget_name) widget.setText(value)

class Email(object): sender = TextWrapper('sender_widget') subject = TextWrapper('subject_widget') message = TextWrapper('message_widget')

def __init__(self, sender, subject, message): self.sender_widget = QLineEdit(sender) self.subject_widget = QLineEdit(subject) self.message_widget = QLineEdit(message)

Page 21: Python Descriptors Demystified

Go forth and refactor

Page 22: Python Descriptors Demystified
Page 23: Python Descriptors Demystified

Descriptor

Recipeshttp://epicthings.net/wp-content/uploads/2011/09/Cookie-Monster-Cookie.jpg

Page 24: Python Descriptors Demystified

Instance-specific data

class Foo(object): x = Descriptor()

f1 = Foo()f2 = Foo()

f1.x = 5f2.x = 4

class Descriptor(object):

def __init__(self): self._data = {}

def __get__(self, instance): return self._data[instance]

Page 25: Python Descriptors Demystified

Accessing Descriptor Methods

class Descriptor(object)

def __get__(self, instance): if instance == None: return self

def cool_descriptor_method(self): pass

desc = Foo.x # instance = Nonedesc.cool_descriptor_method()