SlideShare a Scribd company logo
stupid
stupid awesome
stupid awesome python
stupid awesome python tricks
stupid awesome python tricks stupid
stupid awesome python tricks stupid awesome
stupid awesome python tricks stupid awesome python
stupid awesome python tricks stupid awesome python tricks
stupid awesome python tricks stupid awesome python bryan helmig
# python has... oddities
import sys
print >>sys.stdout, 'hello world!'
# hello world!
from __builtin__ import int
# ... uh thanks?
from __builtin__ import True as False
# uh oh...
from __future__ import braces
# ... SyntaxError: not a chance
likes_art = True
# trivia: what am i?
where_to_go = likes_art and 'museum' or 'nascar'
# this is another way to do it...
where_to_go = ('nascar', 'museum')[bool(likes_art)]
# lazily now!
where_to_go = (lambda: 'nascar', lambda: 'museum')[bool(likes_art)]()
# greanevrf - gunax tbq sbe clguba >2.5!
# jure_g_tb = 'zhfrhz' vs yvxrf_neg ryfr 'anfpne'
likes_art = True
# trivia: what am i?
where_to_go = likes_art and 'museum' or 'nascar'
# this is another way to do it...
where_to_go = ('nascar', 'museum')[bool(likes_art)]
# lazily now!
where_to_go = (lambda: 'nascar', lambda: 'museum')[bool(likes_art)]()
# ternaries - thank god for python >2.5!
where_to_go = 'museum' if likes_art else 'nascar'
# str encoding
print 'hello world!'.encode('rot13')
# uryyb jbeyq!
print 'hello world!'.encode('rot13').decode('rot13')
# hello world!
print 'hello world!.'.encode('zlib')
# xx9cxcbHxcdxc9xc9W(xcf/xcaIQT(xc9xc8...
print 'hello world!'.encode('zlib').decode('zlib')
# hello world!
# registering custom str encoding
def register_codec(name, encode=None, decode=None):
import codecs
if not encode:
def encode(val):
raise Exception(name + ' does not support encoding')
if not decode:
def decode(val):
raise Exception(name + ' does not support decoding')
def codec(searched_name):
if searched_name != name:
return None
return codecs.CodecInfo(
name=name, encode=encode, decode=decode)
codecs.register(codec)
# custom "reverser" encoding
def reverser(val):
return val[::-1], len(val)
register_codec('reverser', encode=reverser, decode=reverser)
print 'hello world!'.encode('reverser')
# !dlrow olleh
print 'hello world!'.encode('reverser').decode('reverser')
# hello world!
# custom "hail mary" decoder
def hail_mary_decode(val):
import chardet
result = chardet.detect(val)
return val.decode(result['encoding']), len(val)
register_codec('hail_mary', decode=hail_mary_decode)
print 'xe3x82xabxe3x83xacxe3x83xb3xe3x83x80'.decode('utf-8')
#
print 'xe3x82xabxe3x83xacxe3x83xb3xe3x83x80'.decode('hail_mary')
#
print 'xa5xabxa5xecxa5xf3xa5xc0'.decode('euc_jp')
#
print 'xa5xabxa5xecxa5xf3xa5xc0'.decode('hail_mary')
#
# slicing / indexing / keying
print range(10)[0]
# 0
print range(10)[0:5]
# [0, 1, 2, 3, 4]
print range(10)[::2]
# [0, 2, 4, 6, 8]
print range(10)[::-1]
# [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print dict(hello='world')['hello']
# world
# deep slicing / indexing / keying
class PassThrough(object):
def __getitem__(self, name):
# magic method to return syntax args directly
return name
pass_through = PassThrough()
print pass_through[1]
# 1
print pass_through[1, 2, 3]
# (1, 2, 3)
print pass_through['hello world!']
# hello world!
# slicing gets weird
print pass_through[:]
# slice(None, None, None)
print pass_through[...]
# Ellipsis
print pass_through[..., ..., ..., ...]
# (Ellipsis, Ellipsis, Ellipsis, Ellipsis)
print pass_through[..., :, ...]
# (Ellipsis, slice(None, None, None), Ellipsis)
# abusing slicing
class parens_be_gone(object):
# square brackets are better than parens
def __init__(self, func):
self.func = func
def __getitem__(self, args):
if not isinstance(args, tuple):
args = (args,)
return self.func(*args)
def __call__(self, *a, **kw):
raise Exception('We do not like (), try []?')
# activate slice abuse
@parens_be_gone
def sum_nums(*args):
return sum(args)
@parens_be_gone
def shout_it(name):
return 'HELLO {}!'.format(name.upper())
print sum_nums[1, 2, 3, 4, 5]
# 15
print shout_it['bryan']
# HELLO WORLD!
# magic methods
class Roughly(object):
def __init__(self, num):
self.num = num
def __invert__(self):
return '%d ± 10%' % self.num
print ~Roughly(5)
# 5 ± 10%
# magic methods continued
class DoublePlus(object):
def __init__(self, plusses=0):
self.plusses = plusses
def __pos__(self):
return DoublePlus(self.plusses + 1)
def __repr__(self):
return '%d plusses' % self.plusses
print ++DoublePlus()
# 2 plusses
# complementary magic methods for operators
class Man(object):
def __add__(self, right_other):
if right_other == 'Dog':
return 'best buds'
return self
def __radd__(self, left_other):
if left_other == 'Dog':
return 'bestest buds'
return self
print Man() + 'Dog'
# best buds
print 'Dog' + Man()
# bestest buds
# magic methods to act like you aren't using python
class pipe(object):
def __init__(self, func):
self.func = func
def __ror__(self, other):
return self.func(other)
def __call__(self, *a, **kw):
return pipe(lambda x: self.func(x, *a, **kw))
# magic methods to act like you aren't using python continued
@pipe
def _map(iterable, func):
return [func(i) for i in iterable]
@pipe
def _filter(iterable, func):
return [i for i in iterable if func(i)]
print (range(10)
| _map(lambda i: i * 3)
| _filter(lambda i: i % 2 == 0)
| _map(str))
# ['0', '6', '12', '18', '24']
# magic methods for elegant DSLs
class RegexEquals(object):
def __init__(self, regex):
import re
self.regex = re.compile(regex)
def __eq__(self, other):
return bool(self.regex.match(other))
class TypeEquals(object):
def __init__(self, *tipes):
self.tipes = tipes
def __eq__(self, other):
return isinstance(other, self.tipes)
# magic methods for elegant DSLs continued
URL = RegexEquals(r'(https?|ftp)://[^s/$.?#].[^s]*')
NUM = RegexEquals(r'd+')
INT = TypeEquals(int, long)
print 'larry' == URL
# False
print 'http://zapier.com/' == URL
# True
print '123' == NUM
# True
print {'url': 'http://zapier.com/', 'visits': 4} == {'url': URL, 'visits': INT}
# True
# magic methods for abuse
class DidYouMean(object):
def __getattr__(self, name):
if name.startswith('__'):
raise AttributeError('No magic did you mean.')
from difflib import SequenceMatcher
scored_attrs = [
(SequenceMatcher(None, name, attr).ratio(), attr)
for attr in dir(self) if not attr.startswith('__')
]
sorted_attrs = sorted([
(score, attr) for score, attr in scored_attrs if score > 0.5
], reverse=True)
best_name = next(iter(sorted_attrs), (None, None))[1]
if not best_name:
raise AttributeError('No "matching" `%s` attribute' % name)
return getattr(self, best_name)
# activate magic methods abuse
class SomeModel(DidYouMean):
first_name = 'bryan'
last_name = 'helmig'
person = SomeModel()
print person.first_name
# bryan
print person.furst_name
# bryan
print person.address
# .. AttributeError: No "matching" `address` attribute
# magic methods for evil
class specialint(int):
def __add__(self, right_other):
if self == 1 and right_other == 1:
return 3
return super(specialint, self).__add__(right_other)
print specialint(1) + 1
# 3
__builtins__.int = specialint
print int(1) + 1
# 3
print 1 + 1
# 2
# literals get coerced way before builtins are referenced... ¯_( )_/¯
# https://benkurtovic.com/2015/01/28/python-object-replacement.html
# http://blaag.haard.se/Using-the-AST-to-hack-constants-into-Python/
# ast / parser
import parser
tree = parser.expr('(a + 1) or {1: "test"}').tolist()
print tree
# [258, [327, [312, [313, [314, [315, [316, [317, [318, [7, '('] ..
# [ ... [3, '"test"'], [27, '}']], [4, ''], ...]
def recurse(val):
import token
if isinstance(val, int):
return token.tok_name.get(val, val)
elif isinstance(val, list):
return [recurse(v) for v in val]
return val
print recurse(tree)
# [258, [327, [312, [313, [314, [315, [316, [317, [318, [7, '('] ..
# [ ... ['STRING', '"test"'], ['RBRACE', '}']], ['NEWLINE', ''], ...]
# ast tools can be repurposed and practical
def pyson(val):
# JSON is lame. Eval is lame.
import ast
return ast.literal_eval(val)
print pyson('"hello world!"')
# hello world!
print pyson("{1234: 'integer keys!'}")
# {1234: 'integer keys!''}
print pyson('import json')
# ... SyntaxError: invalid syntax
# mini lisp calc
def tokenize(program):
return program.replace('(', ' ( ').replace(')', ' ) ').split()
def reshape_tokens(tokens):
token = tokens.pop(0)
if '(' == token:
deep_tokens = []
while tokens[0] != ')':
deep_tokens.append(reshape_tokens(tokens))
tokens.pop(0)
return deep_tokens
try: return int(token)
except: return token
program = '(* 2 (+ 3 5))'
print tokenize(program)
# ['(', '*', '2', '(', '+', '3', '5', ')', ')']
print reshape_tokens(tokenize(program))
# ['*', 2, ['+', 3, 5]]
# mini lisp calc continued
import operator
global_env = {'+': operator.add, '-': operator.sub,
'*': operator.mul, '/': operator.div}
def evaluate(tokens, env=global_env.copy()):
if isinstance(tokens, basestring) and tokens in env:
return env[tokens]
elif not isinstance(tokens, list):
return tokens
else:
func = evaluate(tokens[0], env)
args = [evaluate(arg, env) for arg in tokens[1:]]
return func(*args)
program = '(* 2 (+ 3 5))'
print evaluate(read_tokens(tokenize(program)))
# 16
# http://norvig.com/lispy.html & http://norvig.com/lispy2.html

