Live data from Hacker News

Advanced Python Features

blog.edward-li.com

171–180 of 183 posts

Re: Advanced Python Features

#171
post #70
post #27

Earlier quoted context omitted.

Try: def f(i=0) -> None: reveal_type(i) The inferred type is not `float` nor `int`, but `Any`. Mypy will happily let you call `f("some string")`.

`Any` is the correct call. It could be: def f(i=0) -> None: if i is None: do_something() else: do_something_else() Yeah, I know it's retarded. I don't expect high quality code in a code base missing type annotation like that. Assuming `i` is `int` or `float` just makes incrementally adoption of a type checker harder.

No it’s not. The typing system should use the most specific type available, and it’s your responsability to broaden it if needed. That’s how it works in all statically-typed languages.

Re: Advanced Python Features

#172
post #93

My own opinion is that Python shall remain Python, and golang, Rust and Typescript each should be whichever they are with their unique philosophy and design. I am coding in all 4, with some roughly 28 years now, and I don't like what is becoming of Python There is a reason why python become that popular and widely adapted and used, and it is not the extra layers of type checking, annotations and the likes. this looks…

I have used Python for a long time for glue scripts, build stuff, test systems etc. and I've always thought it was great. I didn't like using it for larger applications though - when I did, I usually got bitten at some point by some effect of the dynamism (regardless of testing). At scale things became more unworkable.

With the type system my opinion on that has changed. We have a pretty large tooling codebase with protocol stacks, GUI, test automation etc. and it's all very maintainable with the type checking.

Re: Advanced Python Features

#173

Earlier quoted context omitted.

1) the code you wrote isn’t Python. 2) inferring the type is int isn’t guaranteed to be correct in this case

I was merely giving an example that strong typing has nothing to do with having to write the types. (and, obviously, the inferred type (int -> int) is correct. )

> and, obviously, the inferred type (int -> int) is correct.

No it’s not. It’s Optional[int] -> int at minimum. There are other completely valid signatures beyond that too.

Re: Advanced Python Features

#174
post #137

Earlier quoted context omitted.

Because it shouldn’t in function arguments. The one defining the function should be responsible enough to know what input they want and actually properly type it. Assuming an int or number type here is wrong (it could be optional int for example).

In TypeScript arguments with a default value "inherit" the type of that value, unless you explicitely mark it otherwise. I believe this is how Pyright works as well.

But the type signature of:

int -> int

Is wrong. At minimum it’s:

Optional[int] -> int

Because you provided a default value so clearly it’s not required to provide an input parameter. It’s also wrong to assume `0` is an int. There’s other valid types it could be. If the default was say `42`, I’d be pushing back a little less (outside of the Optional part), but this contrived example from GP had 0, which is ambiguous on what the inferred typing must be.

Re: Advanced Python Features

#175
post #170
post #64

Earlier quoted context omitted.

How would a typing system know if the right type is `int` or `Optional[int]` or `Union[int, str]` or something else? The only right thing is to type the argument as `Any` in the absence of a type declaration.

The typing system should use the most specific valid type, and the code author can broaden it with explicit typing if needed. No good typing system should ever infer a variable as `Any`: "I don’t know the type of this" (`unknown` in TypeScript) is not the same thing as "This function accepts anything". Conflating these things is one of the main reasons why Mypy is so annoying.

A typing system should only infer things that it knows are true, it should never invent restrictions. In a language like Python that is duck-typed, `Any` is the only reasonable choice in the absence of other real constraints like a type-annotation.

Re: Advanced Python Features

#176

Earlier quoted context omitted.

The "truthy" operator is bool(); the problem here is that empty strings are falsy. For myself, I settled on these patterns for various kinds of tests: # check for None if x is not None: ... # check for empty string if x != "": ... # check for empty collection other than string if not len(x): ... In this last case I rely on 0 being falsy to make this idiom distinct from checking length for a specific value via equalit…

bool( thing ) is overly verbose. It would be nice to have a unary operator. I don't think the problem is that empty strings are falsy per say (although that might not be to your personal preference). Rather I think the problem is the implicit coercion to bool, hence my desire for a unary operator. I think this is yet another entry in the (extremely) long list of examples of why implicit type conversions are a bad thi…

> I don't think the problem is that empty strings are falsy per say (although that might not be to your personal preference).

Let me correct that. The problem isn't so much that they are falsy per se, but rather that they share this property with so many unrelated things - and this is then combined with dynamic typing, so any given `x` can be any of those things. None/'' in particular is exceedingly common because None is the standard way to report absence of a value in Python.

As far as having a symbolic unary operator for such checks, I think that would go stylistically contrary to the overall feel of Python syntax - I mean, this is a language in which you have to spell out things like "not", and len() is also a function unlike say Lua. It feels like the most Pythonic interface for this would be as an instance property with a descriptive name.

Re: Advanced Python Features

#177

Earlier quoted context omitted.

That's exactly my point. Having to search for the meaning of the operator at all makes the code less readable. I recommend reading the Zen of Python, which covers the design principles of the language.

I don’t write code to the level of someone who has just finished Hello, World. This isn’t something esoteric, it’s an extremely basic and useful part of the language. I’ve seen this argument used against multiple languages, and it has never made sense to me. “I don’t want to use windowing functions in SQL, because most people don’t know what they are.” So you’d rather give up an incredibly powerful part of your RDBMS…

We're discussing Python, not SQL or any other language. Using more arcane elements of a language like Python, which emphasizes readability, often makes your code less understandable, difficult to debug, and harder to maintain. I also suggest you read the Zen of Python for an understanding of the language's design principles.

Re: Advanced Python Features

#178

Good list, its one of these things you either never heard of, or used for years and think everyone knew that. I'll add a few: * did you know __init__.py is optional nowadays? * you can do relative imports with things like "from ..other import foo" * since 3.13 there is a @deprecated decorator that does what you think it does * the new generics syntax also works on methods/functions: "def method[T](...)" very cool * y…

> did you know __init__.py is optional nowadays? It's not optional. Omitting it gets you a namespace package, which is probably not what you want. > TypeVar supports binding to enforce subtypes: "TypeVar['T', bound=X]", Using the new generics syntax you mentioned above you can now do: def method[T: X](...)

good points! do you have any more things along those lines you think people might not know about?

Re: Advanced Python Features

#179
post #50

Good list, its one of these things you either never heard of, or used for years and think everyone knew that. I'll add a few: * did you know __init__.py is optional nowadays? * you can do relative imports with things like "from ..other import foo" * since 3.13 there is a @deprecated decorator that does what you think it does * the new generics syntax also works on methods/functions: "def method[T](...)" very cool * y…

> did you know __init__.py is optional nowadays? It has an effect, and is usually worth including anyway. I used to omit it by default; now I include it by default. Also, you say "nowadays" but it's been almost 13 years now ( https://peps.python.org/pep-0420/ ). > since 3.13 there is a @deprecated decorator that does what you think it does Nice find. Probably worth mentioning it comes from the `warnings` standard lib…

do you know any other things you can think of that people might not be aware of? small tricks or some such, perhaps unrelated to type annotations?

Re: Advanced Python Features

#180
It is a great article, but it completely misses what's new in Python parallelism with the GIL being optional since 3.13, also multiple interpreters via InterpreterPoolExecutor coming in 3.14.
Post reply on HN