0% found this document useful (0 votes)
103 views11 pages

Python Best Practice Patterns by Vladimir Keleshev (Notes)

Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

Uploaded by

Mingyu Liu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
103 views11 pages

Python Best Practice Patterns by Vladimir Keleshev (Notes)

Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

Uploaded by

Mingyu Liu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.

com

stevenloria.com about projects scribbles

Python Best Practice Patterns by Vladimir


Keleshev (Notes)
May 09, 2013

These are my notes from Vladimir Keleshev's talk en tled "Python Best
Prac ce Pa erns", given on May , at the Python Meetup in
Denmark. The original video is here (about minutes long).

Note: Some of the code examples have been has been modi ed from the original
presenta on based on readers' feedback.

Composed method
• Divide program into methods that perform one task
• Keep all opera on in a method at the same level of abstrac on

• Use many methods only a few lines long

• Di erent levels of abstrac on: bitmaps, lesystem opera ons, playing sounds...

1 # Better
2 class Boiler:
3 def safety_check(self):
4 if any([self.temperature > MAX_TEMPERATURE,
5 self.pressure > MAX_PRESSURE]):
6 if not self.shutdown():
7 self.alarm()
8
9 def alarm(self):
10 with open(BUZZER_MP3_FILE) as f:
11 play_sound(f.read())
12
13 @property
14 def pressure(self):
15 pressure_psi = abb_f100.register / F100_FACTOR
16 return psi_to_pascal(pressure_psi)
17 ...

https://stevenloria.com/python-best-practice/ 1/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

• safety_check deals with temp and pressure


• alarm deals with les and sound
• pressure deals with bits and conver ng them

Constructor method
• provide constructors that create well-formed instances
• Pass all required parameters to them
1 # At initiation `point` is not well-formed
2 point = Point()
3 point.x = 12
4 point.y = 5
5
6 # Better
7 point = Point(x=12, y=5)

• Can use class methods to make mul ple constructors


• Example: Using Cartesian or polar coordinates
1 class Point:
2 def __init__(self, x, y):
3 self.x, self.y = x, y
4
5 @classmethod
6 def polar(cls, r, theta):
7 return cls(r * cos(theta),
8 r * sin(theta))
9
10 point = Point.polar(r=13, theta=22.6)

Method objects
• How do you code a method where many lines of code share many arguments and
temporary variables?
1 def send_task(self, task, job, obligation):
2 ...
3 processed = ...
4 ...
https://stevenloria.com/python-best-practice/ 2/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

5 copied = ...
6 ...
7 executed = ...
8 100 more lines

• Can't be solved by making many small methods (would use more code)
1 class TaskSender:
2 def __init__(self, task, job obligation):
3 self.task = task
4 self.job = job
5 self.obligation = obligation
6 self.processed = []
7 self.copied = []
8 self.executed = []
9
10 def __call__(self):
11 self.prepare()
12 self.process()
13 self.execute()
14 ...

Execute around method (in Python: Context manager)


• How do you represent pairs of ac ons that should be taken together?
1 f = open('file.txt', 'w')
2 f.write('hi')
3 f.close()
4
5 # Better
6 with open('file.txt', 'w') as f:
7 f.write('hi')
8
9 with pytest.raises(ValueError):
10 int('hi')
11
12 with SomeProtocol(host, port) as protocol:
13 protocol.send(['get', signal])
14 result = protocol.receive()
15
16 class SomeProtocol:
https://stevenloria.com/python-best-practice/ 3/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

17 def __init__(self, host, port):


18 self.host, self.port = host, port
19
20 def __enter__(self):
21 self._client = socket()
22 self._client.connect((self.host,
23 self.port))
24
25 def __exit__(self, exception, value, traceback):
26 self._client.close()
27
28 def send(self, payload): ...
29
30 def receive(self): ...

Debug printing method


• __str__ for users
• e.g. print(point)
• __repr__ for debugging/interac ve mode

Method comment
• small methods can be more e ec ve than comments
1 if self.flags & 0b1000: # Am I visible?
2 ...
3
4 # Better
5 ...
6 @property
7 def is_visible(self):
8 return self.flags & 0b1000
9
10 if self.is_visible:
11 ...

Choosing message
1 # Bad
2 if type(entry) is Film:

https://stevenloria.com/python-best-practice/ 4/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

3 responsible = entry.producer
4 else:
5 responsible = entry.author
6
7 # Shouldn't use type() or isinstance() in conditional --> smelly
8
9 # Better
10 class Film:
11 ...
12 @property
13 def responsible(self):
14 return self.producer
15
16 entry.responsible

Intention revealing message


• How do you communicate your intent when implementa on is simple?
• Use for methods that do the same thing (for readability)
1 class ParagraphEditor:
2 ...
3 def highlight(self, rectangle):
4 self.reverse(rectangle)
5
6 # Better
7 class ParagraphEditor:
8 ...
9 highlight = reverse # More readable, more composable

Constant method (constant class variable)


1 _DEFAULT_PORT = 1234
2
3 class SomeProtocol:
4 ...
5 def __enter__(self):
6 self._client = socket()
7 self._client.connect(
8 (self.host,
9 self.port or _DEFAULT_PORT)
https://stevenloria.com/python-best-practice/ 5/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

10 )
11 return self
12
13 # If you want to subclass SomeProtocol, you would have to overwrite every m
14
15 # Better
16 class SomeProtocol:
17 _default_port = 1234
18 ...
19 def __enter__(self):
20 self._client = socket()
21 self._client.connect(
22 (self.host,
23 self.port or self._default_port))

