Sling Academy
Home/Python/Python: Defining distinct types using NewType class

Python: Defining distinct types using NewType class

Last updated: February 19, 2024

Introduction

In recent versions of Python, particularly Python 3.10 and beyond, the language’s type-hinting capabilities have significantly expanded. Among the many features introduced, the NewType function from the typing module stands out as a powerful tool for creating distinct types. This tutorial will navigate the creation, usage, and implications of using NewType to define distinct types in Python, complemented with practical examples and best practices.

Why Distinct Types? In software development, ensuring that your function parameters, return types, and variable annotations are clearly specified can drastically reduce bugs and misunderstandings about your code’s intent. Python’s dynamic nature makes it permissive and flexible, but this can often lead to confusion and errors in complex systems. By using distinct types, developers can leverage Python’s type checking to enforce stricter type constraints and enhance code readability.

Understanding NewType

The NewType helper function allows developers to create distinct types, which at runtime act exactly like the types they are based on. However, during type checking, these are treated as separate, specific types. This mechanism aids in catching certain classes of bugs early in the development process.

from typing import NewType

UserId = NewType('UserId', int)

# At runtime, UserId acts exactly like an int, but type checkers treat it as a distinct type.

Creating New Types

To create a new type, you need to call the NewType function with two arguments: a string representing the name of the new type and the type from which it should derive.

from typing import NewType

Distance = NewType('Distance', float)

# Now, Distance is treated as a distinct type from float, providing clarity and type safety in your APIs.

Using New Types in Functions

Once you have created a new type, you can use it in function signatures to make your intentions clearer and enforce type safety:

def travel(distance: Distance) -> None:
    assert type(distance) == float  # At runtime, distance is still a float.
    print(f"Traveling {distance} miles")

Type Checking and Dynamic Nature

It’s important to note that while NewType aids in making type hints more explicit, it doesn’t change the runtime behavior of Python. Python remains a dynamically-typed language, and using NewType doesn’t introduce runtime type checks. For static type checking, you’ll need to use tools like mypy.

Advanced Examples

Let’s examine more complex uses of NewType, incorporating it into classes and other typing constructs:

from typing import NewType, List

EmployeeId = NewType('EmployeeId', int)

class Employee:
    def __init__(self, id: EmployeeId):
        self.id = id

# Creating a list of employee IDs, now more explicitly typed.
employee_ids: List[EmployeeId] = [EmployeeId(1), EmployeeId(2)]

Common Pitfalls and How to Avoid Them

While NewType can significantly improve your code’s type safety, there are common pitfalls to be aware of, such as treating new types as entirely new classes and expecting runtime behavior changes. Remember, NewType is primarily a tool for static type checking.

Conclusion

Python’s NewType offers a compelling way to introduce distinct types into your codebase, providing clarity and preventing certain kinds of bugs. Now equipped with the knowledge of how to define and use these distinct types, you can make your Python programs more robust and readable. Remember that NewType is only a part of Python’s type hinting system, and embracing the full spectrum of typing features can considerably improve your development experience.

Next Article: Python typing.Concatenate Examples

Previous Article: Using Type Aliases in Python: A Practical Guide (with Examples)

Series: Basic Python Tutorials

Python

You May Also Like

  • Introduction to yfinance: Fetching Historical Stock Data in Python
  • Monitoring Volatility and Daily Averages Using cryptocompare
  • Advanced DOM Interactions: XPath and CSS Selectors in Playwright (Python)
  • Automating Strategy Updates and Version Control in freqtrade
  • Setting Up a freqtrade Dashboard for Real-Time Monitoring
  • Deploying freqtrade on a Cloud Server or Docker Environment
  • Optimizing Strategy Parameters with freqtrade’s Hyperopt
  • Risk Management: Setting Stop Loss, Trailing Stops, and ROI in freqtrade
  • Integrating freqtrade with TA-Lib and pandas-ta Indicators
  • Handling Multiple Pairs and Portfolios with freqtrade
  • Using freqtrade’s Backtesting and Hyperopt Modules
  • Developing Custom Trading Strategies for freqtrade
  • Debugging Common freqtrade Errors: Exchange Connectivity and More
  • Configuring freqtrade Bot Settings and Strategy Parameters
  • Installing freqtrade for Automated Crypto Trading in Python
  • Scaling cryptofeed for High-Frequency Trading Environments
  • Building a Real-Time Market Dashboard Using cryptofeed in Python
  • Customizing cryptofeed Callbacks for Advanced Market Insights
  • Integrating cryptofeed into Automated Trading Bots