 Thank you for coming to my talk. My name is Anastasia Timushuk. I'm working for a Syrian company in Berlin. You can access presentation slides. They are published online. And also code snippets, if you want to check them later or right now. While doing that, you can make a photo. And I will tell you a story, how I started with Python decorators, and why I wanted to make this talk happen. So basically, when I started working with Python, it was really unbelievable for me that I will turn back to Python, turn just to Python. Because I was C++ developer. We were working in a team of 10 people. We were so excited to start. And then in one week, suddenly, our customer told us, now you're writing Python. And we said, yeah, why not? We would try. It was really nice and funny. And we tried to build something from scratch. And then we were kind of using decorators. It was a bit hard for us to understand. So we googled. We found something. And then it was magically working. Somehow, we didn't go deeply in details. But it was working. It was fine. Sometimes it was throwing some weird bugs, which we couldn't really understand how was it working. So we were just replacing with a normal code. It's fine. It can work. But sometimes, you really would like to have nice decorator, which you can use everywhere to just invent your own wheel or just to reuse the code. So a few words about my company. I'm working for an internet security company. It's all about security. And I will show you some really nice video. So Siren is about security. The internet security is erased against time. And there are only minutes when the virus or some thread is launched and then it's trying to block all the users. It's trying to mess up with the payment system and everything. So it depends on the virus type or the viral email or something. Sometimes, it's coming that, hey, do you know me? And then some of our business partners is answered, yeah, hey, how are you doing? And then please, I'm stuck somewhere. Please pay something. Yeah, yeah, of course, I will give you money. So that's about Siren. We are blocking those kinds of threads. We are fully online, so we have everything as a service. And then it's just numerous seconds to detect something new and then to block it. That's why I just go with us if you are the company. I really like the company because we are pretty open to something new. And then as long as the developer has a new idea, something to use, then the company is saying, yes, just go for it. And we are super happy about that. But we are not open source yet. Maybe in the future, we will see. So what's in the talk? The name of the talk is Python Decorators Gift of Poison. And then maybe at the end of the talk, you will see the answer of it. First, we will think about functions nature in Python. And then I will show you some magic of decorators. Then we will dive into basics. And then I will show you some examples and maybe some examples from my real life. So let's start. Functions nature in Python. All the functions are first class objects. What does it mean? That means that you can return function as an object. You can assign function to another object. You can do whatever you want, the same as you can do with objects. Can you see the code? Yes? OK, let's try to run it. Just a second. So we have just normal function. It's printing hello something and then variable. And we are assigning this function to another function name. And then we are trying to call the function. Let's run it. It's simply printing the same. So those two functions are equal. Basically, it's just one function. The function, which is say hello, it's an object. And this object was assigned to another name. That means that my function is basically the say hello function. And what will happen if we will try to delete say hello? It's still working. Why? Because it's an object. So we assign the object. And then it's working. Another thing that the name of the function is the same. So if we will print, it will have the same name. Because we assigned the say hello name. We didn't delete the function. We just delete the name of it. The name of the object. Let's go further. Now, as you know, functions are objects. You can dive more into the creators and to understand how they are working. Let's see the magic of it. There are two types of decorators. There are function decorators and class decorators. And we will basically cover all of them. First, about function decorators. Let's build the basic one. It's a decorator which is just printing something that something happened. It's decorating some function which is getting as an argument. It's a decorated function. It's an argument. And then we can use the decorator like this. It's a syntax is sugar with add. And then the name of the decorator, the function, which is a decorator, or we can just assign it. It will do exactly the same. So my decorator is the name of the decorator. And my second function is the function which is going to be decorated. Let's run it. So what is actually doing? The decorator is also a function which is taking another function as an argument and also running it or can just skip the running of the function. But it's definitely changing the behavior of the function. That means that just be careful when you're using decorators. You have to be sure how the decorator is working. Because if it's doing something super weird, for example, removing the running of the function, it might be wrong. And if you will not dive deeply into the decorator, the decorator itself, then you will not find out what is happening there. So both of these type of assigning the function into decorators are working the same. As you can see, it printed actually the same. So it called the function. And then it gave the argument there and just printed it. We can use stacked function decorator. That means that you will have a few decorators in the row. You will have a first decorator, the first function, and then the second one. And you will use them one by one. As you can see here, we have just two functions which are the decorators. And they are also taking function as an argument, the same scenario as the previous one. And they are just printing some text. First decorator and second decorator. And you are using two of the decorators. And how will it actually work? So we are assigning the first decorator and then second inside. And then as a parameter to the second, we have a function. So it will call the first one as a first and then the second as a second. It doesn't matter if you will use those decorators with an add symbol or you will just assign them. If you will assign them, you will clearly see how is it working. Maybe at the beginner's time, it's more clear to understand. Class decorators. They're a bit more complicated than just the function decorators. It's also a decorator. It's not a function, it's a class, which is decorating something. So it depends. If we want to decorate a class, it's a class decorator with a function. In this case, we are decorating a class with another class. Probably we want to change the behavior of this class, which is my class, with another class. And that's why we just need to use class decorator. We can use a class as a decorator. For example, we want to count entries into the function, and that's why we need to just adjust a little bit to the function behavior, but it's not really possible with just a function decorators. And then we will use class decorators. In this example, we can have a need when we are assigning the function, and then we are writing the name where we entered and where we exited. Let's run it and see. How will it work? So we decorated function one and function two with the same decorator, and then we just called function one and function two. So the same decorator, the same class decorator, and then class as a decorator, and then different functions. It saved the function name and a need of the decorator, and then it's printing which was entering the name of the function and then exiting the name of the function and then just running the function. As we can see here, it's printing exactly the same for the first one and the second one. Let's go a bit deeper into the decorators. How does the decorator work? We have basic decorator here, which is taking the function as an argument, and then it's printing one line before calling the function and then running the function, printing line after, and then returning the result. It's a classic decorator, which is not really changing the behavior. It's just printing something, but still running the function and then returning the result back. But it couldn't happen that you will change the result and you will return modified result. For example, if you need to beautify some output, if you want to print some table or something in a nice way, then you will probably return not the original result, but the nicer result, which you want to decorate. So let's run the code. It printed the same. It printed before the decorator function and then the function itself and then after the decorator function. And the name of the function, which we try to print here, it's the function name and the name is wrapped. That means, I will show the code again, that means that we printed this name, not the original name of the function. How to get rid of it? There is a trick, which you can use. Reps decorator. It's also the decorator, but it will assign all the function names correctly. And then you will have the correct behavior, which you expected, actually, because when you are using decorators, then be aware that you cannot rely on the name if you are not using reps. And in this case, the name is correct. And also the doc string is correct. It's the same from the function. So when to use decorators? I have prepared a few examples for you. The first one is the timing with function decorators. For example, you have some functions which you want to have timing on them. And you don't want to duplicate code. You don't want to write at the very beginning save time and then after, subtract time and then print it again, and then another one. Sometimes it's just for debugging. And then if you want to get rid of this code, then you probably need to remove all of the lines each time. And it's a bit annoying. So let's run the code. It's taking some time because we have the first function waiting for 0, 2 seconds. And then the second one for 1 second, and then 2 and 0, 3. So in this particular example, we have the function which is doing the timing. It's printing the name of the function and then all the arguments, keyword arguments, and then the timing. Basically, there is a class where you want to decorate just the function, a single function, not the whole class. And then also a function where you want to decorate only the function, then another one with an argument, and then another one with argument and keyword arguments. So the first one is taking nothing. And then the second one is taking some argument. The third one is taking two arguments, and then keyword argument. And then the third one is a class which is calling the class function which is decorated. And then suddenly it's working. It's printing that it was waiting for 1 second, and then for 2 seconds, 0, 3, and then 0, 2. And for that, we use just a single piece of code here, just a function decorator, which is written here. And we're used with all the cases which we wanted to. And next time, if your boss is coming to your door and then asking you to add some timing on the functions, and you are not just throwing your heads away like, oh my god, no, it's taking too much time to decorate all of the 1,000 millionth function. It will take a month. You will say, yeah, in one hour, it will be done. Timing with class decorators. For example, if you have a class and 10,000 functions there inside, and you want to decorate all of them, every single function should be timed. Of course, you can do it like that. You can just use all of the timers to each function. But sometimes it's really annoying because you have too many functions, and then you want to decorate all of them. We can do it in this case as a decorator of the class. We will use the function decorator to decorate all of the functions in one class. It's looking nice, yeah? So this is an example. We have the function, time this. And then we have the class with all of the functions, a, b, c, which are printing something, and simply using one decorator, which is time all class methods, which is a bit more complicated than just one single decorator. Then we will have the same that we wanted to have. So it's decorating, it's starting timer, entering function a, exiting function a, and then printing the time. It looks correct. So the next example, which I have for you, I used in one of my companies. And it was a bit confusing because I used also decorators and late binding and lambdas and everything altogether. And then suddenly, my developers told me, nah, it's too complicated. We don't know how decorators are working. And they said, OK, just come to my workshop and then I will show you the magic. I will show you how is it working because we are running out of time. So we have four functions to test, basically here, three. And sometimes if you want to test functions in the simple way, as a unit testing or whatever, and then you need to pass the parameter as a parameter into function. And then the result, which should be return in the test. And then the function, which to check. You don't want to write all of the functions for testing like a sub equals, and then the function, then input, output, and then the result. What I did, I just used decorators, in this case, which are who are creating the use cases for that. So it looks a bit tricky. It's weird. It's working nice, so we have three functions, which we wanted to check. And the input for the function which I wrote for the decorator is this one. Name of the function, and then arguments, and then the result. So while import time is going, it's adding all of the tests. The class decorator, which is written here, is decorating the class, which will add all of the tests. You can check the example later. It's also using the lambda and late binding. And I want to ask you about some magic. What will be printed here? Any ideas? Which one? Yes, that's correct. That's also a bit complicated. So actually, I would expect here numbers from 0 to 0, 2, 4, 6. But actually, we got just sixes. Why? Because at the time when we are calling the function multi-pliers, then the i variable is already looked up. It's because of late binding, because the i is not binding right away when we are calling the function. It's binding it at the first. So the i looked up until the last one, until the last in our range. And that's why we got all the sixes. How to fix it? We have a few opportunities for that. We can bind it right away. So we can just bind i to i, which we would really expect. Or we can just change the behavior of the function to yield the value. We can try with that, and that should work. Yes, we got what we expected. So now ask yourself, are the decorators in Python gift or poison? It's on you to decide whether you will use them in your code or you will get rid of them. Just think and use them wisely. Thank you for coming. And if you have any questions, and if we have some time. So is anyone a question? Do you have to pay extra attention when you're decorating class methods? For example, will self be available to you as an argument, or will it be already bound? Even in the function you're decorating, will it already be bound to the first argument, self? Or will you have self as an argument? Self, where in the function which you are? In the class method. In the class method of the class which you want to decorate? No, you decorate a method of the class. So if you want to decorate a function with a class or not? No. So you have your class, and you want to decorate one of its methods. So you're writing this decorator. Yes. What kind of arguments will you have access to? Will you be able to see self? So into the decorator, we are passing the function itself. And then it's passed with all of the parameters of it. And if you want to pass any parameters to do any kind of magic on the function which we are passing there, then we need to pass there as a parameter. There is another way to decorate the decorator with another function which is taking arguments and then passing them later. Thank you. So OK. Hi, nice talk. Do you know by any chance what happens if you try to decorate the recursive function? Never tried that. But you want to try. You can try. OK, we still have a tie. So anyone have a question? So thanks for the talk, a quick question. How do you debug decorators? Can you give some tips? You mean in my code? Yes, some tips. How do you debug it? For example, complex decorator, because it can be really painful. Yeah, it can be really, really painful. But it's on you to decide how is it painful and how is it complex. So my advice not to make them too complex because then you will not get a freedom of feeling that something might be wrong inside. Because if you are calling functions in functions in functions and then you are decorating decorators few times, then probably bug can be inside and then you are lost at some point. So your suggestion is to keep them simple enough? Yes, one function at a time. Thanks. OK. Is there a question? OK, if there is no question, let's give a big thanks to Ms. Anatusha to thank you again. Thank you.