I only use it to avoid circular imports. Otherwise, I can import the type plainly.
Python
Welcome to the Python community on the programming.dev Lemmy instance!
📅 Events
Past
November 2023
- PyCon Ireland 2023, 11-12th
- PyData Tel Aviv 2023 14th
October 2023
- PyConES Canarias 2023, 6-8th
- DjangoCon US 2023, 16-20th (!django 💬)
July 2023
- PyDelhi Meetup, 2nd
- PyCon Israel, 4-5th
- DFW Pythoneers, 6th
- Django Girls Abraka, 6-7th
- SciPy 2023 10-16th, Austin
- IndyPy, 11th
- Leipzig Python User Group, 11th
- Austin Python, 12th
- EuroPython 2023, 17-23rd
- Austin Python: Evening of Coding, 18th
- PyHEP.dev 2023 - "Python in HEP" Developer's Workshop, 25th
August 2023
- PyLadies Dublin, 15th
- EuroSciPy 2023, 14-18th
September 2023
- PyData Amsterdam, 14-16th
- PyCon UK, 22nd - 25th
🐍 Python project:
- Python
- Documentation
- News & Blog
- Python Planet blog aggregator
💓 Python Community:
- #python IRC for general questions
- #python-dev IRC for CPython developers
- PySlackers Slack channel
- Python Discord server
- Python Weekly newsletters
- Mailing lists
- Forum
✨ Python Ecosystem:
🌌 Fediverse
Communities
- #python on Mastodon
- c/django on programming.dev
- c/pythorhead on lemmy.dbzer0.com
Projects
- Pythörhead: a Python library for interacting with Lemmy
- Plemmy: a Python package for accessing the Lemmy API
- pylemmy pylemmy enables simple access to Lemmy's API with Python
- mastodon.py, a Python wrapper for the Mastodon API
Feeds
Same, I think it's more common only to use when necessary.
The main case I can think of to use it more is for performance to save an import at runtime, but I don't think that's really valid, especially since the fact you're using the type annotation suggest the module would have been used elsewhere anyway so the import would be cached.
The argument against using anywhere is that it could be misleading as your editor may indicate that the import is definited even if it wouldn't be at runtime. Not sure if things like pylance have special handling to avoid this, would have to check...
I don’t like having to quote the types, so I use it exclusively for avoiding circular imports.
Why not use from __future__ import annotations
?
from __future__ import annotations
Thanks for the tip
You still need to import the type before using it in a stringified type annotation for it to be valid though, so you'd need the import in an if TYPE_CHECKING:
block either way, no?
Yes, but if it’s in a TYPE_CHECKING block I can ONLY use the annotation with quotes*, which is why I only use that method if I must.
- except with
from __future__ import annotations
as I’ve just learned.
Ah yeah, I see what you meant.
That's a very cool feature, had no clue about it!
If it doesn't have any visible downsides, it's be nice use it whenever possible. This should provide the additional benefit of having the imports clearly separated.
The tediousness aspect of it makes me wonder though. I'd probably just only use it when I'm specifically importing something only for typing .
Maybe could be a cool feature request for an lsp as well.
Any time you need different behavior between static type checking and runtime.
in 3.10 I’m using it to work around issue with NamedTuple generics. typing_extensions.NamedTuple allows Generics at runtime but typing.NamedTuple doesn’t. But the type checker we are using doesn’t support typing_extensions.NamedTuple like it does for the typing version so we lie at type checking time to get the typing to make sense but have different runtime type because otherwise its a TypeError
A cheeky answer: whenever Ruff/flake8-type-checking tells me to. Though I'd only enable that check now that there's an autofix in Ruff as well.
You should have part of your test harness perform a separate import of every module. If your module is idempotent (most good code is) you could do this in a single process by cleaning sys.modules
I guess ... but it still won't be part of your pytest
process.
Static analyzers can only detect some cases, so can't be fully trusted.
I've also found there are a lot of cases where performant Python code has to be implemented in a distinct way from what the type-checker sees. You can do this with aggressive type: ignore
but I often find it cleaner to use separate if
blocks.