More Related Content

PDF
Imugi: Compiler made with Python
PDF
Advanced python
PDF
ES6 - Next Generation Javascript
PDF
NativeBoost
KEY
Exhibition of Atrocity
PDF
C++ L01-Variables
PDF
The Vanishing Pattern: from iterators to generators in Python
PDF
An Intro To ES6
Imugi: Compiler made with Python
Advanced python
ES6 - Next Generation Javascript
NativeBoost
Exhibition of Atrocity
C++ L01-Variables
The Vanishing Pattern: from iterators to generators in Python
An Intro To ES6

What's hot (20)

PPTX
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
PDF
ECMAScript 6
PDF
C++ L05-Functions
PPTX
Academy PRO: ES2015
PPT
Advance features of C++
TXT
Advance C++notes
PPTX
ES6 Overview
PDF
C++ L08-Classes Part1
PPTX
EcmaScript unchained
PDF
Advanced Python, Part 2
PDF
ES6 - Level up your JavaScript Skills
PDF
JavaScript ES6
PDF
C++ game development with oxygine
PPT
ODP
EcmaScript 6
PDF
Arduino coding class
PDF
EcmaScript 6 - The future is here
PPT
C++totural file
PPTX
Dynamic memory allocation
PDF
ES2015 (ES6) Overview
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
ECMAScript 6
C++ L05-Functions
Academy PRO: ES2015
Advance features of C++
Advance C++notes
ES6 Overview
C++ L08-Classes Part1
EcmaScript unchained
Advanced Python, Part 2
ES6 - Level up your JavaScript Skills
JavaScript ES6
C++ game development with oxygine
EcmaScript 6
Arduino coding class
EcmaScript 6 - The future is here
C++totural file
Dynamic memory allocation
ES2015 (ES6) Overview
Ad

