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

Using and Abusing Magic methods in Python

Embed Size (px)

Citation preview

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