Custom types in python

Create custom datatypes using Pydantic module in Python

Many times, we find that we need to pass in a long list of variables to a function, and specifying all of that in the Python function signature can be a bit messy. Again, problems also arise when you want some kind of validation to variables passed. For a long list of variables, it is really difficult to keep validating the data inside the main function body, also it is not a good practice. In that scenario, what you want to do is separate and segregate your variables into different classes. Here, we are going to demonstrate how can use pydantic to create models along with your custom validations. First, let’s discuss the use case.

Consider, we are receiving some data from an API call, and we need to do some kind of analysis on it. Typically, an API response will send the response in form of JSON, so we would want our models to be able to serialize and deserialize JSON (1).

Читайте также:  Какие существуют типы тегов html

Also, we would assume types of certain variables. For example, if we are passing an address, we would assume the pincode to be an Integer value. This is type checking (2).

To perform analysis, you would make some assumptions on the data, like say, pincode should match with the district name provided. This is validation (3).

We might also assume that for certain fields like states, it should be within a list of states say in India, and not any random arbitrary value. This falls under cleaning (4).

So, with these four requirements, let’s start coding out mode. I would assume that you have python installed on your system. To, install pydantic simply run,

With that set, create a file called models.py and paste the below code in it. We have added detailed in-line comments in the code itself to make it easier to understand directly.

Источник

Intro

Since Python 3, classes and types are pretty much the same thing.

A class is a blueprint for creating objects, which defines the attributes and methods that the objects will have. When you create an instance of a class, you are creating an object with those attributes and methods.

A type is the category to which an object belongs. Every object in Python has a type, which defines the set of operations that can be performed on it. For example, the type of an integer is int and the type of a string is str .

Classes are used to create new types. When you define a class, you are defining a new type of object. The type of the objects created from a class is the class itself.

Consider the following class definition:

class Person: def __init__(self, name, age): self.name = name self.age = age 

In this case, Person is a class that defines the structure and behavior of a Person object. When this class is defined, it creates a new type object called Person . This type object can be used to create new instances of the Person class

>>> alice = Person("Alice", 25) >>> type(alice) class '__main__.Person'> 

This type can be used to statically type your code.

def get_person() -> Person: return Person(name="Alice", age=25) 

1. typing.TypeVar PEP 484

typing.TypeVar allows you to create type variables that can be used to specify types in a flexible way. Type variables can be used to define generic functions, classes, and protocols that can work with different types.

import random import typing T = typing.TypeVar('T') def get_random_item(items: typing.List[T]) -> T: return random.choice(items) class Person: def __init__(self, name, age): self.name = name self.age = age alice = Person("Alice", 25) bob = Person("Bob", 35) get_random_item([alice, bob]) get_random_item(['not alice', 'not bob']) 

In this example, we create a type variable T using TypeVar(‘T’) , which represents an unknown type. We can use this type variable to define a function that takes a list of items of type T and returns a random item from that list, which is also of type T .

TypeVar shines when used with Generic , if you can find a use for it in your codebase.

import typing T = typing.TypeVar('T') class Person: def __init__(self, name, age): self.name = name self.age = age class ObjectsStore(typing.Generic[T]): def __init__(self): self.objects: list[T] = [] def append(self, obj: T): self.objects.append(obj) class PeopleStore(ObjectsStore[Person]): pass people_store = PeopleStore() alice = Person("Alice", 25) people_store.append(alice) people_store.append('asd') 

In the dummy example above, when creating a class PeopleStore , we tell it to inherit from ObjectsStore and that the type T is Person , so all objects within PeopleStore need to be of type People .

When we run mypy on this, we see

main.py:29: error: Argument 1 to “append” of “ObjectsStore” has incompatible type “str»; expected «Person” [arg-type]

2. typing.NewType PEP 484

typing.NewType is a typing module that allows you to create new types that are NOT aliases for existing types.

from typing import NewType PersonAge = NewType("PersonAge", int) class Person: def __init__(self, name, age: PersonAge): self.name = name self.age = age def __str__(self): return self.name alice = Person("Alice", 25) 

Even though PersonAge was derived from int type, mypy complains.

main.py:15: error: Argument 2 to “Person” has incompatible type “int»; expected «PersonAge” [arg-type]

We’re forced to cast it to the correct type, even though it’s an instance of int .

>>> alice = Person("Alice", PersonAge(25)) >>> isinstance(PersonAge(25), int) True >>> alice.age.__class__.mro() [class 'int'>, class 'object'>] >>> alice.age is 25 True 

I think it’s best to think about it as a special kind of alias, because static type checkers will know not to treat it as such.

3. typing.TypeAlias PEP 613

typing.TypeAlias allows you to create a new name for an existing type. It is essentially an alias for the type, which means that the new type is equivalent to the original type for both — human and static type checker.