Viewers also liked (20)

PPTX
Ag pres sopac_contestability_public_sector_business_model_of_the_future_march...
PDF
Raa taltree presentation
PDF
2005 Cuban Tourism Presentation "Making up for lost time"
PPT
Kateeeeeeeeeeeeeeeeeeeee
PDF
PNG : A Million Different Journeys
DOC
Paratirisymperasmata
PPTX
Ag pres cpa public_sector leaders_series_luncheon_june_27_2014
PPT
FMSEA 2012 generic slides
PPTX
Payforit4 training jul13
PPTX
Lets get rocked
PPTX
Alimentos elaborados
PDF
Alcohol and other drugs procedure[1]
PPTX
エンディングノートとは?
PDF
Edlt116 learners and teaching assignment 2 e portfolio
PPTX
Edss223 assignment 2
PDF
Engl001 assignment 1
PPT
Dust bowl
PPT
Dust bowl
PPTX
Lets get rocked
DOC
Δραστηριότητες
Ag pres sopac_contestability_public_sector_business_model_of_the_future_march...
Raa taltree presentation
2005 Cuban Tourism Presentation "Making up for lost time"
Kateeeeeeeeeeeeeeeeeeeee
PNG : A Million Different Journeys
Paratirisymperasmata
Ag pres cpa public_sector leaders_series_luncheon_june_27_2014
FMSEA 2012 generic slides
Payforit4 training jul13
Lets get rocked
Alimentos elaborados
Alcohol and other drugs procedure[1]
エンディングノートとは?
Edlt116 learners and teaching assignment 2 e portfolio
Edss223 assignment 2
Engl001 assignment 1
Dust bowl
Dust bowl
Lets get rocked
Δραστηριότητες
Ad

