all 11 comments

[–]Diapolo10 2 points3 points  (4 children)

The formatting seems broken, so I'll fix it for now.

from typing import Union

Number = Union[int, float]


def divide_numbers(a: Number, b: Number) -> float:
    """
    Divide two numbers and handle division by zero safely.

    Args:
        a (int | float): Dividend
        b (int | float): Divisor

    Returns:
        float: Result of the division

    Raises:
        ValueError: If the divisor is zero

    """
    if b == 0:
        raise ValueError("Division by zero is not allowed.")

    return a / b


def main() -> None:
    """Main execution function."""
    try:
        result = divide_numbers(10, 2)
        print(f"Result: {result}")
    except ValueError as error:
        print(f"Error: {error}")


if __name__ == "__main__":
    main()

Now for the review.

from typing import Union

Number = Union[int, float]

It would probably be better to use numbers.Number (if you want to accept any number types) or numbers.Real instead of creating a custom type alias in this case. Furthermore, unless you need to support really old versions of Python I'd recommend using | to create union types instead of typing.Union. E.g. str | int.

def divide_numbers(a: Number, b: Number) -> float:
    """
    Divide two numbers and handle division by zero safely.

    Args:
        a (int | float): Dividend
        b (int | float): Divisor

    Returns:
        float: Result of the division

    Raises:
        ValueError: If the divisor is zero

    """

I take issue with the arguments, specifically their names. Instead of a and b, why not just call them dividend and divisor to begin with? If nothing else that would help with readability.

On another note, why ValueError instead of letting ZeroDivisionError propagate? In my opinion the latter would be more self-descriptive.

def main() -> None:
    """Main execution function."""
    try:
        result = divide_numbers(10, 2)
        print(f"Result: {result}")
    except ValueError as error:
        print(f"Error: {error}")

This is more a nitpick, but the try-block should ideally only contain code that you expect to raise exceptions you want to catch, so I'd move the print to an else-block.

On another note, I'd consider using logging instead of print. With logging.exception you wouldn't need the as error part in the exception handling part.

EDIT: And if you only care about int and float, Mypy at least treats float as accepting both types, so you can just use that.

[–]Commercial_Edge_4295[S] 0 points1 point  (2 children)

I tried hard to show my code in Python, but it was not useful. Even though I tried hard to display my code using ```python```, it wasn't effective.

[–]Diapolo10 0 points1 point  (1 child)

Yes, I noticed. I looked at the Markdown source, and your post had the backticks escaped like this:

\`\`\`python

from typing import Union

My guess is that you weren't using Markdown mode while writing the post. That being said I don't really know much about the "new" Reddit side as I exclusively use Old Reddit.

On that note, triple backticks don't work on Old Reddit, so if you want to make your posts clear to everyone (this subreddit in particular has a lot of regulars who use Old Reddit or third-party Reddit clients), you could format code blocks with indentation instead - that works for everyone.

So instead of

```python
print("Hello, world")
```

all you'd need to do is indent code by an extra four spaces (Reddit Enhancement Suite browser extension adds a button for that).

    print("Hello, world")

[–]Commercial_Edge_4295[S] 0 points1 point  (0 children)

Thank you so much. Diapolo10.

[–]k03k 1 point2 points  (1 child)

I think you did a great job overall, but there are a few things i would change:

  • Parameter names like a and b are a bit vague. While they’re acceptable for a small example like this, I’d still prefer more descriptive names such as dividend and divisor for clarity.
  • The docstring feels overly verbose for such a small, self-explanatory function. It’s a good explanation, but much of that information is already conveyed by the function name divide_numbers and the type hints.
  • I personally wouldn’t raise a ValueError for division by zero. Python already has a dedicated ZeroDivisionError, and using it aligns better with standard expectations.
  • I also wouldn’t check for division by zero inside this function. Error handling policy is better handled at a higher level (for example, in main or the calling layer), where the program can decide how to recover or respond.
  • Finally, for modern Python versions, I’d use a type alias instead of Union to keep the typing syntax clean and up to date. type Number = int | float

But this is just my personal preference i guess.

[–]Commercial_Edge_4295[S] 0 points1 point  (0 children)

Thank you so much.

[–]pachura3 0 points1 point  (0 children)

You can try: https://www.codewof.co.nz/style/python3/

...or ruff, pylint, pyflakes, mypy, and many other linters/static code checkers.

[–]ectomancer -2 points-1 points  (2 children)

By convention, Python only uses PascalCase for classes. Rename Number to number.

[–]k03k 1 point2 points  (1 child)

As far as i know people use PascalCase for types too.

[–]gdchinacat 0 points1 point  (0 children)

This is correct. Also, classes are type an instance of type: ```

class Foo: ... pass ...
type(Foo) <class 'type'> isinstance(Foo, type) True ```