Top Banner
USING (AND ABUSING) PYTHON'S MAGIC METHODS TO REDUCE GOO CODE
19

Using and Abusing Magic methods in Python

Apr 16, 2017

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Using and Abusing Magic methods in Python

USING (AND ABUSING) PYTHON'S MAGIC METHODS

TO REDUCE GOO CODE

Page 2: Using and Abusing Magic methods in Python

WHO AM I?

• Work at indico (small local company)

• Previously at Olin College, Pearson, edX, fetchnotes, and freelance work

• Semi-retired SO & quora user

• Love playing with the dirty little secrets of python

Page 3: Using and Abusing Magic methods in Python

PART 1: USING MAGIC METHODS

Page 4: Using and Abusing Magic methods in Python

YOU CAN’T CONTROL ACCESS TO ATTRIBUTES IN

PYTHON

Page 5: Using and Abusing Magic methods in Python

class MutableObject(object): def __init__(self, a): self.a = a

>>> test = MutableObject("one") >>> test.a = "two"

NORMAL PYTHON ATTRIBUTES

Page 6: Using and Abusing Magic methods in Python

class MutableObject(object): def __init__(self, a): self._a = a

>>> test = MutableObject("one") >>> test._a = "two" # Feels Wrong

TELLING OTHER USERS NOT TO TOUCH YOUR ATTRIBUTES

Page 7: Using and Abusing Magic methods in Python

class StubbornObject(object):

def __setattr__(self, key, value): if hasattr(self, key): raise ValueError(“Already set in my ways") else: object.__setattr__(self, key, value)

>>> test = StubbornObject() >>> test.a = "one" >>> test.a = “two” # Now actually errors

ACTUALLY STOPPING PEOPLE FROM TOUCHING YOUR ATTRIBUTES

Page 8: Using and Abusing Magic methods in Python

PART 2: (AB)USING MAGIC METHODS

Page 9: Using and Abusing Magic methods in Python

results = my_object.attribute if not isinstance(results, list): results = list(results) # Do Something

EVER WRITTEN CODE LIKE THIS?

Page 10: Using and Abusing Magic methods in Python

class ChangelingObject(object): list_fields = {"a", "b", "c"}

def __setattr__(self, key, value): if key in self.list_fields: value = [value] object.__setattr__(self, key, value)

>>> test = ChangelingObject() >>> test.a = 1 >>> print test.a [1]

NEVER AGAIN WITH SPECIAL PYTHON MAGIC

Page 11: Using and Abusing Magic methods in Python

PART 3: ABUSING MAGIC METHODS

Page 12: Using and Abusing Magic methods in Python

def add_money(user_id, amount): session = Session() user_object = session.query(User).filter_by(id=user_id).first()

current_value = user_object.balance try: user_object.balance = current_value + amount session.commit() except ORMException: session.rollback

Page 13: Using and Abusing Magic methods in Python

class User(object): # Standard ORM stuff

def __iadd__(self, other): current = user_object.balance try: user_object.balance = current + other session.commit() except ORMException: session.rollback()

Page 14: Using and Abusing Magic methods in Python

def add_money(user_id, amount): session = Session() user_object = session.query(User).filter_by(id=user_id).first() user_object += amount

SHORT CODE, BUT AT WHAT COST?

Page 15: Using and Abusing Magic methods in Python

PART 4: HERE THERE BE DRAGONS

Page 16: Using and Abusing Magic methods in Python

class Food(object): recipes = { frozenset({"flour", "water"}): "dough", frozenset({"dough", "yeast"}): "bread", frozenset({"avocado", "onion"}): "guac", frozenset({"guac", "bread"}): "tasty snack" }

def __init__(self, ingredient): self.name = ingredient

def _mix(self, second): current_pantry = frozenset({self.name, second.name}) try: return self.recipes[current_pantry] except KeyError: raise ValueError("%s and %s don't mix, trust me" % (self.name, second.name))

def __add__(self, other): return Food(self._mix(other))

def __iadd__(self, other): self.name = self._mix(other)

def __repr__(self): return self.name

Page 17: Using and Abusing Magic methods in Python

>>> step_one = Food("flour") + Food("water") + Food("yeast") >>> step_two = Food("avocado") + Food("onion") >>> print step_one + step_two tasty snack

PLEASE NEVER ACTUALLY DO THIS

Page 18: Using and Abusing Magic methods in Python

MAGIC METHODS ARE EXTREMELY POWERFUL, BUT

REMEMBER:

Page 19: Using and Abusing Magic methods in Python

ALWAYS CODE AS IF THE PERSON WHO ENDS UP

MAINTAINING YOUR CODE IS A VIOLENT PSYCHOPATH WHO

KNOWS WHERE YOU LIVE.— Jeff Atwood