using and abusing magic methods in python
TRANSCRIPT
![Page 1: Using and Abusing Magic methods in Python](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/1.jpg)
USING (AND ABUSING) PYTHON'S MAGIC METHODS
TO REDUCE GOO CODE
![Page 2: Using and Abusing Magic methods in Python](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/2.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/3.jpg)
PART 1: USING MAGIC METHODS
![Page 4: Using and Abusing Magic methods in Python](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/4.jpg)
YOU CAN’T CONTROL ACCESS TO ATTRIBUTES IN
PYTHON
![Page 5: Using and Abusing Magic methods in Python](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/5.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/6.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/7.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/8.jpg)
PART 2: (AB)USING MAGIC METHODS
![Page 9: Using and Abusing Magic methods in Python](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/9.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/10.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/11.jpg)
PART 3: ABUSING MAGIC METHODS
![Page 12: Using and Abusing Magic methods in Python](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/12.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/13.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/14.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/15.jpg)
PART 4: HERE THERE BE DRAGONS
![Page 16: Using and Abusing Magic methods in Python](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/16.jpg)
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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/17.jpg)
>>> 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](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/18.jpg)
MAGIC METHODS ARE EXTREMELY POWERFUL, BUT
REMEMBER:
![Page 19: Using and Abusing Magic methods in Python](https://reader030.vdocuments.us/reader030/viewer/2022020301/58703d541a28ab4e2c8b55e5/html5/thumbnails/19.jpg)
ALWAYS CODE AS IF THE PERSON WHO ENDS UP
MAINTAINING YOUR CODE IS A VIOLENT PSYCHOPATH WHO
KNOWS WHERE YOU LIVE.— Jeff Atwood