Type hinting in Python 2
According to Suggested syntax for Python 2.7 and straddling code in PEP 484 which defined type hinting, there is an alternative syntax for compatibility with Python 2.7. It is however not mandatory so I don't know how well supported it is, but quoting the PEP:
ForSome tools may want to support type annotations in code that must be compatible with Python 2.7. For this purpose this PEP has a suggested (but not mandatory) extension where function annotations are placed in a # type: comment. Such a comment must be placed immediately following the function header (before the docstring). An example: the following Python 3 code:
def embezzle(self, account: str, funds: int = 1000000, *fake_receipts: str) -> None:
"""Embezzle funds from account using fake receipts."""
<code goes here>
is equivalent to the following:
def embezzle(self, account, funds=1000000, *fake_receipts):
# type: (str, int, *str) -> None
"""Embezzle funds from account using fake receipts."""
<code goes here>
mypy
support, see Type checking Python 2 code. How to specify multiple return types using type-hints
From the documentation - Union Type:
A union object holds the value of theThis use of|
(bitwise or) operation on multiple type objects. These types are intended primarily for type annotations. The union type expression enables cleaner type hinting syntax compared totyping.Union
.
|
was added in Python 3.10. Hence the proper way to represent more than one return data type is:def foo(client_id: str) -> list | bool:
For earlier versions, use typing.Union
:from typing import Union
def foo(client_id: str) -> Union[list, bool]:
But do note that typing is not enforced. Python continues to remain a dynamically-typed language. The annotation syntax has been developed to help during the development of the code prior to being released into production. As PEP 484 states, "no type checking happens at runtime."
>>> def foo(a: str) -> list:
... return "Works"
...
>>> foo(1)
'Works'
As you can see I am passing an int value and returning a str. However the __annotations__
will be set to the respective values.>>> foo.__annotations__
{'return': <class 'list'>, 'a': <class 'str'>}
Please go through PEP 483 for more about Type hints. Also see What are type hints in Python 3.5??
Kindly note that this is available only for Python 3.5 and upwards. This is mentioned clearly in PEP 484.
Python 2.7 type hinting callable types in PyCharm
The correct way to document a callable within Pycharm (or within any other tool that understands PEP 484 type hints) is like so:
from typing import Callable
def set_function(self, function):
# type: (Callable[[int], None]) -> None
...
Since you're using Python 2, you'll need to install the typing
module from PyPi, if you haven't already. (typing
was added to Python's standard library in 3.5, the module on PyPi is a backport).You can find more information on using the typing module in Python's documentation, and within the documentation for mypy.
(If you're not aware, mypy is a command line tool that also understands PEP 484 type hints and will also statically analyze and typecheck your code. It is an independent effort from Pycharm's built-in type checker. Since both Pycharm and mypy use PEP 484 types, mypy's documentation is often a good place to start looking to learn more about using type hints.)
Type hints in PyCharm for Python 2.7 (named tuple)
Try:
def foo(args):
"""
:type args: CreateVhostDoArgs
"""
In the settings there are different docstring formats which might be of use to you. Settings | Tools | Python Integrated Tools
The default which I tested with is reStructredText
. The other ones might behave a little differently (or not at all)In this SO post I try to expand a-lot on type hinting in PyCharm if you want some more details.
I did this a-lot a number of years ago when python first introduced type hinting and pycharm quickly rolled out an update supporting it, but it did not support everything that the PEP outlines, and I think I only found reStructredText
to work, but things might have changed since then. When I was doing it back then I remember it being really annoying with maintenance of class names changing and that not getting propagated to the docstrings properly. If that type isn't actually used in the file (not imported) it just won't give an error or warning and I guess it just thinks you are a dumb user writing stuff in there incorrectly. Then you need to do an import just for something in the comments, which it doesn't seem like PyCharm is complaining these days about that, but if you have other linters they might. There are probably other pitfalls to watch out for too, so tread cautiously.
It definitely works, but I don't recommend it to anyone in python 3.5+ (when python introduced type hinting) for reasons detailed in the other post.
I did test locally specifically with namedtuple
and it worked.
Is there a way to use type hinting on back-compatible code in Python?
To use type hints in a fully backwards-compatible way, you will need to...
- Always use the comment-based syntax: Python 2 does not support function annotations; Python 3.0-3.5 do not support variable annotations.
- Install the backport of the typing module when using Python 2.7 and 3.0 - 3.4. The typing module was added to the standard library in Python 3.5 and must be pip-installed for earlier versions of Python.
If you want to use those types and still support Python 3.5 and 3.6, additionally install the typing_extensions module. You can find a full list of backported types on the github repo.
Basically, if you want to use any of the types listed in the github repo linked above, and support Python 3.5.0 - 3.6.x, always import them from typing_extensions
instead of from typing
.
Some additional details and caveats that you may or may not care about:
About
typing_extensions
:If you plan on using
typing_extensions
, also pay careful attention if you need to support Python 3.5.0 - 3.5.2. The typing module went through several, often substantial, internal changes since it was first released in Python 3.5.0.The
typing_extension
module tries to bridge between these different internal APIs in a sane way, but there's always the chance that something was overlooked. The latest minor versions of Python 3.5 and Python 3.6 are much more up-to-date though, and so are far less likely to have issues.(You might also be able to get away without using
typing_extensions
if you want to support only the latest minor versions of Python 3.5 and 3.6: several of the types that were missing in Python 3.5.0 and Python 3.6.0 were added later on. But it's honestly hard to keep track of what was added when, so it might be safer to just default to using typing_extensions and not worry about it.)About mypy:
If want to use mypy, keep in mind that mypy can be run using only non EOL'd versions of Python 3. So, at time of writing, Python 3.4+.
However, mypy itself can be used to analyze Python 2.7+ code.
About typeshed and Python 3.0 - 3.2:
Mypy, and most other PEP 484-compliant type checking tools, rely on typeshed, a collection of type annotations for the standard library and popular 3rd party libraries.
Typeshed keeps track of when functions and classes were added to the standard library. That way, you can ask tools like mypy to make sure your code works with specific versions of Python and that you didn't accidentally import anything from the future.
However, typeshed only keeps track of this info for Python 2.7 and 3.3+. So, you need to be careful if you're targeting specifically Python 3.0 - 3.2.
About unicode_literals and mypy/typeshed:
Some people recommend using unicode_literals as a technique to help with Python 2/3 compatibility.
However, I believe using unicode_literals causes a number of issues with either typeshed or mypy. I forget the exact details, but the upshot is that you're probably better off not using it (at least for the time being).
Instead, avoid unicode-related issues by using the type system to your advantage. Specifically:
- Use
typing.Text
when something MUST be unicode. This type is aliased tounicode
in Python 2 andstr
in Python 3. - Use
bytes
(or maybebytearray
?) when something MUST be bytes. Be sure to keep in mind that thebytes
behaves slightly differently between Python 2 and 3. - Use
str
when that a value should be whateverstr
means for that particular version of Python.
Union
orAnyStr
.- Use
Typing for python2.7?
As you can read in the documentation:
https://github.com/python/typing
So, no - you cannot use it with 2.7, sadly.This GitHub repo is used for development of the typing module defined
by PEP 484. The module is available in Python since version 3.5.0 on a
provisional basis until Python 3.7.0.
Using typing module in Python 2.7
typing
is a module that was introduced in Python 3.5 . The examples in PEP 484 rely on a Python 3+, and __annotations__
is a Python 3 concept. The backport can only allow to use the types of functions defined in the typing
module, but it does not change the Python engine to magically understand all Python 3 concepts.
A discussion in that other SO post suggests that the annotations should be accessible by using inspect.getsourcelines
to research the first line right after the function declaration and starting with # type. A typed-ast
module exists on pypi and should be able to parse Python 2.7 style annotations. Unfortunately it is only declared at beta level and only compatible with Python 3.
Related Topics
What Is the Max Length of a Python String
Suppressing Scientific Notation in Pandas
How to Change a Widget's Font Style Without Knowing the Widget's Font Family/Size
Simple Way to Query Connected Usb Devices Info in Python
_Getattr_ for Static/Class Variables
Why Isn't .Ico File Defined When Setting Window's Icon
Range Over Character in Python
How to Write Utf-8 in a CSV File
How to Test a Function with Input Call
Global Dictionaries Don't Need Keyword Global to Modify Them
Complete Scan of Dynamodb with Boto3
How to Import a Module in Python with Importlib.Import_Module
Is It Bad Practice to Use a Built-In Function Name as an Attribute or Method Identifier
Join Two Lists of Dictionaries on a Single Key
Quickest Way to Make a Get_Dummies Type Dataframe from a Column with a Multiple of Strings