Similar to Stupid Awesome Python Tricks (20)

PDF
Building Interpreters with PyPy
PDF
Python 2.5 reference card (2009)
PPT
Python 3000
PDF
Snakes for Camels
PDF
KEY
Charming python
PDF
Python Usage (5-minute-summary)
PDF
Python Part 1
PDF
Intro to Python
PDF
A tour of Python
PDF
An overview of Python 2.7
PPTX
Python Workshop - Learn Python the Hard Way
PPT
python within 50 page .ppt
PPT
Os Vanrossum
PDF
A Taste of Python - Devdays Toronto 2009
ODP
Why Python by Marilyn Davis, Marakana
PDF
pa-pe-pi-po-pure Python Text Processing
PDF
Python Cheat Sheet
PDF
Python for PHP developers
PDF
Python: The Dynamic!
Building Interpreters with PyPy
Python 2.5 reference card (2009)
Python 3000
Snakes for Camels
Charming python
Python Usage (5-minute-summary)
Python Part 1
Intro to Python
A tour of Python
An overview of Python 2.7
Python Workshop - Learn Python the Hard Way
python within 50 page .ppt
Os Vanrossum
A Taste of Python - Devdays Toronto 2009
Why Python by Marilyn Davis, Marakana
pa-pe-pi-po-pure Python Text Processing
Python Cheat Sheet
Python for PHP developers
Python: The Dynamic!

Recently uploaded (20)

