Thank you very much. Can you all hear me? Okay, so I'm gonna talk about the type hints and as Like pointed out last time this lasted 40 minutes. So let's get started. So Yeah, type hints inside python Just a caveat. They're gonna be a few animal cute animal pictures on the slice most because this is kind of hard subject So it's easy to it's nice to actually have it wrapped up in some nice animals. Okay, so Type hints was laid its foundation were laid down in this lovely pep by these lovely gentlemen and their other people implemented The typing system in Python is mostly based on whatever my pie dreamed up beforehand Gido looked at it and liked it So he made some adjustment to it, but it's heavily based on that for any people used my pie before Types for instead of the standard library which happened just around the time with Python 3.5. Okay, so Type hinting so the first thing is if in case you're still on Python 2 I have a bad news the end of an era is here So you might want to migrate But that doesn't stop you from actually using type hinting because you can lovely use it because it has been backported We are pipe I packaged to Python 2.7 So really you don't have any excuse to not start using type hints Okay, so the first question is why do it? So why do we need type hints? I thought Python is this lovely language dynamic language doesn't really need types. Why do we want still to add type hints? So I'm gonna present the reasons mostly in order their importance So I think the first and biggest reason why you want type hints is it just makes the code a lot easier to understand Then debug or maintain generally so the idea is that you know what your types are when you write the function But if you come back two months down the line You probably no longer remember what were the inputs and outputs for that function for example in this case That type insert sort of like a nice speed up to catch up with the code, okay? For example in this case you can easily see that the request data can really be anything but for example the headers Must be like a dictionary of string or the user ID must be Optional of user ID where user ID means whatever someone defined it some verse you have to look up What is an user ID still? But the idea should be able to help it locating that easily And we also finally have a flag the other thing is it makes a lot easier Refactoring because being a dynamic language means that you don't really know where your objectives are used inside your language So means it when you refactor your rottenary sure if you refactor or you changed all the places in your application Where you're actually there to change Some ideas help some detection with it But by having typing in your code the idea can be 100% in all the location where that Object is actually used The following reason is also read it now you can actually make 100% correct suggestions So if you're an ID developer you're happy if you're a library user You're also happy because you now you actually know what type of function slash Attributes you have on a object and you don't have to read up the documentation on it Okay, so just pizza up the development makes development a lot easier and The fourth reason in this is actually you can find type logical box by running some kind of linter for example my pie But there are other linters out there okay, and The another thing which is he actually helps improve the documentation because now the documentation can be actually based on something Which is checked and maintained and not just some Things which some some months at some point wrote it in the documentation, but no one really updated since five years Okay, and the final reason what you can do with it is you actually can make a lot easier Diapalidations for example you can use paid by the antique which allows you to specify the types of your input objects And you can do automatically this kind of checks it before and you would have done with like an assert functions In this case you can basically make it just reuse the typing to ensure that your input parameters are whatever you Made it by contract to be Okay, so what it is not so It was actually stated that the typing in Python means to be not to be a few things that doesn't stop anyone in Python to actually do it But it's not designed to do that One of this is no runtime type inference meaning that the Python interpreter at runtime will not actually tell you what the types are it Basically already tell you at runtime what the types are but we're not actually try to deduce what the types are at runtime There will gonna be no informant if you had type annotations your code will not be faster and also You can think of them at basically the interpreter treat the mess comments meaning I can discard it easily It doesn't matter for executing the script or just the Request so generally it is made to improve the developer experience not to make your application better I could argue that improving the developer experience makes happier developers makes better applications But that's like a indirect benefit of it okay, so The first thing what kind of type what are type annotations what kind of type information does it provide? The answer to this is gradual typing meaning that it's an opt-in You don't have to type into your entire application or at once you can start typing in just one single logic Where you type in and just that part of your code basically gonna be type checked so to say okay So gradual typing means that if you edit only those places will actually be in for example in this case Just won't maybe a bit smaller. So Slightly zoom in so people can actually see you can actually see that in this case for example If you're on the type into it will magically run that hey by the way, this doesn't make sense You passed an invalid argument or also this property doesn't exist Maybe you mean something which exists. It's really closely. We can all see it's just a type. Okay, so How to edit this is the question so if you want to actually edit what are your options? How you can actually add it inside your application as always there is one more than one way of skinning the cat the The most basic one is using the type annotations type annotations index is based on the pep 2170 of function annotations and then later at the Variable annotations these types are like for example given this function this yeah Highlighted terms are the function notation and this other one is the variable annotation basically meaning you can use the Double that the basically specify by the way. I attached this additional information to this Attribute or return value and those this is it's this type okay Next up type annotations are The canonical and clean way So these are the way they were designed. I do were actually meant to be used They are packaging itself because it's actually inside your code So you don't need to actually think about how you package your type information with your application But it does require Python 3.6 You can use Python 3.4 or 3.5 if you are willing to not have variable annotations But the function annotations will quietly 3.4. Okay, so One of the problems is requires importing all of the dependencies For example, you see at that place we imported the list at the top of it. The other thing is it also Requires Evaluating this kind of for example in this case there is a list in that actually is an object creation So what to it doesn't it's meant to be treated as comments at runtime at things like Python 3.6 You actually have a runtime performance penalty Which through negligible but still existent because you need to do extra imports and extra object creations as the script first time loads But that has been actually sort to say solved with Python 3.7 In Python 3.7 you can import from future annotations and once the interpreter sees this magical flag Sorry, it will actually treat all those Type information as comments and we'll actually not evaluate it as the script is loaded. Okay But you need Python 3.7 in Python for the mythical Python for this is gonna be the default So type annotations will be by default not evaluated when the interpreter evaluates It leaves it only for the type linter to actually do the evaluation okay so There are other ways to edit one of the popular ways is using type comments The good thing about type comments that type comments were introduced in Python 1.0 or even before that So it works on ready Python version The type information is still kept locally because you add your information right after the function or right beside the variable the packaging is solved because you're usually don't sweep your comments from your packages and also The bad things it's kind of ugly because now you have all this type comment another bad thing is You can now have a new import remember in the previous time you have Imports used or import you made but you actually still used in this case because all those type information is in the comment They're actually unused from the point of view of any linter and also often confused with other linters adding Comments it's one of the main ways how Various developer tools interact or add their own logic for example pilot or flake eight all do have options to turn off Faryl checks by using type cut this kind of comments, okay So the what I mean by kind ugly a lot of noise beside let's imagine this simple function This function basically takes two variables, and it swaps around inside the context manager those two variables Okay, it's fairly innocent. It just had like six lines. Let's add type information Well, because you still want to keep the 80 line rate in our column limit You start splitting up in multiple sections, which means that now you actually have to add four extra lines You just add the type information around sided Then you need to do the extra imports now You also need to various imports for all your types you're referencing which opens you up to the potential of having circular imports Which before and you might not have actually had and then you also have to add various Disable functions just to make the linter happy Which leaves you at the end of the day that from having just six readable line of code now you have 16 a lot harder readable code So yeah, it definitely adds an overhead once you add it It makes the code a bit less readable But the other hand I would just argue that all the information you had do make your life a bit easier But it definitely complicates the code bit a bit more than otherwise would be Yeah The downside it is that you have more lines of To actually maintain this is only sounds good if you get paid by the number of lines you write Okay, so the other option is you have interposed of us many other languages already invented this If you want to have some type information some interface type information You can just use stuff files C++ is probably added this already in the last 40 years. So Let's use this in Python 2 the idea is that you can add a pie information right alongside your file and This works on ready Python version now you can you don't need to take change the original source code So means you can add it without actually modifying your code It also means that can use the latest Python features because this Interface file doesn't actually get checked you can write it by the actual interpreter You can write any syntax you want in it basically so means you can use the Python 3.7 features happily inside No conflicts with other linter tools because the linters usually don't check the type stuff files informations and also as well tested because basically if you Already have used type in thing. This is how the oldest hander library is actually type in to just buy stuff files We signed it and it's published under the project up shed type shed Okay, the problem is you duplicated your card now you basically Defined every definition you have twice You have extra content to package which is sort of sold by this additional pet what that means that you need to pet You need to package additional files with your application which did for and you did not have so there is some downside there and also One specify the source signal so most of the type link how they treat it is basically once you have a stuff file The stuff file is a golden standard. They don't hear what is inside the actual source file Which opens you up to your box once you actually those two can diverge because somehow for example updated the source file But not actually the interface file Okay, also, there is no actual checking at the moment to actually do this The smash the stuff file against the source file also cannot and it look at variables because the stuff files only let you define the interface Now all this I think I zoomed a bit to out all this there is a work in progress solution it There's a work solution to be able to merge stuff science into source trees Which would bypass all the following all the extra three problems at the end With a little luck should be merged in my pie in the next month or so Okay Docks rings so docks rings basically Or another way we specify at this has been existed for all the time The main problems with this is that there is no standard way to actually specify complex type By Trump defined its own way or the Sphinx has its own way to define complex type by complex I mean not a single type by this or that type or that kind of complex type definitions It is too dependent supports recollection in the documentation the documentation is often not checked against Application code, which leaves you to open to easily deprecated code quickly or like with the out-of-date typing quickly Okay, so what to add so this is gonna be a quick introduction of what kind of type information you can add the main one is the nominal types nominal types are basically our classes or your Primitive types like in float. So these are basically You can have also like generic containers like topple list Iterable you can alias type just in case you don't have to type that much if you use one of the types heavily Or you can have distinct types, which basically just means that by the way, this is a user ID It is a type of int but make sure that whenever I pass in an object to this I don't mess up passing in an interstate of the actual user ID or that other way around Or you have the name tuppers The composer which is like union or optional are one of these which allow you to specify complex types and You can also actually define your functions. So if you want to have a column a callback function you can even type into even that and You also have generic which basically means think of it as the list the list is a generic type meaning it contains some type of collection, okay, you can do this also for your classes and You also have finally the any which is basically disabled type checking and it means fall back to the whole system of dynamic typing okay The other way you can actually specify this is I would argue a bit more Pythonic But not all the time best is structural typing This is the logic we have in Python that if it looks like a duck and it quirks like the duck It is a duck so meaning in this case we don't specify that by the way I want a class which has this type instead. I say I want some type Which has this kind of function on it or this kind of ability on it, okay? So these are called inside Python type ending protocols So in this case, for example, you have a protocol of each basically means I only want to be able to get Use it's a generic type and it has a getter and it will always return the string any type Which satisfies this requirement is good for my Function, okay, so this allows you to have even more generic Definitions of types Okay, so gotcha so once you start to actually add your type information decided what type of you for information yet You decide that if you're gonna be eight or a nominal or a gradual type The next question is okay, you know the next thing you want to run into is some kind of gotchas meaning some kind of edge cases Which makes you think like okay? It was nice not to have to think about before I had times So one of this is for example there is a if you have Python for both Or if you have a code which needs to run both on Python 2 and 3 You need know that the string or the percentage function always returns a string where the string means different thing on the Python 2 and 3 Which means that this simple function definition if you start type ending actually becomes this a lot more complicated one And this is the magic made nearly needed because now you actually have to return different type on their different Python versions For example once you use a from future import unicode it first You basically now have to add runtime logic to actually check that ensure that whenever you return it's actually By thunder Python 2 and it's actually a unicorn string on the Python tree So may add a bit of obfuscation to the problem the other thing is multiple return types So imagine you write a function which basically multiplies the things so basically it takes either a string or an int and it returns Basically the same the question is if you were calling for if you write it in this order and you write it with a number You're gonna quickly realize that that number is actually That can the response can be a string and in the way you define and now you actually have to assert that by the way The response is the int if the input is in this kind of thing is the way the in typeshed is often sold by basically adding This any which means disable the checks on the return value Which is of course kind of the piece the purpose better way you can do is now you have this overload come sex Overloadment that for this given type always this given type is returned So in this case I can specify for int always int will be returned for string always string will be returned now obviously The that now you don't need to add any assertions when you call it But the pre-downside is that now you define the same function three times which means that The linter will not be happy. It'll be like what are you doing? Why do you define your functions? Okay, the third one is the way the type look up looks inside the Linting logic is basically if you define this function for example a function has various types And you want to provide quick properties which return the correct type for example It can take a float so the user can just call the float property once you run this on the checker The linter is going to complain that invalid type test a dot flat and you'll be like what I really did not define their test That a that's flat. I just say this the float return value and The reason is once you start googling what the hell is up The you're gonna look up to this issue which basically means that the lookup always happens to the closest namespace meaning When the pie the plinter wants to check for a given type it starts to look at the Inner logic or like it starts to look where you define it and go one namespace level up up until it finds something that Matches once it looks at the float. He says, okay, I have a float. Oh, it's a function. I don't feel a carry still I got a float. I just gonna reintroduce that so the way to actually solve this problem is you Specify it. I really mean the built-in float not any other fort you may be able to find but now you actually import this built-in thing one caveat that is typing but type checking is something which is Is only interpreted this is always the true inside the linter and always files inside the interpreter So you can use this to guard to execute logic only for one Environment or the other, okay So the fourth one are contraband arguments types the fourth gotcha This basically means that if you define for example a base class which handles all the world And then you want to have specialized classes which handle only a part of the world For example in this case the base less treats both intense drinks But I have a specialized test which tricks only with strings and one just treats only with with int Once you type into you're on the type until you're gonna find that this link But it was super type This basically means that whatever you do you cannot have this kind of thing you can only extend Your type information in your derived class. You cannot constrain it For example, this would be happily running if I had I'm say my children hand us even more than the parent That's completely fine, but in the type hinting logic It makes no sense to constrain it which can go against if you probably it's quite often People tend to have this kind of restriction that try to specialize a given type of implementation for a given subset, okay The fifth gotcha is basically compatibility meaning that let's imagine we have this runtime We have just a base class which has a magic is a class method Then we derive from it and then we Try to run it And anyone sees what the problem with this So the problem with this is actually that once you try to run it This will happily fail because for example someone could easily specify that the they want any type of a and they want a So it can put in a be also in the list of this and once you run this log It will actually fail because for example the be magic constructor cannot pig that single type of Cannot complete with actually having a non optional argument. Okay, so this means that whenever you Have your functions, you can only also only enrich the function you cannot constrain to not run So like it the children must always satisfy the parents requirements so to say so the obvious solution to this one Is that you actually need to make the second argument optional and now that's everything will work Okay, now let this turn turn this to ground. Let's move basically this class method into an in it It's basically the same. I just move from a class method to an in it So if you run this one with the linter or if you turn with runtime, it will still feel at runtime If you run it in the linter the link for which say that yeah, it's correct It will say nothing it say everything's fine and the reason for these inconsistencies Because the linter developers created it's too common to prohibit Incapitable in it and new things This is just a slight caveat that you can if you're typing thing is correct You can still have incorrect long time code even from a typing point of view Because they started to not break too much code when they introduced this kind of logic Okay, so I think this is the general consensus once you start adding type in you sort of Get at some point at this point so Type in thing once you are typing thing is not trivial But don't despair you can take out always the bigger hammer and by bigger hammer You mean you can use the river type function to see whatever my biting the type is and when you don't agree with its Duction you can use the cast to force something that you have This is just a simple function you can use to actually force a given type to the linter And you can also when you gave up all of you just like okay I don't want to really solve this typing problem You can just always place the typing or comment and say that this I just don't want to deal with it Okay, so one extra thing which I'm gonna repeat one it is possible to actually merge your duck string at typing Typing you can use basically as things plug-in which means that if you annotate instead of annotating your Docs things like this you can basically move it inside the by using the spring plug-in inside your application And once you add the install the plug-in and install enable the extension You can have to that kind of type into the information Automatically inject your type information in your documentation Okay So what's next for my pie? This is one of the most popular linters the major thing is performance. Oh wait that or has been done So there has been introduced a demon which basically means that now you can run your typing information even faster It will define an APN and plug-in system. So people can extend it It will stretch type and information with even more popular libraries So we have even more good typing and it will offer you the option to merge stops and typing type source trees Okay, and finally, when do you want to use it? I think you should think of them as those tests whenever you want to write a test you should also add type-ins type-ins are basically just test which actually That's which actually instead of writing unit tests for it You use the linter to check the same time of that the contract is met Okay, and thank you very much I think we have time for one question is anybody got one quick question they would like to ask Hi Because a lot of application nowadays handle json blobs Is there any kind of way to ensure that the json blob a certain properties or that certain attribute of the json blob are a string or a number Or something there there is you can specify that you want if you think of them as a dictionary Which has different contract you can have defined that you can say for example This kind of a dictionary where at this key is going to be as this type So that is possible you cannot define a generic json type though Like that's not possible Gido tried it and and just gave up basically say this impossible to actually without having infinite recursion it's impossible to define a json type Okay, but you can define keys Having given type. Thank you very much burner. That's all we've got time for it. Thank you