Learn These 6 Interesting Features of Python Functions
today we're looking at six hidden features of python functions they get more and more interesting as we go through them so make sure you stick around until the end of the video let's begin with hidden feature number one now the first feature to look at here is that python functions can actually accept an unlimited number of positional or keyword arguments the way that we do that is by using something known as star args and star star quarks now let's begin by looking at Star arcs when we put a parameter inside of the function that has an AS and then args this allows us to have any number of positional arguments be passed to the function a positional argument is one that's in a specific order so what I can do here is put maybe a 1 2 3 doesn't matter and as long as I save the code and run this you can see that we print out args it actually gives us a topple that contains all of the different arguments now we can use this in combination with other mandatory arguments so maybe I have an argument a b and then args and now what will happen is the remainder of the arguments will be put inside of args whereas the rest will be stored in A and B in the correct corresponding order so when I run this here you get a as a and b as one and then we get two and three this is great when you don't know the number of arguments that will be passed to a function and you want to accept any number of them you may actually know that if you look at the print function in Python that's exactly how this works it accepts any number of positional arguments you can see that right here as value use and then it has some optional keyword arguments that you can pass to it so let's continue looking at this because it gets even more interesting so as well as star args we can have something known as star star quars and we can use this in combination with all of the other parameters that we've looked at and what this allows us to do is accept any number of keyword arguments so here if I print out quarks what I can do now is pass any keyword argument I want to this function so I can just make this up I can do something like key is equal to two value is equal to 7 really doesn't matter because we can pass anything that we want and now when we run the code you see that we actually get a python dictionary that contains the various keyword arguments corresponding with their values this can be useful when you don't know what keyword arguments are going to be accepting and you want to use specific dictionary values inside of your function now as a last note about this feature you can also combine it with keyword arguments that have default values so I can do something like values is equal to and then make this an array just note that in order for that to work you need to put it before quars so quars needs to be the last argument in your list so in this case now I can also pass values equal to 1 2 3 and if we want to go here and print out our values as long as we save and run you see that we get that popping up here there you go that is star args and star star quars and this will become more useful throughout the rest of the examples where you'll see how we write some more advanced functions that utilize these features now before we continue I want to talk to any of you that are serious about becoming software developers look it's no surprise that today's market is more difficult than it was a few years ago it can be difficult to get interviews and especially to land jobs however what makes that a lot more difficult is if you don't know how to present yourself correctly you don't have the right guidance or years of experience helping you out I've reviewed hundreds of different rums a lot of them from subscribers of mine and it's really unfortunate how many mistakes people are making in the small details that can really hold you back now I do have a program with course careers where not only do we teach you all of the skills you need to actually land a software development position but we give you all of that guidance and really focus on helping you land a job we give you res tips we have an entire section in the course just dedicated to that we explain to you how to make connections on LinkedIn and what type of jobs you should actually be applying for we also give you a specialization in front end backend or devops so you have those specialized skills that you need in a competitive market like today we've already had a lot of success Landing developers jobs even when they have no prior experience and I'm confident we can help you out if you want to check out the program there's a free introduction course with no obligation I'll leave a link to it in the description and I look forward to seeing you there now let's get into the next feature so this next feature to look at is known as functions as first class citizens now what that really means is that we can treat python functions just like any other object we can store them in a variable we can pass them as an argument to a function we can return them from a function and we can store them in various data structures we can use Python functions like we use any other pyth Pyon object and I want to show you a few examples so you really understand this feature because that's how a lot of more advanced python code works so let's look at this function right here which is called function caller now what this does is actually call any arbitrary function with any args and quars that are provided to it now when we use star args and we use star star quars we create kind of this Dynamic parameter system where we can accept any number of positional arguments and any number of keyword arguments now what we do here is we return whatever is returned from this function right here because remember this will be a function object so we can call it using the calling syntax and we pass to this star args and star star quarks now when we use the asteris before args what this will do is take all of our arguments which are normally stored in something like a tupple and it will actually split them into the individual positional arguments and pass that to the function so imagine it like actually removing these parentheses here and just writing inside of the function call 1 2 3 so it will pass them properly as three individual arguments now same thing happens when we use that with quars let's say we have a dictionary value like value equals 1 this is simply going to write it as value equals 1 so if we have no keyword arguments nothing will be passed and if we have no positional arguments nothing will be passed as well this just splits them and passes it to the function so it can call it dynamically okay so let's have a quick example of actually using this I'm just going to say result is equal to my function caller and what I'm going to do is use my function as first class s and principle which means I can pass the function add and notice I don't call the function I simply write the name of it now this will give me a reference to this function just like a normal python object and then I can call it later on so I say function caller is equal to add and then I'm going to pass to this function caller function the parameters that I need so maybe we'll go with 10 and 11 and now what I can do is simply print out this result and when we run the code here you see we get the value of 21 now let's look at the same example Now by using the PO function so I'm going to change this to say Po and now we're going to pass some keyword arguments so I'm going to say base is equal to 2 and I'm going to go exponent is equal to 5 okay I'm going to save my code here and run and notice we get the value of 32 so that's great now let me show you a more advanced example so you can really see the power of doing this all right so I've just written a bit more of an advanced example here feel free to pause the video if you need some time to understand it but what I'm doing here is using this Advanced Property as functions as first class citizens now you can see that I have a list of functions I have four functions inside of here I've simply written their names again I haven't called them then what I've done is created a list of arguments now notice inside of my list I have another list and inside of here I have a tupple this contains my positional arguments and I have a dictionary which contains my keyword arguments now I've done that for all of the corresponding functions the idea is I want to write a for Loop which I've done right here that Loops through all of my various functions and all of my arguments that correspond to those functions and then calls those functions and prints out the result this way I can call all of the functions in one for Loop rather than doing them manually now what I've done for the for Loop is again use some Advanced syntax because this is meant to be a more advanced video where what I'm doing is looping through all of the functions and then their coresponding arguments and keyword arguments and I'm doing that using the zip function what the zip function will do is generate a list of topples for me that contain the function and then all of the corresponding arguments so it's going to give me a list that looks something like this it's going to have inside of here a tupple where it's going to have ADD and then it's going to have my list that contains the positional arguments and the keyword arguments now it's going to do that for all of the different entries that I have here giving me a convenient way to Loop through this structure so we can have dot dot dot here now what I can do is I can simply parse through these by using this for Loop syntax so I use function which references the first object inside of my tupple and then I put a tupple here indicating that I'm going to have two elements and then I do args and quars and get the arguments and get the keyword arguments you might not have seen this before but this is valid inside of a for Loop then what I do is I call my function because this is an object so I can call it and then I pass to it the star args and the star star quars and I print out the result now I know this looks a little bit complicated but when I run the code here you can see that we get the result 3 25 11 and 7 which is exactly what I expected there you go that is functions as first class citizens moving on we are talking about closures now a closure is simply when you have a nested function that accesses a value from the outside function so in this case you can see that I have a function defined as Adder now inside of here it's actually perfectly valid for me to Define another function I can Define multiple functions and I can Define multiple levels of different inner functions in this case what this acts as is actually a function Factory what that means is that we Define this inner function notice the inner function uses the parameter from the outer function and then we actually return a reference to this inner function now this is a way for us to actually create a function that is dynamic based on what we pass to the function Factory I know this is a bit abstract but let's look at this example so I'm going to say Adder five is equal to and then I'm going to call Adder function and give it the value five what this is actually going to return to me is now a function that I can use that will add five to a particular value so now what I can do is I can say addore 5 I can give this a value of 10 we can store this in a result variable and we can print out the result so let's go ahead and do that save our code and run and notice that we get the value of 15 now we can utilize this function multiple times right so I can say result 2 is equal to Adder 5 and then I can pass to this maybe -7 and now we can print result and result 2 and you can see that we get the value sorry I need to save this and run it again of 15 and -2 so this is how we actually create a function dynamically based on a value that we're passing to another function now there's all kinds of ways to use closures but they're typically used for something like a function Factory now just to show you a bit more in depth here we can also create an Adder of 10 right and now I'm going to use my function Factory of Adder and I'm going to pass to this 10 so now when I use this function right if we hover over it you can see that it is really a function then what I can do is add 10 to a value so result three can be equal to Adder underscore 10 we can pass a value like -2 and then we'll print out our result three and when we run the code here you can see that we get eight so we've just used this function to create different versions of an inside function in this case we're just calling it Adder five or Adder 10 and that is how the closure operates again a lot of other examples I can show you but this simple one really illustrates all you need to know a closure utilizing a value from the outside function so now that we understand closures we can go ahead and have a look at decorators now a decorator is simply a function that modifies another function they might look a little bit complicated but I promise you now that we understand closures and star arcs and star star quarks you'll see how they work quite clearly if you want an entire tutorial on decorators and how to write your own I'll link one on screen but for now let me give you a quick look into how they work so let's focus our attention on this function right here which is one that I've just written quickly what this function does is accept two lists and accept some value called mod what it does is it checks all of the values in both of the list and sees if they're divisible by this mod value if they are it adds the new value to a new list and then returns that to me so in this case it's going to give me all of the even numbers from both of these lists in one list let's quickly have a look at that just to make sure that we understand how that works I'm going to say result is equal to this and then go down here and print my result and if we make sure that the code is saved and we run this you can see we get all of the even values uh that are inside of this list okay that's correct now let's say we want to modify this function and we actually want to print out all of the arguments it was called with and all of the keyword arguments it was called with as well as the result well I could just modify the function manually by going in here and adding those various print functions or I can use a decorator now this is The Decorator right here notice that what this function does is accept another function then it has an inner function inside of it this inner function accepts any number of arguments and any number of keyword arguments and what it does is it prints out what the function was called with in terms of its arguments and keyword arguments it actually calls the function so it says result is equal to and then it calls that outer function with the arguments and the keyword arguments it prints the result and then it Returns the result now how do we use this decorator function well what I can do is use this at symbol here and then write function printer what's actually going to happen now is that when I call my custom function it's going to actually call the modified function that was returned from this function DEC so just have a quick look here I'm not going to print out the result anymore because we're not going to need that and I'll break this down more in depth but again just bear with me so now notice that I get my two print statements function called with these different arguments and mod 2 and the result is 2 46 81 so I didn't change anything on this function I just decorated it with another function and again what's happening now is we're going to call the function that was returned from this decorator Again The Decorator is a function that's modifying a another function what's actually happening equivalently when I write that line here is the following we're having my custom function is equal to and then the function printer called with my custom function this is really the equivalent line watch now when I run this and you're going to see that we get the exact same result so The Decorator is just a shorthand Syntax for writing this we've changed my custom function to actually be whatever is returned from this here this modified function and the reason why this decorator will work for us is because it's Dynamic and it accepts any number of keyword arguments and any number of positional arguments it does a slight modification by for example printing out the arcs and the quarg getting the result printing it out and then returning the result but this function itself doesn't change and it still has the same behavior this function printer can be used on any function because of the way we've ridden it now I have an entire tutorial on decorators that goes through this more in depth so if you're still confused then check that out going to leave it on screen I just want to give you a little bit of a taste of how they work and this kind of hidden python feature moving on we're now going to look at a more complicated keyword that you might never have seen before in Python and that's the non-local keyword now in order to understand that let's first look at this closure that we have right here so we have some outer function and inside of the function we Define a variable like x = 10 we then have an inner function where we say x = 20 now when we do this really what's happening is creating a local variable that's local to this function scope so when we print inner X we're going to get 20 but sometimes what we want to do is inside of this inner function we want to modify a variable that's in the outside scope or the enclosing scope the one where this function is defined now in order to do that we can utilize the non-local keyword but first let's just print this out so we can see what we're getting notice we get Inner X is 20 and the outer X is 10 again what I want to do is I want to modify this x not modify this x now in order to do that I can Define nonlocal X when I do that what's going to happen is now python is going to look for a reference to X in the enclosing scope the enclosing scope is the scope in which this function is defined in which is this outer function so now what's going to happen when I say xal 20 is I'm going to reference the X in the enclosing scope and I'm going to modify that instead so when I run the code here you can see I get Inner xal 20 and outer x = 20 as well now this works with nested levels of functions so I could Define another function inside of here and then utilize the non-local X there in fact let's do that we're going to say inner Funk 2 and here we're going to say x equals 100 and we're going to say print inner inner X and this time we're going to say that it's X and then we're going to call inside of here the inner function 2 Okay so let's run the code now and you can see that we get inner xal 20 inner X or inner inner X sorry equal 100 and then outer x equal 20 now again if we want the same thing where we're actually going to reference this x which then in turn is referencing this x what I can do is have my nonlocal X here okay and now let's watch what happens when we have multiple levels of nesting and notice we have the first inner X is equal to 20 and then we have 100 and 100 now the reason why this works is because again we're printing inner X here this is before it's defined in side of the inner function two and change to 100 but you can see the final outer X is still equal to 100 because we have two levels of non-local meaning that we're always referencing this x up here okay that's how it works I know a little bit confusing especially when we get into this level of nesting but when you have a closure and you want to reference a variable in the scope outside of the current scope so the enclosing scope you use nonlocal x I can come up with a lot more advanced examples but I think that's enough to demonstrate the capability of this keyword now this next feature is simply function annotations you may have seen this before but I know a lot of people don't even know it exists now a function annotation is a way to define the type of your various parameters and return types for your functions it's super useful and I recommend you use it if you want more readable code now the main benefit of function annotations is simply readability and documentation it doesn't actually modify how the code works at all it still works the exact same way it would before and you can still incorrectly call a function so for example I can have ADD and I can pass two strings this is perfectly valid Python's not going to get mad at me for this even though the function is annotated as int int and int however you'll notice when I start writing my functions out here when I get my auto complete it's significantly better than it was before because it knows what type the various value should be it knows that X should be an INT y should be an INT and that the return type will be an integer this makes your code a lot easier to read and work with especially if it's in some kind of library or the developer can't directly see it now these are very simple function annotations which you can see right here we're defining the type of a parameter using the colon right so we say Name colon string and then we use this Arrow syntax to denote the return type however we can also use more advanced typings from the python typings Library which I'm going to show you right now so you can see here we have some more advanced types now coming from the python typing library in this case we have processed data which utilizes a list notice when we specify a list we also specify what's going to be inside of the list so in this case I'm saying we're going to have a list containing integers we then have a return type this will be a tupple that contains two ins so the first position is an INT and the second position is an INT as well but it's worth noting that we could Nest various types here and we can maybe have a list that contains an INT as the second position that's totally valid we can write that out now continuing here we also have optional optional specifies that a parameter will be optional and it has a default value so we can say that we're going to have an optional list containing integers this is equal to none and then we're going to return an optional int when we do this it means that if we don't have this int instead we're going to be returning the nun type which is a common convention in Python there you go those are typing annotations you obviously can get a lot more advanced with these but they're super useful and something I definitely recommend using especially if you're working on a larger project or something other people will be touching anyways that's going to wrap up this video I hope you found it helpful and I look forward to seeing you in another one [Music]
2024-06-20 12:03