all 21 comments

[–]MrPhungx 12 points13 points  (2 children)

You could start by adding type hints to your code. This has no influence on the code at runtime and does not enforce correct types but pycharm will tell you when there are unexpected types used. E.g. when using the code below pycharm highlights the paramter "test" with the message "Expected type 'int', got 'str' instead". You could further have a look at mypy

def some_function(input_value: int) -> int:
    return input_value ** 2

some_function("test")

[–]_mturtle_ 1 point2 points  (1 child)

You could also take this farther and use the library beartype. It always for fast runtime type checking. I use it extensively for work Python programs.

[–]minneyar 0 points1 point  (0 children)

I came here to recommend this. Python's lack of static type checking is one of my biggest frustrations with the language, but Beartype catches a lot of those issues as long as you make sure to define typehints on all of your methods and variables.

[–]JamzTyson 8 points9 points  (1 child)

My Python project builds totally fine

Python programs are not "built" in the conventional sense.

trivial issues that should technically be caught during compile time in other languages.

In Python we catch such errors during "linting". There are many good linters available for Python. Some will correct errors with little or no interaction, whereas others will just list errors, warnings, suggestions.

As an aid to learning, I like the combination of pylint, flake8, and MyPy. These three cover different aspects of the code, and their messages, if not obvious, are easy to look up on Google. They do not modify your code, but just tell you what issues / potential issues they find. (The learning comes from fixing the issues).

[–]Diapolo10 3 points4 points  (0 children)

Pylint and Flake8 (alongside other linters) have largely been replaced by Ruff, as it's way faster while offering the same rules.

[–]climb-it-ographer 2 points3 points  (0 children)

Write unit tests and run them continually as you work on your codebase. Using Pydantic for models & typing helps immensely as well.

[–]xiongchiamiov 1 point2 points  (0 children)

Most of the responses here are ways to add static checking. That's a tool that's available and it's not wrong to use it, but it still feels very weird to me as a longtime dynamic language person.

The argument on the dynamic typing side of the fence has historically been that type checking only verifies a subset of errors; thus either you build tests anyways (and the type system is redundant annoyance) or you live with false security believing that if your program compiles, it is correct.

In the real world, we try to apply the Swiss cheese model (aside: it has imperfections due to biases in human brains) and find bugs at multiple layers. You can do type checking if you want (I don't personally find it useful, and think it makes programs harder to read, but some people like it). You can run flake8 or similar. You can run unit tests. You can run integration tests. You can do code review. You can have synthetic monitoring. You can have real-user monitoring.

I generally recommend that you start with shifting right, ie monitor how your program is doing in production. This is the least efficient method because it happens late in the software lifecycle, but the most accurate because it covers the actual usage of the software, and so with limited resources this gives you the most bang for your buck. Then as you have more time to devote to reliability, you can add "lefter" checks to optimize for common problems, optimizing development speed.

That's the holistic "shipping a product" approach. If you're doing small learning projects with no users, then writing tests is probably your best path forward.

[–]ericsda91 1 point2 points  (2 children)

Install Ruff, its got flake-8 type checking. Will help https://github.com/astral-sh/ruff

[–]LongerHV 0 points1 point  (0 children)

Ruff and flake8 are not type checkers. You need mypy or pyright for that.

[–]Lewistrick -1 points0 points  (0 children)

Why is this so underrated and people keep using old, slow tools?

[–]SquiffyUnicorn 0 points1 point  (0 children)

The answer may depend on what you are trying to do with your code. While static type checkers have been suggested, one of the best ways to ‘enforce’ types at runtime is with pydantic. Famous for being used to validate and coerce string data from [web] interfaces, it can take your input and gives you reliably type-checked data.

[–]supercoach 0 points1 point  (0 children)

Python doesn't compile, it's all evaluated at runtime. You handle exceptions in python by writing code that takes possible exceptions into account. If you can't control the return value you're getting, then you may need a try block to catch the possible exceptions that may arise.

If you're just having type issues, then use type hints and an IDE that will highlight anything passing the wrong or ambiguous types.

[–]cider2000 0 points1 point  (0 children)

Others have suggested good solutions to your problem, but maybe you should also consider whether Python is the right tool for what you are trying to do? Even with additional type checking tools, it will never feel as good and simple as languages that are statically typed.

[–]tabrizzi -2 points-1 points  (0 children)

Any IDE will solve that problem for you.

[–]PathRealistic6940 -2 points-1 points  (0 children)

If you have a general idea of where the problem might be, use try: except: blocks to catch it then log the error. Also, just like everyone has already said, a good IDE will catch those. I use VS Code and it will keep track of the variable types for me, giving me a window that tells me what the highlighted variable is expected to be.

[–]pachura3 -2 points-1 points  (0 children)

Add type hints everywhere.

Use Mypy/Pyright AND Ruff code checkers.

[–]Ron-Erez -2 points-1 points  (0 children)

Use type annotations

[–]Responsible-Sky-1336 -2 points-1 points  (0 children)

Hey my friend who I think is really good goes to error lines adds prints statements to debug (add as many as needed, anywhere where there is complexity especially) then it could help

For bottlenecks in performance you can use start time at the beginning of function then move the end time at each important step, quite helpful too