 It feels like at some point this is going to be like an AA meeting, so I might as well try now. So my plan was to talk a little bit about type hints, what they are and why they're fun, or why they're useful and why you do them for profit. I haven't really prepared a big presentation because I figured this is a thing that it goes best in code. And if you at any point, first off, can everyone see this properly? Should I make anything bigger? I'll take the note, the silence for yes, it's okay. So if there's any questions as you go along, please say it's your hand and ask it. We'll walk it through. I was figuring that towards the end, if you have any particular issue, thing you would like to solve with type hints, we could walk it through together because I could probably talk through examples for a very long time and I don't want to bore you all. So it's better if you get some practical examples. So first off, what are type hints? One of the things that Python doesn't do compared to other languages is that you don't know for sure that whatever thing you put into a variable is necessarily of a particular type. So if I type in foo, I'm putting one, we know now because we see that it is a number. But if I go somewhere else, I don't necessarily know that foo is a number. All the questions, I'm probably going to be very scratching in this recording, but it works. So yeah, so we know here because we can see that it's a number. But we can also do from Python 3.6, 3 and onward, so we can do add a colon. We know now it's an int and we're now told Python that this is supposed to be an integer and wherever you see this variable, you can expect it to respond to whatever messages that you can do on an int, like bit length and so on. Now, most of this just kind of works when you're working in the same file as you defined it, but it doesn't necessarily work when you go outside the current file. So if we take some examples here, so if you want to add something together, so this is my little add method that just takes one and two, puts them together and I want to see what goes with it. This method hasn't been configured to support type int thing, so if I try to do anything with it, it will just go, oh, so there's nothing I can do. I have no idea what's going on here. But I have this thing here that supports type ints where support said that the first thing is an integer, the second thing is an integer, and it returns an integer. And when I do a period here, IntelliJ or PyCharm will tell me that it's an integer and despite not being in the same file, which can get really convenient when you get into a larger code base and you don't even know how many layers through you have and it's passed through, so super, super convenient. And you can also get warnings in your editor saying that, oh, so you expected this to be an integer, but you got a string instead. You probably want to fix that because this is going to give you an unexpected behavior, unless you fixed it, but in that case you should have a type int saying that you support multiple types. And here's as well like you wouldn't support an int, whenever you take an int, you shouldn't support a float, but we'll also later see that you can pass in an integer and someone ask for a float because that's normal Python type inting, it just supports that out of the box. And so, yeah. Now, another thing that's fairly common in Python is that we have default arguments and what that is is just that, my examples, by the way, are going to be extremely contrived just because I want to show how the actual type ints work and not so much advanced Python. So I have here a function that takes in a name and then optionally provides some kind of greeting and then you write that out. So this is F formatted strings which available in Python 3.6, fantastic. You don't have to do the annoying format syntax anymore. So also a nice thing to know about. And what I've done here is I just said that I optionally take in something that is a text and by default that's the value none and I just check it. So here it just works as I would expect, returns hello, Björn and I change it to howdy, howdy, Björn and down here I get a warning that this is supposed to be an integer but it's supposed to be a string but I got an integer. But because it's Python, it will actually run, it won't be an issue because like it will just convert that into a string and deal with it. So you can do it on the IDE, you can also do it in the console, so that's a good, I was going to go to that. So on the console there's a little tool called MyPy and MyPy is the type hinting engine that Python uses. So if you do install MyPy you can then run it against a file, so if I run it against my example 2Py it will tell me that on line 10 the second argument to the greeting has an incompatible type int expected optional string. And this, you can run this in your entire code base and now I haven't prepared this because it's in the package and it's all nice and up so I can't run the entire thing but so that's how that kind of works. Sorry, MyPy, no it's a static checker so it doesn't run your code, it just runs through the AST and checks so you don't have to worry about it performing side effects in your code. Another one, union arguments, which is sometimes you have objects that takes any of a certain amount of types, you know duck typing, you want to support anything that kind of looks like this thing. So here's an example using a class that represents a longitude and latitude, a position on a map. And this thing supports either a flow through a decimal which is a fairly reasonable thing because maybe you need to have more precision somewhere or your database returns that or whatever. And the way you define that is you mark it as a union and then you say that I take a union of flow through a decimal and as long I get either of them I will just accept that, that's what we find. I do recommend that you convert it into one of the types when you save it internally though so you're consistent in your external behavior, so that's a good idea. And there should be no, alright it doesn't know what decimal is, okay then we'll deal with that some other day. Yes, so the colon is an indication that this is using a type hint and the equals is what it is, so this is a typo, thank you. The problem when you don't really run your code, you just write it. This is the way I wish it worked at work as well, but there I always get caught. So that's the union argument, so looking at this thing though it gets kind of gnarly when you want to work with this because you're doing this in multiple places and these can get really long, so if you're taking in a function for instance you might say that I want to take any function that takes two integers and return an integer which looks a little bit something like this and if you want to do that in a couple places you pretty soon get kind of bored. So what you can do instead is you can make alias types and the way they work is that you simply put in a name and then you define it as part of that and then you can just use that name wherever you would use that anyways and then the hint and engine will tell you that expected union of these values and then give you a warning from that. So now I have a feeling that my pipe will complain about missing decimal. So here you can see it from the command line, so you can run this on your CI server. So generics, if you've used any like Java or anything like this you'll soon realize that it's kind of useful that there are certain types of problems where it's nice to have the types because I'm supposed to be kind of consistent in what I do. In Python I can just put in whatever I want, so in this case like take you to have a stack which is something that you put things in on and then you remove them from the back. The stack doesn't care whether it takes in a string or an integer or a Pokemon or whatever as long as it is handled in the same way. So you can make a generic stack by defining a type variable that you can name whatever you want in this case t because that's what people usually name a single type variable and then whenever you initialize it you know that you're always going to get out something of type t. Now the sad part here is that IntelliJ or PyCharm doesn't actually support this yet so I can't get any type hinting or help or any help from IntelliJ. It will just use it as if you would normally in Python but MyPy will at least give you warnings if you're using it incorrectly and that will at least still help you catch errors. Now some of the things that if you're building larger code bases in Python especially code that has been around for a long time you probably know that a lot of your data is just dictionaries and hopefully it has some keys and hopefully it's going to be fine. But every so often you're going to be like oh so I'm adding this movie here's the director Steven Spielberg in year something something except that this that's not a movie that's a director and a year of something and he probably wasn't born then because he's definitely older so it would be nice if this also could tell me that oh as I'm inputting this data I know that it is wrong whatever I'm passing in here is never going to be the type of dictionary that I want and you can do that you can use something called type dicts which is part of MyPy extensions and something that is probably coming out with Python 3.7 but it is supported in the recent version of MyPy and the way you create one of these is that you can create a class that derives from type dict and then you just provide parameters and then the type that it uses and that way you can say wherever you get with a movie you know that these values are going to be there or you're supposed to know that they're there as long as people are using MyPy and following through there's also different syntax you can use for this if you would rather do it but personally I like this kind of class syntax because I think it'd be nicer but it's nice to know about and if you if you're using a key that is not in your class it's going to warn you with MyPy I don't think it will warn you if you use a key that's not there there are some settings I haven't explored all of them it will definitely warn you if something is missing that they expect to be there and I would say that generally these are more the structured type of hints that you can get are more towards does it do I live up to the minimal requirements that I'm asking of my code rather than is it only this? yeah exactly so in this case let's just check that so I don't have a hulu in my definition so hopefully it won't complain about that so we confirm what it is actually it is saying that it's an extra so that was different from what I expected does it look like we've got a clean couple? I actually don't know I don't have interest I can't check it out but I think, yeah, I'm sorry I don't know there is a lot of support for the built-in types that are in Python and there's also the discoverability of what hints you have is quite good so if we go into so many of them are American movies no you can use any movie you want absolutely with Python 3 you have full UTF-8 support so you can have any name you want including emojis but not in the names so there is support for name tuples so the exact usage of that I'm not entirely sure of it seems to be similar give it like that so another thing I wanted to mention is structured typing which is if anyone has used go one of the really nice things in Golang is that if you define an interface saying that I want to take an object that has this method on it I don't care what it is you don't have to define it anywhere in your type system as long as it has the method in this case right takes a string and returns nothing I'll just accept it it doesn't matter I don't care what it does under the hood and that's kind of how I would like this thing to work sadly this is not the way Python works by default well actually it is true Python does work like that by default and if you don't know about it it will go boom which also is good but it can make it harder to figure out where something went wrong when you're trying to track down a bug so in typing extensions there is something called a protocol that you can use to define that let's see a protocol which says that any method that takes a right is a text that returns nothing that is allowed in here and then that way it won't complain about it so if I do my py it will warn me that my second object here that has wrote instead of right is not actually a writer class and when I'm going to pass that in it will go boom for me which is not what I wanted and I could just run this code I would get the same warning but if you're living in a large code base and you don't know you may not necessarily know all the deep boughs of it what's going on this might catch you some bugs this it doesn't the thing is that the protocols don't really provide anything apart from the fact that you're just saying that I want an object that kind of looks like this and then my py will tell you whether it's there where the object has that method or these methods that you asked for the type in system in python is heavily reliant on abstract base classes so they do encourage you to use abstract base classes and then you can do at method required I think it is and that will provide you with race not implemented error and you just give it a pass as a method body and most of the built in type in are also dependent on abstract base classes in some way I don't quite understand but they all use them and that way you can implement an iterable which will just work anywhere and anywhere python asks for an iterable as long as you've implemented it correctly it will just work so that's kind of how that goes and so yeah so that's the main types of hints I figured would be a good idea to talk about and why it's useful and the second part is so say that you're all blown away by this and want to start doing this but if you're anything like where I'm at you have a large code base that's been living there for a couple of years and putting this on is going to give you just so many warnings that it's not going to be worth it because you're just going to be spending weeks trying to figure out where everything comes from well it's optional you don't have to get started with it the way you tell my pie that I want to see type in is that you define the return method and then it will go into the method and check what's going on so if you want to start somewhere small like this is some new code that I want to get started with you can just add in that this is where I start add a return value now my pie will check it whenever I ask what's going on so here we see that we have two the string is not an integer we turn it off there's nothing a sweet silence yes is the return type also checking the returns inside the function yes it is so if I were to say that this returns a string or text because we also want to support Python 2 because in Python 3 you always use a string but in Python 2 you probably want to use a unicode and so on so now it's telling us here it's yellow because I expect there to be a return value and there's no return value yet so if I return now 10 it will tell me that this 10 is an integer instead of a string so if I go hello it will then be happy what happens if you return with a variable which was not used with this type in so it could have multiple types it depends on the code so here in this method I return something that it doesn't know what the type is going to be so if I take this thing it doesn't, IntelliJ for instance doesn't know so if I do return a here it will just assume that it's fine because it doesn't know it doesn't have any integer information but if I instead define the b that's a 2 and I do that it will go yellow because it knows that it's not there so the hinting engine that's built into PyCharm and the hinting engine that's used in MyPy are actually different so some of these things are going to work better on the command line some of them are going to work in the editor the advantage of having it built into your editor is of course that you can see it really quickly what you have to change and some of the extra nice benefits is that if you want to change your methods signatures or you want to rename something it has a much better idea than what it used because it actually knows that this variable has been tagged to be of this class type so when I'm three levels deep in some method call it still knows that this is a type writer so when I rewrite that from wrote to write it will just do it so it's really powerful and really kind of allows you to do Python like you do in Java or C sharp or something where you always know what everything is and this has dramatically sped up my development experience this year is there a big difference between text and STR? yeah not here this is mostly I'm doing it because of Python 2 so in Python 2 text is an alias to unicode whereas if I did string and we were using this in Python 2 we would think it would be a binary type or like equivalent to so it's for compatibility between Python 2 and 3 yes so I just got into the habit of always writing it like this we have parts of the code that I write that are Python 2 and Python 3 and that's also something else that sorry nice yeah it is and there's also that you don't have to do this all in like with this syntax if you're on Python 3 you can actually provide your hints like this and it will also pick them up and it will work it's a little bit annoying because it's a comment but it will work as at least some things you can get going and whenever you would expect that oh this variable is an integer so you just add type type and if we go into the position class for instance where I had like this you can either put them like I have here or you can do because they can get really really long especially if you do them inline so all of this also works in Python 2 which is really good because it makes it easier if if you want to do a Python 2 to 3 conversion project I feel like this is also one of those things that can help you out because it's easier to find where everything is and yeah and refactorings good stuff luckily I got the management buy in so no the the advantage I felt like the when I got in there and I wanted to introduce this my team was they weren't they didn't use any of this stuff they were using Atom with some basic Python plug-in so they couldn't easily jump to code they didn't know anything so just showing them like if you add type pins and you're trying to understand that this thing that you defined here that lives in a separate project in the same giant monorepo that we have on the type in thing stuff you can actually understand your code really quickly they really they bought into it quite a quick the only annoying bit is getting them to actually write it because remembering and getting used to it and not wanting to force all code on CI yet to not go green if you haven't added the type pins so overall no the hopefully most people that see this they see that there is some kind of value to it and I'm kind of curious do you think that would type pins be able to add any kind of value to the work that you do on a day-to-day basis or is it more like how would you document the parameter types now since your type pins you don't have to so I don't have to that's true I still would though there are classes where I define this is the argument that I take in here it is I would still define the type because it's still useful and the way it would look like so if I use Python 2 for instance I would do my hints like this and then I would do my doc string below because that's the syntax that mypy and intelligence expects it to be in and then you would just add your definitions to your comments so I expect this to be with the difference that I usually use the Google styles I don't actually know what this format is correct now but I would still do that and that's actually how I started out with type-inting because with IntelliJ or PyCharm at least if you put your types in the documentation string that will also give you all the benefits of always it's the right type can I do the auto-completion on it which is also why so much of the scientific Python stuff kind of works I was using Pandas the other day or PyArrow and discovered that basically everything type-ins out of the box because all the documentation is written with the hints which is fantastic Yes Is there a convenient way to enforce these type-ins in runtime and on the other hand is it a good idea to do so so there's no enforcing in runtime so the you can do is instant checks but like for protocols the structured types there are some ways that work with instance and so on but yeah it's a little bit botchy you can but I would suggest sticking to more traditional duck typing ways of doing it so if I want to be sure that I want a writer and I want to get type-ins to help me out but if I want to make sure and then if it's not there either blow up normally like I try to call this method on your object you don't have it do a check-in say that like does this do this object have this attribute and is it callable so and then just work it from there that would be my suggestion to do instead and because that way you don't have to really worry about like you get some nice way of describing it and a little bit better this idea of how you want your code to work because sadly it is still not Java or something like that but yeah it will happily compile it will happily go boom on you in production so and in my world trying to avoid and going boom is production is part of the big benefits of using type-inting is there some potential to crawl yes so this is also my pie so I haven't gone through my pie completely and figured out all the switches for using it one of the things is that I have a package and I don't have a package because I just made a director with a bunch of example files so it does absolutely support it I just sadly don't know the exact switches for doing it absolutely yes absolutely so it's definitely something to do and there's also a lot of configuration you can do for how it should follow which type of hints it should warn about whether it should yeah I haven't gone through it the documentation is actually quite nice it's relatively straightforward to get into type-in so if you search for my pie and go through the PEPs you'll have a really good understanding of how it works this is the only way to and it will take you because in the past what some people does is use separators to recognize how each of the I didn't know that there was a decorator version before it's not a decorator it's like they write their own decorator and they see the decorator just taking a list of arguments of pipe and then you run the pipe before you run you wrap it around the actual function you want to run but the decorator function basically oh you mean like a insert int or something like that they would just make sure it's an int but it doesn't give you any of that if you want that type of checking you have to do it yourself that's just a it's just a hint it's here to support static analysis making better editors and IDEs it's not there to make things faster or more secure in production now if you you can use it and you can extend it in your own code like this is a critical path or something to help you do that but it's still down to you personally so is there a reason why you use optional as well as text when you're already specifying the format? in this particular case just because I wanted to show what it looked like I wanted a contrived example what you why you would do it is that so in this case I had an optional optional with a value of none and while none is absolutely a valid value I wanted to be that if you don't give me a none I want you to give me a string and then my pie it was looking like that there we are so yeah if I had set this hello here instead I wouldn't have to because it would understand that either it will be a string it will be the string you pass in it will be hello and then my pie is smart enough that there's no need to define it it will just take care of it itself yes so can you do the type to return radians sorry to return radians so the radians conventionally we can't do that but in this particular case can you do that because if you are doing a whole lot like for the whole world so that is a lot quicker so radians it depends on how you want to represent your radians so you want to do it as an example yeah so normally you would have a method that either converts it to a radian or whatever and the question is do you want it to be a float or do you want it to be a class that in turn wraps something else and that's how you work it so you have to decide on how do you want it to look like so for instance I want it to be a class so yeah can you show that yep absolutely let me go up to the position example so say that we now I am not entirely sure how the radian example would look like so let's just assume the most basic thing that I can think of which looks like this and I expect it to have to be a float and then if I said in here I want to convert it it would then return an instance of a class radian and that way you would work it out is there a way to like monkey page libraries that don't support typehands and you have like this one function that you always call and you want to make sure that your code knows what's in which I'm done you can I have had mixed success with doing it so there is there is something called a type shed you that generally gets installed by default the way it works is that you create a file with the same name as the library you want to add to and then you provide stubs like the method you want to use so I was using it for the responses library for instance and responses has a lot of methods that goes something like this and the way you would define it is that when this when it gets back it returns a connection so you would just create a file with a lot of stubs like this and then you would tell you can tell my pi that here's my stub folder and the exact syntax I don't remember but you can absolutely do it in theory you're supposed to be able to distribute it on Pi Pi as well but last time I tried it I couldn't upload it because it didn't get bundled but I think they might have fixed that now so yes how would you do a return type for a constructor method try that and I couldn't find a good way to do it so could you give an example so it's a class and it has a constructor method so it's a class method returning a new instance class so because it's defined inside it doesn't accept the return type so let's call this new because why not so the way you do that is that you do it as a string and that way it knows that because it's very common that sometimes you have to refer to the class you're in but it's not defined otherwise you have to import it so you can do it as a string so this one is a pure Python thing or is it also accepted by Pi Pi Pi also accepted by Pi Pi Pi it's the default way to work around this and the same thing goes that if you have like a nested structure because yeah it's absolutely common to do and that's the way it is okay cool does it plays well I don't think they play well with inheritance yes I would say yes there's a little bit inheritance has its own little issues like I found that sometimes at least PyCharm is a little bit bad at telling me that oh so you inherited from this and you're trying to call this method for some reason it messes up my inheritance chain and thinks method that don't exist exist I don't know exactly what that's about it mostly works the way you expect though so any other questions yes so since functions are nested and objects in Python is there a way to retrieve the type in runtime so if I want to know what was the type in purpose that is a great question I am pretty sure it works because it's supposed to be as part of the commenting system and the method data I have never tried it but I'm pretty sure that it works but sorry for that so anything else otherwise yes yes so if you use the comment based version it works in any version of Python that you can run MyPy on and MyPy itself doesn't care what Python version you use it needs I think MyPy is Python 3.3 or so and above but I don't think MyPy needs to be running the same version of Python that you're checking in Python 2.6 code because luckily those days are behind me but it definitely works in 2.7 cool I think I want to talk with the most questions ever that was my goal if anyone has more questions go to Facebook and just ask them please do ask questions if you have anything more I'll post some links tonight what you can read more about this