I spoke at a virtual conference!
I was recently invited to speak at Code Newbie's CodeLand 2022. I had a wonderful time at the virtual conference and got the chance to speak with some great people including experts in the field (I was part of a roundtable discussion with Kelsey Hightower, I was starstruck!). Code Newbie's community is a lovely welcoming place for everyone, especially folks who are just getting started in software professionally. I'm definitely interested to go along again next year.
If you'd like to watch my talk, it's still available on demand here
I spent the last few days at PyCon UK, and thought I'd write a post about my experiences there. It was my first time at the conference and I thoroughly enjoyed it, as you can probably tell from the liberal number of exclamation marks scattered through this post.
I gave a talk!
On the first day of the conference I spoke about Python As a Second Language. The organisers put me in the Biggest Room so I had to fight off some pre-talk nerves,
but I was glad to have the chance to do it and got some lovely feedback afterwards. Thanks again to Emma Gordon for encouraging me to give it a go and push my comfort zone! Doing a talk on Thursday also meant I was free to enjoy the rest of the conference without worrying, which I definitely recommend.
For those who are interested, a video of my talk is now up on YouTube!
I went to talks and workshops!
The conference was full of great talks and sessions, so this is just a small sampling of what I particularly remember enjoying. Of course, I'd like to give a shout-out to my colleagues Emma Gordon and Jan Chwiejczak who respectively gave the very silly and fun Python Spelling Bee, and a (very oversubscribed) workshop on Python Bytecode & lavishly illustrated talk on the Art of Testing.
-
Unsafe At Any Speed Rae Knowler made some great points about dangerous library defaults, illustrated with scary examples from the wild. I'll be sure to use PyYAML.safe_load()
rather than load()
from now on...!
-
Shaping the World David McIver's keyote was thought-provoking and fascinating, not just about software, but ethics, history and human interactions - the sort of thing Stuart Wray would probably enjoy.
-
Docs or it didn't happen! I was encouraged to join the Documentarian Club by Mikey Ariel, who gave an inspiring talk about why good documentation is so important.
-
Software's Seven Deadly Wastes Jez applied the Toyota Production System's 'Seven Wastes' concept to software engineering beautifully - pleasing my manufacturing engineering heart and giving me some food for thought.
-
Circumnavigating the Antarctic with Python and Django A fascinating talk that cast a light on the challenge developing with no (or a very patchy) Internet connection. What, no googling for StackOverflow posts?! Carles and Jen managed data for 22 scientists on a trip circumnavigating the Antarctic, and built them some useful tools as well like an intranet 'Facebook' and web portal to enter their latest data.
-
The micro:bit talks I discovered from the team at the micro:bit foundation how the BBC micro:bit is being used by teachers and for STEM outreach. It's a great project and it sounds like it's already having a lot of success getting kids into learning to code in an accessible way.
-
Choo choo! All aboard the Data Train! It turns out there is a lot of open data available from TfL and National Rail about train movements in the UK. The talk went by quickly but I'll definitely be rewatching to get inspiration for my next project!
-
Lightning Talks One of the highlights of the conference was the range of lightning talks at the end of each day. Among much else they gave me a great brownie recipe, book recommendations and a moment of meditation calm. A particular favourite was the children's lightning talks - they were so confident speaking about their projects, it was lovely to hear.
The nice thing about PyCon UK is that they video all of the talks in the Assembly Room, so I'll be able to go back and watch the ones I missed over the next few weeks, and learn more from the ones I went to.
I didn't take part in many workshops as I was busy manning the CMR stall (we were one of the sponsors so were giving away some free trinkets). I did really enjoy Alex Chan's A Plumber's Guide To Git workshop - I think it really helped unpack the inner workings of Git for me. At the end I started to understand what's going on 'under the hood' when I git add
and git commit
and it's really neat.
I got swag!
As well as this snazzy pair of Python socks as a thank-you for giving a talk, I also picked up a free BBC micro:bit delightfully packaged in a sweetie-bag and enjoyed playing with it. For such a small bit of kit is has a surprising range of functions, including an accelerometer, 25 LEDs with variable brightness, two buttons and some I/O. I look forward to using it for embedded projects!
I met new people!
One of the best things about PyCon was a chance to meet people using Python from around the UK (and further afield). It was inspiring to see how the language is being used by all sorts of folks. Everyone was friendly and welcoming, and it was a great place to give a talk. I also got the chance to spend more time getting to know people I already was acquainted with from CamPUG, the Cambridge Python Users Group, and had some really interesting discussions.
If anyone is thinking of going but isn't sure if it's for them, I'd really reccomend giving PyCon UK a try - the environment is relaxed and friendly, and the organisers try hard to make everyone feel welcome and included. I'll definitely be coming back next year!
It turns out that things aren't as simple as they seemed in my last post. A couple of people have pointed out to me that Python can indeed do monkey patching - so what's the difference between this and Ruby? Am I just making a fuss over nothing? First of all, to some proper definitions.
What Even Is Monkey Patching?
It's also known as guerilla (/gorilla) patching, hot-fixing, and more recently, 'duck-punching'.
Geoffrey: Now, you went to PyCon a couple months ago. And it’s well-known that in the Python world, they frown on monkey-patching. Do you think they would think more positively of duck-punching?
Adam: No, I think they will continue to look down on us, no matter how awesome and hilarious we become.
Voice In Background: Isn’t that the truth.
Geoffrey: I also have Patrick Ewing. Is this a good idea, and will it catch on?
Patrick Ewing: Well, I was just totally sold by Adam, the idea being that if it walks like a duck and talks like a duck, it’s a duck, right? So if this duck is not giving you the noise that you want, you’ve got to just punch that duck until it returns what you expect.
Transcript from Geoffrey Grosenbach podcast at RailsConf2007
Monkey patching can mean some subtly different things:
- Changing a class's methods at runtime
- Changing a class's methods at runtime and making all the instances of that class change after the fact
As pointed out in this thread on StackOverFlow by Dan Lenski, both variants are indeed possible with Python. Here's an example:
class Widget:
def __init__(self):
pass
def who_am_i(self):
print("I'm a widget")
>>> my_widget = Widget()
>>> my_widget
<Widget object at 0x7f6b5aa52e80>
>>> my_widget.who_am_i()
I'm a widget
>>> def teapot(self):
... print("I'm a little teapot")
...
>>> Widget.who_am_i = teapot
>>> my_widget.who_am_i()
I'm a little teapot
>>> new_widget = Widget()
>>> new_widget.who_am_i()
I'm a little teapot
And Python doesn't warn you either! So perhaps I was unfairly harsh to Ruby? Not quite.
One Important Difference
Unlike with Ruby, we can't monkeypatch the basic built-in classes, such as int
, float
or str
. This is because they are defined in C extension modules which are immutable. These modules are shared between multiple interpreters and made immutable for efficiency (and safety)'s sake. So when you try to change the behaviour of the built-ins, you can't -
def own_up(self, a_string):
return a_string.length()*"!"
>>>my_string = "Hello, World!"
>>> my_string.upper()
'HELLO, WORLD!'
>>> str.upper = own_up
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
To do something which approximates the effects of monkeypatching a built-in we have to subclass, like so - this example lets us write a custom instance of the str.upper() method by inheriting from str.
class CustomString(str):
def upper(self):
desired_value = "!" * len(self)
return CustomString(desired_value)
>>> custom = CustomString("hello world")
>>> custom
'hello world'
>>> custom.upper()
'!!!!!!!!!!!'
Ta-da! I still maintain that this is saner behaviour than Ruby.
(Sidenote - Remember, for str and any class based on it, Python strings are immutable - when we call methods on a string, we just get a new return value that we have to assign to some other string object to store.)
If Python and Ruby do it in similar ways, is Monkey Patching even All That Bad, then?
Yes! I still maintain that monkey patching is dangerous and shouldn't be used often. I think it says something positive about Python that it's not something you need to know intimately in order to program competently in the language, and indeed most Python programmers I know feel a bit iffy about it. It's a little off-putting (to say the least) to realise how much of a way of life it is for Ruby programmers.
But don't just take my word for it - have a read of this insightful blog post by Avdi Grimm, an experienced Rubyist worried about the impact of thoughtless 'hip' monkey patching - a choice quote:
Where I work, we are already seeing subtle, difficult-to-debug problems crop up as the result of monkey patching in plugins. Patches interact in unpredictable, combinatoric ways. And by their nature, bugs caused by monkey patches are more difficult to track down than those introduced by more traditional classes and methods. As just one example: on one project, it was a known caveat that we could not rely on class inheritable attributes as provided by ActiveSupport. No one knew why.
A fun (scary) read.
Temporary Monkey Patching in Python for testing
As I was looking around at this stuff, I discovered there are a couple of libraries, unittest.mock.patch
and pytest monkeypatch
designed to allow temporary monkeypatching for testing - when the function or statement using it exits, the patch disappears. I can see how useful it would be to set up mocks in this controlled way, rather than having to worry about it affecting all of your tests. It was deemed so handy that mock
is now part of the standard library in Python3. Time to investigate further!
I listened to a great talk recently called Stop Using Classes by Peter Diedrich. The talk goes through some of the unhelpful ways classes can be used in Python and makes good points about readability and simplicity. Here's my mindmap of the talk.
Game of Life
Diedrich uses as an example a neat implementation of Conway's Game of Life which is beautifully straightforward and avoids the tempting trap of making a class for a Cell, a class for a Board, etc. His example is so small I've copied and annotated it here (renamed a few of the variables for extra clarity):
""" Example Game of Life from 'Stop Writing Classes' talk by Jack Diedrich. """
import itertools
def neighbours(point):
x, y = point
yield x+1, y-1
yield x+1, y
yield x+1, y+1
yield x, y-1
yield x, y+1
yield x-1, y-1
yield x-1, y
yield x-1, y+1
def advance(board):
new_state = set() # initialises a set with a blank list inside
friends = set(itertools.chain(*map(neighbours, board)))
cells_we_care_about = board | friends
for point in cells_we_care_about:
count = sum((cell in board)
for cell in neighbours(point))
if count == 3 or (count == 2 and point in board):
new_state.add(point)
return new_state
glider = set([(0,0), (1,0), (2,0), (0,1), (1,2)])
for i in range(1000):
glider = advance(glider)
print glider
What friends
does requires some unpacking. First of all, *map(neighbours, board)
takes the iterable returned from map(neighbours, board)
and returns it. The *
is a useful way to split up the returned single thing from map
into each piece and feed them separately to the chain()
function as arguments. Here's an example of *
in action:
def hallo(arg1, arg2):
print(arg1)
print(arg2)
print("Hallo!!")
>>> printme = ("Yes", "Indeed")
>>> hallo(printme)
Traceback (most recent call last):
File "/usr/lib/python3.5/code.py", line 91, in runcode
exec(code, self.locals)
File "<input>", line 1, in <module>
TypeError: hallo() missing 1 required positional argument: 'arg2'
>>> hallo(*printme)
Yes
Indeed
Hallo!!
This map()
iterable is the function neighbours()
applied to every point in board
. So map(neighbours, board)
returns sets of all the live cells' neighbours. This is used as an argument to the chain()
function. What chain()
does is glues groups of iterable things together into a chain
object. For example:
>>> import itertools
>>> love = itertools.chain("123", "DEF")
>>> print love
<itertools.chain object at 0x7fe58ada5810>
>>> for item in love:
... print item
...
1
2
3
D
E
F
>>> sling_it_into_a_set = set(love)
>>> print sling_it_into_a_set
set(['D', 'E', 'F', 1, 2, 3])
>>>
So it bungs all the sets of neighbours into one single set. Because of how Python sets work, this gets rid of any duplicate points - eg points which neighbour a couple of living cells should still only be mentioned once.
|
is just Python's binary OR operator - so cells_we_care_about
is a set which contains all points that are in the list of live cells OR the list of their neighbours
count
counts neighbours for each living and dead cell. Diedrich then applies the rules for Conway's Game of Life in one line:
A dead cell that has 3 live neighbours becomes alive
A live cell that has 2 live neighbours remains alive
* Every other cell dies.
Sets are awesome
One of the reasons his implementation is so tidy and has so few lines is his great use of set()
, one of the built-in Python types. Sets are particularly great for this problem because they contain only unique elements - if you try to add multiples of the same element to a set you only end up with one in there. This means any duplicate points are eliminated without having to think about it.
For more examples of how to get good use out of Python's built-ins I recommend Built in Super Heroes by the excellent Dave Beazley.