#internals-and-peps
1 messages · Page 30 of 1
def foo(l):
l.append(1)
return l
x = []
foo(x) += 2,
print(x) # [1, 2]
better example
calls which you can do augmented assignment on
ooh i just had an idea for julia-style functions
ok?
i don't even know what point i'm trying to make
i'm curious though
so first of all i rarely have great ideas
second of all i don't have my thoughts in order
third of all i'm scared of controversy
order is for the feebleminded
i'm feeble minded :3
don't share it then :p
share what-
your idea
it's a good idea currently
sometimes ideas already have stuff i can build upon in my toy collection
so it makes it easier to implement
but it bothers me that my toy collection is about 2 years deviated from the current python/cpython
i'm surprised the for-if change worked so flawlessly once you gave me the hint about the make parser
and that's with the current 3.14 code
can i propose a pep to adopt latex-style versioning from 3.14 on? 🙂
or rather Tex
adding more digits to approach pi
oh, oh no
nvm
nvm nvm
nvm nvm nvm, i'm getting worked up over nothing
can we have a something like ```py
type foo(x: int, y: int) = str
what do you have in mind with that?
more readable Callable type hinting, i guess
what's the str? return type?
yup
why not have it type foo(x: int, y: int) -> str?
it seems logical to me, since we already have that for defs
so you could just copy&paste the function head
ooh that just solved another idea problem with my julia-style function declarations
what makes you think it's based on the person?
politics usually is
There are both PEPs by very well-connected people that get rejected (recent example: PEP 760) and PEPs by people outside the core team that get accepted (example: PEP 692). I can't guarantee that personality plays zero role, but clearly it's not the major one.
Also, you talk about technical merit as the alternative. I don't think many of these decisions can be purely technical; they are based on a social judgment of what things would be acceptable to the community.
😦 for PEP 760, i liked it
but if it's a beauty contest, we could also have community votes
It's not
what's the point of a council if they can't rule against public opinion and make unpopular decisions? then we could just put everything to public vote
Public voting can be easily abused
Making them meaningless
Especially for something as popular as python
depends on the system
Public (including me) also like to think about "I would love this feature right now" and less of "How will this look in python after 10 years"
what's so bad about that? we gave up a unified vision when guido quit
guido didn't exactly quit did he? he just changed roles
I don't think popular votes are all that useful tbh. Most changes are only bad for a minority of usecases, but that's still a Python usecase
i would say he quit and now enjoys his old days doing what he wants without bothering with politics
then how about the other way round? council proposes and public doesn't get a vote but a veto
If the council doesn't have the power to decide, why bother with it?
in most cases proposals require expert knowledge, dedicated people to work through the process. but it doesn't require expert knowledge to understand if a change would negatively affect you in your specific case
so public veto would essentially formalize an "outcry" when people realize that a certain change negatively impacts them
isn't that the point of PEPs
How would you envision a representative election among the whole Python developer community working?
representative election as in council?
An election that is representative, which is what you appear to want
public veto wouldn't require representation, you could just make a poll (with some caveats)
So the side wins that's best at getting their friends to click a button on the Internet
as i said, with some caveats
also, it's not about winning in this case
it's about losing
it's not "do you want this feature?" but rather "do you NOT want this feature?"
the worst case would be status quo
nobody would bother to rally their friends to stop a PEP if it wasn't something important. it's about a simple "go ahead/no way" question, not about forcing a certain path
Right, just as nobody would rally their friends just so a ship gets called Boaty McBoatface
only the council could propose to call the ship Boaty McBoatface. the public only could say "that's crazy, this can't pass!"
the public could petition the council for proposals, but the council has no obligations to follow through
does that make sense now?
They can. They're elected to represent the community's needs, and they do so to the best of their ability. Part of doing that is gathering feedback from diverse stakeholders. The steering council is allowed to make unpopular decisions, of course, but they shouldn't be making uninformed decisions
The whole point of a elected council is that you don't have to bother the entire community for every decision
i'm not proposing to bother the entire community for every decision
i'm proposing to give the community a chance to veto changes so the council can propose more bold changes without having to worry that the community could complain afterwards not having had a chance to stop it
And what would the threshold be? A percentage of people who voted in the poll? A fixed target amount of veto votes?
both, would make sense
a minimum amount of votes to start the poll, then some percentage?
The steering council can already do that. Your "veto" proposal would be making them less able to make bold changes than they are today, not more
What about a citizen council?
Perhaps an anarcho-syndicalist commune would be appropriate? https://youtu.be/R7qT-C-0ajI?t=147 /j
Supreme executive power derives from a mandate from the masses, not from some farcical aquatic ceremony
if any one senior devloper her so please help me to working with this pocket option api
https://github.com/ChipaDevTeam/BinaryOptionsToolsV1
please give me script for giving historical data of particular asset
Also, it's not clear to me what problem this veto proposal solves that isn't already solved by the "vote of no confidence" option provided by the existing governance model.
A public veto system is a disproportionately reactionary form of governance that incentivizes language decisions that aren't necessarily great, but are inoffensive. I say disproportionately reactionary because it does not distinguish between apathy and support (only highlighting dissenting opinions) and caters towards users that dislike change overall (by magnifying their opinions on new, not-yet-shipped features). Maybe the idea can be remedied using something like a big public-beta phase, but at that point you can just collect feedback normally.
I do think being very adverse to change is a good idea when it comes to Python
i think it would incentivize prototypes and demos to get people on board with big changes to avoid a veto. of course it also could result in different factions that could block each other to push their agendas
scipy geeks vs AI nerds vs web devs
shrug
a veto isn't a vote of no confidence. it's not about "i think you're an idiot" but rather "this needs to go back to the drawing board and i want my voice heard"
Sure, but a vote of no confidence solves the same issue, right?
The steering council makes a big decision without considering your needs, so you replace them with a new steering council that will consider your needs
it is, but you have to make sure the decision is informed rather than gut-based
not really. it makes it all about personal issues while it's supposed to be about technical issues.. i know it's a thing in RL politics to associate a certain decision to a vote of no confidence, but that always comes with a taste of "it's my way or the highway". in german politics, we have a second instance where the länder have a chance to veto law proposals to exactly get that effect - back to the drawing board without making it a personal issue
both do attempt to avoid the same scenario (council not being able to make good decisions)
but i'd say that one is more extreme than the other
a vote of no confidence would directly result in new elections and until the whole process is re-established, the original issue is off the table and nobody will want to touch it again to avoid another desaster
i rather think it should be a kind of dialogue, a back and forth
only because a proposal was veto'ed, it doesn't have to mean people have to be afraid of getting mobbed off the board just for mentioning it
maybe the whole walrus debacle could have been avoided that way
dunno
But that's what we have today, right?
The steering council makes decisions based on their understanding of the needs and desires of the community, and in particular they are reluctant to make changes that many core devs oppose
which makes it susceptible to a vocal minority, not necessarily the community at large
if vetos were an explicit process, the steering council could go for broader strokes, maybe with the risk of getting veto'ed, but not to a point where they couldn't continue working, and if there's opposition, it's not about who is loudest anymore
...isn't the job of the SC to do the vetoing? why do we want vetos for the vetoers?
i don't think the job of the SC is to veto 🙂
well, what is it then?
The same is true for vetoes
as i see it, it's the interface between the public and the core devs. come up with proposals, based on input. i wouldn't say filtering or policing ideas is their job but rather mediate
core devs are supposed to talk to the public too
"a minimum amount of votes to start the poll, then some percentage" would at least give two parameters to tune the size and loudness of that minority necessary to have an impact
Sure, but the results will be the same. Only people with very strong opinions answer surveys or respond to polls
And if it's a public poll, it's easily gameable with bot farms or Mechanical Turk or whatever
And if it's not a public poll, then the higher barrier to entry makes it even more likely that only people who have strong negative opinions will vote at all
those are three different issues :p
- yes, but: someone who is directly impacted by a change can get strongly motivated even though they are usually not. in python that's probably maintainers of important packages (thinking of annotations and beartype, for example) who normally don't care about politics, but get strongly motivated to voice their concerns if they realize that their stuff won't work anymore
Those people are already represented well by the current process, right?
not really. remember the debacle with annotations?
they voice their concerns on the DPO thread and it's taken into account before something gets accepted
That's exactly what I'm thinking of
or after..
is there a case of that happening?
Even though they got involved very late in the process, after a decision had ostensibly been made, they brought new data forward that caused the decision to be unwound and a new path pursued
- it could be restricted to github accounts with a certain amount of activity or somesuch. identity is always an issue in polling, but should be manageable
yes, there was
now i'm curious. which PEP and what happened? (and how would a veto vote have solved it?)
uff.
deferred annotation evaluation?
I for one am glad that my vote has no bearing nor that of other people like me who know as little as I about the inner workings and history and complexities involved (genuine opinion, not just a joke)
that hasn't been implemented yet (on a released version)
Yea, it was to be implemented, then people who use non-type hint annotations took issue with it
exactly because of that.
right, so what would a public veto vote have done?
that's my point though. you don't need knowledge of inner workings and history in order to tell that a change would negatively affect you. you need the knowledge when coming up with a proposal or to decide on alternatives, but not to reject something
exactly - that's an example of the current process working perfectly well, not of it failing
not saying it's failing but rather how it could be better
Given the extreme difficulty (as far as I've read) of getting something passed/approved, I can't quite see a problem that this is solving. Again, from an outsiders view
it would've short-circuited the proposal and instantly defer it for further discussion without putting blame on the council for not considering that use case. just another day.
but you haven't demonstrated that there's anything wrong with the current process
the right people are getting involved and representing their constituencies
that's already what happened, right?
wouldn't the theoretical veto vote have already passed by the time that case got brought up?
that's what happened. it wasn't a planned process and it put a lot of stress on everyone involved.
in fact - if anything, I suspect the veto wouldn't have passed
the constituency that cares about annotations for things other than types is so much smaller than the constituency that cares about annotations for type hints, and the issue is so wonky and difficult to wrap your head around, that it's unlikely the maintainers of the libraries who deeply care about annotations for things other than type hints would have been able to rally support for a veto. The steering council listened to their needs despite that
well. a veto poll would've put a number to that, now we could just speculate
I don't think a number matters. Breaking an entire usecase like that should be avoided regardless of how many users it ends up affecting
exactly. This is a thing that's handled well by the small circle of deciders responsible for representing everyone model, and not handled well by a popular vote model
if a change helps 90% of users and forces 2% of users into never updating Python again, it shouldn't happen.
such a proposal shouldn't be made by the steering council in the first place
exactly!
the steering council should be representing the entire Python community, by gathering feedback on proposals even from small constituencies with uncommon use cases
Python is a vast language, it is possible no one near the language leadership knew about that 2%.
but the sampling is lacking!
I have a vague memory of some stdlib module that was only used in one industry without any sharing, which was almost deprecated. Can't actually find it tho.
so, you want a "steering senate"?
i think i said clear enough what I want :-p
why do you say so?
I'm not seeing what you're basing that claim on - you've only provided an example where the sampling was sufficient
it wasn't sufficient, otherwise it wouldn't have ended in a crisis with people throwing the process overboard and deferring the PEP ad hoc
I don't understand what you mean by "crisis" or "ad hoc" here
the proposal was determined to be fundamentally flawed as it relates to those use cases, and so it was shelved - a veto would have accomplished the exact same thing, right?
and a new proposal that does address those use cases was instead proposed instead
as far as i understood, the situation was that they were about to release new code, already had everything ready. then they got hammered with "oh shit, stop it!" and everything was put on hold with no clue how to proceed
how would the process have been any different if the SC were veto-able?
depends on the implementation?
someone came in at the last minute with a new concern for delayed evaluation of annotations that caused everyone to slam on the breaks. A veto would have at best achieved the exact same result
you asked why i think the sampling is lacking, i've got some anectodal evidence
lambdas
why do many (most) people think lambdas suck and (like guido argued once) should be removed from the language? because the use-cases where they are useful - GUIs and networking - are nowhere near the core language dev
networking is very, very near the core language dev - a massive amount of investment into asyncio has happened over the last few years
that was before asyncio, then guido learned that one-off functions do have a purpose
there are also 6 core dev experts for idle and tkinter
anyway, your veto proposal wouldn't change anything here. If the SC doesn't find it useful to allow multi-statement lambdas, then you can't veto their inaction
that's true. and you're mean to turn this against me :p
i'm shocked you remember
at least you can't hold it against me that i'm proposing something that doesn't benefit me directly.
@raven ridge i'm exhausted. was nice talking to you 🙂
my understanding of why the deferred annotations thing led to such drama is that the maintainers of at least one of those big libraries using annotations for something other than types not only waited until the last minute to voice their concerns, but then also advocated for their community members to complain directly to the Steering Council - a "call your representative and tell them not to break your favorite library!" sort of thing
it was chaotic - but the way in which it was chaotic is exactly the way in which public calls for vetoes of already-accepted and implemented features would be chaotic (since people would need to rally their constituencies to advocate for a vote, and then vote to veto). So the proposal to enshrine public vetoes in the governance model would only cause more of that sort of chaos, not less
Was part of it because the impact wasn't clear until the implementation was solidified? Or was it predictable from pep alone?
totally predictable from the PEP alone; the implementation had been ready for literally years under a __future__ import
You don't need callbacks in an async framework
no, but guido got a lot of inspiration for asyncio from glyph and twisted
You do in the implementation of an async framework
The entire abstraction is built on callbacks
$ git grep callback Lib/asyncio | wc -l
236
Nope, curio and trio are task first
I'm not sure what "task first" means, but I suppose I shouldn't generalize: asyncio is full of callbacks, at least, even if other async libraries aren't
There's 58 matches for "callback" in trio, fwiw
Lots in docstrings, but about 30 seem to be real code
Most are related to guest mode, ExitStack or ssl
There's a callback in ParkingLot.park, which is used very heavily
More than 200 matches for "Callable[" too. There's plenty of callbacks in this code base
What I'm saying is there's no continuation passing
Also curio is a bit more pedantic about not having callbacks
I thought the stringifying type hints pep is what was breaking say pydantic, and not the deferred eval pep
The deferred eval pep was to actually be a working replacement for the stringifying pep
Did deferred annotations get cut out again?
No, I misspoke. You have it right, string annotations was what got cut, in favor of deferred evaluation of annotations
Deferred evaluation is going to be in Python 3.14
That's what I thought but it's taken a long time for it get in
I remember the discourse being one of the bigger ones
it is not even syntactically valid
While
that's not even the only syntax error
took me a while to find the other one
@hot aurora I have this mug
luckyyy
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print("Loading word list from file...")
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r')
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print(" ", len(wordlist), "words loaded.")
return wordlist
Has anyone used weakref in "actual" code? I'm interested to know why and how.
I have. Particularly when a descriptor stores a value where it's hashing owning instance into like weakkeydict
And I want the stored value to be released when the owning instance is garbage collected
Use it in trio recently
Use it for marking regions that can receive keyboard interrupt
Using a identity based weak map of code objects
weakref.finalize is the safest way to run some cleanup when an object is destroyed. It can come in very handy for cleaning up after objects in C extensions
it is only possible if the object supports weakrefs, which is not always the case
I was writing a UI library of sorts, and I needed a list of all widgets, but someone could write code like this and repeat it several times across the application runtime
def on_click1():
foo.contents = Text("Please select an option")
def on_click2():
foo.contents = Button("continue")
``` and so just naively maintaining a list would keep those stale Text and Button objects around until shutdown. It would be possible to track whether an object is attached or detached as part of the objects and manually remove them from the list, but a collection of weakrefs can end up nicer.
i use it also to keep reference to widgets
like, might keep a weakset of all Focusable widgets, because widgets have a lot of state and you don't want to keep them alive if other references are gone
we use weakref.WeakValueDictionary in @fallen slate for our lock decorator, so that after the function is done, the reference to the lock is dropped
Could you not use a strong reference that you delete when the function is done?
I think we did at one point, then we added namespaces for locks, the weakref is on the namespace key, so once all locks in that namespace are done it's removed
All good
:incoming_envelope: :ok_hand: applied timeout to @errant bison until <t:1735472841:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
@steel solstice Am I missing something? Your last comment is correct, slice instances are still not subscriptable, it's the slice class https://github.com/python/cpython/pull/128336
- Make :class:`slice` objects subscriptable at runtime.
+ Make the :class:`slice` class subscriptable at runtime to be consistent with `typeshed <https://github.com/python/typeshed/issues/8647>`.
(or something to that effect)
yeah I think I miscommited
Why do we want slices to be generic though. For what purpose
slices can have different parameters to the familiar ints, the old implementation left them as Any and changing that would have been too disruptive without default type parameters, but they can now hold any types as there start, stop and step so they are better typed in the cases they use datetimes or anything other than ints
see https://github.com/python/typeshed/issues/8647 if you want more rationale
This is a port of python/typing#159, which was closed as being out of scope, with https://github.com/srittau suggesting it maybe be more suitable for typeshed instead. It would be useful to have sl...
That discussion reminded me that pep 637 got rejected.
i've used it to implement a flyweight pattern something like ```py
import weakref
_id2name = weakref.WeakKeyDictionary()
class Thing:
slots = ("id", "weakref") # Add weakref to support weak references
def __init__(self, id_):
self.id = id_
@property
def name(self):
return _id2name[self]
def add_name(thing, name):
_id2name[thing] = name # int isn't weakrefable, needs to be the Thing itself
Example usage:
if name == "main":
thing = Thing(1)
add_name(thing, "Alice")
print(thing.name) # Alice
has some benefits on memory consumption and i find it easier to fiddle with attributes to a large number of objects on the fly
the weakkeydict takes care of cleanup if the thing is deleted
new year, new segfault report! https://github.com/python/cpython/issues/128396
ridiculous
<@&831776746206265384>
!pban 1297923384692441129
:incoming_envelope: :ok_hand: applied ban to @modest flower permanently.
the repl waterfall
:incoming_envelope: :ok_hand: applied timeout to @unkempt rock until <t:1736274948:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
core dev friends: my understanding is that the end goal of the free threading project is to get to a point a few years down the line where the GIL is gone and cannot be reenabled at runtime.
@uneven raptor believes that the goal is to get to a point where it's no longer possible to build an interpreter without free-threading support, but that it will always be possible to create a GIL at runtime if an extension module doesn't support free threading.
Which of us is right?
also for the core devs: if he's right, i'm curious about why. won't removing the runtime GIL break the compatibility for the extensions that don't support it?
https://peps.python.org/pep-0703/#python-build-modes pep is pretty clear
The current goal of the free threading project is to fix all the threading issues in the stdlib and also some work getting the ecosystem working with free threading
yeah,
The author believes a worthwhile goal is to combine these build modes and have the global interpreter lock controlled at runtime, possibly disabled by default. The path to this goal remains an open issue, but a possible path might look like the following:
[...]
3. After another 2–3 release (i.e., 2028–2030), CPython switches to the GIL being disabled by default. The GIL can still be enabled at runtime via an environment variable or command line flag
I suspect it will become clear in the future if that's necessary
If the GIL is universally disabled it will probably be deprecated and removed
But it's not a goal of the free threading project
It's still in the "get the damn thing working" phase
perma-removed GIl might be significant and backwards-incompatible enough to justify the enormous leap to python 4, too
Python breaks compatibility with pretty much everything every 3.x release anyways. Especially c extensions
not limited API ones
Like the wheels install and run, they just don't behave correctly
we're disagreeing about how to parse the SC's acceptance message in https://discuss.python.org/t/pep-703-making-the-global-interpreter-lock-optional-in-cpython-acceptance/37075, and in particular the phrase
Some time after the default flip, when we have a good indication it’s no longer widely used, we should start the discussion on removing the GIL build entirely.
Zero thinks that's just about removing the --disable-gil option (and whatever its contrapositive is). I think that's about removing the GIL.
I realize that the short term goal is definitely just "get it working", but my understanding is that the long term goal is to reach a point where the GIL no longer exists, and core devs don't need to do 2x the reasoning about correctness.
hmm, it sounds like the SC and the pep author may have differing ideas. need for a coredev opinion, indeed
To me mentioning the "GIL build" suggests that "the distribution of Python without the t letter" will no longer be issued officially, but could still be built customly if you really needed it. But it could be kinda ambiguous
yeah, that's definitely what that wording says, but it doesn't match what I've heard from core devs (and SC members 🙂)
has the idea been suggested to ask in the discuss thread? last comment is from march 2024, but it's not locked
my main argument, at least from my experience when working on FT, is that you don't necessarily have to do 2x the reasoning. you only have to maintain 2x the code for Py_GIL_DISABLED and not. if you write something that's FT safe, it's also safe to run when the GIL is enabled on FT.
I don't want to necro a >1 year old thread just to ask that, personally
Well, removing the t letter build is a prerequisite to removing the GIL entirely, so I guess they could start the discussion on the former before talking about the latter
so you could both be right (in the future)
I don't believe this is true in general. I'm confident that it's possible to write code that works in free threading builds but fails in non-free-threading builds.
fails in non-free-threading builds, or fails when the GIL is enabled by -Xgil=1?
both
The details of the phases are deliberately vague, simply because we can’t know all the ecosystem impact details yet
shame wouters has no discord account here (afaik), but i'm not sure the SC knows the answer yet
heh. Pablo does have one, but I don't think he pays any attention to it, and in any event it's 1 AM for him 😄
for -Xgil=1, how so? the free-threading team has put tremendous effort into keeping it backwards compatible
I'm confident that it's possible to omit a call to PY_BEGIN_ALLOW_THREADS and have your code work when the GIL has not been created but fail when it has
yeah, but that's a legitimate bug. you can't omit Py_BEGIN_ALLOW_THREADS on FT because it breaks critical sections
yes, it's a legitimate bug - I never said it wasn't
right, i could crash on FT with only the GIL enabled by doing if (_PyEval_IsGILEnabled(_PyThreadState_GET())) { abort(); }, but that's my fault
er - sure, but that's a hard bug to write accidentally
omitting a call to PY_BEGIN_ALLOW_THREADS is an easy bug to write accidentally
i guess so. but i'm not sure that means it's a good idea to remove the -Xgil option
I haven't seen this discussed explicitly but my understanding is that the long-term goal is there's no GIL at all
that's what i understood from talking to brandt and guido at pycon too
NO GIL Python should be Python 4 since it will be a breaking change. Like Python 2 to 3
Python releases breaking changes in minor versions, there's no need for a new major version
yeah, Python doesn't try or advertise following semver
i still think python should move to a pi-oriented versioning scheme after reaching version 3.14 🙂
next version after 3.14 would be 3.141 and so on, adding more digits towards pi
thus putting the neverending python 4 discussion ad acta
That's exactly what TeX does
smh stealing
that's where i got the idea from
the highest form of praise!
hrhrhr
i mean, we're already making tons of p[y|i] related jokes as a community, so why not
the major version numbers are dead after 3, there's no point in pretending
I am making a wikipedia page on pyi jokes, but for now it's a stub
😄
versioning is pretty much arbitrary anyway - we could even just use github commit hashes and celebrate prime numbers
Well, both pi and the current scheme have an advantage over commit hashes. You can more easily figure out which is newer
sure, ok.
if that's the major benefit we're aiming for, we could just go the ubuntu way and use year.month
but the current scheme suggests we're still hanging onto semver
and eventually there will be some grand py 4
at least year.month would make it easier to figure out how long a version will be supported
!pep 2026
Another benefit of the current versioning scheme is that previous Python versions also used it 😉
i would prefer the pi scheme though to follow through with self-deprecating humor - "there will never be a py 4!"
the pi scheme would be compatible with that!
It gets very annoying after 5 or so versions
It works ok for Tex because Tex evolves much more slowly, and is basically in bugfix only mode now. But imagine trying to tell people "it's not working because you're using Python 3. 1415, but that feature wasn't introduced until 3.141592". Sounds very un-fun.
I am really getting old, I forgot all the digits of pi
And pi-based versioning doesn't work for how Python represents versions in the stable C API, anyway, so it's a moot point. Nothing that breaks the limited API is gonna happen
!d Py_Version
const unsigned long Py_Version```
*Part of the [Stable ABI](https://docs.python.org/3/c-api/stable.html#stable) since version 3.11.*
The Python runtime version number encoded in a single constant integer, with the same format as the [`PY_VERSION_HEX`](https://docs.python.org/3/c-api/apiabiversion.html#c.PY_VERSION_HEX) macro. This contains the Python version used at run time.
Added in version 3.11.
so we're stuck with "let's do py4!" discussions
that wouldn't go away though - it's just how it's presented that changes
!d PY_VERSION_HEX
PY_VERSION_HEX```
The Python version number encoded in a single integer.
The underlying version information can be found by treating it as a 32 bit number in the following manner...
Ah, hex. Something to do with curses
You get the minor version by looking at bits 9-16 of Py_Version. Which means the highest possible minor version is 255, so the highest representable "pi-versioned" version number would be 3.141, you can't do 3.1415
we'd need a mapping, but we'd need that with any other scheme, too
i mean, android does that - just use a simple number internally to check for updates, and presentation can be anything
That sounds even more horrible than the horribleness I described above. "that feature wasn't introduced until 3.141592, which was the 4th minor version after Python switched to pi based versioning in 3.14, so you need to check if the minor version reported by the interpreter is at least 14+4 to test if that feature is available"
alright, alright. how about we drop the "3." and just call the next version 15 then?
after 3.14 that is
Also, patch versions ruin the joke. And also, it seems un-fun to distinguish between Python 3.14.1 and 3.141.0, or 3.141.5 and 3.1415
Are you aware of the proposal currently being discussed to make the version after 3.14 be 3.26? I think that, if that proposal was accepted, we'd quickly get to the point where everyone accepts "Python '27" as a minor version
nope, first time i hear about that
Fix linked it to you above
ah
so the new scheme would be "3.major.minor.patch"
kinda
No, it would be 3.year.patch, with an implication that there will never be more than 1 minor version per year
it's weird, i don't like it. dropping the "3." and just keep counting is more elegant
it achieves the goal of being able to tell versions apart easily
gets rid of the py4 discussions. simple, no confusion about the meaning of the leading "3."
switching to a date-based schema midway is more confusing, i think
just imagine how you would have to explain it to a newbie
i'd say the pi-schema would even be less annoying
IIRC the complaints about dropping the leading three is that “python 26” reads as 2.6, not 3.26
can't we just ignore python 2 at this point?
it’s kind of hard to if the version starts with 2
it really does. html5lib went up to 0.999999999 before finally releasing 1.0
https://pypi.org/project/html5lib/#history
Calling it Python '26 solves that
but i don't wanna use python 2.6!
And then that problem goes away after 5 years once we'd hit Python '30
I would prefer to drop the "3.", but it would break more people's code, and need more changes, including for packaging and deciding about the python3 command
https://peps.python.org/pep-2026/#yy-0
that still reads to me as python 3.0. the ' helps a little bit, but what's wrong with calling it 3.30 anyway?
Only redundancy. It feels pointless to say "3." once we codify that everything will always be "3." forever
slugs are fairly typically just [a-z0-9-]+, so they are just kind forced into the ambiguity. But they already do python314, so it's kind of fine.
weren't we just talking yesterday about a hypothetical python 4 😛
Only in the context of what sorts of breaking changes might happen. But no one wants a Python 4
I think it's more likely that we'd see a fork of the language than see Python 4
I'm not convinced shifting the entire versioning scheme 11 versions forward is actually going to simplify understanding Python versions within the next decade or so.
I think it's a small improvement. At the very least, it gives a pithy answer to "when will we get Python 4": "maybe in 2100"
We’ll keep major version 3. Python 3 is the brand; there will be no Python 4.
In the year 2100, the minor will be 2100-2000 = 100, therefore the version will be 3.100.0.
Explaining that takes more work than saying "maybe in 2100", though
And realistically, we don't need to decide what the version number will be in 2100 until ~2098
shorter version: "when will we get Python 4": "never" 🙂
Having to remember that 3.14 and 3.26 are 1 version apart rather than expected ~12 seems harder than just having sequential numbers.
Imagine waking up in 2101 and now having to port from 2 to 4, that's going to be an even bigger undertaking
woah, this pep will make it "official" that there wont be a python 4 wont it? so far it's mainly an implicit understanding with no official codification anywhere
yes, if it's accepted, and if it's accepted with that text
a coworker of mine noted:
The discussion thread was closed by the PEP author in September, which doesn't bode well for acceptance of this PEP.
oh, hugo is here
@wanton flame how's the PEP looking like?
i meant to do a silent ping, didn't work, sorry bout that
well, there could be a superseding PEP if they really wanted a python 4 someday
I honestly much prefer the idea of just python 26
you're planning to live that long?
double it and pass it to the next person /s
Yeah, I asked to close it because I'd already submitted it to the SC, and the discussion was going very off-topic from the PEP and suggesting things like ditching the annual release policy altogether 🙂
and the SC punted it to next year's SC
which is now this year, so I assume they'll be working on a decision soonish
hey, I know this is perhaps a bit weird but the coincidences I see here are even weirder. We have the same name AND you have the same last name as my mother. Are you perhaps Dutch too?
:ok_hand: applied timeout to @quasi talon until <t:1736438826:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
Can I create an image processing project using Django?
If u know you can
:incoming_envelope: :ok_hand: applied timeout to @flat musk until <t:1736527947:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
:incoming_envelope: :ok_hand: applied timeout to @unreal python until <t:1736530657:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
Does anyone have a c++ server
Please don't spam, ask in the off topic channels
I forgot... what's the point of abc.ABC allowing you to execute the body of an @abstractmethod?
The documentation says:
This could be useful as an end-point for a super-call in a framework that uses cooperative multiple-inheritance.
but in that case don't make the method abstract, no?
Imagine using it for something like Widget.draw() - it makes sense for that to be abstract, because every widget needs to define how it gets rendered, but the base class could still do useful work (say, flipping the double buffer and actually outputting the rendered representation to the screen)
You can use it when the base class knows some of what needs to be done to implement a particular method, but not everything
Why does it have to be abstract though?
If it does something useful, then it seems plausible that "every widget needs to define how it gets rendered" is not true (maybe just a lack of imagination from the base class author)
Because if it wasn't, nothing would enforce that a subclass overrides it, and the parent class doesn't contain a complete implementation, just something that can be delegated to in order to start the work or to finish it
🤷♀️ nothing stops the child class from creating an implementation of the method that just delegates to the parent, if they're sure that's what they want to do. But the fact of making the method abstract is the author of the parent class telling you that they don't think that makes sense to do
Does it have to be the same method? Usually I'd just make two methods in this case
It doesn't, and you could do that. Making it the same method is just an option
The reason I don't feel very well about this is: most ABCs I worked with don't make use of this feature, but if you don't remember to add a raise NotImplementedError, you get a potential footgun. To me it would make sense to make this an optional thing you have to opt into
Like ```py
@abstractmethod(fallback=True)
The implementation of an abstract method is usually pass, not raise NotImplementedError
If you make it raise NotImplementedError, you need to know the MRO
if it returns None, possibly
Because you need all the subclasses to delegate to the next class in the MRO except the one right before the abstract class
If the method returns None and an empty action makes sense in that case, then yes, it makes sense to have ```py
def method(self):
pass
or
@abstractmethod(fallback=True)
def method(self):
pass
Which seems to make this idea fundamentally unworkable, since the code executed by a method is static but the MRO is dynamic
Here's the kind of footgun I meant. https://github.com/apache/flink/blob/master/flink-python/pyflink/datastream/functions.py#L70-L82
The contract of the method states that it returns ValueState, but this fallback implementation returns None.
flink-python/pyflink/datastream/functions.py lines 70 to 82
@abstractmethod
def get_state(self, state_descriptor: ValueStateDescriptor) -> ValueState:
"""
Gets a handle to the system's key/value state. THe key/value state is only accessible if the
function is executed on a KeyedStream. On each access, the state exposes the value for the
key of the element currently processed by the function. Each function may have multiple
partitioned states, addressed with different names.
Because the scope of each value is the key of the currently processed element, and the
elements are distributed by the Flink runtime, the system can transparently scale out and
redistribute the state and KeyedStream.
"""
pass```
The raise NotImplementedError approach is fundamentally incompatible with cooperative multiple inheritance, as far as I can see, unless every subclass implementation of the method either a) examines the MRO to decide whether or not to make a super() call, or b) unconditionally makes the call but suppresses any NotImplementedError
If it makes sense to have a terminating action like pass, then as I said in #internals-and-peps message, this behaviour makes sense.
But it doesn't make sense in the case where the method is never expected to return None
which is why I thought it would be good as an opt-in when you know about this feature, not an opt-out
When the method is never expected to return None, you need to implement a different default. But yea, this is surprising behaviour for sure.
When the method is never expected to return None, you need to implement a different default.
Exactly. But I've seen a lot of methods that justpassin that case. Like the above example from Apache. Or the standard library: https://github.com/python/cpython/blob/main/Lib/typing.py#L2855-L2863
Lib/typing.py lines 2855 to 2863
@runtime_checkable
class SupportsInt(Protocol):
"""An ABC with one abstract method __int__."""
__slots__ = ()
@abstractmethod
def __int__(self) -> int:
pass```
and type checkers don't complain about this
Yea, it does seem like library authors don't really know how to write their classes WRT multiple inheritance
Though I doubt that Guido doesn't know how ABCs or multiple inheritance work. So I wonder why this __int__ is like this
Yea, that I don't know. Tho at least __int__ is unlikely to participate in any delegation chains
maybe it's more of a type checking issue, and type checkers should just treat abstract method bodies like ordinary bodies
hm, that would make a lot of common patterns inexpressible.
IG the simple answer is to just be very careful about using multiple inheritance.
what do you mean?
class AbstractStorage[T](ABC):
@abstractmethod
def take(k: object) -> T:
pass
@abstractmethod
def give(v: T) -> object:
pass
```I don't really see how you'd implement `take` here
in a typesafe way
IG you just have to use a protocol and not inherit from it
if you want to write something like AbstractStorage and use multiple inheritance
Why not raise NotImplementedError in the abstract implementation?
Oh, if you want that
Well, presumably you want to raise some exception if the T or object was not found or something like that. You might raise that instead
Yea, that'd work.
:incoming_envelope: :ok_hand: applied timeout to @broken lance until <t:1736664962:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
I'm working on a project which includes an emulation of the behavior of Python's module global scope. I noticed that while all of the initial module globals can be deleted as one would expect, for whatever reason doing del __builtins__ simply replaces the module it is bound to with a dictionary containing all of the builtin names (in CPython 3.13.0). All future deletions of this name do nothing.
It makes sense why this happens, since actually deleting __builtins__ would make all the builtin bindings inaccessible. But doing something like __builtins__ = 3 correctly rebinds the name to 3, and therefore breaks the builtin bindings. Is anyone aware of why these evidently contradictory behaviors occur, or know where in the CPython docs/code I could look for an answer myself?
may I ask what project you're working on? sounds interesting
:incoming_envelope: :ok_hand: applied timeout to @hybrid hearth until <t:1736713993:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
a friend and i were trying to write code for a class using only expressions and i finally am getting around to writing a general program translation pass
This seems to actually just be a thing the interpreter does based on some lines in the github; executing a file as a script works as I would expect
but you can still use builtin functions after deleting __builtins__ and builtins, so I guess there is some other reference to the builtins aside from that
Another fun thing is that if you del __builtins__.len in the interpreter, the interpreter crashes since for whatever reason that code deletes the interpreter's len function
for more fun in the REPL, you can do ```>>> l = builtins.len
def len(x):
... print(x)
... return l(x)
...
builtins.len = len
Yeah that makes sense, should also when executing a script
Does anyone know why the interpreter would share builtins with the program it is interpreting?
All I can think of is that it is technically more performant to run the python code natively rather than actually interpreting but that would mean the interpreter could maybe just be a loop around exec at that point
The way you use the word "interpreter" doesn't really align with how we normally use it, I think you mean the REPL?
The REPL is basically a loop around exec
so true its all an interpreter
:incoming_envelope: :ok_hand: applied timeout to @pseudo burrow until <t:1736840956:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
!rule
The rules and guidelines that apply to this community can be found on our rules page. We expect all members of the community to have read and understood these.
https://discuss.python.org/t/new-function-repr-args-in-pprint-or-reprlib/65193 can i get some opinions? :D
During writing representation string builders, an often practice is to represent every argument from a known tuple-like structure and every keyword argument from a known dict-like structure using a variant of arg_repr = [] arg_repr.extend(map(repr, args)) arg_repr.extend(f"{k}={v!r}" for k, v in kwargs.items()) return f"{type(self).name}({'...
:incoming_envelope: :ok_hand: applied timeout to @tough light until <t:1737164819:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
I got hacked
:incoming_envelope: :ok_hand: applied timeout to @amber charm until <t:1737242576:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
!pban 1304594867132825721
:incoming_envelope: :ok_hand: applied ban to @spare garnet permanently.
thanks Luna
op
Good bye
currently we use _ variable for throw-away values: ```py
_ = f() # function returns something, but we explicitly dont care
begin, _, end = s.partition(sep) # throw away the separator
for _ in range(n): # do something n times, dont care about iteration counter
do()
match f():
case foo(): ...
case bar(): ...
case x: ... # everything else, we do need the value
case _: ... # everything else, we dont need the value
this is fine, but it binds a real variable called `_` ||(except for match-case situation, where `_` is considered a keyword)||
what do you think about using `...` as assignment target?
```py
... = f()
begin, ..., end = s.partition(sep)
for ... in range(n):
do()
Wait can you do that? I thought variables could not have special characters
has too much connotation of *_ due to numpy's usage
Huh - I like that idea. That would have been a better wildcard pattern than _ for the match statement, too
Your post has been removed. This isn't a job board. If you'd like to discuss career and how to conduct a job search, visit #career-advice
+1
very subtle advantage in the repl, no conflict with _ that is implicitly assigned the most recent value
The conflict with _ for the most recent value does regularly annoy me in IPython. I'll write a, _ = b() and then suddenly I can't use _ anymore to get the most recent value
it also makes sense semantically, since ellipsis signifies a missing value.
more!
i think it can also be of speed up advantage, couldn't it?
imagine we iterate over range(100) like for ... in range(100).
the interpreter can know to not assign ... another element
otoh this a, ..., b can be a little unobvious at first glance. in math it is often semantically closer to a, *_, b
while a, ..., b in fact means a, _, b
consequently, those elements would never even get any new references
so if we iterate over a collection that produces new elements, those could be destroyed immediately in many simple cases... correct?
though not in case of structural unpacking.
for (..., ..., ...) in triples:
...
would require a temporary reference to every next element of triples in order to attempt to unpack it to (..., ..., ...)
but in case of ```py
for ... in whatever:
...
we'd never need any references to consecutive elements of `whatever`.
structural unpacking would introduce some interesting dynamics.
for instance the all-equivalent ```py
(*..., ..., ...)
(..., *..., ...)
(..., ..., *...)
i think it would as well be useful to allow ... as a target in signatures.
some functions have to take unused arguments for interface compatibility.
def foo(*..., **...):
print("passed arguments are accepted, but the function never uses the passed-in objects and thus never increases the refcounts of any of them")
wdyt about this @feral island?
cc @dusk comet @raven ridge
we'd also allow things like ```py
def foo(..., bar: int, ...) -> None:
pass
... would then not require a type annotation (inferred from parent methods or Any (i think object would be inconvenient for some variance-related cases)), and foo() could only be called with one positional argument at the beginning and at the end
this wouldn't support standalone keyword parameters though.
but there is no need for such
I like it
some advantages of ... assignment target:
- on bytecode level
STOREinstruction could be replaced withPOP, which in theory should be faster - it does not introduce local variable, which saves a bit of memory.
- earlier you drop the reference, earlier the value will be GCd, which should lower average memory usage in some cases
about def f(*...): not sure how often that pattern occurs
related: https://peps.python.org/pep-0640/
they suggested ? instead of ...
after more thinking, this is more complicated than i say
currently def f(_, bar, _): is an invalid syntax, we need to do def f(_1, bar, _2): or something like that
which makes the def f(..., bar, ...): more appealing
indeed
though ... would probably be only useful if "parents" for args were strictly positional
imagine ```py
class Parent:
def foo(self, arg, arg2, arg3):
...
class Base(Parent):
# imagine arg in foo() as unused here.
# can't use ... for arg, because it is both positional and keyword
def foo(self, arg, arg2, arg3): # :/
...
def foo(self, arg..., arg2, arg2): 🥴
this resembles syntax for variadic args in other languages
btw type stubs use ... as a default value for arguments
like C++ etc.
though it is not the best practice, i think
that's the reason why https://github.com/jellezijlstra/stubdefaulter was created
and applied to all over typeshed
specifically for "any number of arguments"
Callable[..., T]
i believe we're not talking about the gradual form used for Callable
well then let's do that
but for RHS values of defaults in signatures, e.g. foo: int = ..., bar: int = ...
right ye
so @dusk comet didn't mean ... in Callable, but ... in default values of params in signatures.
def foo(n: int = ...) -> int: ... # n has some default value, we don't specify it here
SomeCallableType = Callable[..., int] # accepts any args, returns int
so there are actually two places in typing where ... is used
also variadic tuples
i like it, but my biggest concern would be:
... = 42
print(...) # Ellipsis?!
these two ...'s look similar but do different things:
(a, ..., b) = foo # throw away the middle item
p[a, ..., b] = foo # numpy stuff, idk
I mean, the same could be said about _ ```py
for _ in range(3):
match (420, 69):
case (x, _):
print((x, _))
can anyone help me with the choice makin one code
Ask in #python-discussion please!
k thnks
something I've thought for a while would be nice to have is a context manager that force-exits the context after a specified amount of time. is that something that would become possible without the GIL?
i'm not too familiar with async python but it would seem that the context body would have to periodically ping and see if time is up? or otherwise define some cleanup procedure that could work after any intermediate instruction of the body
but i guess that would be up to the user
:incoming_envelope: :ok_hand: applied timeout to @balmy birch until <t:1737481087:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
This is the anyio.CancelScope
Also worked in https://github.com/dabeaz/thredo
Not having the GIL isn't relevant
even for non-async?
Yeah, see thredo it just works even with the GIL
Perhaps a similar idea using interpreterpoolexecutors would be viable. The premise of thredo seems scary 😂
You couldn't cancel the body of a context manager with an interpreter pool
You have to be able to pickle the function you want to execute, you can't just send a particular block of code
couldn't you send a SIGINT and hope that the interpreter notices a KeyboardInterrupt sooner rather than later?
Works only on the main thread
The keyboard interrupt handler could see the frame it gets raised in to see if it should raise an exception
You'd probably use sigalrm
A quick sanity check before I make an ill-informed discourse post... Is it generally true that resetting the state of an iterator in the __iter__ method like this is wrong and should never be done in Python code? ```py
class MyRange:
def init(self, start, stop):
self.start = self.n = start
self.stop = stop
def __iter__(self):
self.n = self.start
return self
def __next__(self):
if self.n >= self.stop:
raise StopIteration
self.n += 1
return self.n - 1
``` (because it makes it impossible to pass this iterator where an iterable is expected, including for loops, making it pretty much useless)
I'm not sure if it's wrong
Don't for loops only call __iter__ once?
The way it's wrong is if you advance it a bit before the for loop
Well it's not wrong you're just rewinding it in some circumstances
Should a iterator do that tho? Let me check if docs say anything on this
the docs don't say anything about this
A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.
For example, consider this itertools recipe (from 3.11 docs): py def batched(iterable, n): "Batch data into tuples of length n. The last batch may be shorter." # batched('ABCDEFG', 3) --> ABC DEF G if n < 1: raise ValueError('n must be at least one') it = iter(iterable) while batch := tuple(islice(it, n)): yield batch It doesn't seem to have any unusual preconditions. If it is MyRange, this is going to yield completely wrong results, as islice will reset the iterator on each call.
hm... that just seems like a note of caution to users of iterators, not an explicit requirement (even if advisory) for iterators
maybe I'm reading it wrong though
@grave jolt
Once an iterator’s next() method raises StopIteration, it must continue to do so on subsequent calls. Implementations that do not obey this property are deemed broken.
Actually, maybe that works. Interesting.
Tho that is specifically talking about the stdlib afaik
But it's a very strong argument for why you shouldn't do it
That doesn't prohibit resetting the state on an infinite iterator, but that's a less frequent occurrence anyway
(imo the easiest way to implement __iter__ on a collection without having to define a extra class is to just make it a generator)
The motivation for the question is: I've seen several low-quality pages (ex. 1, ex. 2, ex. 3, ex. 4) suggest that an __iter__ of an iterator can or even must reset/initialize its state.
I mostly wanted some piece of docs to easily show that no, this is not how Python iterators are normally supposed to work
Yhe the closest I have found is that a iterator that raised stop iteration can't be reset
well, this example iterator from geeks4geeks doesn't violate that rule ```py
class EvenNumbers:
def iter(self):
self.n = 2 # Start from the first even number
return self
def __next__(self):
x = self.n
self.n += 2 # Increment by 2 to get the next even number
return x
Right, __iter__ does say
Return the iterator object itself.
But unfortunately doesn't explicit rule out side effects
Correctness aside, I like how this code example straight up ignores the steps for making an iterator class just above it
Argh, a lot of places just state "... can just return self" implying it could do more
@grave jolt there's also this in the FP section of the docs
Note that you can only go forward in an iterator; there’s no way to get the previous element, reset the iterator, or make a copy of it
That last one is very arguably false tho
Pretty sure asyncgenerator.aclose is broken per this definition
Yhe, I'm pretty sure that definitions scope is limited to the built-ins
asyncgenerator is built in
...Iterator objects can optionally provide these additional capabilities,
I seemingly can't read
But I guess that's a strong contender for it being allowed as well
that doesn't mean that it's appropriate in __iter__ though
For example, you can .seek() on a file object
True, honestly I can't find anything that explicitly says it's bad
So are file objects
with open("thing.txt", encoding="utf-8") as file:
print(next(file), next(file), next(file)) # foo bar baz
try:
next(file)
except StopIteration:
print("Yep, no more lines")
# Yep, no more lines
file.seek(0)
print(next(file)) # foo
# oh no!
Hmm, time to open GitHub issue? /hj
insert link to the /hj video
I suppose the definition might mean "... it must continue to do so on subsequent calls. assuming no other methods are called on the object"
Or something along those lines
other methods, like __iter__? 🙂
I suppose yhe
Huh list iterator actually obeys it, it will happily iterate new elements assuming it wasn't exhausted
!e ```py
x = [1,2]
y = iter(x)
for _ in y: pass
x.append(10)
for e in y: print(e)
:warning: Your 3.12 eval job has completed with return code 0.
[No output]
!e ```py
x = [1,2]
y = iter(x)
next(y)
next(y)
x.append(10)
for e in y: print(e)
:white_check_mark: Your 3.12 eval job has completed with return code 0.
10
This doesn't break the rule, because the iterator had never produced a StopIterator exception before you added the 10
Exactly, "actually obeys it"
Kinda surprised it likely has a flag for it or something
Honestly I think the strongest argument for resetting in iter being wrong is that it breaks the itertools examples
Unrelated but... array.array has no clear method?
!e
from array import array
xs = array("i", [420, 69])
xs.clear()
:x: Your 3.12 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "/home/main.py", line 3, in <module>
003 | xs.clear()
004 | ^^^^^^^^
005 | AttributeError: 'array.array' object has no attribute 'clear'
Huh
smh lies in the typeshed
!e 3.13
from array import array
xs = array("i", [420, 69])
xs.clear()
:warning: Your 3.13 eval job has completed with return code 0.
[No output]
It was added in 3.13
ah
Smh should have looked at the docs
was that one of the things we added because otherwise array was lying about being a MutableSequence?
I mean, it kinda makes sense to have clear, since lists also have it
yep ```$ python3.12
Python 3.12.3 (main, Jan 16 2025, 20:46:45) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
import collections.abc, array
issubclass(array.array, collections.abc.MutableSequence)
True
collections.abc.MutableSequence.clear
<function MutableSequence.clear at 0x1045abba0>
array.array.clear
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'array.array' has no attribute 'clear'```
Btw Jelle, what do you think about the whole reset-in-__iter__ situation?
#internals-and-peps message
#internals-and-peps message
don't do it
that's essentially my problem... I wouldn't do that, but I don't know if there's a place in the docs saying that I shouldn't
related https://github.com/python/cpython/issues/128161, which has some discussion about documented semantics
Ah got to love a classic example of "we told you not to do that, but didn't stop you from doing it, and now stuff is broken because you did it"
I guess the docs say iterator.__self__ should return self but not that you shouldn't do other random stuff in it
(also that issue name should likely be updated, as defining iterators in separate classes work, defining them wrongly doesn't, "omitting __iter__ in iterators is not optional for for loops in 3.13", or similar)
I understand that my questions may sound stupid, because there are uncountably many wrong things you can do
but for some reason this particular wrong thing comes up on the first two pages when I search for "python iterators"
Whoa. Is this where the PEP magic happens for Python 
nope
disappointment
@feral island would you like to join the discussion? https://discuss.python.org/t/new-function-repr-args-in-pprint-or-reprlib/65193/20 :D
(everybody is invited)
hello guys, i’m a college student who really sucks at python and i just need like a tutor or something. i try to study on my own but i dont really know how. im currently in Advanced Python Application Class but i dont remember a lot from Python Scripting Class, please help
Could you ask in #python-discussion ? This is the wrong channel.
:incoming_envelope: :ok_hand: applied timeout to @split herald until <t:1737651694:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
This is very cool https://github.com/python/cpython/pull/124640
This PR introduces low overhead utils to enable async stack reconstruction for running and suspended tasks and futures. The runtime overhead this PR adds is making tasks set & reset a refer...
The coolest bit is f_generator
I want to deepen in python memory management.
def generate_data(start, end):
return list(range(start, end))
def get_data(count=1):
result = list()
start = 1_000_000
end = 2_000_000
for counter in range(count):
result += generate_data(start+counter, end+counter)
del result
return
get_data(count=1)
get_data(count=10)
get_data(count=10)
get_data(count=10)
gc.collect()
for example, when I run this code on my machine and track the Python process, memory usage goes up from 10MB to 27MB
But if I run the same code with end = 10_000_000, the memory usage stage on 10MB, can anybody explain this behavior?
The second test.
def generate_data(start, end):
return list(range(start, end))
def get_data(count=1):
result = list()
start = 1_000_000
end = 10_000_000
for counter in range(count):
result += generate_data(start+counter, end+counter)
del result
return
get_data(count=1)
get_data(count=10)
get_data(count=10)
get_data(count=10)
gc.collect()
!rules 6 9
6. Do not post unapproved advertising.
9. Do not offer or ask for paid work of any kind.
how are you measuring memory usage?
By top or other system monitoring apps.
Try with https://github.com/bloomberg/memray
But the value that k8s used to decide to restart the pod is based on the process allocated memory, the same value as top showed
k8s will decide to restart the pod based on the maximum amount of memory that it ever uses, and top is showing you only the current memory usage as of some point in time. If you want to know the maximum memory that the process used, you should print resource.getrusage(resource.RUSAGE_SELF).ru_maxrss after your gc.collect call
memray’s documentation has a great page about the python memory allocator
:incoming_envelope: :ok_hand: applied timeout to @velvet echo until <t:1737814454:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
In [1]: if 1 + 2 == 4:
...: pass
...: else:
...: pass
...: elif 1 + 2 == 3:
...: pass
Cell In[1], line 5
elif 1 + 2 == 3:
^
SyntaxError: invalid syntax
If I wanted to make this error message more informative, where in the cpython code base should I be looking?
looks like it's here https://github.com/python/cpython/blob/3f2cfd0462e13368092a3edccdb2ebb5e57459f9/Grammar/python.gram
(knowing nothing about this code): Perhaps you could add an "outofplace_elif_statement after the else_block in 370, something like: py elif_outofplace_stmt[stmt_ty]: | outofplace_elif_statement then define invalid_outofplace_elif_statement like the other invalid...stmts
I'm already recompiling cpython in a container
||because windows was being a pain||
... more gross gcc output above
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/home/python.exe', '-W', 'ignore::DeprecationWarning', '-c', '\nimport runpy\nimport sys\nsys.path = [\'/tmp/tmpikvdd___/pip-24.3.1-py3-none-any.whl\'] + sys.path\nsys.argv[1:] = [\'install\', \'--no-cache-dir\', \'--no-index\', \'--find-links\', \'/tmp/tmpikvdd___\', \'--root\', \'/\', \'--upgrade\', \'pip\']\nrunpy.run_module("pip", run_name="__main__", alter_sys=True)\n']' returned non-zero exit status 1.
make: *** [Makefile:2330: install] Error 1
root@3f02464a54a4:/home# which python3
/usr/local/bin/python3
root@3f02464a54a4:/home# python3
Python 3.14.0a4+ (main, Jan 26 2025, 00:49:54) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
warning: can't use pyrepl: No module named 'msvcrt'
>>> if True: pass
... else: pass
... elif False: pass
File "<stdin>", line 3
elif False: pass
^^^^
SyntaxError: elif not allowed after else
let's goooooooooooooooooo
there was another error message I wanted to change, but I forgot which one
Looks like my solution causes a different syntax error to cause the wrong message
if something:
pass
elif something_else:
pass
else:
pass
this doesn't give the correct message for the indentation error.
Is there a way to force a thread never to give up the GIL (until I tell it to)?
i did something related to this once
python/cpython#29513 python/cpython#119974
python/cpython#119724
TL;DR that is kind of unadvisable (for now)
it's easier to teach that "elif follows if and comes before else" (and it also comes as common sense) than add complexity to have a special error for it
but i guess it's useful when the blocks get too big
!d sys.setswitchinterval
sys.setswitchinterval(interval)```
Set the interpreter’s thread switch interval (in seconds). This floating-point value determines the ideal duration of the “timeslices” allocated to concurrently running Python threads. Please note that the actual value can be higher, especially if long-running internal functions or methods are used. Also, which thread becomes scheduled at the end of the interval is the operating system’s decision. The interpreter doesn’t have its own scheduler.
Added in version 3.2.
But aren't there some things that will implicitly switch anyway? Like writing to a socket or sleeping?
i thought that would fall under the category of “until I tell it to”
@feral island do you think it's worth putting in a PR with this? it passes all the unit tests.
In general, no
probably, seems like a good case for a custom error
The special case where it would be possible is when you write a C extension module, and create a block of code that never explicitly releases the GIL, and never calls anything that implicitly releases the GIL, and never calls into any Python bytecode (including by creating objects with a __init__ written in Python, or destroying objects with a __del__ written in Python). Note that this implies that it cannot allow the GC to run. And even this won't work in a free threaded build of the interpreter, of course
I know your specially is typing. Do you know if it's possible to have a different error message depending on the level of indentation? This line suggests that there's awareness of indentation level, but I'm not sure what to make of it. https://github.com/python/cpython/blob/b543b32eff78ce214e68e8c5fc15a8c843fa8dec/Grammar/python.gram#L1184
Grammar/python.gram line 1184
_PyPegen_check_legacy_stmt(p, a) ? NULL : p->tokens[p->mark-1]->level == 0 ? NULL :```
shouldn't your answer be that your error case should match elif at the right indentation level but after else in exactly the same way as the grammar normally matches elif at the right indentation level but before else?
That's how it currently works. But it would be even better if it knew that the invalid post-else-elif was within an if block somewhere higher up, so that it could suggest to the user that the elif is at the wrong indentation level (ie, that it belongs at the same level as the higher if)
ah, I see... I think you'd need to add state to the parser to handle that (not just whether the line is indented, but whether the thing it's inside of is an if or else or elif block)
e.g. you wouldn't want to suggest that the elif is at the wrong indentation level for ```py
for i in range(10):
if i % 3 == 0:
print("divisible by 3")
else:
print("not divisible by 3")
elif i % 2 == 0:
print("divisible by 2")
Exactly
And you already know that the parser isn't stateful enough for that?
Hello @exotic star . This is the wrong channel. Please read #❓|how-to-get-help
sorry
:incoming_envelope: :ok_hand: applied timeout to @worn atlas until <t:1737913350:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
I don't know. I'd be surprised, but I'm not very familiar with the parser
actually, you'd need to know specifically that that there's an if or elif block above at a lower indentation level, but not an else
since you wouldn't want to make that suggestion for this, either: ```py
if done:
print("exiting")
else:
if i % 3 == 0:
print("divisible by 3")
else:
print("not divisible by 3")
elif i % 2 == 0:
print("divisible by 2")
I don't think there's any chance that the parser already has that state, that's very specific
Right, I mean within Python code. What I was planning was already pretty cursed; it's probably for the better.
it'd also just break in ~3 years when we have a Python without a GIL
it's easy on FT if you're willing to use the private API
marking the interpreter as finalizing will prevent threads from attaching a thread state, and you can force all threads to detach with a stop-the-world
wait, wouldn't that also cause daemon threads to exit when they try to attach a thread state?
i think that would only be if the runtime was finalizing, not if the interpreter was
even for the main interpreter?
I didn't realize that the main interpreter being finalized and the runtime being finalized were two distinct states
Normally those two things happen in tandem
it's a gray area IIUC
sometimes it falls back to the main interpreter even if the runtime says it's not being finalized
but in general special-casing the main interpreter for anything is bad
is there anything in the stdlib that implements collecting errors of consecutive calls into an exception group?
like in https://github.com/bswck/autohelper/blob/e7a563ac0e20c7e62edccfb31162866a6ef9ef95/autohelper/framework/features.py#L121-L129
if not (i assume there's nothing like that), what about adding this sort of functionality to map()/starmap()?
autohelper/framework/features.py lines 121 to 129
exceptions = []
for hook in hooks:
try:
hook()
except Exception as exc: # noqa: BLE001
exceptions.append(exc)
if exceptions:
msg = "Error calling configuration hooks"
raise ExceptionGroup(msg, exceptions)```
Remember to also delete the exceptions list
EG is mainly for concurrent calls
it doesn't have to be, i want to not fail early
I think it's uncommon enough that it shouldn't be in the stdlib
ok, that would be an argument
It would encourage people to use it instead of comprehensions which fail early
Running everything and failing if any is also quite tricky to name
makes sense. this functionality could be part of a third-party package
something like jaraco.functools could fit
Omg the jaraco package
been helping to get it typed
need to reiterate on that though, i think
oh wow jaraco/jaraco.functools#23
quite some time passed since. maybe one day i'll get back to it
now i see a subtle mistake there
- hold strong references to instances we store IDs of, because once they are no longer strongly referenced by any object, those IDs may point to something else.
this assumes objects with no strong references to them are immediately freed
but otherwise it's ig mostly valid
this gave me an idea for cpython4
There are going to be four different interpreters in CPython. Wow, I haven't kept up with the recent cevel changes. https://github.com/python/cpython/issues/128563
The first two are actually variations of each other and differ solely in dispatch methods and have been around since 2009. The third is solely used for debugging and was introduced in 2023-2024. The fourth one is a pretty large shift in how interpreters are done in CPython.
:incoming_envelope: :ok_hand: applied timeout to @young axle until <t:1738434001:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
s
Hi
Hello
#python-discussion is the general Python discussion chat.
:incoming_envelope: :ok_hand: applied timeout to @whole badge until <t:1738532982:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
can i have full code pls i wanna look at it
The full code of what? I don't understand what you're asking for
In [3]: def func(*args, **kwargs):
...: print(args, kwargs)
...:
In [4]: class foo(func): pass
# nothing is printed
TypeError: function() argument 'code' must be code, not str
I'm not sure what to make of this.
https://docs.python.org/3/reference/datamodel.html#metaclasses
By default, classes are constructed using type(). The class body is executed in a new namespace and the class name is bound locally to the result of type(name, bases, namespace)
Iffuncwas a type, likeCat, this would do: ```py
class Foo(Cat):
bar = 42
m = type(Cat)
Foo = m("Foo", (Cat,), {"bar": 42})
``` the same thing happens in your case, except m happens to not be a metaclass at runtime
!e
Example:
class Foo(slice(0)):
pass
print(Foo.start)
print(Foo.stop)
print(Foo.step)
:white_check_mark: Your 3.12 eval job has completed with return code 0.
001 | Foo
002 | (slice(None, 0, None),)
003 | {'__module__': '__main__', '__qualname__': 'Foo'}
(well, I omitted some elements from the namespace dict)
this is the best thing i've read today, thank you @grave jolt
Damn
it is of my opinion that this is appropriate
while i did not like the pep, @wanton flame, i nonetheless hope that its rejection does not bring you too much unhappiness. my feelings were not personal, and i know you were trying to make things easier for others, including newbies
I think i probably told this story somewhere here before... At PyCon last year, Guido and Hugo were talking about the calver proposal. Guido said, "Why start with 3.15, why not do it for the next release?" Hugo said, "well, there's a lot of tooling to update, and people have to get used to it, etc." Guido said, "That doesn't seem like it would take so much time." Hugo: "We also don't want to skip 3.14 (pi)". Guido: "Why didn't you just say so!"
Hah, I do love that this is a language where that whim would be taken seriously!
Sure thing, thank you! I'm fine with it 🙂
I enshrined that in the rejected ideas 😅
Change during 3.14 cycle
The Python 3.14 release must go ahead because: π.
why when i try to run a script it auto closes???
function type subscription like we do for classes?
class A[T]:
...
x = A[int]()
def oper[T](...):
...
t = oper[str]()
I want to learn php, do you have any suggestions?
!off topic. I'd recommend the Django girls tutorial which will teach you enough to build a software project then transferring those skills to php
There are three off-topic channels:
The channel names change every night at midnight UTC and are often fun meta references to jokes or conversations that happened on the server.
See our off-topic etiquette page for more guidance on how the channels should be used.
:incoming_envelope: :ok_hand: applied timeout to @mental bloom until <t:1738938457:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
can anyone confirm whether this is accurate? https://github.com/python/cpython/issues/82616#issuecomment-2642033035
ah you'll want to see what trio does
for the does not block from IO part
thanks I'll check that out now! also just asked on the forum https://discuss.python.org/t/proper-way-to-create-a-daemon-process/79824
Shameless self-advertising 🙂 https://docs.python.org/3.14/whatsnew/3.14.html#whatsnew314-tail-call
what's the difference between "a new type of interpreter" and "an alternative implementation of python"?
Good question. The specific parts of the interpreter we modified were the representation of each bytecode. It's still the same old CPython we all know and love 🙂
Is the goal to make it the default or even remove the current default once it works on GCC, after a while?
2 years or so from now, we'll probably autodetect it on compilers that support it in our build processes. So we turn it on for newer compilers, but keep the old interpreter for older compilers.
I like the note: This is not to be confused with tail call optimization of Python functions, which is currently not implemented in CPython.
The wording is more hopeful than previous attempts to do tco
I don't think I meant to be optimistic about TCO in Python. But you never know. If the JIT optimizer goes well, we might even get TCO even with working tracebacks. That's super super far out though.
What's the difference between PTC and TCO? I think one's the what and the other is the way?
My understanding is PTC is a language feature, TCO is a "compiler optimization".
PTC is no visible stack frames in this case and no expansion of memory for recursion/co-recursion. And TCO is the conversion of code into branch/jumps?
Hmm not sure
what is PTC short for?
Proper Tail Call
I think @kenjin has it right: PTC is a language guarantee, and TCO is a technique to achieve PTC, or to use even if the language doesn't guarantee it.
You can get PTC without TCO right?
I'm not a fan of "Proper" as a way to describe something, seems needlessly judgmental
i don't see how you can, but I'm no expert.
I thought TCO was replacing stack operations with jumps and branches
seems like PTC is "we guarantee a tail call won't grow the stack" and TCO is "a tail call might not grow the stack"
like every other word about programming languages, I bet there is not consensus about the precise definition.
I also thought that PTC results in recursive functions that are slower than loops but don't grow the stack
And TCO was that plus recursive functions were just as efficient as the iterative version
¯_(ツ)_/¯
As defined by the scheme report, PTC means every tail call is guaranteed to not grow the stack, regardless of what procedure is called. TCO is an optimalization technique where the stack growth may be omitted.
so basically what you said
I vote for including something like -this- in the note, if this is what this feature does. I had no idea what #internals-and-peps message meant until now.
Oh. Then I still don't.
it is a novel way to implement interpreter loops in C that is better than while(true) switch(opcode)
https://blog.reverberate.org/2021/04/21/musttail-efficient-interpreters.html this article is the best explanation I've found.
the What's New should include something like, "This is an implementation detail of the CPython interpreter. It doesn't change the visible behavior of Python programs at all. It improves their performance, but doesn't change anything else."
Hmm I thought the existing note at the bottom was sufficient to imply that, but I guess not. Could you open a PR please and I'll happily approve it? These things are hard to explain.
(or anyone here can open a PR too if they want)
This is not to be confused with tail call optimization of Python functions, which is currently not implemented in CPython.
That's not exactly true these days. Tail calls of Python functions now grow the Python stack, but don't grow the C stack
Elsewhere I saw someone misunderstand the What's New, despite the note.
!e ```py
import sys
sys.setrecursionlimit(2**31 - 1)
def f(n):
if n:
return f(n-1)
f(100_000)
:warning: Your 3.12 eval job has completed with return code 0.
[No output]
is that changed by this? https://docs.python.org/3.14/whatsnew/3.14.html#a-new-type-of-interpreter
The requirement to be called tail calls is O(1) space. The fact we still use the Python stack means it's not tail calls.
Nope. Yeah the wording is confusing to non-expert users. Thanks for pointing that out!
no
Though you're also right that in 3.11, we made it much easier to implement tail calls if we wanted in Python.
fair enough. Well, tail recursive Python functions are no longer able to cause a stack overflow even if you screw with sys.setrecursionlimit(), and haven't been able to for a few years now - since 3.11 I think
@round path https://github.com/python/cpython/pull/129863
📚 Documentation preview 📚: https://cpython-previews--129863.org.readthedocs.build/
Thank you. Left a comment.
Also: I think it'd help to reference the GitHub issue rather than the PR.
(The issue and lak's link #internals-and-peps message got me over the confusion)
I agree on that, but I think the CPython convention in whats new entries is to point to PR sadly, not the issue.
Oh. The notes do reference other issues rather than PR's. 66436 for instance.
Speaking of map... Is it documented anywhere that map will also stop producing items if the given function raises a StopIteration exception?
or is that something that you're supposed to have guessed
!e
def f(x):
if x == 5:
raise StopIteration
else:
return x + 10
print(list(map(f, [3, 4, 5, 6, 7])))
:white_check_mark: Your 3.12 eval job has completed with return code 0.
[13, 14]
same with filter and other functions, actually
!e
def f(x):
if x == 5:
raise StopIteration
else:
return x + 10
x = map(f, [3, 4, 5, 6, 7])
print(list(x))
print(list(x))
:white_check_mark: Your 3.12 eval job has completed with return code 0.
001 | [13, 14]
002 | [16, 17]
It doesn't stop, it just lets the exception propagate which causes the caller to assume it stopped
I guess that explanation works, but it feels like a footgun to swallow an exception like that. It's probably not an intentional control flow thing when this function raises StopIteration. For example, it could stem from the thing = next(x for x if condition) idiom raising StopIteration somewhere deep inside f.
!e
For example, if a generator function raises StopIteration, it's transformed to a RuntimeError and not "propagated"
def my_genf():
yield 1
yield 2
raise StopIteration
print(list(my_genf()))
:x: Your 3.12 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "/home/main.py", line 4, in my_genf
003 | raise StopIteration
004 | StopIteration
005 |
006 | The above exception was the direct cause of the following exception:
007 |
008 | Traceback (most recent call last):
009 | File "/home/main.py", line 6, in <module>
010 | print(list(my_genf()))
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/N6NRRA5FLKSXZN5W64YJYVHQEM
!e
In fact, if you try to implement map yourself:
def f(x):
if x == 5:
raise StopIteration
else:
return x + 10
def my_map(f, it):
for x in it:
yield f(x)
print(list(my_map(f, [1, 2, 3, 4, 5, 6, 7])))
:x: Your 3.12 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "/home/main.py", line 9, in my_map
003 | yield f(x)
004 | ^^^^
005 | File "/home/main.py", line 3, in f
006 | raise StopIteration
007 | StopIteration
008 |
009 | The above exception was the direct cause of the following exception:
010 |
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/F77X5XNZSXN5Z55N7OUVJO36BA
Using a generator sure, but if you did it using a class, you would likely end up with the same behavior as map unless you explicitly catch it
Of course, that's probably the explanation of how map came to be like this
but from the perspective of the user of map, that's probably not the most obvious behaviour
(if you're trying to debug why map is not producing the right amount of items)
:incoming_envelope: :ok_hand: applied timeout to @warm ember until <t:1739065414:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
This question got me curious: #1337961771121770507 message
how is the pycharm debugger able to see and change interpreter state?
i would've assumed it only applied to the iterable
and the applying function's StopIteration would be turned into a RuntimeError
that seems potentially worth fixing
you mean, documenting it? or changing the behaviour?
because maybe that's intended
(and there's probably someone depending on this)
I can see how it happens but it's not really great behavior
yeah BC probably means we can't change it
we did change it for generators but that went through a __future__
not sure what all the debugger can do, but there's various introspection APIs, and with ctypes (or with running C code) you can do whatever you want
If we step back, I think the underlying problem is that StopIteration is used by the __next__ method to signal exhaustion, and in next to signal the the thing you're nexting is exhausted.
We could have StopIteration be used as part of __next__'s interface, and have next raise its own IterationStopped. Kinda like __eq__ can return NotImplemented, but a == b provides a more sensible interface. That would eliminate all the footguns where you accidentally signal that your iteration is over when you didn't mean to
(of course, that is just hypothetical thinking, there's no way that's changing, that's a huge break)
Btw, here's another consequence of this behaviour ```py
In [2]: def f(x):
...: if x == 3: raise StopIteration
...: return x + 10
...:
In [3]: m = map(f, [1, 2, 3, 4, 5])
In [4]: list(m)
Out[4]: [11, 12]
In [5]: next(m)
Out[5]: 14
> Once an iterator’s `__next__()` method raises `StopIteration`, it must continue to do so on subsequent calls. Implementations that do not obey this property **are deemed broken**.
Though... the file iterator is also broken in this way. You can exhaust the file iterator, then call `seek(0)` and now it's not exhausted anymore. So not sure if this property is really _required_ required
This is where this happens for what it's worth: https://github.com/python/cpython/blob/f72977b2f4a29063ae3019e50360f4af869f4149/Python/bltinmodule.c#L1487 . It just returns whatever the func() returns, so if it returns NULL (raises an error) then that error gets propagated as is.
Python/bltinmodule.c line 1487
result = _PyObject_VectorcallTstate(tstate, lz->func, stack, nargs, NULL);```
yep
Arguably it's your f() that's broken, not map().
Though I guess f() is not an iterator.
Yeah, the object map(f, [1, 2, 3, 4, 5]) is a BrokenIterator, which doesn't necessarily mean that the map class has an implementation bug. Maybe it's just a documentation bug (i.e.: f not raising StopIteration is a precondition of map?)
This is also how I learned about map(strict=True). New in 3.14.
Yes, possibly a documentation bug. Currently map's documentation is very concise though (https://docs.python.org/3.14/library/functions.html#map); mentioning this arcane issue would probably feel disproportionate
And confuse more people than it helps
I wonder if there's any way to grep for open-source code that relies on this behaviour
realistically the only place StopIteration would come up is calling next and doing raise StopIteration (outside of a __next__), maybe I could look into that
Yeah I guess you'd want to look for map/filter calls where the function calls next(). Though of course it could be multiple levels down the callstack
Wonder if this works with listcomps
a genexpr should perform the StopIteration->RuntimeError conversion
!e
def nasty(x):
if x == 3: raise StopIteration
list(nasty(y) for y in [2, 3, 4, 5])
:x: Your 3.12 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "/home/main.py", line 4, in <genexpr>
003 | list(nasty(y) for y in [2, 3, 4, 5])
004 | ^^^^^^^^
005 | File "/home/main.py", line 2, in nasty
006 | if x == 3: raise StopIteration
007 | ^^^^^^^^^^^^^^^^^^^
008 | StopIteration
009 |
010 | The above exception was the direct cause of the following exception:
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/JLVL6AKTGL5H26SQCR4BRBDNZI
yep
this could be used for implementing more_itertools.split_at()
I wonder if there's a combination of https://grep.app and astgrep
It could quite easily be made such that send wraps in a special RuntimeError subclass caused by StopIteraton
Then have yield from unwrap the cause of this special RuntimeError
TIL about grep.app, thanks
:incoming_envelope: :ok_hand: applied timeout to @signal monolith until <t:1739128110:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
is there an easier way to generate cleanup code for going from one point to another in the bytecode in codegen.c
for example ```py
for x in A:
for y in B:
from here
go here
``` when going from line 3 to line 5, it exits 2 loops which needs 2 sets of END_FOR and POP_ITER
ask in #python-discussion or #❓|how-to-get-help
alr
I guess I should ask here: anyone got any tricky ideas how to determine if an AST expression node will compile to a compile-time constant?
Taking into account the AST optimizer?
taking into account all optimizations
I think Irit has been working on exposing the AST optimizer, so maybe it's now possible to do it directly
I think otherwise you have to exactly replicate the logic of the AST optimizer
eventually: i need to support 3.9
Mostly binary operations with constants operands are folded, but not always
do you know an example that isn't?
I think if it throws an error, or results in an overly big constant
1 0 LOAD_CONST 0 (4)
2 RETURN_VALUE
>>> dis.dis("20 ** 20")
1 0 LOAD_CONST 0 (104857600000000000000000000)
2 RETURN_VALUE
>>> dis.dis("200 ** 200")
1 0 LOAD_CONST 0 (200)
2 LOAD_CONST 0 (200)
4 BINARY_POWER
6 RETURN_VALUE
(on 3.9)
Also if it throws an error
right.
>>> @dis.dis
... def f():
... if 9**9**2: print(1)
...
1 0 RESUME 0
3 2 LOAD_CONST 1 (9)
4 LOAD_CONST 2 (81)
6 BINARY_OP 8 (**)
10 POP_JUMP_IF_FALSE 12 (to 36)
12 LOAD_GLOBAL 1 (NULL + print)
22 LOAD_CONST 3 (1)
24 CALL 1
32 POP_TOP
34 RETURN_CONST 0 (None)
1 0 LOAD_CONST 0 (0.0)
2 RETURN_VALUE
>>> dis.dis("1/0")
1 0 LOAD_CONST 0 (1)
2 LOAD_CONST 1 (0)
4 BINARY_TRUE_DIVIDE
6 RETURN_VALUE
Tuples are also folded if they contain only constants, not sure if there's more complex conditions there too
1 0 LOAD_CONST 0 ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1))
2 RETURN_VALUE
>>> dis.dis("(1,) * 1000")
1 0 LOAD_CONST 0 ((1,))
2 LOAD_CONST 1 (1000)
4 BINARY_MULTIPLY
6 RETURN_VALUE
@feral island I'm trying to predict when branches will be optimized away, because sys.monitoring won't tell me about them if they are gone. sys.settrace will.
Unfortunately that reduces to the same problem. >>> dis.dis("if (1,) * 100: print('hi')\nelse: print('bye')") optimizes away the else. If you change it to *1000 it doesn't.
right
:incoming_envelope: :ok_hand: applied timeout to @wheat tulip until <t:1739150713:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
:incoming_envelope: :ok_hand: applied timeout to @unkempt rock until <t:1739216472:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
;
pyautogui
Who know use it ?
I dont know
And
I need help
Too
Big python project
!tvmute @zinc rain 7d You were told pretty clearly not to spam to meet the voice gate
:incoming_envelope: :ok_hand: applied voice mute to @zinc rain until <t:1739824714:f> (7 days).
bruh, u are following me
?
Why
I am mute ?
So, i am creating a big casino project
Respect the channel topics. This channel has a specific purposes
As I mentioned in pydis, use #❓|how-to-get-help a help thread to get help.
a repl PR awaiting reviews...
https://github.com/python/cpython/pull/129488
Hi
hello
Welcome... #python-discussion is the main channel for python topics!
This is off topic for this channel
Sorry, bt isn't it for python?
It's not acceptable to spam the same video in multiple channels, this is also an advanced python channel, not about learning python. Also your first 3 messages were the same spam in 3 channels, don't do that
Maybe you meant to post in #community-meta ?
Hello
We were previously talking about this.
that's my message, right?
i see
btw, since then I have added to coverage.py to solve the problem: https://github.com/nedbat/coveragepy/commit/3e87fab41c9532e2bf8e5a5ccf2b9c3570a55cf4
It occurs to me that a fully general solution for your problem could be to look at the PEP 657 information for each opcode and find AST nodes for which there's no corresponding bytecode instruction. Would probably be quite complex though and run into edge cases where bytecodes have strange associated ranges. Also, works only on 3.11+.
i'm fine with only handling the usual simple expressions. also i don't know where "the PEP 657 info for each opcode" is 😄
I think the co_positions method on the code object. But totally makes sense to keep it simple!
i have to think about what that could do for me.
romania ?
We only allow English. If you need help in Romanian, try one of the Romanian python user groups: https://wiki.python.org/moin/LocalUserGroups#Romania
some other core dev mind taking a look? 😅 https://github.com/python/cpython/pull/130071
:incoming_envelope: :ok_hand: applied timeout to @verbal bridge until <t:1739978410:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
The Python app is more busy on this channel than anything else
Compromised accounts for some reason spam messages in all four of the discussion channels, and the bot gets triggered on the 4th message - which happens in this channel the most often
Has anyone suggested automatically deleting the automatic "applied timeout" message when the user gets banned within a few minutes?
This sounds vaguely familiar...but maybe I am thinking of the help post messages
Could be a good idea, I'll raise it internally
Maybe could also make it a one liner message, less noisy.
If you want to talk about python go to #python-discussion otherwise go to #ot0-psvm’s-eternal-disapproval or one of the ot channels instead of spamming hello in every channel you come across.
I just ran into an interesting test case issue that looks like it should have been resolved, but probably hasn't been. In one of my tests there is mock_queue.assert_called_with(None, fw.process, valid_file), but it leads to the error:
E AssertionError: Expected 'mock' to be called once. Called 2 times.
E Calls: [call(None, <function process at 0x7685d67e3b00>, PosixPath('/tmp/pytest-of-skeledrew/pytest-9/test_watch_cdr_dir0/active.wav')),
E call(None, <function process at 0x7685d67e3b00>, PosixPath('/tmp/pytest-of-skeledrew/pytest-9/test_watch_cdr_dir0/valid.wav'))].
Eventually discovered (through looking at mock.py) that it's due to an ambiguity, which is addressed in a GH issue (https://github.com/python/cpython/issues/73097) as well as in the docs. Reason why I find this interesting though is because I generated this and a few other test cases with AI, and the "error" above is expected behavior. So I'm thinking:
- There is a substantial enough number of projects out there using that method with that particular expectation that it's significantly represented in training sets, leading to actual generation.
- Without checking the code and docs, it's likely that many users won't understand why their test is failing (especially if it was generated).
Maybe there could be some kind of warning in the implementation itself to alert users?
what's the situation with frame.f_locals these days? is it a reliable way to change locals from the outside? iirc there were some changes made regarding this in some version right?
Yeah, depends on the version. In 3.13+ you can write to it, before you need to call some internal function (PyFrame_LocalsToFast) to make your changes take effect.
!pep 667
Using del, or the pop() method, to remove keys that correspond to local variables on the underlying frame is NOT supported, and attempting to do so will raise ValueError.
This is a bit weird, I think. You can del local variables in functions.
i see, thanks
As I recall; there's a specific warning about -not- adding anything to the frames because it may work but is unsupported. I have a place where I had to do this, and am waiting for it to break.
Was the warning (documentation note, not warning) removed for 3.13? I'll find the reference, I thought it said not to add. Edited I guess I just needed to read the pep
But if you use del, it's statically visible. Letting users randomly delete variables anywhere in the function would defeat optimizations that use control flow analysis to determine when a variable is always defined
Here you can see that the first print(x) uses LOAD_FAST and the second uses LOAD_FAST_CHECK: ```>>> dis.dis("""
... def f1():
... x = 1
... print(x)
... def f2():
... x = 1
... if something: del x
... print(x)
... """)
0 RESUME 0
2 LOAD_CONST 0 (<code object f1 at 0x1051bfb40, file "<dis>", line 2>)
MAKE_FUNCTION
STORE_NAME 0 (f1)
5 LOAD_CONST 1 (<code object f2 at 0x105212230, file "<dis>", line 5>)
MAKE_FUNCTION
STORE_NAME 1 (f2)
RETURN_CONST 2 (None)
Disassembly of <code object f1 at 0x1051bfb40, file "<dis>", line 2>:
2 RESUME 0
3 LOAD_CONST 1 (1)
STORE_FAST 0 (x)
4 LOAD_GLOBAL 1 (print + NULL)
LOAD_FAST 0 (x)
CALL 1
POP_TOP
RETURN_CONST 0 (None)
Disassembly of <code object f2 at 0x105212230, file "<dis>", line 5>:
5 RESUME 0
6 LOAD_CONST 1 (1)
STORE_FAST 0 (x)
7 LOAD_GLOBAL 0 (something)
TO_BOOL
POP_JUMP_IF_FALSE 1 (to L1)
DELETE_FAST 0 (x)
8 L1: LOAD_GLOBAL 3 (print + NULL)
LOAD_FAST_CHECK 0 (x)
CALL 1
POP_TOP
RETURN_CONST 0 (None)
I see, thanks for the explanation!
It's a shame you can't del it from the dict and it just not apply to inside the function body
:incoming_envelope: :ok_hand: applied timeout to @lofty bridge until <t:1740851074:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
:incoming_envelope: :ok_hand: applied timeout to @cunning cove until <t:1740858644:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
are there any weird issues that could arise from having a non-string key in f_locals
definitely. i'm surprised it even works.
im aware that pep 667 guarantees consistency between locals() and f_locals, but is f_locals always consistent with itself?
it should be, but be aware that PEP 667 is only 3.13+. this won't work for 3.12 and lower, if you're worried about portability.
!ot
Please read our off-topic etiquette before participating in conversations.
ok
:incoming_envelope: :ok_hand: applied timeout to @finite arrow until <t:1741002104:f> (10 minutes) (reason: duplicates spam - sent 4 duplicate messages).
The <@&831776746206265384> have been alerted for review.
what would be some examples of issues that could come up with a nonstring key?
crashes, probably. i don’t think it’s something that’s tested for.
why do you want a non-string key anyway?
doing a bit of an experiment. needed to add extra info to specific frames to mark them for analysis later on, and adding something to f_locals seemed like the most straightforward to do that
using an non-string as the key was intended to pretty much eliminate the possibility of whatever was added to conflict with something already in f_locals or be removed. could just use a random string of course.
You should be able to use a string that's not a valid variable name
I'm not sure I understand the purpose of this channel. What is it about? 😅
python internals and features