PDF
PRIZ Academy - 9 Windows Thinking Where to Invest Today to Win Tomorrow.pdf
PPT
Mechanical Engineering MATERIALS Selection
PPTX
Recipes for Real Time Voice AI WebRTC, SLMs and Open Source Software.pptx
PPTX
CARTOGRAPHY AND GEOINFORMATION VISUALIZATION chapter1 NPTE (2).pptx
PDF
Well-logging-methods_new................
PDF
Embodied AI: Ushering in the Next Era of Intelligent Systems
PPTX
M Tech Sem 1 Civil Engineering Environmental Sciences.pptx
PDF
Model Code of Practice - Construction Work - 21102022 .pdf
PDF
Digital Logic Computer Design lecture notes
PPTX
Foundation to blockchain - A guide to Blockchain Tech
PPTX
Engineering Ethics, Safety and Environment [Autosaved] (1).pptx
PDF
composite construction of structures.pdf
PPTX
Strings in CPP - Strings in C++ are sequences of characters used to store and...
PPTX
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
PPTX
web development for engineering and engineering
PPTX
CYBER-CRIMES AND SECURITY A guide to understanding
PPTX
Geodesy 1.pptx...............................................
PPTX
OOP with Java - Java Introduction (Basics)
PDF
Operating System & Kernel Study Guide-1 - converted.pdf
PDF
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
PRIZ Academy - 9 Windows Thinking Where to Invest Today to Win Tomorrow.pdf
Mechanical Engineering MATERIALS Selection
Recipes for Real Time Voice AI WebRTC, SLMs and Open Source Software.pptx
CARTOGRAPHY AND GEOINFORMATION VISUALIZATION chapter1 NPTE (2).pptx
Well-logging-methods_new................
Embodied AI: Ushering in the Next Era of Intelligent Systems
M Tech Sem 1 Civil Engineering Environmental Sciences.pptx
Model Code of Practice - Construction Work - 21102022 .pdf
Digital Logic Computer Design lecture notes
Foundation to blockchain - A guide to Blockchain Tech
Engineering Ethics, Safety and Environment [Autosaved] (1).pptx
composite construction of structures.pdf
Strings in CPP - Strings in C++ are sequences of characters used to store and...
FINAL REVIEW FOR COPD DIANOSIS FOR PULMONARY DISEASE.pptx
web development for engineering and engineering
CYBER-CRIMES AND SECURITY A guide to understanding
Geodesy 1.pptx...............................................
OOP with Java - Java Introduction (Basics)
Operating System & Kernel Study Guide-1 - converted.pdf
keyrequirementskkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk

Stupid Awesome Python Tricks

  • 1. stupid stupid awesome stupid awesome python stupid awesome python tricks stupid awesome python tricks stupid stupid awesome python tricks stupid awesome stupid awesome python tricks stupid awesome python stupid awesome python tricks stupid awesome python tricks stupid awesome python tricks stupid awesome python bryan helmig
  • 2. # python has... oddities import sys print >>sys.stdout, 'hello world!' # hello world! from __builtin__ import int # ... uh thanks? from __builtin__ import True as False # uh oh... from __future__ import braces # ... SyntaxError: not a chance
  • 3. likes_art = True # trivia: what am i? where_to_go = likes_art and 'museum' or 'nascar' # this is another way to do it... where_to_go = ('nascar', 'museum')[bool(likes_art)] # lazily now! where_to_go = (lambda: 'nascar', lambda: 'museum')[bool(likes_art)]() # greanevrf - gunax tbq sbe clguba >2.5! # jure_g_tb = 'zhfrhz' vs yvxrf_neg ryfr 'anfpne'
  • 4. likes_art = True # trivia: what am i? where_to_go = likes_art and 'museum' or 'nascar' # this is another way to do it... where_to_go = ('nascar', 'museum')[bool(likes_art)] # lazily now! where_to_go = (lambda: 'nascar', lambda: 'museum')[bool(likes_art)]() # ternaries - thank god for python >2.5! where_to_go = 'museum' if likes_art else 'nascar'
  • 5. # str encoding print 'hello world!'.encode('rot13') # uryyb jbeyq! print 'hello world!'.encode('rot13').decode('rot13') # hello world! print 'hello world!.'.encode('zlib') # xx9cxcbHxcdxc9xc9W(xcf/xcaIQT(xc9xc8... print 'hello world!'.encode('zlib').decode('zlib') # hello world!
  • 6. # registering custom str encoding def register_codec(name, encode=None, decode=None): import codecs if not encode: def encode(val): raise Exception(name + ' does not support encoding') if not decode: def decode(val): raise Exception(name + ' does not support decoding') def codec(searched_name): if searched_name != name: return None return codecs.CodecInfo( name=name, encode=encode, decode=decode) codecs.register(codec)
  • 7. # custom "reverser" encoding def reverser(val): return val[::-1], len(val) register_codec('reverser', encode=reverser, decode=reverser) print 'hello world!'.encode('reverser') # !dlrow olleh print 'hello world!'.encode('reverser').decode('reverser') # hello world!
  • 8. # custom "hail mary" decoder def hail_mary_decode(val): import chardet result = chardet.detect(val) return val.decode(result['encoding']), len(val) register_codec('hail_mary', decode=hail_mary_decode) print 'xe3x82xabxe3x83xacxe3x83xb3xe3x83x80'.decode('utf-8') # print 'xe3x82xabxe3x83xacxe3x83xb3xe3x83x80'.decode('hail_mary') # print 'xa5xabxa5xecxa5xf3xa5xc0'.decode('euc_jp') # print 'xa5xabxa5xecxa5xf3xa5xc0'.decode('hail_mary') #
  • 9. # slicing / indexing / keying print range(10)[0] # 0 print range(10)[0:5] # [0, 1, 2, 3, 4] print range(10)[::2] # [0, 2, 4, 6, 8] print range(10)[::-1] # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] print dict(hello='world')['hello'] # world
  • 10. # deep slicing / indexing / keying class PassThrough(object): def __getitem__(self, name): # magic method to return syntax args directly return name pass_through = PassThrough() print pass_through[1] # 1 print pass_through[1, 2, 3] # (1, 2, 3) print pass_through['hello world!'] # hello world!
  • 11. # slicing gets weird print pass_through[:] # slice(None, None, None) print pass_through[...] # Ellipsis print pass_through[..., ..., ..., ...] # (Ellipsis, Ellipsis, Ellipsis, Ellipsis) print pass_through[..., :, ...] # (Ellipsis, slice(None, None, None), Ellipsis)
  • 12. # abusing slicing class parens_be_gone(object): # square brackets are better than parens def __init__(self, func): self.func = func def __getitem__(self, args): if not isinstance(args, tuple): args = (args,) return self.func(*args) def __call__(self, *a, **kw): raise Exception('We do not like (), try []?')
  • 13. # activate slice abuse @parens_be_gone def sum_nums(*args): return sum(args) @parens_be_gone def shout_it(name): return 'HELLO {}!'.format(name.upper()) print sum_nums[1, 2, 3, 4, 5] # 15 print shout_it['bryan'] # HELLO WORLD!
  • 14. # magic methods class Roughly(object): def __init__(self, num): self.num = num def __invert__(self): return '%d ± 10%' % self.num print ~Roughly(5) # 5 ± 10%
  • 15. # magic methods continued class DoublePlus(object): def __init__(self, plusses=0): self.plusses = plusses def __pos__(self): return DoublePlus(self.plusses + 1) def __repr__(self): return '%d plusses' % self.plusses print ++DoublePlus() # 2 plusses
  • 16. # complementary magic methods for operators class Man(object): def __add__(self, right_other): if right_other == 'Dog': return 'best buds' return self def __radd__(self, left_other): if left_other == 'Dog': return 'bestest buds' return self print Man() + 'Dog' # best buds print 'Dog' + Man() # bestest buds
  • 17. # magic methods to act like you aren't using python class pipe(object): def __init__(self, func): self.func = func def __ror__(self, other): return self.func(other) def __call__(self, *a, **kw): return pipe(lambda x: self.func(x, *a, **kw))
  • 18. # magic methods to act like you aren't using python continued @pipe def _map(iterable, func): return [func(i) for i in iterable] @pipe def _filter(iterable, func): return [i for i in iterable if func(i)] print (range(10) | _map(lambda i: i * 3) | _filter(lambda i: i % 2 == 0) | _map(str)) # ['0', '6', '12', '18', '24']
  • 19. # magic methods for elegant DSLs class RegexEquals(object): def __init__(self, regex): import re self.regex = re.compile(regex) def __eq__(self, other): return bool(self.regex.match(other)) class TypeEquals(object): def __init__(self, *tipes): self.tipes = tipes def __eq__(self, other): return isinstance(other, self.tipes)
  • 20. # magic methods for elegant DSLs continued URL = RegexEquals(r'(https?|ftp)://[^s/$.?#].[^s]*') NUM = RegexEquals(r'd+') INT = TypeEquals(int, long) print 'larry' == URL # False print 'http://zapier.com/' == URL # True print '123' == NUM # True print {'url': 'http://zapier.com/', 'visits': 4} == {'url': URL, 'visits': INT} # True
  • 21. # magic methods for abuse class DidYouMean(object): def __getattr__(self, name): if name.startswith('__'): raise AttributeError('No magic did you mean.') from difflib import SequenceMatcher scored_attrs = [ (SequenceMatcher(None, name, attr).ratio(), attr) for attr in dir(self) if not attr.startswith('__') ] sorted_attrs = sorted([ (score, attr) for score, attr in scored_attrs if score > 0.5 ], reverse=True) best_name = next(iter(sorted_attrs), (None, None))[1] if not best_name: raise AttributeError('No "matching" `%s` attribute' % name) return getattr(self, best_name)
  • 22. # activate magic methods abuse class SomeModel(DidYouMean): first_name = 'bryan' last_name = 'helmig' person = SomeModel() print person.first_name # bryan print person.furst_name # bryan print person.address # .. AttributeError: No "matching" `address` attribute
  • 23. # magic methods for evil class specialint(int): def __add__(self, right_other): if self == 1 and right_other == 1: return 3 return super(specialint, self).__add__(right_other) print specialint(1) + 1 # 3 __builtins__.int = specialint print int(1) + 1 # 3 print 1 + 1 # 2 # literals get coerced way before builtins are referenced... ¯_( )_/¯ # https://benkurtovic.com/2015/01/28/python-object-replacement.html # http://blaag.haard.se/Using-the-AST-to-hack-constants-into-Python/
  • 24. # ast / parser import parser tree = parser.expr('(a + 1) or {1: "test"}').tolist() print tree # [258, [327, [312, [313, [314, [315, [316, [317, [318, [7, '('] .. # [ ... [3, '"test"'], [27, '}']], [4, ''], ...] def recurse(val): import token if isinstance(val, int): return token.tok_name.get(val, val) elif isinstance(val, list): return [recurse(v) for v in val] return val print recurse(tree) # [258, [327, [312, [313, [314, [315, [316, [317, [318, [7, '('] .. # [ ... ['STRING', '"test"'], ['RBRACE', '}']], ['NEWLINE', ''], ...]
  • 25. # ast tools can be repurposed and practical def pyson(val): # JSON is lame. Eval is lame. import ast return ast.literal_eval(val) print pyson('"hello world!"') # hello world! print pyson("{1234: 'integer keys!'}") # {1234: 'integer keys!''} print pyson('import json') # ... SyntaxError: invalid syntax
  • 26. # mini lisp calc def tokenize(program): return program.replace('(', ' ( ').replace(')', ' ) ').split() def reshape_tokens(tokens): token = tokens.pop(0) if '(' == token: deep_tokens = [] while tokens[0] != ')': deep_tokens.append(reshape_tokens(tokens)) tokens.pop(0) return deep_tokens try: return int(token) except: return token program = '(* 2 (+ 3 5))' print tokenize(program) # ['(', '*', '2', '(', '+', '3', '5', ')', ')'] print reshape_tokens(tokenize(program)) # ['*', 2, ['+', 3, 5]]
  • 27. # mini lisp calc continued import operator global_env = {'+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.div} def evaluate(tokens, env=global_env.copy()): if isinstance(tokens, basestring) and tokens in env: return env[tokens] elif not isinstance(tokens, list): return tokens else: func = evaluate(tokens[0], env) args = [evaluate(arg, env) for arg in tokens[1:]] return func(*args) program = '(* 2 (+ 3 5))' print evaluate(read_tokens(tokenize(program))) # 16 # http://norvig.com/lispy.html & http://norvig.com/lispy2.html