from typing import TypeAlias PersonAge: TypeAlias = int class Person: def __init__(self, name, age: PersonAge): self.name = name self.age = age def __str__(self): return self.name alice = Person("Alice", 25) assert isinstance(alice.age, int) assert type(alice.age) == int 

4. types.GenericAlias PEP 585

I’m not sure what’s the use case for it and I assume I will never find one, as typing using the standard library has improved a lot since GenericAlias was added. For example, these two are identical:

>>> assert GenericAlias(list, Person, ) == list[Person] >>> True 

One use case for GenericAlias is to create custom generic types that are not included in the typing module. For example, suppose you want to create a generic type Pair that represents a pair of two values of potentially different types. You could define it like this:

import types class Pair: def __class_getitem__(cls, params): return types.GenericAlias(cls, params) PairType = Pair[str, int] # creates a GenericAlias representing Pair[str, int] 

In this example, Pair is a custom class that has a __class_getitem__ method, which is called when the class is parameterized with type arguments. This method returns a GenericAlias object that represents the parameterized class.

Though it doesn’t look very useful to me.

Источник

Python Data Types

Python is an object-oriented programming language. Every variable in Python is an instance of some class. There are many pre-defined Python data types. We can create our own classes to define custom data types in Python.

Some of the popular data types in Python are:

Python Data Types Check

We can use type() function to check the data type of a variable.

Python Data Types

Let’s look at some examples of data types in Python.

Python String Data Type

Python strings are the instances of class ‘str‘. The string is a sequence of Unicode characters. Python strings are immutable. We can define a string using single quotes (‘) or double quotes(“).

The string is the most popular data type in Python. There are various operations supported for string objects – length, format, split, join, slicing, etc.

s = "abc" print(type(s)) s1 = 'hello' print(type(s1)) print(s[1:2]) print(len(s)) print(s.split('b'))

Python Numbers Data Types

There are three data types in the numbers category – int, float, and complex. There was another data type ‘long’ in Python 2 but it got deprecated in Python 3.

i = 10 print(type(i)) i = 1.23 print(type(i)) i = 1 + 2j print(type(i))

Python Numbers Data Types

Python Tuple Data Type

A tuple in Python is an ordered sequence of items. The tuple is immutable i.e. once defined we can’t change its values.

We can define a tuple using parentheses where items are separated using a comma. A tuple can contain any number of elements and the elements can be of any type.

t = (1, 2, 3) print(type(t)) t = ('a', 1, [1, 2]) print(type(t))

Python List Data Type

The list is almost the same as Tuple, except that it’s mutable. The order of the elements is maintained.

Python List is defined using brackets and the elements are separated using commas.

my_list = [1, 2, 3] print(type(my_list)) my_list = ['a', 1, [1, 2]] print(type(my_list))

Python Set Data Type

Python Set is an unordered collection of items. Set can’t have duplicate values. The order of elements is not maintained in the Set.

A set is defined using braces where the elements are separated using commas. Python Set uses hashing to store elements. So the elements must be hashable i.e. hash() function should work on them. Since List is unhashable, we can’t store a List object in the Set.

my_set = print(type(my_set)) print(my_set) my_set = print(type(my_set)) print(my_set)

Let’s see what happens when we try to have a List as the Set element.

>>> my_set = Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: 'list' >>>

Python Dictionary Data Type

Python Dictionary is an unordered collection of key-value pairs. It’s defined using braces and the elements are separated using commas. The key and value can be of any type. The key-value pair is defined using a colon (key: value).

Python Dictionary objects are of type ‘dict’. They are good to store a large number of values where fast retrieving is required.

my_dict = print(type(my_dict)) my_dict = print(type(my_dict))

Python dictionary uses hashing on the key to store and retrieve elements, so the key object must support the hash() function. That’s why we can’t use a list as the key of a dictionary element.

>>> my_dict = Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: 'list' >>>

Defining Custom Data Type in Python

We can define a custom data type by creating a class in Python.

class Data: pass d = Data() print(type(d))

Python Custom Data Type

Does Python Functions have a Data Type?

So far we have seen that the data type is associated with Python variables. But, do python functions also have a data type?

Let’s check this with a simple program.

def foo(): pass print(type(foo))

So Python functions also have a data type – function. They are the instances of class function.

Does Python Class Methods have a Data Type?

Let’s see if the python class methods also have a data type or not.

class Data: def foo(self): pass d = Data() print(type(d.foo))

So Python class methods have the data type as ‘method’. They are the instances of class ‘method’.

Summary

Python is an object-oriented programming language. Everything in Python is an object of some class, even the functions and class methods. We can use the built-in type() function to determine the data type of an entity in Python.

What’s Next?

References

Источник

Оцените статью