Matt Harrison Profile picture
Aug 4 13 tweets 5 min read
I often teach about Decorators in Python.

Many know how to use them, but few can write them.

These are tricky because nested functions make our brains hurt.

Here are some hints for grokking them.

1/
In short, decorators allow you to inject orthogonal behavior before or after a function is executed.

But my favorite decorator definition is related to the construction and will help you easily create them: A callable that takes a callable and returns a callable.

2/
What do I mean by "orthogonal"?

A function should do one thing. If you want to add caching or logging, it really isn't related to the function (and could be applied to multiple functions). It is "orthogonal" behavior.

3/
What is "callable that takes a callable and returns a callable"?

Remember this. It will make decorators easy. When we execute a function in Python we "call" it.

So, you could also say: A decorator is a function that takes a function and returns a function.

4/
(Although Python has other *callables* like methods, classes, lambdas, or instances with .__call__. You can implement decorators with these, but we will ignore them here.)

5/
The simplest decorator is one I call the *identity* decorator. It is a function that accepts a function and returns a function:

6/
We can decorate a function by redefining it or using Python's syntactic sugar: "@". These two snippets are equivalent:

7/
If your brain is fine with the identity decorator, let's just expand it and write the decorator like this. (Remember "a function that takes a function and returns a function".)

8/
When we decorate with this new code, the call to "add" actually calls "wrapper" which calls add ("func") when it executes.

The key point is that we can inject logic before "func" and after. (See blue and orange in the image.)

9/
To make a caching decorator, insert the logic to look for a prior answer in #before, and stick the result of the function in the cache in #after.

Here is an example that would cache in Redis:

gist.github.com/mminer/34d4746…

10/
So back to the first image.

Here's your template for decorators.

The final bit with
@wraps
(func) updates .__name__ and .__doc__ so that code completion works in editors and you can pull up documentation.

11/
@wraps I have a book, Intermediate Python Programming, covering decorators and other fun constructs like generators, comprehensions, and functional programming.

store.metasnake.com/intermediate-p…
@wraps That's a wrap!

If you enjoyed this thread:

1. Follow me @__mharrison__ for more of these
2. RT the tweet below to share this thread with your audience

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Matt Harrison

Matt Harrison Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @__mharrison__

Aug 5
Big O notation (pronounced Big-Oh) is a way to discuss how long an algorithm takes to run. It is also called "runtime complexity".

Understanding this is key for technologists.

Let's look at it.

1/
If we want to calculate the mean of a sequence, a naive implementation will calculate the sum and divide it by the length:

2/ Image
Often we express Big O in terms of the size of the data and N is commonly used to represent the numbers of items.

We have to loop over every item in seq. There are N items, so the runtime complexity of the mean function is O(N).

3/
Read 10 tweets
Aug 4
Folks who complain about Pandas and Matplotlib have never had to create a semi-complex plot in Excel, Google Sheets, AWS Quicksite, Google Data Studio, or Tableau... 🤪
What does this even mean? Image
More crazy. What is "Series"? Image
Read 5 tweets
Jul 13
Let's recreate this plot using Pandas (and Matplotlib).

Here's the basic bar plot... Image
Normally, I would just create a horizontal bar plot and be done Image
Read 8 tweets
Jun 26
People judge a book by its cover! Look at most Twitter accounts that you follow and they probably have a professional (looking) image.

Here's how to create a professional profile image! #twitter4devs
Take a photo (phone is fine) against a white background, using your camera. If you have a lighting source, slightly in front and above you. (Folks like it if you smile at least a little bit.. 😉)
Load it into Gimp (free) or Photoshop and convert it to grayscale. (Or leave it if you like it).
Read 5 tweets
Jun 1
The .pipe method in Pandas is powerful (yet potentially confusing if you aren't comfortable with passing functions around).
The .pipe method takes a dataframe (or series when called on a series) and can return whatever it wants. Generally, I'll return a dataframe so I can continue to chain operations.
🐼 .pipe is useful for operations that don't have methods (such as flatten_cols).

There is no method that will flatten hierarchical columns in Pandas. You need to mutate the .column attribute. But we can use .pipe to do this and still allow us to chain.
Read 5 tweets
May 31
Evaluating whether to replace my PDF viewer/inking tool of choice on Windows with @foxitsoftware or Okular (@kdecommunity). Seem more stable and quicker than @drawboard but also have other quirks. 🤔
Drawboard:
+: Intuitive, relatively cheap
-: Slow rendering, visual noise in fullscreen, stops working,
Foxit:
+: Speedy, quick rendering
-: Need quick access to pen color (preferably in presentation mode). Erase doesn't erase whole line. Pricey.
Read 6 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us on Twitter!

:(