Things (Almost) No One Thinks About When Designing Functions in Python

preview_player
Показать описание

In this video, I'll show you how to design a great function header in Python. I’ll mention things you probably haven’t considered but that can make or break your code.

🔖 Chapters:
0:00 Intro
0:20 Function Naming
5:17 Function Arguments
8:01 Function Default Arguments
13:17 Args and Kwargs arguments
15:56 Options object
21:05 Return Type
22:34 Making your function more generic
27:41 Final thoughts

#arjancodes #softwaredesign #python
Рекомендации по теме
Комментарии
Автор

An approach I use is by going a level up to the function that is calling the one I'm about to write. In that calling function, the name and arguments should read in plain English, almost like a story. Ultimately, if you've got your face in a function you can see what it does, but if you are in the outer scope, a good signature means you don't need to dig deeper on that line to reason about what's going on.
Great video, thank you!

DrGreenGiant
Автор

Combination "_and_" functions are useful at collapsing common boilerplate code down into a single line used in high level applications. For example, all applications may need to setup logging, read the local config, open a database, and connect to the attached device. Having a method for that reduces code duplication, allows to improve that common code in one place, makes the app easier to read, and makes creating new apps significantly easier.

harveychapman
Автор

Great video. At first I was wondering what could you possibly talk about 30 mins for just the function signature but I actually learned a lot. Thanks for putting this together

yvesdeutschmann
Автор

"Make interfaces easy to use correctly and hard to use incorrectly."
- Scott Meyers, The Most Important Design Guideline

metal
Автор

Calling it a "function header" is weird. The usual name you see for it is "function signature". That's what it's called in Python itself (see inspect.Signature).

maleldil
Автор

Also crucial: function arguments should always be annotated with the most general protocol possible, but the return type should always be as specific as possible type as possible.

jakobullmann
Автор

I also read that the function name specificity should be inversely proportional to its scope, e.g. a function might be used once or twice within the same class/module, but if a function is used all over the place, it should have a very short name, e.g. python's "open" function.
thank you for another great video.

UNgineering
Автор

When handling default arguments, I often use the following line to set them at runtime:
`timestamp = timestamp or time.time()`
This works if the default value is `None`, because `None` is a "False" value and a valid timestamp is a `True` value.
It also uses the fact that Python passes on the actual value of the first `True` element in an `or` operation, and does not evaluate the second value if the first one is already `True`. If the first value is `False`, it yields the second value regardless of whether it is `True` or `False`.

TheEvertw
Автор

There's another naming style sometimes used in the Python stdlib and ecosystem: adjectives describing the quality of the returned object, like reversed, sorted and functools.batched. They do not change the argument, so a name like "sort" would be confusing in this case, it's used for the corresponding method, which actually transforms the object.
I don't know how this style is named though.

saitaro
Автор

Actually, the two hardest things in computer science is naming things, cache invalidation, and off-by-1 errors. 😉

ondskabenselv
Автор

thanks for posting. I'd rethink naming functions using their implementation detail. is perhaps overly close to the implementation detail. I'd suggest something like that may read better in the caller's code too, as in ìf I'd also argue about the benefit of verbs in functions names… after decades of using them! :) Writing in an FP language and everything is just data to me now :)

video-carl
Автор

A tip I want to share which is slightly related is the “extract function” feature that a lot of IDEs have, which allows you to highlight a code block and press a hotkey to turn it into a function automatically. At least pycharm has this, and I guess you can find extensions for it for most of the popular editors. You can also do the inverse operation, meaning turning a function into inline code).

MCeplekake
Автор

Loooved this video, so clear and helpful! Keep them coming!

hcubill
Автор

Great video Arjen, yes would love to hear your thoughts on function body design 👍

karlwiren
Автор

Great video as Always Arjan. Thanks for covering this topic. A real bugbear of mine is splitting function headers across multiple lines like @ 8:14 this is obviously auto-formated and it's a PEP8 guideline I know but I find it makes headers much more difficult to read (unless they are really long with lots of arguments - which they shouldn't be). I started using "autopep8.args": ["--ignore=E501"] in my settings to ignore long lines.

dannorris
Автор

You could use NamedTuple for Options in that case it could be destructured almost like in TS

antoniov
Автор

Regarding variable naming, I use plural form for a collection as in "cars" unless the variable name hints to a collection as in "list_car", in which case I use the singular form.

youmal
Автор

Something worth noting is that a better type annotation for generic numeric types is a union of numbers.Integral, numbers.Real, and decimal.Decimal (or numbers.Number if complex numbers are allowed as well).

tannerbobanner
Автор

If I’m not mistaken, starting with Python 3.7, the order of dictionaries is guaranteed.

difegam
Автор

Regarding object options: if you use any specific value from it or want to set as default, it should be a normal argument. The only reason to use **kwargs is if you do not access its data and only pass it as dict to other functions

floriandyck