While working on an assignment I came across a couple of interesting python concepts that I thought I’d share with all of my millions of (imaginary) readers. I won’t go into too much, because really this is just for me, but I’ll give a brief overview on how I think about it (cause frankly I think it doesn’t need to be as hard as other articles make it seem).
The first (and simpler) is the * operator, but not like in multiplication. (The ** operator also applies to most of these but with dictionaries as opposed to lists/tuples but I’ll leave the inference to you (or rather, me).) It has a few uses, some relatively unrelated, but syntax overloading is always fine, just look at *s in c (in just throwing shade, it’s actually fine).
The uses for * in python come down to:
– function definitions:
– put a *something in there to take a variable number of arguments (I already knew this one, just wait though, it gets cooler) (** for dicts and keyword arguments)
– put a * in there after your positional arguments and you make it so that keyword arguments can only be given with keywords (instead of the sneaky extra positional argument going into your first keyword argument, ninja style)
– dump a list
– using *something will make the list something drop all of it’s elements (instead of being a list type) (or that’s how I think about it at least, you could also think about it like a throwback to c “arrays”) (** for dicts to dump their keyword:value pairs)
– while this is already cool, it has a bunch of neat use cases, like passing it to a function gives a whole bunch of arguments instead of a single list argument (although I think python would unpack it into the correct positions anyway, but if the function takes variable arguments? Maybe python would do that anyway too, either way the next use case is the coolest)
– concatenating lists (or whatever other operations you want to do), say you want to double the list you could just go new = [*old, *old], and the *s would dump out all the elements and you would have a brand new list (instead of two list elements)
– this last one is alright, but definitely not the highlight of the article, you can use it on the right of a tuple(/list) unpack to capture a variable number of elements (function argument style), so if you wanted a shift (perl style, ah, I miss shift) instead of a pop(0) (cause you’re too cool for those) you could go first, *rest = *list (notice the sick dump in there too) and take first all the way to the bank
Neat. This is already long, but that’s fine because it won’t take me long to de-magic-ify closure for you. This is something I spend a solid 10 minutes trying to get, but once I got it it wasn’t so hard, and I think by thinking about it this way I might change your life (oreo mcflurry with caramel sauce style).
So you have a function, with a function defined inside (whose only purpose is this, more or less). The outer function takes an argument, or you define something in it, whatever. And the inner function uses a variable from the outer functions scope (because you can do that, read only though (you could nonlocal it but I don’t know if this would still work, wither way it would defeat the purpose), just hold that thought, we’ll need it in a bit. Now, the outer function returns the inner function, so when you call the outer function (not that you can call the inner function from outside the outer function) you just get a copy of the inner function. So far so good (you can use functions just like any other variable in python). But, remember how the inner function used the variable from the outer function? Well when you now call the version of the inner function that you got before, which used the argument(s)(/variable(s)) passed to the outer function, it remembers what they were. (Because of some magic involving the stack, maybe?) Easy right?
Now you may be asking, what’s the point? You can use the outer function as a factory function, which means that it’s a function to generate other functions. So you can create a bunch of versions of the function by using different arguments when you create the function. Great. I mean, you could just pass more arguments to the function every time, but this saves you a bit of typing, and you can name them all different things. Look. I get it, and I get it’s use cases, but… it doesn’t really seem to be revolutionary. But, that’s what the cool kids are doing these days so that’s what you should do too. You know, peer pressure and all.
(But seriously, I think there mostly used for decorators? (aside from some small convenience based uses, which aren’t just factory functions). I’ll have to do some more reading on what decorators are beyond an @property and get back to you.)