10 tips for writing pythonic code by michael kennedy

22
10 Tips for Pythonic Code Michael Kennedy talkpython.com @mkennedy

Upload: michael-kennedy

Post on 16-Apr-2017

337 views

Category:

Software


2 download

TRANSCRIPT

10 Tips for Pythonic Code

Michael Kennedytalkpython.com

@mkennedy

Topics1. Dictionaries for performance2. __slots__3. Merge dicts4. yield and generator methods5. lambda expressions6. adding iteration to custom types7. comprehensions and expressions8. json back and forth (files and web services)9. slicing (collections and databases)10. yield + recursion

Who decides what is Pythonic?

The community

Who decides what is Pythonic?

Python core developers + Tim Peters

Who decides what is Pythonic?

PEP 8 Style Guide

The 10 examples

1. Dictionary for performance

data_list = [ ... ] # len = 500,000 itemsinteresting_points = [ ... ] # len = 100 itemsfor i in interesting_ids:

pt = find_point_by_id_in_list(data_list, i)interesting_points.append(pt)

data_lookup = dict( ... ) # len = 500,000 itemsinteresting_points = [ ... ] # len = 100 itemsfor i in interesting_ids:

pt = data_lookup[i]interesting_points.append(pt)

What is the relative performance of these two algorithms?

2. Memory efficiency with slots

Saving 9 GB of RAM with Python’s __slots__http://tech.oyster.com/save-ram-with-python-slots/

2. Memory efficiency with slots

class ImmutableThing:__slots__ = ['a', 'b', 'c']

def __init__(self, a, b, c):self.a = aself.b = bself.c = c

Defining __slots__ restricts values allowed in type but removes per instance dictionary backing story.

Special cases aren't special enough to break the rules.Although practicality beats purity.

3. Merging dictionaries

route = {'id': 271, 'title': 'Fast apps'}query = {'id': 1, 'render_fast': True}post = {'email': '[email protected]', 'name': 'Jeff'}

# Non-pythonic procedural waym1 = {}for k in query:

m1[k] = query[k]for k in post:

m1[k] = post[k]for k in route:

m1[k] = route[k]

3. Merging dictionaries

route = {'id': 271, 'title': 'Fast apps'}query = {'id': 1, 'render_fast': True}post = {'email': '[email protected]', 'name': 'Jeff'}

m1 = {**query, **post, **route}

Py3

4. Generators with yield

def classic_fibonacci(limit):nums = []current, nxt = 0, 1

while current < limit:current, nxt = nxt, nxt + currentnums.append(current)

return nums

4. Generators with yield

def fibonacci_generator():current, nxt = 0, 1while True:

current, nxt = nxt, nxt + currentyield current

5. Passing function expressions

def find_special_numbers(special_selector, limit=10):found = []n = 0while len(found) < limit:

if special_selector(n):found.append(n)

n += 1return found

find_special_numbers(lambda x: x % 6 == 0)

6. Adding custom iterationclass ShoppingCart:

def __init__(self):self.items = []

def add_item(self, it):self.items.append(it)

def __iter__(self):for it in sorted(self.items, key=lambda i: i.price):

yield it

cart = ShoppingCart()cart.add_item(CartItem("guitar", 799))cart.add_item(CartItem("cd", 19))cart.add_item(CartItem("iPhone", 699))

for item in cart:print('{} for ${}'.format(item.name, item.price))

7. Comprehensions everywhere

# direct loop stylehigh_measurements = []for m in measurements:

if m.value >= 70:high_measurements.append(m.value)

7. Comprehensions everywhere

# generator stylehigh_measurements = (

m.valuefor m in measurementsif m.value >= 70

)

8. JSON to dictionaries and back

movie_json = """{

"Title":"Johnny 5","Year":"2001","Runtime":"119 min","Country":"USA"

}"""

movie_data = json.loads(movie_json)# movie_data is a dict

movie_json2 = json.dumps(movie_data)# movie_json2 is a str

9. Slicingnums = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 ]

num_2_to_7 = nums[2:8]# num_2_to_7 = [2, 3, 5, 8, 13, 21]

num_last_3 = nums[-3:]# num_last_3 = [89, 144, 233]

10. yield fromdef get_files(folder):

for item in os.listdir(folder):full_item = os.path.join(folder, item)

if os.path.isfile(full_item):yield full_item

elif os.path.isdir(full_item):yield from get_files(full_item)

Py3

Source code

https://github.com/mikeckennedy/ten-tips-for-pythonic-code-jetbrains-webcast

talkpython.fm

Want to go deeper?

training.talkpython.fm

[email protected]

@mkennedy