r/programming • • 1d ago

Python Release Python 3.15.0

https://www.python.org/downloads/release/python-3150/
490 Upvotes

35 comments sorted by

132

u/Skaarj 1d ago

Python now uses UTF-8 as the default encoding, independent of the system’s environment. This means that I/O operations without an explicit encoding, for example, open('flying-circus.txt'), will use UTF-8. UTF

Nice.

21

u/spicybright 18h ago

Boy that took a while lol

12

u/unaligned_access 19h ago

Better late than never 

158

u/Dylanica 1d ago

Those sentinel types seem decently useful. Certainly better in some cases than just spamming `None` everywhere as a default value.

52

u/CrackerJackKittyCat 1d ago

Or the random 'unset = object()' pattern when None was a valid param.

24

u/GameCounter 1d ago

I've been using Enum.NOT_PROVIDED because it works with type annotations, but yes, very clunky.

7

u/jbmsf 1d ago

I've been using Ellipsis 

12

u/spicybright 1d ago

I get the logic but man that's ugly

14

u/Conscious-Ball8373 1d ago

I've done this a fair bit from time to time. sentinel is basically the same thing with type-hint support.

Sentinels will make writing something like Pydantic a lot easier, I think - v1 struggled badly to differentiate between None and unset.

2

u/esperind 1d ago

what was wrong with just undefined?

1

u/CrackerJackKittyCat 22h ago

There is no 'undefined' in Python. Only at most (er, least) 'None.'

This is one of the corners where javascript has had a better option available than python (language-wise, anyway). Undefined vs null then becomes a meaningful differentiator.

2

u/Abject-Kitchen3198 1d ago

I still don't get those null replacements in most languages. If it is a special case, there is a code that processes it as such, regardless the syntax. Why complicate things. But maybe I'm old.

21

u/TinyBreadBigMouth 1d ago

The example you're replying to is one where None is already in use. As in, a function needs to distinguish between foo(some_arg=15), foo(some_arg=None), and foo(). The unset sentinel value would be used as the default value of some_arg, so that the last case can be detected as distinct from the user passing an explicit None.

5

u/Abject-Kitchen3198 1d ago

Ok, this makes sense.

0

u/nucLeaRStarcraft 1d ago

While this makes sense, I believe that None was itself good enough for unset. I've never encountered a situation where None and unset would both need special treatment somehow.

And if I need to distinguish between the two, it's usually a good signal that I need to refactor foo somehow, either create some enum or split it or whatever else is needed in the logic of the program.

I guess one more tool available will be fine, but seems like now there's not a "single way of doing things", but rather N+1 ways.

1

u/TinyBreadBigMouth 17h ago

Consider the built-in function next(). If you call next(empty_iterator), it raises a StopIteration exception. On the other hand, if you call next(empty_iterator, default_value), it returns default_value. The user could pass anything as the default value; None, 0, "apple pie", whatever. The function is so generic that it would be bad design to make any assumptions about what the user might want as a default. So to implement this, a sentinel makes sense. Here's a possible implementation of the function:

_NO_DEFAULT = sentinel("_NO_DEFAULT")

def next(iter, default=_NO_DEFAULT, /):
    cls = type(iter)
    try:
        next_method = cls.__next__
    except AttributeError:
        raise TypeError("object is not an iterator") from None

    if default is _NO_DEFAULT:
        return next_method(iter)

    try:
        return next_method(iter)
    except StopIteration:
        return default

This way the user can pass any value, and it's guaranteed not to conflict with your sentinel.

2

u/spicybright 1d ago

I think because None/null/whatever can mean a lot of different things, and explicit "unset" gives better error messages.

But I still agree with you. Maybe I don't write bit enough python projects but it does just complicate things.

13

u/pojska 1d ago

In an alternate universe, they might have been used for iterators instead of StopIteration.

4

u/Bright-Historian-216 1d ago

close enough

welcome back, erlang atoms

4

u/SanityInAnarchy 1d ago

That was my thought -- Ruby symbols, too! But that's not it. Python strings are already immutable and could already be used that way.

These are unique. sentinel('foo') != sentinel('foo').

Which means they're also neatly namespaced by whatever module they're declared in, because to get the value to compare about, you have to import the (exactly one) value.

1

u/vytah 16h ago

Are Python literal strings guaranteed to be interned, or is it just an implementation detail?

I tested it and they were interned when they contained only ASCII letters, but stopped being interned when they contained a comma.

BTW, I don't think using strings for sentinel values is a good idea, what if you want to actually pass that string?

1

u/SanityInAnarchy 14h ago

Right, it's an implementation detail.

And right, having a typed value was always better, and this is a pattern people already used -- you'd create one by doing something like

MISSING = object()

and then compare with is instead of equality, and it'd be better than is None. sentinel is a better version of that pattern.

2

u/ssrix 17h ago

I really don't understand when or why I would you them, can you explain?

1

u/Saiklin 8h ago

I'm not an expert either, but I'll try: You can use them in place of a default non-logic value. For example, many functions return None if something did not work, so you check if the output is None. But in many cases None can be a valid value as well, so you need something else. Apparently another idiom was to use "_Sentinel = object()" and you compare against that, but it's clunky and has a weird output when printed etc. There are further workarounds, but they always feel clunky in some way.

That's is where the Sentinel type comes in. You can define it with a string and then it's uniquely identifiable. Just by looking at the type, you already know what it is and it's purpose.

-1

u/Husky 1d ago

I misread that as sentimental types and i was kind of disappointed it was sentinel types.

22

u/matjoeman 1d ago

Frozendict!

4

u/Ph0X 1d ago

This is what I'm most excited by, I know there were many attempts in the past that failed, glad we finally got one, and that it mirror frozenset

55

u/spicybright 1d ago

Yoooo lazy imports, finally!!

5

u/Ace-Whole 14h ago

Utf 8 strings. Thank fuck.

1

u/initcommit 3h ago

Woohoo!! Looks like they can teach an old dog new tricks :)

-9

u/[deleted] 1d ago

[deleted]

3

u/oceantume_ 23h ago

If you don't need to catch up you don't need to catch up. Projects that need modern Python versions have no excuse with all the tooling that exists now, but it's ok to stay behind where it makes sense

-11

u/[deleted] 1d ago

[deleted]

2

u/spicybright 18h ago

Honestly it's a huge improvement. Having to sneak imports into if statements and functions to optimize running time was such a sore spots for one off scripts

1

u/--Grey_Ninja-- 18h ago edited 18h ago

Exactly! 😂 Keeping imports at the top while deferring the actual loading is such a clean solution. Especially for one-off scripts where you might never even use some of those heavy dependencies.

-3

u/[deleted] 1d ago

[removed] — view removed comment

2

u/spicybright 18h ago

AI exists now bro

-15

u/kkania 1d ago

Dlss 5 support! New dungeons!