Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

Type Validation

Here are resources for more information about type checking and data classes in Python:

00:00 In this lesson, I’m going to introduce you to type validation for command line arguments in Python. Now, keep in mind that Python is a dynamically typed language, so type validation in general in Python can be a difficult task.

00:13 If you’re having any trouble, I’m going to link some resources from Real Python below with some more information about typing in Python in general. So, let’s take a look at a basic example of a command line interface in Python that does some type validation.

00:28 This Python file uses the dataclasses.dataclass to validate three simple arguments. By looking at the USAGE string, you can see that this can be run with an optional --help argument or three arguments of which the last is optional: firstname, lastname, and age.

00:49 You can tell from this @dataclasses.dataclass, which is called Arguments, that the firstname and the lastname should be strings, whereas the age should be an integer with a default of 0.

01:01 Now, you don’t fully need to know data classes in order to understand this Python file. What you do need to know is that data classes can allow you to record the expected types of each parameter of a class so that you can then check them later.

01:19 I’ll show you how to do that in a moment with this check_type() function. But taking a look at these other two functions you can see that validate() simply checks the length of the arguments—the number of arguments—and if the third argument exists, then it converts that argument from a string to an integer.

01:38 Then, it generates the actual Arguments data class by using this class constructor on those arguments. Then, it calls check_type(), which I will implement in a second.

01:50 Going down to main(), you can see that main() gets the args, it checks to make sure that there are some actual arguments, and if the arguments are --help, it prints USAGE. Otherwise, it just validates those args.

02:02 So, this is really a command line interface that does nothing except gets firstname, lastname, and an age, and checks to make sure that they’re of the correct type, and prints out a little bit of helpful output.

02:12 It doesn’t really do anything other than that.

02:15 So now, going back to this check_type(), let’s take a look at this. What you want to do is go through, and the data class has a field parameter that

02:27 will let you iterate through all of the fields in the data class, and then you can get access to both their values and their types. So, for field in dataclasses.fields() of this object—

02:41 which is in fact, a data class—you can say that the value = getattr() (get attributes), which is an inbuilt Python function. So, you’re getting the attribute of that object with this field’s .name.

02:55 Then, you can actually check to see if the value has the type that you expect. I’ll print out here print(f"Value: {value}").

03:09 Then, I can print(f"Expected type:

03:16 {field.type}

03:19 for field {}").

03:25 And then, of course, I should print out whether they actually match, so I’ll say print(f"Types matched") and then I can simply use up some Python logic here, and I could say f"{field.type == type(value)}" of the actual value.

03:44 This will iterate through all of these fields in the data class. It will get the actual value that’s been stored in this class, and then it will print out the expected types and whether those types matched.

03:55 Let’s try it and see it run. All right, so I can say here python and I’ll put in my own name and then I’ll say that I’m 99 years old, just for fun. And as usual, I need to include an extra quotation mark, which I failed to include here. I’ll just try it one more time.

04:17 And now you can see here, I ran this—and let me make this a tiny bit bigger. And I’ll say for the value Liam, expected type 'str' (string), and the types did indeed match. And the value Pulsifer—the types did indeed match.

04:33 And the same thing for the integer. Now, I can do this as well without the age argument,

04:39 and this matched too because this default value was 0, which is of type int. If I say the same thing and I say Liam Pulsifer Ninety-Nine, then that did not in fact match here.

04:55 One thing you probably want to watch out for is that it might be the case that I put in something like 99 Liam Pulsifer, and this would not match the age field, obviously, because Pulsifer is not an int, but it would match this first field, right?

05:12 So this is in fact a string, because all things passed in on the command line are strings, whereas you might be more familiar with calling this an integer.

05:20 So, it might be worth doing even a little bit more type validation for something like that case.

05:27 You can do similar kinds of type analysis with the typing.NamedTuple module. This is another kind of class that lets you define the expected types of

05:41 fields of that class beforehand. So, I’m not going to do any actual code writing here because a lot of this code looks very similar, but the general idea here is the same: that you annotate first the actual type that you expect for each field of your NamedTuple—in this case, also called arguments. And then your check_type() and your validate() and your main() really look almost exactly the same as they did in the last example with the data class, except in this case, you use the object __annotations__ dictionary to actually get access to

06:17 those annotations beforehand. So instead of the dataclasses.fields(), you’re using annotation logic. This comes directly from Python’s typing initiative, which was an idea to allow people to annotate types in Python so that you can do what’s called type linting, which is kind of a pre-runtime type checking just to see if your code is all typing out as it should. Now again, this stuff—if you’re interested in it, then feel free to browse.

06:47 I’m going to post some materials underneath this tutorial on typing in Python from Real Python. But otherwise, just understand that as long as you have some way of figuring out what the field’s type should be before you’re actually working with them, then you can do your type checking in this similar fashion by looping through all of the attributes and their expected types.

07:09 So, that’s a quick introduction to type validation in Python. As I said, this topic is complex but it can be a great way to really understand the behavior of your code on a deeper level and catch errors before they happen at runtime.

07:22 In the next section of this tutorial, I’ll be going through how you can use established libraries in Python to build command line interfaces really easily and without doing a lot of this hard work that I’ve gone through in this section.

Become a Member to join the conversation.