Python 3.9
docs.python.org
docs.python.org
Now you can use list, dict, tuple instead of typing.List, typing.Dict, typing.Tuple.
I think it was the right choice.
The system has been rolled out slowly in general, without hasty changes to the core language.
There's a similar change coming in 3.10: https://docs.python.org/3.10/whatsnew/3.10.html#pep604-new-t...
test-all:
mypy main.py
pytest test/main.py`public static void main(string args)` but an "annotation"?
You can stick "untyped" code in any language. You just have to annotate things with `Object` and cast them.
`var list = new ArrayList<String>();` [1]
The compiler figures out the type of `list` without "annotations". Same with C++'s `auto` and Rust's `let`.
I think the key difference between the annotations in Python and types in Java, or even more strongly in languages like Rust and Haskell, is how they are used in the language ecosystem. In Java and Rust, the types are cental to how programmers think in those languages. A large part of the dev cycle goes into ensuring the types are consistent. In python, these type annotations are a relatively recent addition that the community has not completely adopted yet. A lot of real-world python code will have no types, thus the (3rd party) python type checkers will fail to ensure the benefits of having strong consistent types.
And how can we then justify "types" like Object in Java or Any in Rust? Well, sometimes we do want to write code where we want to tell the compiler to stop checking types. However, these are more of an escape hatch rather than a central part of the language ecosystem. As someone else already pointed out, the Java or Rust community does not go about writing code with only Object or Any, even though they can in principle. But in python, that's what the community has been doing till now.
It goes the other way too. If the python community starts taking the type annotations seriously, it will start approaching the same usefulness as in these other static languages with good type systems. Then we can start expecting that the 3rd party library type annotations being accurate, which started this discussion in the first place.
I think you'll find I've said as much elsewhere ;)
I think I make essentially the same argument as you do here: https://news.ycombinator.com/item?id=24701113
However, "that's true of any type system" just feels dismissive of the current state of the world. The comment you were replying to was pointing out that at present, enabling strict type checking in Python, that has been bolted on as an add-on only recently, will not be able to provide benefits to the same level as the ones in Java and Rust where types are front and center. That might become true tomorrow when all Python libraries have adopted types. Hypothetically, tomorrow the Rust community could also decide to adopt Any as the central type everyone uses. But today, the state of the world is very different. Python is still known as a dynamically typed language where devs can essentially forget explicit types, and Rust is a strongly statically typed language where devs will rarely have to worry about missing types.
What you're referring to are called type ascriptions, and they are often seen in what are sometimes called manifest type systems, where you must explicitly write out your types within a static type system. C and Java are common examples of this. These are not annotations because they have real meaning (either used for declaration or for type conversion).
Additionally, there are plenty of statically typed languages which do not require ascription. These languages feature type inference, which is a process that allows the programmer to leave the deduction of the actual types to the compiler. Haskell, Swift, OCaml, Scala, and I think now C++ to some degree (with `auto`) allow for this (to name but a few).
This is equally true in Java. Types are erased at runtime. They don't exist in the bytecode.
Just because the type checking and evaluation are done using one tool, "javac" doesn't really mean anything.
Again, what's the difference between a bash script that runs mypy prior to invoking python and a bash script that compiles and runs a java program, from the perspective of type safety, assuming you know nothing about the two programs?
There is no difference. Neither provides any more guarantees than the other. Put another way, by enforcing use of mypy prior to invocation, you convert the annotation to an ascription.
A deeper analysis would suggest that "ascriptions" are actually the things you use to disambiguate when type inference is not powerful enough (https://docs.scala-lang.org/style/types.html).
Scala, for example, calls its type declarations "annotations", except when they are needed to disambiguate, when they are "ascriptions". So under the scala definition, python's annotations are exactly the same as scalas as long as they are used for type checking, which, if you use mypy, they are.
For the record this isn't true, as anyone who's seen a ClassCastException knows. A subset of type information is erased under limited circumstances, but a lot of type information is still present in the bytecode.
> Just because the type checking and evaluation are done using one tool, "javac" doesn't really mean anything.
What means something is that the types are part of the language specification and, even more importantly, part of the consensus of the language community.
In particular, if you depend on a Java library, you can be extremely confident that the type information of that Java library is actually correct, because you can be extremely confident that the library was built in a way that involved checking the types. This is simply not the case for Python; it's very normal to build Python without running mypy. It's like arguing that C is a safe language because you can run Valgrind on your C code: yes, that external tool exists, but it's not part of the language by default, and so you can't rely on the rest of the ecosystem to have used it.
> A deeper analysis would suggest that "ascriptions" are actually the things you use to disambiguate when type inference is not powerful enough (https://docs.scala-lang.org/style/types.html).
> Scala, for example, calls its type declarations "annotations", except when they are needed to disambiguate, when they are "ascriptions". So under the scala definition, python's annotations are exactly the same as scalas as long as they are used for type checking, which, if you use mypy, they are.
The distinction is a lot more general: type ascriptions change the behaviour of the code while type annotations do not. So a system that only has annotations and not ascriptions is significantly more limited than a full type system that has ascriptions as well, at least in practice - in theory we can do perfect type inference (e.g. H-M), but that ignores some edge cases that are important for real-world programming e.g. handling literals in the source code.
Indeed, so the only difference is that you trust one languages annotations more than the others. Which is what I said.
> The distinction is a lot more general: type ascriptions change the behaviour of the code while type annotations do not.
Well no, ascriptions don't change behavior, they remove ambiguity when systems aren't able to infer things on their own. Literals aren't the issue for H-M. They're relatively easy. H-M has trouble with inheritance and heavily polymorphic code.
Eh, that's like saying there's no difference between breaking the law and not breaking the law, someone might kidnap you and lock you up either way. It's true in a sense, but it's more misleading than helpful.
> Well no, ascriptions don't change behavior, they remove ambiguity when systems aren't able to infer things on their own.
You're trying to gloss over everything as "removing ambiguity", but by that logic any change to a program is just "removing ambiguity". In general there are other possible ascriptions for a given term that would form valid programs, and in general those programs could have arbitrarily different behaviour from the program in question.
I'm not, for what it's worth. There are cases where you could argue that type annotations are just removing "ambiguity" (the type system is successfully inferring, you place an annotation that agrees with the inference, or a stricter annotation that still checks successfully). I can see how this is an ambiguity, but it isn't what I meant.
But scala's definition of ascriptions are for places where the type system can't figure something out, and needs extra information to successfully check. More powerful type inference might address these issues (most common languages don't use H-M). Ambiguity was perhaps the wrong word to use. "aren't able to infer things on their own" is maybe the more important bit.
Type ascriptions don't "change" behavior, because there wasn't valid behavior without them. The type system failed to check (but again, different inference algorithms might be able to get around this)
No, they exist to change behaviour, that's the whole point of that terminology. The example they give is passing a sequence to a vararg method: if you have a generic method that takes a vararg (generic) parameter, then calling that method with multiple parameters from a sequence, or a single parameter that is a sequence, are both valid but have different behaviours.
I work with bytecode on a daily basis (I develop a commercial Java obfuscator) and this is untrue. You may be thinking of generic type parameter erasure, but even then special interface methods are generated by the compiler so that no lowering to java/lang/Object happens too soon.
In non-generic code, the types remain and are strongly enforced. Methods have descriptors that restrict parameters to certain types (you can get a VerifyError upon loading the class if you've generated code with a type confusion), there is a 'checkcast' instruction to ensure that a stack values is a certain type, and a ClassCastException is thrown if a cast is impossible.
---
As far as "annotation" vs "ascription", you've actually just reinforced what I said.
> This is equally true in Java. Types are erased at runtime. They don't exist in the bytecode.
Types are erased at compile time, which means that the type-checking analysis has completed. Many compilers erase types after doing type checking to improve runtime performance. That doesn't mean the types don't do anything. They're used for guiding the type-checking by the compiler.
This is in contrast to Python, which does literally nothing with the stuff you throw in the annotations. MyPy doesn't play a role in this specific aspect of the discussion because we're talking about language implementations, and in Python the type annotations are just artifacts in the code that get ignored during compilation and evaluation.
This is the distinction between ascriptions and annotations, which you actually corroborated here:
> Scala, for example, calls its type declarations "annotations", except when they are needed to disambiguate, when they are "ascriptions".
All of the type stuff in Python is handled via annotations because the language proper does not make use of them whatsoever. They're just decoration, really.
In contrast, Java uses all the types to perform type-checking, making them ascriptions.
In languages with lots of type inference, like Scala, you can supply type information. Sometimes these are ascriptions (which either help the inference algorithm or are used for casting), and sometimes they are just artifacts to help the programmer (in which case they can be regarded as annotations, which I didn't address previously).
But the key component in all of this is that we are only looking at the languages proper, not the suite of third-party tools available to those languages, because this is what dictates the correct terminology. In Python the language, types are just annotations which are completely ignored, and this is not the case in statically typed languages.
---
Which brings us to the second point: your original argument.
This thread started with somebody asking whether static typing will ever be implemented in Python proper, to which somebody said there's no reason for that when we can use MyPy and disable support for `Any` types. The response to this was that it would require all third-party libraries to be fully and correctly annotated, where you came in and claimed "that's true in any type system."
The reason I disagreed with this is because in statically typed languages you're not relying on annotations for anything. Keep in mind that we've established that annotations are specifically artifacts in the code that the language itself doesn't care about, because when the language does care they are called ascriptions. Annotations are supplied by the programmer by desire, not by necessity of the language proper.
You can release a fully-functioning Python library with absolutely zero type annotations, and it will run exactly the same as if you annotated everything. This is because type annotations don't do anything in Python; to gain any use from them requires using third-party tools, like MyPy.
But you cannot release a Java library that doesn't have all its types specified in some manner. Because the Java language requires the types to be present, meaning they aren't annotations like they are in Python.
I guess really what I'm trying to get at is that your response where you said "That's true of any type system" was completely missing the point. The point being made by the person you responded to was about how in a Python ecosystem, simply using MyPy and disabling the `Any` type requires all third-party libraries to be fully and correctly annotated — something which is not usually required in Python, so it's an extra burden on the libraries' developers. This is entirely distinct behavior from any statically typed language because in those languages, you can't just leave out the types and call it a day.
Javac uses them to perform type checking, prior to runtime. Exactly the same way that mypy uses them to perform type checking prior to runtime.
> The reason I disagreed with this is because in statically typed languages you're not relying on annotations for anything. Keep in mind that we've established that annotations are specifically artifacts in the code that the language itself doesn't care about, because when the language does care they are called ascriptions. Annotations are supplied by the programmer by desire, not by necessity of the language proper.
But Scala's annotations are used for type checking. Much as python's are if you enable mypy.
> But you cannot release a Java library that doesn't have all its types specified in some manner. Because the Java language requires the types to be present, meaning they aren't annotations like they are in Python.
Of course you can. You can write a functional java library that specifies that all functions take `Object`. Your argument comes down to that syntactically, java requires you stick something in the place-where-type-declarations-go, while python does not.
This ultimately doesn't have any impact on the strictness of the type checking done, because you can stick useless annotations (Any, Object) in the syntactic spot in either case. The semantics are the same.
Ultimately, your argument comes down to "I trust that more third party libraries will have useful types in Java than in python", but that isn't implicit to the type system, it's because the type ecosystem has been around longer.
Which, like, sure. But to say that python doesn't have static typing is silly. Nearly all the python I write is statically typed.
> In Python the language, types are just annotations which are completely ignored, and this is not the case in statically typed languages.
This is a uselessly semantic argument. Much as if you choose to not typecheck your python, you can choose to write essentially untyped java using Object and casts. Are you really certain that no library you depend on does that, or uses reflection to access dynamic and non-statically-verifiable features?
The safety you get from any static analysis tool, whether a type system or a linter or whatever, relies on your dependencies not trying to subvert the tool (or doing so correctly).
This is essentially the argument about rust's Unsafe. You, or any of your dependencies, is free to subvert the borrow checker and do "unsafe" things.
You either have to trust that they are doing so responsibly, or manually verify the correctness of their unsafe code. Having to opt-in to unsafe access is, indeed, an advantage since it makes static analysis of how much "unsafety" there is easy (much as it's easier to find non-static things in vanilla Java than in python), but you can (and some do!) use static analysis to enforce type annotations in python throughout the entire code base.
> so it's an extra burden on the libraries' developers.
It's exactly the same burden as they would have in Java. So I'm not clear on what the point is. Worth noting though, that mypy supports stub files, so you can annotate a third party api yourself (https://github.com/python/typeshed, https://github.com/google/pytype/tree/master/pytype/pytd/std...), so even this claim is ultimately untrue.
I'm sorry, but it is your argument that is uselessly semantic.
Yes, people could write Java code where all the type ascriptions are for Object. It is technically possible. But nobody does this. It has nothing to do with "the type ecosystem has been around longer" — it has to do with the fact that the types do something in Java, and always have and always will. You cannot compile a Java program and just not check the types.
But people do write Python libraries without type annotations, and that's fine. There's plenty of not-explicitly-typed Python in the world because that's all there was for a long time before the introduction of optional type annotations. And a lot of people prefer to write Python without type annotations at all because that's one of the benefits of a dynamically typed language — explicit types are unnecessary.
I think your argument is useless because you're intentionally conflating these things and arguing that people could write type-less Java, but since this is not actually done in practice it has no bearing in this conversation.
The point originally being addressed was that in Python you either need fully annotated libraries or else you cannot simply "use MyPy with Any turned off" as the far-parent comment suggested. And my point has been that this is a genuine concern in Python because there's lots of Python code without annotations because Python the language doesn't require or even use the annotations, so they are (from the perspective of the language) purely artifacts of no consequence. This is not the case in real, actually used Java code.
Please stop making arguments in bad faith to "prove a point" or whatever. The point the entire time has been about the use of type annotations in practice, and you appear to be intentionally disregarding this in an attempt to... I don't even know. What are you after here? Do you just not like that somebody disagreed with you? Like, I'm genuinely unsure what your purpose is other than to be contrarian. The concern about "are all the third-party libraries I'm using fully annotated?" is a genuine one in Python that is never even thought about when writing Java (have you ever paused to wonder this when writing Java?), so your argument amounts to a semantic debate that has no basis in the real world.
But is the case in its type system, which is what I said. If you want to argue that the python developers are less prone to typing things than the java devs, then say that. Don't claim wrong things about the type systems. They're functionally equivalent.
The type checkers have all the same information, however much the users choose to give them. There are actually a few ways in which python's type system is fundamentally more capable than java's (literal types, protocols).
Literally all a static type system is is an assertion (and tooling to assert) that types must validate before you can run the code. That's it. If you provide a presubmit check that types must validate before you run the code, congratulations, your code is statically typed.
Put simply: enabling mypy + no-any gives you all the same static guarantees (and arguably more) that java does, so in what way isn't it statically typed?
The original question was about Python the language, not Python the ecosystem. At no point is it ever likely to be correct to say "Python is statically typed"; it will only be possible to say "this specific Python code can be statically typed, if you run the static type checker". This is a fundamental difference between optional static typing in Python versus a natively statically typed language. Because you can run the Python code without running the static type checks, which you cannot do in, say, Java.
Because of this distinction, it is never a genuine concern of a developer in Java or another statically typed language whether third-party libraries will be properly typed. There do not exist libraries without valid static types. You can't install something from Maven or what-have-you that won't type-check.
But you can do this in Python. You can install something via pip and there is no guarantee it will come with good type annotations for your type-checking tool to use, because the type checker is not part of the language proper. It's not required. So Python code exists in the real world that cannot be used with the same assumptions as you can use code in the Java ecosystem. And this is fine, by and large, because Python wasn't meant to be typed. There's nothing wrong with using code like this, nor is there anything wrong with writing code like this. You may not wish to do so personally, which is fine, but I don't think there will ever be an expectation made by the Python language proper of all Python developers to annotate their code. Python will always work without explicit types.
My point in all of this is that your original argument that "[whether there are concerns about third-party libraries having valid type annotations] is true in any type system" does not hold in the real world, because you simply won't have untyped libraries in a statically typed language's ecosystem like you will in Python. Perhaps you didn't realize that this was the point being made, but in any case you went off on a very semantic tangent that had no real bearing on the conversation at hand: the use of type annotations in practice.
Python doesn't have a spec, so the argument that the language doesn't support static typing is dubious at best, since a static type checker is maintained by the language itself. If I alias python to `mypy $0 && python $0` or whatnot, is it no longer python? It's certainly statically typed.
> Because of this distinction, it is never a genuine concern of a developer in Java or another statically typed language whether third-party libraries will be properly typed. There do not exist libraries without valid static types. You can't install something from Maven or what-have-you that won't type-check.
Is this enforced by the language, or is this just an aspect of the ecosystem? "Maven-packages must typecheck" is enforced by the spec?
> But you can do this in Python. You can install something via pip and there is no guarantee it will come with good type annotations for your type-checking tool to use, because the type checker is not part of the language proper. It's not required.
Are you saying that there is a guarantee in Java that the types need to be "good"? I'm not even clear that maven (which again isn't part of the java language) requires that uploads compile, much less that the type declarations be "good", whatever that means.
Which all returns to my central point: you trust the java ecosystem more that the python ecosystem to have "good" type declarations. There is nothing implicit in the type systems of those languages that enforces that one or the other have better or worse type annotations.
Your argument relies on conflating use in practice with theoretical guarantees, I'm just pointing that out. If you want to say that your experience is that python has less reliable types than java, then sure, that's probably true. But the type systems available in those languages are functionally equivalent. The use, however, differs.
I would politely suggest you consider whether this is a common issue you have with people or whether it's just me (certainly a possibility, I admit). If this happens to you often, you may want to try alternative approaches to broaching your points if you'd like better engagement. I think most people don't enjoy when their main points are continually ignored in favor of bringing up other minutiae to prove that they're wrong or something.
Regardless, cheers.
I had no idea. Super cool — thanks for letting me know!
> Auto discovery of types for boto3.client and boto3.session calls
I'm curious how this is possible. I didn't realize mypy could inspect function arguments and use them to determine the returned type.
I see it as ‘use strict’ in JS land
Mypy doesn't work for code that isn't statically available before runtime. Though there are ways to do runtime type checking as well.
I have been type annotating my project over time in the hopes I eventually have just enough context about what I am doing. Also a good IDE will show you any place wrong types are criss crossed.
And the lack of static typing is a fundamental feature of the language. I doubt very much whether a static type system will ever be implemented in Python proper.
Wow, this is pretty exciting. Hope we also see match being accepted in Python 3.10, so this would make (for me at least) one of the best Python releases in years.
def square(number: int | float) -> int | float:
return number ** 2
A TypeVar constrained to int and float, T = TypeVar('T', int, float), should be used instead to indicate that the return type is the same as the argument type, no?Why would you constrain a function like `square` to only accept `int`s and `float`s? What if I want to square, say, a `fractions.Fraction`?
Not really. Doing so won't cause an error at runtime, but it will produce an error when you run the type checker.
Tell the type-checker to buzz-off by any number of means, including # type: ignore
It's like duck typing with a built-in Audubon society taxonomy chart.
You can always do whatever you want at runtime, it's still python.
IMHO, duck typing is strictly inferior to interface typing. You'd define a `Number` interface which `int`, `float`, ect all implement.
Duck typing has been fundamental to Python for a long time. Do you think we're seeing a shift away from it? In the future, do you think "Pythonic" code will include significant use of explicit interfaces?
We have been since at least the introduction of abstract base classes; even in purely dynamic python, having the ability to more explicitly declare and interrogate intent than pure duck typing is frequently useful.
> do you think "Pythonic" code will include significant use of explicit interfaces?
Sure, as it already does via abcs. But it will also still use lots of duck typing, though over time more of it will be “static duck typing” by way of protocols.
But of course give the slightest whiff of types and the type police will come and want to shove types down your throat all the way
>>> import numpy as np
>>> np.array("asdgh")**2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ufunc 'square' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe'' >>> import numpy as np
>>> np.mat(((1,0),(0,1)))**2
matrix([[1, 0],
[0, 1]]) >>> np.array([[1, 0], [0, 1]])**2
array([[1, 0],
[0, 1]])
Here: >>> np.array([[1, 2], [3, 4]])**2
array([[ 1, 4],
[ 9, 16]])
>>> np.mat([[1, 2], [3, 4]])**2
matrix([[ 7, 10],
[15, 22]])
The real problem with the np.array("asdgh")**2
example is squaring doesn't make sense for character data.Matrix vs. array squaring has other issues too, as matrix squaring only works with square matrices:
>>> np.mat([1, 2])**2
[...]
LinAlgError: Last 2 dimensions of the array must be square
>>> np.array([1, 2])**2
array([1, 4])I think typing_extensions.Protocol helps support the general duck typing "any object that has method x", though there are some implementation issues w/ dataclasses and such..
That won't help if I want to square a matrix, or a polynomial.
> typing_extensions.Protocol helps support the general duck typing "any object that has method x"
Even if there's a `powerable` protocol that could be used to annotate `square` and `cube`, how would you annotate a slightly more complex function like `poly`?
def square(x): return x**2
def cube(x): return x**3
def poly(x): return 3 * x**2 + 2 * xWhat’s you want is something like “commutative multiplication”
From comments? They are again limited by the authors imagination. From reading the source?
In quite a few cases where one would overload a mathematical operation to, say, sum two objects of certain type, it'd be better to explicitly type out the operation as a functor/lambda.
How would you use type annotations to show that `square` accepts a matrix (as well as an int, float, rational number etc.)?
Semi-seriously: by specifying the input type is a Monoid.
How do you find out that a function exists, what it accepts, and what it does normally?
> From comments? They are again limited by the authors imagination.
Sure, but an author which much experience with duck typing will typically write documentation that specified that expected methods (informal structural “types”) rather than nominal types.
With the static equivalent (protocols), it’s conceivable that this is also discoverable via tooling.
It's to enable tooling, but not just autocomplete. The main purpose of typing is preventing type-related bugs, though making editor autocompletion and other editor information more robust is a not-insignificant additional benefit.
PEP 484 (created 29-Sep-2014, accepted 22-May-2015) wasn't motivated by VS Code (announced April 29, 2015).
Edit: Microsoft Python Language Server has it (i read)
With CPython they don't. Cython actually uses annotations to optimize the generated code.
It's essentially type-safe duck typing. In the case of square, you say i want x and y to support the multiply-operator, but i don't care what type they are otherwise.
Available since 3.8: https://www.python.org/dev/peps/pep-0544/
def square(number: numbers.Complex) -> numbers.Real: ...
T = typing.TypeVar('T', numbers.Real)
def square(number: T) -> T:
return number ** 2
What a rabbit hole!However, in general, squaring a complex number results in another complex number.
If only they'd had that idea a bit earlier in the Python 3 life cycle...
MyContainer = List[int]
On top of that, the typing module was also backported to Python 3 versions before 3.5, where you do have annotation syntax.Why though? Even in 2.7, isn't the : type and -> type part just taken as annotation (that is, could just be ignored and not clash because it's a valid type)? Or was it some parser shortcoming?
One of the reasons was that `list[int]` could not be done, as that would refer to a list index. Same as you would do `my_var = [1,2,3]` `my_var[0]`
Therefore it was possible to use just `int` as a type.
From python 3.9 (unless you used from __future__ import annotations in 3.7+) type hints are not parsed "as python", at function definition time, but more or less as text. In 3.9 `list[int]` does not want an item from object `list` at index 'int' when using it as a type annotation.
The typing library did not have these issues because the `types` altered the way the objects worked. Probably (didnt check it!) by overriding __getitem__ and the likes.
from typing import List
List[int]
Now you can just write this: list[int]But humans do understand what a city is, and if they live in or near one they understand what the time is in that city, adjusting for any weird local political rules like "Daylight saving" because those rules affect their life.
It's the right granularity practically too. Can politicians decide that Dublin and Belfast are in different timezones? Yeah, it'd be difficult but I think they could make that happen. How about Queens and Brooklyn? Ahahaha No. The residents will defy any pretence that clocks change between one city block and the next, it would never stick.
Going from the example of "Europe/Lisbon", Valença and Tui have 1h of difference, but are located on the same longitude, <3km from one another...
- https://en.wikipedia.org/wiki/Valen%C3%A7a,_Portugal - https://en.wikipedia.org/wiki/Tui,_Pontevedra
Take Indiana. Indiana is in the US Eastern time zone, except for some places near the Illinois border, which are US Central. But Indiana also didn't observe DST until 2006 (although some counties did observe DST). Consequently, what could generally be described as three timezones (as in the MS timezone selector) is actually described as 11 timezones: https://en.wikipedia.org/wiki/Time_in_Indiana#tz_database
From what I understand, locals in Indiana actually refer to time simply as Eastern or Central (with non-observance of DST meaning you shift from Eastern in winter to Central in summer).
Years ago we visited my wife's family in Columbus with some frequency, once we visited the Wal-Mart supercenter in Phenix City (yes, it's spelled way wrong) Alabama, which is right on the eastern border of Alabama, also next to the river. Since I worked in Wal-Mart Information Systems at the time, I had quite a bit of access and noted that the store's systems were on Eastern time, even though the entire state of Alabama is on Central.
Sure enough: https://en.wikipedia.org/wiki/Phenix_City,_Alabama "Phenix City lies immediately west across the Chattahoochee River from the much larger Columbus, Georgia and observes Eastern Time on a de facto basis (in contrast to the rest of Alabama, which observes Central Time) due to Phenix City's strong economic ties to Columbus."
The Olson Database is amazing; I've non-trivially interacted with it a number of times in my career.
Even so, the final, on the ground authority is the people who use and are affected by time zones.
I found the Pendulum library [0] very intuitive when it comes to working with time. It makes it easy to do the right thing. For example, if you call `pendulum.now` it gives you a timestamp including your local timezone information. In other words, it preserves "the time on the clock on the wall", which is lost if you do what so many people do and just take UTC timestamps.
pendulum.now()
# DateTime(2020, 5, 28, 13, 32, 1, 303100, tzinfo=Timezone('Europe/London'))
Doing this in the standard library, or with pytz, is very unintuitive and often done incorrectly in practice.– zoneinfo
– dict update operators
– str.removeprefix and str.removesuffix
– “Any valid expression can now be used as a decorator. Previously, the grammar was much more restrictive.”
– “Python now gets the absolute path of the script filename specified on the command line (ex: python3 script.py): the __file__ attribute of the __main__ module became an absolute path, rather than a relative path.”
On the last one I rarely if ever use __file__ as a relative path and have definitely typed os.path.abspath(__file__) many many times.
"There have been repeated issues on Python-Ideas [2] [3], Python-Dev [4] [5] [6] [7], the Bug Tracker, and StackOverflow [8], related to user confusion about the existing str.lstrip and str.rstrip methods. These users are typically expecting the behavior of removeprefix and removesuffix, but they are surprised that the parameter for lstrip is interpreted as a set of characters, not a substring."
'prix fixe'.lstrip('prefix')
truncating 'prix fixe' to ' fixe'. "aaamap".rstrip("map") != "aaa"This case is actually an interesting edge case - I think downvoters are of the mindset that the comment might spread disinformation, therefore it's better to hide it. But I actually agree with you here - this is something a lot of people think, it is wrong, and it's better to explicitly have people see the wrong information, and learn why it's wrong. That's why the PEP itself mentions this as a common misunderstanding!
Good lord, finally! The number of times I've tripped over this.
Because in the context of imports it does: https://docs.python.org/3/tutorial/modules.html#the-module-s...
> Note: On file systems which support symlinks, the directory containing the input script is calculated after the symlink is followed. In other words the directory containing the symlink is not added to the module search path.
Pretty useful for DP interview questions when implementing top down.
See: https://docs.python.org/3.2/library/functools.html#functools...
(This is a great addition and I'm very excited for it. Just a little sore haha.)
I have mixed feelings about a 12 month development cycle. From the perspective of a library maintainer but not a core contributor, this seems like a headache to support up to five versions concurrently. I understand we want to avoid the Python 2.7 debacle, but seems pretty rapid no?
- 3.1 in September 2018
- 3.2 in November 2018
- 3.3 in January 2019
- 3.4 in March 2019
- 3.5 in May 2019
- 3.6 in August 2019
- 3.7 in November 2019
- 3.8 in February 2020
- 3.9 in May 2020
- 4.0 in August 2020
I'm not saying that this doesn't cause headaches, but do we really want less progress?
I seems to have worked out well but they only support the two most recent (stable) versions - https://perldoc.perl.org/perlpolicy#MAINTENANCE-AND-SUPPORT
disclaimer: I like Python and find it a lot more fun than C++, although C++/STL are getting better over time!
(Because the C++ program is too hard to write and doesn't come into existence!)
There is value to being able to say "I'm done" and walking away knowing my code will happily chug along for the next 20 years.
I don't understand why programming languages need to be released like other "software". I see it a lot for modern languages like Rust.
To me, a programming language should have a major revision only once in 5-10 years. All other changes should be performance improvements or implementation changes which do not affect the end user which in this case is the programmer.
If you use RedHat or CentOS I would highly recommend ius.us repo, it contains latest versions of python and it's pretty much all what's needed.
As a former package maintainer I can assure you that every update of gcc breaks the build of some other package. And we are talking about C or c++, languages existing longer than Python and having much stronger backward compatibility story. And no one ever said that upgrade to recent gcc is a problem.
Iow there is hardly any up to date system which do not require constant maintenance.
https://support.microsoft.com/en-gb/help/13853/windows-lifec...
As a consumer, I have an old Windows 7 laptop that I use once a month or less (don't need to travel much lately). I can tell you that it's been continuing to run windows updates all year long after the EOL. It's a major issue for me to use the laptop because it's running updates for hours whenever it's taken out of storage :(
I can't say how much of a nice improve removeprefix() and removesuffix() is. lstrip and rstrip prefix and suffix trimming bugs crop up in people's code constantly. This seems like a nice change, especially since the alternatives are so ugly.
{**a, **b}
You could see this as an improvement.The dict literal with dict-splats conveys a sense of ordering that makes the behavior of taking values for overlapping keys from the lattermost dict make more sense to me.
I'm also a fan of the walrus operator. These are small, rare, clear, useful, idiomatic new features, in my opinion.
One frets that Python could become a victim of 'featuritis' as the devs try to shop for a new kitchen sink for each release.
But of course, both are very welcomed!
What do you mean by that? Can't we clear a list by doing:
L[:] = []
(useful when L is defined in another scope, or when you want to keep a reference to the same list object)Unfortunately it's not possible to search for "[:]", so pointers appreciated
L[1:] = [] if "foobar".startswith("foo"): "foobar"[len("foo"):] > "foobar".lstrip("foo")
"bar"
Of course, if the developer making this mistake tested with "foofbar" instead then they would realise their mistake. A more typical example of this type of mistake would be url.lstrip("http://"). > "foobar".lstrip("wooowweeezoweeef")
bar >>> "foobarbaz".lstrip("fo")
'barbaz' >>> {0} | {False}
{0}
>>> {False} | {0}
{False}A nice side effect is that bools can used with sum:
sum(x % 10 for x in range(1000))For future internet historians, it should have been:
sum(x % 10 == 0 for x in range(1000)) >>> {1} | {1.0}
{1}
>>> {1.0} | {1}
{1.0}
>>> import fractions
>>> x = fractions.Fraction(1)
>>> {x} | {1}
{Fraction(1, 1)}
>>> {1} | {x}
{1}Before bool existed, some folks had a habit of writing `False = 0` and `True = 1` for readability.
If you read the dict union operator "|" as something similar to "or", (like me), you are in for a surprise:
>>> x = {"key1": "value1 from x", "key2": "value2 from x"}
>>> y = {"key2": "value2 from y", "key3": "value3 from y"}
>>> x | y
{'key1': 'value1 from x', 'key2': 'value2 from y', 'key3': 'value3 from y'}
What I expect is
>>> x | y
{"key1": "value1 from x", "key2": "value2 from x", "key3": "value3 from y"}
Are you also surprised when the original bitwise meaning of "|" does not return either of the two arguments?
>>> 5 | 3
7
Here's the same thing as binary: >>> bin(0b101 | 0b011)
'0b111' >>> bin(0b011 | 0b010)
'0b11'
Does the leading 1 come from the first argument or the second argument? It isn't really a sensible question for bits, since the 1s are indistinguishable. However the values in the hash table are distinguishable, so it's a valid question.Also, taking an example from another comment:
>>> {0} | {False}
{0}
>>> {False} | {0}
{False}
This is another example where the union operator is used, but here it picks the first value, rather than the second value.EDIT: Previously had a typo "3.8" instead of "3.9", my apologies.
https://www.python.org/downloads/release/python-390/
> Release Date: Oct. 5, 2020
> This is the stable release of Python 3.9.0
I love python but these short release cycles can be really annoying.
It's a strange HN-ism that puzzles me - "OK, what's so important about Foo 3.14?" There is a rule that is (barely IMO) on point though in the posting guidelines you linked to:
> If the title begins with a number or number + gratuitous adjective, we'd appreciate it if you'd crop it. E.g. translate "10 Ways To Do X" to "How To Do X," and "14 Amazing Ys" to "Ys." Exception: when the number is meaningful, e.g. "The 5 Platonic Solids."
sums = [s for s in [0] for x in data for s in [s + x]]
Why would you do "for s in" twice? Is that intentional? It would make more sense to me if the variables would have been different. And why would you want to add 0 to numbers?! Curious about a real world use case for this. sums = []
s = 0
for x in data:
s = s + x
sums.append(s)
`for s in [0]` assigns 0 to `s`, as an initial value. `for s in [s + x]` adds `x` to `s`. Both instances of `s` are the same variable, there's no shadowing going on. s
for s in [0] # for every s of 0 (there is only one)
for x in data # for every x in data
for s in [s + x] # s is s + x.
so s = 0 + x[0], then s = (0 + x[0]) + x[1], then (0 + x[0] + x[1]) + x[2] it results in an array of rolling sums.Edit: someone already answered, I am blind.
That's probably gonna be very useful when reusing types with different libraries (such as ORMs or serializers). I think anyway, gonna have to experiment.
I've always wonder why NotImplemented is used in a boolean context in the first place, iirc when it evaluates to True the overrided comparison now becomes a source of hard to spot bug
Compared to Python, good old Windows DLL hell looks like a paradise to me.
print "Hey, they brought back the print statement!"
print("But you can still call the print() function!")
print ("printing", "tuples", "works", "like", "python2")
It would be a massive QoL improvement and also accelerate Python 3 adoption.(I'd actually be OK with allowing keywords to be used as method/function names in general, but that's a more extensive change than
from __past__ import print_statement
)Removing it (and breaking compatibility in general with no easy workarounds) is one of the major footguns in Python 3 that drastically slowed its adoption and basically forked the language.
It's a prime example of ideology trumping usability and practicality, resulting in the waste of probably millions of programmer hours, and orphaning millions of lines of code in Python 2 programs and libraries.
Other languages have managed to evolve effectively for decades without breaking backward compatibility; it's disappointing and embarrassing that Python simply hasn't.
I’ve definitely run into issues 2to3 couldn’t automatically fix (encoding issues in some py2-only lib I needed to use IIRC), but upgrading print doesn’t really have much overhead.
1) it modified the file object's "softspace"
>>> class MyFile(object):
... softspace = "Hello"
... def write(self, s):
... pass
...
>>> f = MyFile()
>>> f.softspace
'Hello'
>>> print >>f, "spam"
>>> f.softspace
0
2) This wasn't a problem until >> was added, because of problem #2 - the print statement didn't originally let you print to anything other than stdout. Which meant that if you wanted to support writing to a file instead of a stdout then you had to re-implement print yourself.In practice, I've also found that having print as a function adds functionality because I can do things like:
print(*data_values, sep="\n")
which is a quick way to print each value in a list on its own line. for v in data_values: print v
Is exactly the same length but much more readable.I can also disable all print statements with "def print(* args, * * kwargs): pass" at the top of the module.
I've had times where I couldn't figure out where a print was coming from, so I could replace print() to check the arguments passed in:
import builtins
builtin_print = builtins.print
def my_print(*args, **kwargs):
if "looking for" in args: # adjust as appropriate
1/0
return builtin_print(*args, **kwargs)
builtins.print = my_print
Previously I had to do that by wrapping sys.stdout with my own file-like object, to intercept write(). (Granted, not hard, but harder.)And the other example was in module scope.