Python for the .NET Developer Transcripts
Chapter: The Python Language
Lecture: Concept: Python function overloading
0:00 Let's quickly review functions in Python. Here, we have a function called named arguments and it has one required positional parameter
0:10 called name, ironically. And then, it takes arbitrary positional arguments *args, remember that's like params, object array but we just say *.
0:20 And then, we can pass arbitrary keyword arguments to it and that appears in the dictionary, kwargs. I don't really love that style because
0:30 it doesn't tell me what arbitrary keywords I could pass. A way to accomplish almost exactly the same thing
0:38 like 90% of the time, if you just have default values like this times here. If you could've said times=1
0:45 but you don't have to, well, you could also just say times=1 as a default argument and it turns out the editors give you way more help
0:54 because if ask what is the signature of named args in the top one, it tells me I can pass anything. I don't know what type those are.
1:02 I don't know the values of them, the names of the parameters are, the list of options, nothing. And this is prevalent in Python
1:09 and I kind of hate it because usually what you can do is just name out the optional named arguments as default values
1:17 and folks can decide to pass them by name or not, right? So really, really nice to do this second one. I feel it's better than the top one.
1:26 There's a few use cases where you really don't know what could go in there 'cause your passing it along but most of the time, you actually know.
1:32 It's just you don't want to say. So anyway, I kind of like the bottom say hello version over the named args.
1:38 One thing you do want to be careful about though with these default values here, these can be dangerous.
1:44 So see this say no, as in no, no, no, don't do this? This one actually is a bit of an anti-pattern and let me tell you why.
1:52 If you pass a mutable type or if you set a mutable type for the default value, this could go really, really wrong and let me tell you how.
2:01 You might think when you call this function the default value is created and set each time the function is called
2:08 but that's not actually where the default value is set. The default value is set when that module, that file
2:14 is loaded, once, ever, so there is a singleton list that is the default value for names. That singleton is, well, it's a singleton
2:26 and that means it's shared by everyone who calls that function every time. So imagine something happens inside
2:33 that function where names is altered, right? An item is added or removed to names if it's empty. Well, guess what.
2:40 Now the default value has that change reflected in it or worse, if this function returns names makes some changes, adds more names
2:48 and returns that list, then it's open to the rest of the program to possibly add or remove items from that default value
2:55 so never, never put a mutable value here. The way you would accomplish this is you would say names=None and then, in that function you say
3:03 if names is None, names=, like this. And that way, you get a new copy every time you call it not the one that got set when you imported the module.
3:13 That's super not obvious, so I wanted to call it out and make it really clear. This seems okay but it turns out to actually be an anti-pattern.