• Depends if you are designing to make your class subclassable

Direct and indirect variable access


• Direct
• no need for ge ers and se ers
1 class Point:
2 def __init__(self, x, y):
3 self.x, self.y = x, y
4
5 # Sometimes need more flexibility --> use properties
6
7 class Point:
8 def __init__(self, x, y):
9 self._x, self._y = x, y
10
11 @property
12 def x(self):
13 return self._x
14
15 @x.setter
16 def x(self, value):
17 self._x = value

https://stevenloria.com/python-best-practice/ 6/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

Enumeration (iteration) method


1 # Bad
2 # Can't change type of collection
3 # e.g. can't change employees from a list to a set
4 class Department:
5 def __init__(self, *employees):
6 self.employees = employees
7
8 for employee in department.employees:
9 ...
10
11 # Better
12 class Department:
13 def __init__(self, *employees):
14 self._employees = employees
15
16 def __iter__(self):
17 return iter(self._employees)
18
19 for employee in department: # More readable, more composable
20 ...
21

Temporary variable
1 # Meh
2 class Rectangle:
3 def bottom_right(self):
4 return Point(self.left + self.width,
5 self.top + self.height)
6
7 # Better to use temporary variables for readability
8 class Rectangle:
9 ...
10 def bottom_right(self):
11 right = self.left + self.width
12 bottom = self.top + self.height
13 return Point(right, bottom)
14

https://stevenloria.com/python-best-practice/ 7/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

Sets
• Can o en use sets instead of combina on of for loops
1 item in a_set
2 item not in a_set
3
4 # a_set <= other
5 a_set.is_subset(other)
6
7 # a_set | other
8 a_set.union(other)
9
10 # a_set & other
11 a_set.intersection(other)
12
13 # a_set - other
14 a_set.difference(other)

Equality method
1 obj == obj2
2 obj1 is obj2
3
4 class Book:
5 ...
6 def __eq__(self, other):
7 if not isinstance(other, self.__class__):
8 return NotImplemented
9 return (self.author == other.author and
10 self.title == other.title)

• Probably the only case to check isinstance()

Hashing method
1 class Book:
2 ...
3 def __hash__(self):
4 return hash(self.author) ^ hash(self.other)

https://stevenloria.com/python-best-practice/ 8/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

Sorted collection
1 class Book:
2 ...
3 def __lt__(self, other):
4 return (self.author, self.title) < (other.author, other.title)

Concatenation
1 class Config:
2 def __init__(self, **entries):
3 self.entries = entries
4
5 def __add__(self, other):
6 entries = (self.entries.items() +
7 other.entries.items())
8 return Config(**entries)
9 default_config = Config(color=False, port=8080)
10 config = default_config + Config(color=True)

Simple enumeration parameter


• When you can't come up with an itera on param that makes sense, just use each
1 # Awkward
2 for options_shortcut in self.options_shortcuts:
3 options_shortcut.this()
4 options_shortcut.that()
5
6 # Better
7 for each in self.options_shortcuts:
8 each.this()
9 each.that()

Cascades
https://stevenloria.com/python-best-practice/ 9/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

• Instead of wri ng methods without return values, make them return self
• allows cascading of methods
1 # Instead of this
2 self.release_water()
3 self.shutdown()
4 self.alarm()
5
6 class Reactor:
7 ...
8 def release_water(self):
9 self.valve.open()
10 return self
11
12 self.release_water().shutdown().alarm()

Interesting return value


1 # Meh
2 def match(self, items):
3 for each in items:
4 if each.match(self):
5 return each
6 # Is this supposed to reach the end? Is this a bug?
7
8 # Better
9 def match(self, items):
10 for each in items:
11 if each.match(self):
12 return each
13 return None

• Explicit be er than implicit


• Include return value if it's interes ng (even if it's None)

Further reading
• Smalltalk Best Prac ce Pa erns
• Not just for Smalltalk: applicable to Python, Ruby, and many other languages

https://stevenloria.com/python-best-practice/ 10/11
01/07/2019 Python Best Practice Patterns by Vladimir Keleshev (Notes) | stevenloria.com

Edits

March , : Fix condi onal in Composed Method sec on. Thanks Rufus Smith.

February , : __eq__ returns NotImplemented to avoid asymmetric


comparison. Thanks Daniel Smith.

February , : Removed enumerate usage in "Interes ng Return Value" sec on.


Thanks Hugh Brown and Paul Winkler.

September , : Fixed error in Sorted Collec on. Thanks Frank Sievertsen.

September , : Fixed typo in Choosing Message gist. instanceof() should be


isinstance(). Thanks to richardborcsik for catching this.

July , : Fixed typo in Sorted Collec on gist. __lt__(self, other) needs


two arguments. Thanks to Tiago Oliveira for catching this.

tagged in python notes

Please send comments by email. I welcome your feedback, advice, and cri cism.

© Copyright 2019 by Steven Loria


All content is licensed under the CC-BY 4.0 License.

https://stevenloria.com/python-best-practice/ 11/11

You might also like