#internals-and-peps

1 messages · Page 36 of 1

raven ridge
#

!e ```py
class MyException(Exception):
def init(self, *args):
pass

print(MyException(1, 2, 3).args)

fallen slateBOT
raven ridge
#

though I doubt that behavior is guaranteed by the language. That code might behave differently on other Python implementations, or even future versions of CPython.

whole jewel
#

That would be bad if it does change

raven ridge
#

well, I'd be interested in a core dev's opinion on whether that's a language guarantee or an implementation detail 🙂

boreal umbra
#

If it's not part of the interface, it should have a dunder name, should it not?

icy bough
#

It could be part of the interface but whether it's set in __new__ or __init__ could be an implementation detail.

raven ridge
#

that, and also I think you mean sunder, not dunder. dunders are definitely part of the interface.

icy bough
#

And this is probably code that Guido wrote 30 years ago.

boreal umbra
raven ridge
#

that just means that new dunders may be added to future versions of the language, right?

boreal umbra
#

I thought they could still use used for non-public implementation details

raven ridge
#

I don't see why you'd choose to use a dunder for that instead of a sunder. dunders are specifically for protocols - the whole point of dunders is that something else is gonna call them

icy bough
#

If it's part of the language or the standard library it's going to be documented somewhere.

boreal umbra
#

I just thought cpython had unspecified dunders that were basically sunders but only for cpython itself shrug2

uncut quest
#

sunders aren't really a thing IMO. They're a convention for library code to say "this thing should be kinda dunder-like but doesn't actually have any special syntax support, it's just that we have to make the name special for some reason"
(for example, because it's supposed to be possible to attach "arbitrarily" named attributes, like with dataclasses and namedtuples and such)

#

and I feel like only the core dev team should really be defining semantics for dunders

whole jewel
#

Should i post this on discourse python website to get more reach and Attention of core devs? pithink ducky_concerned

Not meaning to spam or disturb core devs

clear hill
#

posting a question on discourse isn’t spamming

#

it’s be spamming if you ask and then re-ask though

feral island
#

as a core dev my opinion is that you don't need to be a core dev to have a good answer to these questions

feral island
whole jewel
#

Thanks Jelle & ngoldbaum! I will soon post on discourse.

clear hill
#

too bad adding stuff to the standard library breaks ecosystem packages

meager nacelle
#

I hadn't realised that adding colour to argparse had lead to argparse importing dataclasses and as such getting hit with the import penalty of dataclasses I'd otherwise been working hard to avoid.

#

I already have one work-around to prevent it from importing shutil unnecessarily to work out terminal width

tidal sorrel
#

what happens if I do token lookahead

#define LOOKAHEAD1(NAME, RES_TYPE)                                  \
    int                                                             \
    NAME (int positive, RES_TYPE (func)(Parser *), Parser *p)       \
    {                                                               \
        int mark = p->mark;                                         \
        void *res = func(p);                                        \
        p->mark = mark;                                             \
        return (res != NULL) == positive;                           \
    }
 
LOOKAHEAD1(_PyPegen_lookahead, void *)

until the tokenizer passes to a new line and updates tok->linestart. If I then request a token _PyPegen_fill_token, tok->line_start wont be restored.

tidal sorrel
#

Forget, LOOKAHEAD restores the position

#

can lookahead be chained?

quick snow
#

Hello @tidal token, I've deleted your message. I don't believe we can help you with it, doing it would be illegal if I understand it correctly. In addition, it's also off-topic for this channel.

tidal token
quick snow
meager nacelle
#

So I've been using it as an example in discussion on an @ syntax for Annotated (not in favour) but I was wondering if it's worth changing the __repr__ of ForwardRef for unions to show the type_repr of object names instead of showing the internal names.

boreal umbra
meager nacelle
#

It's just a discussion on dpo, not at pep stage

boreal umbra
#

do you have the link?

meager nacelle
#

But I'm talking about this

#
>>> from annotationlib import get_annotations, Format
>>> class Example:
...     a: ref | str
...     
>>> get_annotations(Example, format=Format.FORWARDREF)['a']
ForwardRef('ref | __annotationlib_name_1__', is_class=True, owner=<class '__main__.Example'>)
#

The names are needed internally, but I think it would be nicer to not show them to users. I've been experimenting with this in my reannotate library when given a ForwardRef as the source for a deferred annotation and I think we could do something similar for ForwardRef.

#
>>> from reannotate import DeferredAnnotation
>>> anno = get_annotations(Example, format=Format.FORWARDREF)['a']
>>> anno
ForwardRef('ref | __annotationlib_name_1__', is_class=True, owner=<class '__main__.Example'>)
>>> DeferredAnnotation(anno)
DeferredAnnotation('ref | str')
#

I was unsure if this would be considered a bug, but the names do also 'leak' for .evaluate(format=Format.STRING) so maybe?

feral island
quick snow
#

!clban 631391575674585089 some kind of scam

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied ban to @wind jolt permanently.

quick snow
#

!warn 1476993310399791145 stop spamming

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied warning to @verbal gate.

deep dirge
#

I don't see how that's related to Python internals?

boreal umbra
#

@sharp furnace I removed your message as it isn't related to the channel, but you can post it in #1468524576479641744 if it meets the requirements given in the pinned thread there.

meager nacelle
#

Huh, dataclasses has some special case handling for when it has no methods to generate, but it then still execs and calls an empty __create_fn__ method generating function.

feral island
meager nacelle
#

Well it works, but it's calling a function that returns an empty tuple and then does nothing with it because there are no names.

#

The use would be wanting dataclasses to do all of the internal stuff, but replacing all of the methods

feral island
#

what is the internal stuff? just creating the __dataclass_fields__ dict?

meager nacelle
#

also potentially slots

feral island
#

I guess it's at least an easy performance optimization, we should fix it on main

meager nacelle
#

It's somewhat related to the _colorize performance issue, I was investigating replacing all of the execed methods with regular dynamic ones. Outside of imports the module spends most of its time execing dataclass methods.

wooden summit
#

is it normal to have your repo name and source folder be the same?

feral island
feral island
#

Brandt did some experiments in the past to cache things more, but we didn't end up landing that

meager nacelle
#

Well this is more specific to _colorize. In this case the methods themselves would be slower and dynamic, but it doesn't matter much as they're not heavily used (or not used at all).

#

I have a classbuilder like dataclasses which instead generates the methods when used. You don't avoid the exec() penalty completely, but do for methods that you want to have but don't actually use.

#

(Like the __setattr__ and __delattr__ on frozen dataclasses, which in most cases should never get touched)

grave jolt
#

!compban 1483490818735210607

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied ban to @coral turtle until <t:1777064424:f> (4 days).

boreal umbra
#
In [48]: defaultdict[str, list[int]]
Out[48]: collections.defaultdict[str, list[int]]

In [51]: defaultdict[str, list[int]]()
Out[51]: defaultdict(None, {})

Is there any way this could be made smart enough that defaultdict[X, Y[Z]]() evaluates to defaultdict(Y, {})?
so that you don't have to do defaultdict[X, Y[Z]](Y)

feral island
#

this is not advisable

quick snow
#

I think Stel is asking if this could be added to the language/collections

boreal umbra
feral island
meager nacelle
#

I'm not sure it generalises. Also it would make more sense to me for it to evaluate to defaultdict(list[int], {}) if it did.

light void
#

Guess the first code every python developer should know
Print("hello, world")

boreal umbra
feral island
#

Possibly something like this could be made to work, but it would require parsing type annotations in C

grave jolt
#

it would also be a breaking change

meager nacelle
#

You could subclass defaultdict and define __class_getitem__ to implement it on that subclass.

grave jolt
#

it would be cool to be able to write defaultdict[str, _](list[int]) similar ot Rust

#

where _ is deduced automatically, but str cannot be deduced automatically

meager nacelle
#

I feel like that would be more confusing in the python context given how these things 'normally' work.

halcyon trail
#

better yet, avoid defaultdict entirely and use dict.setdefault as needed 😛

feral island
#

no better way to get quicknir to show up than to talk about defaultdict 😛

halcyon trail
#

maybe I should learn how to write a discord bot and automate myself 😂

grave jolt
#

!warn @shrewd terrace you need to stop advertising your AI-generated AI learning website.

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied warning to @shrewd terrace.

quick snow
#

!compban 1495168519870877868

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied ban to @buoyant summit until <t:1777316021:f> (4 days).

marble vine
#

Hi all, I'm new to contributing to cpython (other than opening issues). Last week I went down the rabbit hole of improving re.search performance for some use cases, and I made two PRs. The first of them is trivial: make "^foo" fast-forward to the next newline, which is often 10x faster (https://github.com/python/cpython/issues/148762). The other has more nuanced results: using memchr instead of a handwritten loop to fast-forward to the next possible match of "foo"; it's very fast if the first char is rare, but slow if dense in the string (https://github.com/python/cpython/issues/148729). Wondering if I can nerd-snipe someone here and wanted to start a discussion what use cases re.search should be optimized for.

deep dirge
uneven raptor
#

PEP 661 accepted 😁

#

i've wanted sentinels for so long

grave jolt
#

I guess it's a very rare occasion

uneven raptor
#

lots of # noqa I would imagine

boreal umbra
#

!pep 661

fallen slateBOT
faint river
#

yay

boreal umbra
#

I'm on a walk right now, but it looks like the tldr is that you can use what is essentialy the object-sentinel pattern in a way that won't upset linters?

grave jolt
swift imp
#

I strongly dislike the customization fo __bool__ and __repr__ but whatever

#

Glad it's finally in, I've been watching that discussion for a few years now it seems

grave jolt
swift imp
#

I mean I live without the repr

clear hill
#

this will be nice for NumPy in a few places

#

we have a singleton that represents a default argument that’s not None

#

for example

swift imp
#

I'm surprised that one was rejected. Seems very useful

grave jolt
#

but I am also a truthiness hater, so I am biased

swift imp
#

I'm wondering if the typing aspect was the complexity

#

Mentioned complexity for rejection, I mean

feral island
uneven raptor
#

sorry, did I spoil the surprise 😅

primal cypress
#

that's a really cool pep

meager nacelle
#

I have a fun case of two sentinels where one is due to None being a valid value and the other is due to the first sentinel being a valid value

#

It's a dataclass-like where the equivalent of dataclasses.Field is essentially also a dataclass

clear hill
meager nacelle
#

It's kind of the case that for this bootstrapped field default=MISSING needs to indicate that the default value is actually the value MISSING and not that there's no value.

#

But that means it needs a new value to represent actually missing

clear hill
#

@feral island are you planning to also publish a backport package for PEP 661 after beta1?

feral island
clear hill
#

I think NumPy already even depends on that

feral island
#

(though with slightly different behaviors, I'll update that to the extent typing-extensions's own BC allows)

clear hill
#

maybe it makes sense to publish backports.sentinels with exactly the same behaviors? if that matters at all.

feral island
#

feels like overkill

#

differences are:

  • typing_extensions.Sentinel is subclassable
  • it accepts an extra repr= argument, and the default repr is different
  • it's not picklable
grave jolt
feral island
#

yes

clear hill
#

I might see if we can replace np._NoValue with the typing_extensions implementation today.

feral island
clear hill
#

I guess I can read the PEP, but are the 3.15 sentinels immortal?

feral island
#

no

clear hill
#

I guess there’s always the unstable SetImmortal C API as an escape hatch if that ever matters for performance

feral island
#

yes. this didn't come up during the discussion and I hadn't thought about it

#

but yeah the existing SetImmortal should be enough

meager nacelle
#

With this and lazy imports I already want to drop support for 3.14 and earlier in projects 😂

clear hill
#

you don’t really notice reference count churn much except on the free-threaded build when it introduces contention, I expect making things immortal will come up more as more people use the free-threaded build. The thought of publishing a package that ships wheels and exposes a Python API for PyUnstable_SetImmortal has occurred to me.

feral island
#

ctypes? 😄

uneven raptor
#

I can tell you from my own experience with PEP 797 that immortalizing GC-tracked objects is extremely difficult to do safely

#

I would just enable deferred refcounting on sentinels if it becomes an issue

clear hill
#

I’ll try to keep that advice in my back pocket. I want to add more profiling and performance tuning advice to the free-threaded guide. I also should play with tachyon finally.

feral island
marble vine
# deep dirge A little suggestion, I’d wait for maintainer feedback on one of the optimisation...

Thanks. The first PR got approved within a day (but maybe not by a core cpython member?), and the second PR is similar but sufficiently different. That's about a 9-10x performance improvement (https://github.com/python/cpython/issues/148762) for matching re.compile("^foo", re.MULTILINE) and is almost trivial and very similar to an existing optimization. Would be nice to discuss re performance with someone.

gilded flare
grave jolt
#

That seems a bit strange. I would put stuff that's not yet a backport into a separate namespace, like typing_extensions.nightly or typing_extensions.experimental. For example:

  • PEP 999 proposing to add Foo is posted as draft and typing-extensions maintainers decide that it's pretty cool
  • typing_extensions.experimental.Foo is added for type checker authors and people who want to play around with it.
  • once the PEP is finalized, Foo is removed from the experimental module
  • if PEP 999 is rejected, nothing else happens
  • if PEP 999 is accepted as is, Foo is just moved to typing_extensions
  • if PEP 999 is accepted with changes, the changed Foo is added to typing_extensions
deep dirge
marble vine
#

Heh, yes, it was missing ptr > state->beginning, I'll stay away from mentioning "trivial" next time. And @deep dirge, good to know. I've closed both PRs to reduce the noise and left the issues open; the suggested patch fits in the issue anyway.

boreal umbra
#
In [37]: text = "Data science is fun. Data science is powerful. Data!"

In [38]: sorted(re.findall(r"\w+", text.lower()))
Out[38]: ['data', 'data', 'data', 'fun', 'is', 'is', 'powerful', 'science', 'science']

In [39]: Counter(sorted(re.findall(r"\w+", text.lower())))
Out[39]: Counter({'data': 3, 'is': 2, 'science': 2, 'fun': 1, 'powerful': 1})

In [40]: Counter(sorted(re.findall(r"\w+", text.lower()))).keys()
# The order of the keys changes!
Out[40]: dict_keys(['data', 'fun', 'is', 'powerful', 'science'])

In [41]: sys.version
Out[41]: '3.12.9 (main, Mar 17 2025, 21:01:58) [Clang 20.1.0 ]'

doesn't this contradict specified behavior for dict iteration order?

#

looks like Counter.__str__ displays the KV pairs in descending order of (v, k), but that might be separate from its iteration order

meager nacelle
#

The __repr__ uses Counter.most_common

#
>>> l
Counter({'data': 3, 'is': 2, 'science': 2, 'fun': 1, 'powerful': 1})
>>> l.most_common()
[('data', 3), ('is', 2), ('science', 2), ('fun', 1), ('powerful', 1)]
swift imp
#

does anyone ever wish dict.setdefault could take a callable?

faint river
#

I don't see why it would need to (and also, it can take a callable, it's just not gonna call it)

swift imp
#

Yeah I mean take a callable and only call it if the key does not exist. Its nice for placement of nested dictionaries. I know there's collections.defaultdict but its not as flexible

#

defaultdict just isn't a good because its for the entire dict whereas I may I want a different container per key

faint river
#

I see, only call it if the key doesn't exist. Because you could just call the function and pass it as the default

swift imp
#

yeah I could do dict.setdefault(key, {}) but then im making a dict that may just get thrown out

halcyon trail
#

and you do see this in other languages, fwiw

#

that said the cost of making a dict that potentially gets thrown out is negligible in like 99% of contexts

spark magnet
#

is __missing__ an option?

halcyon trail
#

the other option is obviously to just write a function; not as nice as a member but on the flip side you can hardcode a dict as the default for example, for that use case

#

and since passing a lambda in python is also not super nice, it's a decent option

#

get_or_dict(my_dict, key)[...]

fallen slateBOT
#

pytype/vm.py line 515

# I have no idea why we need to push the exception twice! See```
frigid bison
#

does anyone know the reason that we have to do this?

swift imp
clear hill
#

not that adding your feature would break that, it just couldn’t be atomic with a python callable involved

meager nacelle
#

I think you'd need something like setdefaultfactory as a callable could itself be a valid value

meager nacelle
#

Though I'd be surprised if you could write a version of that in Python that wasn't slower than creating and throwing out the unneeded dict

#

Maybe if the container is sufficiently slow to construct

radiant garden
#

if it's a meaningful amount of work / has side effects I'd even argue for desugaring the setdefault call into an if x not in y: block

marble vine
#

I also miss that in Python. if x not in y: y[x] = <expression> hashes twice, which can be expensive, and y.setdefault(x, <expression>) evaluates eagerly, often leading to redundant allocations, defaultdict is too static for all use cases.

swift imp
clear hill
#

right, like i said, this can't be atomic with a python callable

#

dict.setdefault is a nice primitive for building thread-safe caches and you kinda want that property, but adding callables to that complicates things

#

hard to think of a safe way to do it without a lock

swift imp
#

You mean the note from *PyDict_SetDefault?

#

Im probably asking stupid questions because I dont understand a lot of threading stuff

clear hill
#

ideally you'd want what you're proposing to work like the c++ std::call_once

meager nacelle
#

I've been investigating the cached code idea for dataclasses again by implementing it on my own classbuilder. It does seem to be fast if you have a lot of similarly-shaped functions which works well for things like __eq__ and __repr__.

rough wave
#

!learn

fallen slateBOT
wooden summit
feral island
spark magnet
raven ridge
#

the argument for the src/ layout is that it forces you to install the project before you can test it, which means your tests exercise the project as it gets installed, instead of as it exists in the source tree, and therefore they test the package build setup.

the argument against the src/ layout is that it forces you to install the project, and people who don't understand that try to work around it by doing from src import ... and making things worse and harder to clean up while working around the feature that the src/ layout is meant to give

feral island
#

I don't really like that it forces a mostly useless layer of extra directory

swift imp
#

src/ is good for namespace packages

raven ridge
#

The whole point of the src/ layout is just to force maintainers to install the module before running the test suite. Whether having the extra directory is a worthwhile cost to be able to enforce this is a matter of opinion 🙂

#

The src/ layout is a low tech hack to work around the Python interpreter having bad defaults - importing random files from the current working directory might be what you want before you've learned to make packages, but it's certainly not what you want when trying to test a package

sturdy timber
merry bramble
raven ridge
#

yep, if you don't understand what it's for and how it's achieving that goal, it's easy to make things worse with it.

merry bramble
#

I used to think it was pointless, then i thought it was good, now (after maintaining a type checker for a bit and seeing the many ways in which folks misunderstand Python import conventions) I'm once again no longer convinced it's a net positive

#

If the convention was s-r-c or source-code it would be much more obvious that it's not meant to be importable

raven ridge
#

I'm not sure that'd stop people from doing export PYTHONPATH=source-code, but at least it'd stop from ..source-code import ...

merry bramble
#

i feel like most of the folks doing this kind of thing are just doing the first thing that works, and have never heard of PYTHONPATH

raven ridge
#

probably true. I think most of the from ..src import ... lines get written by IDEs or text editors trying to be helpful without understanding the src/ layout convention

merry bramble
#

Nowadays it might be agents doing the first thing that works, and i guess they've probably heard of PYTHONPATH... but I'd also expect them to understand the convention more fully out of the gate

raven ridge
#

I think there's plenty of arguments on both sides of it being good and bad, but I think whichever way anyone feels about it, the important thing to understand about the src/ layout is that it is a (low tech, hacky, easily subverted) way to work around Python's defaults doing something different than package maintainers need. Being able to run the tests or the entry points without installing the package is bad - the dependencies don't get installed, generated files might not be generated, things might not be in the right layout, you're not testing that your packaging configuration copies every file it's meant to, etc. Python putting $PWD on the path by default bit enough maintainers that the src/ layout naturally arose as a way to try to work around the maintainer-hostile default

merry bramble
#

Yes. I think it is almost certainly beneficial for experienced maintainers of projects who want to make sure they're actually testing what they want to test, etc. But it definitely has costs as well, especially for beginners (and even intermediate developers) who aren't up to date with the latest conventions and the motivations behind them

raven ridge
#

yeah. That's pretty much where I land on it at this point: I use it for my own projects, but I no longer recommend it to beginners

wooden summit
#

if you happen to find one please let me know

#

thanks

spark magnet
meager nacelle
#

I do actually find the import from working folder useful sometimes. I'd say the 'src' layout is fairly well established for actual projects at this point.

clear hill
#

someone should give @meager nacelle a core role, they’re a CPython triager

#

me too I guess but I’m already purple

feral island
wooden summit
wheat marsh
#

Guys! PEP 810 is coming! 😭 I've been praying for this!

spark magnet
wheat marsh
#

Dude I stopped paying attention to Python for like... a year and I came back to this

#

Ok, I just checked. That's a pre-release. I don't touch it until it's a stable release.

spark magnet
wheat marsh
uneven raptor
#

i'm personally quite excited about sentinels and tachyon

boreal umbra
neat delta
#

let's try something
the hard way then 😔

neat delta
#

(new to 3.15)

deep dirge
glass mulch
meager nacelle
#

I like the additional colour, but I'm a little torn on the addition to more modules right now due to the design of _colorize. Each new theme adds a new frozen dataclass and makes the module slower.

glass mulch
#

Couldn't the themes live in another module and be lazy imported?

meager nacelle
#

I don't know, the whole design has one main class that then has an instance of each 'theme' dataclass as attributes

#

There's also some stuff that we're maintaining that could just be removed in there. I'm pretty sure copy_with is just __replace__ written by hand.

deep dirge
meager nacelle
#

That would probably be a good thing to add in before making improvements to it to compare options.

#

That said I only really have synthetic benchmarks I've used to compare things, other than "how fast does _colorize import with these changes"

clear hill
feral island
wheat marsh
# uneven raptor 3.15 has a ton of cool stuff in addition to lazy imports

It's all quite interesting I just saw news of the lazy imports and got excited. I read through it, I'm definitely excited for Sentinels so I can stop doing X: Int | None. I haven't read into Tachyon enough but the claims made sound very... iffy? I'd like to see it before I believe it. Finally moving to UTF-8 as standard encoding is a big win and the FrozenDict is cool but FrozenDict seems kind of niche. I'm definitely excited for the Free-threading updates

spark magnet
wheat marsh
#

I meant int | None I apologize, I'm shuffling back and forth between apps right now

#

Trying to get Wayland and XWayland to play nice

spark magnet
clear hill
#

IMO None should still be the default argument you use most of the time

#

builtin sentinels only help for situations where passing None is semantically meaningful and you need something else to represent nothing being passed in

#

and even then you can do it without the builtin support, it just adds boilerplate

spark magnet
#

tbh, i'm still a bit surprised that specialized sentinels are important enough to become a feature, including a word in builtins

meager nacelle
#

I think if the alternative is _sentinel = object() it generally makes that nicer, and there are quite a few places where None ends up as valid or that it really just doesn't mean the right thing.

spark magnet
swift imp
#

Few others too but they're interval iirc

spark magnet
meager nacelle
#

You need a sentinel to represent no default

swift imp
#

It's like MISSING or something for the default

meager nacelle
#

because None could be a valid default

spark magnet
#

hmm, ok, and why a builtin?

safe basalt
swift imp
#
dataclasses.field(*, default=MISSING, default_factory=MISSING, init=True, repr=True, hash=None, compare=True, metadata=None, kw_only=MISSING, doc=None)
meager nacelle
#

More arguable, it does mean that it can essentially be used everywhere where they are needed

spark magnet
#

do we think we need more sentinel than Callable or Any?

meager nacelle
#

Personally I wouldn't be fussed over a new import but I would over a new slow import. There was the issue of a pre-existing package called sentinels?

#

If I had to import typing for it I couldn't use it (with typing as it is now)

swift imp
spark magnet
#

i shouldn't second-guess the PEP.

swift imp
#

I do wish they didn't have to be imported though, it's annoying to do it on so many files

meager nacelle
#

I really don't mind the extra line for import, it's the import time that bugs me

spark magnet
meager nacelle
#

It probably will for a bit

quick snow
#

Was there ever a proposal to special-case more built-in names in a typing context? E.g. make callable and any behave like typing.Callable and typing.Any.

meager nacelle
#

One thing I will like is the typing fix it gives where you have to use them

meager nacelle
#

not sure what the resolution was or where so I'm not very helpful here though 🤔

#

But it will be nice to not have type checkers complain that an object could be some other instance of _SentinelType

quick snow
spark magnet
#

i'm still not sure about my original question: how would you use sentinel to help with x: int | None?

meager nacelle
#

You don't really? I'm not sure how it was supposed to help there either.

meager nacelle
#

I want it to help with:

thing: int | SentinelType = get_thing()
if thing is not Sentinel:
    # type checker still thinks it can be SentinelType
    # because it may theoretically be a different instance
    ...
swift imp
#

And there's a pep from @feral island for that ? Which may clash

#

Cuz jelle's is for generics

#

probably butchering that

feral island
#

We're going to make it so sentinels can be used directly in types (like None today), though type checkers still have to implement that

#

There's an active PEP (718) for subscripting functions, it's not mine and I don't see how it relates to sentinels

swift imp
#

Making callable double as Callable

feral island
#

I think somebody already linked my page explaining the problems with that idea

swift imp
#

Ah I didn't scroll

clear hill
#

I should read more about how __class_getitem__ is supposed to work with typing. Right now the numpy dtype class has an implementation that exists for typing purposes but I also think it would be neat if it worked at runtime

#

so np.dtype[np.int64] returned the dtype type at runtime

feral island
clear hill
#

yeah that’s how it works, but that’s not terribly useful for anyone doing anything at runtime

feral island
#

it's not? what would you want instead?

clear hill
#

an actual instance of the dtype type, what you’d get from np.dtype(np.int64) instead. I guess it doesn’t make much difference though, just parens and brackets

atomic frigate
#

ayooo i’m scarlett, first of all, i want to say that i’m TERRIBLE at computers, and I'm really interested in learning, it doesn't matter what it is, i honestly want to learn everything, although i’m a little more interested in coding and programming 😭 but idk how to start

halcyon trail
#

if you're in principle taking an int or str then None is a fine default to indicate absence but in almost all situations where you're taking a T it's not really okay to use None as a default

#

One place you see this is in the standard library btw; it's a bit of a niche case but it means that API like dict.get (the one argument form) is not really useful in some situations because you lose the ability to tell if a key was absent, or present and mapping to None

#

Kotlin has the same issue; any language where the "None" situation is such that there isn't really nesting has a tendency to run into this

raven ridge
wanton flame
feral island
#

which I guess mostly missed the boat for 3.15, oh well

#

but we got a few:

$ ./python.exe
Python 3.15.0b1+ (heads/3.15:e81025e6d2e, May  7 2026, 10:29:46) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import typing
>>> type(typing.NoExtraItems)
<class 'sentinel'>
>>> import dataclasses
>>> type(dataclasses.KW_ONLY)
<class 'sentinel'>
wanton flame
#

Well, we have to save something for 3.16

meager nacelle
#

The stdlib advantage of being able to use the new features immediately

raven ridge
#

It's the other way around, isn't it? If something can be released as a PyPI package, people can start using it immediately. If it's released as part of the stdlib, people need to wait until the minimum Python version they support has the feature in its stdlib

feral island
#

but in the stdlib, we can use it immediately

#

for sentinel specifically, third-party users can also use it already via typing_extensions.Sentinel

sturdy timber
#

Advantage for the stdlib, not for the users of the stdlib

meager nacelle
#

Yes I meant that the stdlib can immediately use new language features, while outside of it you have to wait to use them until you don't need to support python versions without the features

feral island
#

Which is useful because it gives us some immediate usability feedback for new features

meager nacelle
#

Yes it's definitely useful to be able to do it inside of the stdlib and good to do so

#

But I want to drop all my lazy import hacks now 😐

clear hill
#

for a few years

#

it’s good to think on long time horizons for this stuff

feral island
#

(And again in this case they can use typing_extensions.Sentinel)

clear hill
#

yeah backports help a lot with this

#

someone could publish a backports.sentinels or something else outside the backports namespace too

meager nacelle
#

Unfortunately typing_extensions kind of falls into the heavy import category for the library I'd be using sentinels in.

merry bramble
meager nacelle
#

To be fair, with this library I've been very careful about import time from the beginning. It's about a 2ms import on this (old) machine, while typing_extensions is closer to 30ms.

dim atlas
#

How do people reason about acceptable import times?

#

is there a good enough line?

halcyon trail
#

it depends completely what software you're running

meager nacelle
#

I tend to think of it somewhat relatively?

halcyon trail
#

if it's a long running server then import time is almost always irrelevant. If it's a command line utility that should run pretty quickly then long imports can become unacceptable

meager nacelle
#

Yeah, this library is kind of dataclasses but everything is lazy (and now also potentially pre-cached) because I wanted to use it for quick command-line stuff

halcyon trail
#

i admit, I haven't personally seen dataclasses become an issue, though I know people have talked about this before

#

python is just kind of slow in general so I'm mostly using it for things where my expectations are low, unless almost all the heavy lifting is in C

meager nacelle
#

Dataclass construction is kinda slow and up until the new beta it also imported a bunch of other slow modules.

#

Again, relatively speaking

#

Like, if you're doing import numpy then dataclasses is relatively small

halcyon trail
#

I do personally think the dataclass situation is a little bonkers in some sense. Almost every class I write is a dataclass, so that's an awful lot of codegen for very basic functionality

halcyon trail
feral island
#

it's not just import dataclasses itself being slow, but also every individual dataclass is slow

#

because executing the @dataclass decorator does a bunch of expensive work

meager nacelle
#

Yeah, although until we improved the import time of dataclasses itself it was somewhat overshadowed?

halcyon trail
#

interesting my intuition would have actually been what jelle said

#

i.e. I thought the actual codegen would be the expensive part

#

it scales with the number of dataclasses after all

feral island
#

I don't recall the numbers but I think it used to import inspect which is quite expensive? And enums are not great either

halcyon trail
#

Unfortunate, I ❤️ enums too

#

I'm actually surprised how many python devs I've talked to who would rather use Literal type annotations over an enum

feral island
#

enum has a few more features than necessary

merry bramble
#

I love enums too, but the amount of work the EnumType metaclass does every time you subclass Enum is a little scary

halcyon trail
#

that's probably true, but being able to iterate is pretty convenient

meager nacelle
#

Yes inspect was the most expensive part, it also meant that you couldn't remove most of the other imports

#

Well you could, but then they'd still be imported by inspect

halcyon trail
#

Mostly though I just like that enum lets you create a real type with defined alternatives

#

Literal feels very ad hoc, and you have things like different type checkers handling things differently

clear hill
#

rust enums are really nice; i’ve honestly never used a Python enum

halcyon trail
#

they're not really similar, naming aside

grave jolt
#

Rust enums can be used as "enums" but it's like two features rolled into one

halcyon trail
#

Python enums are more like C/C++/Java etc enums

#

Yeah

#

Rust enums are sum types, it's just that sum types are a super set of C style enums

meager nacelle
#

It does scale with the number of dataclasses and depending on their methods, but I think it's probably around 20 dataclasses before you catch up with the import time? Unless they're frozen. These are just guesses based on other ancient timings though I've not tested this recently.

#

(Well, the old import time)

halcyon trail
#

oh, but 20 is peanuts (right?)

grave jolt
#

If Literal had a more ergonomic ability to iterate over its members and maybe support checks like a_str in Literal[...] (with type checker support), I think it would mostly replace features used in enum.Enum?

halcyon trail
#

I was imagining like a decent size codebase, you could easily have hundreds of dataclasses

meager nacelle
#

hundreds of different dataclasses 😰

halcyon trail
#

and python doesn't

#
from typing import Any, Literal

def foo() -> Literal["hello"]:
    x = "hello"
    return x

Maybe there's an option but this still doesn't type check on mypy 2.0 by default

grave jolt
halcyon trail
#

yeah. but like, you cannot really blame type checkers because none of this is even vaguely spelled out anywhere canonically, and it's non trivial

#

like, look at C++ constexpr rules, or Rust const rules - it's complicated. That's what we're talking about.

#

I accept the practical utility of Literal for typing existing code but I personally don't think it makes sense for new code in like 95% of cases.
For me it's very similar to typed dict vs dataclass in that sense.

grave jolt
#

Yes, you cannot just infer the type of every string literal as Literal. Otherwise e.g. it would infer py fruits = ["apple", "banana"] as list[Literal["apple", "banana"]] which is not very useful

halcyon trail
#

yeah, since list is not covariant

#

it just becomes a mess

#

enums are totally unambiguous and at the call site it's also clear that you're passing one of several alternatives rather than a magic string

grave jolt
#

I think the main advantage literals have is concision. In some languages, you can write something like .RED instead of some_module.SomethingColorChannel.RED, which is of course impossible in Python

#

but I do agree that the inference rules make Literal janky to use sometimes

halcyon trail
#

you never have to write the module name

#

but yeah you have to write the enum name

grave jolt
#

Well, yes, I was exaggerating a bit. (some codebases have a code style where you can only import modules and not individual items)

halcyon trail
#

that's a pretty awful style for a typed codebase regardless tbh

grave jolt
halcyon trail
#

but yeah, I mean the issues with enums to me - import time (almost always a non-issue), a little verbosity
still pale compared to the readability benefits, plus not ever getting caught in some kind of weird type checker case, type checkers disagreeing with each other, etc

#

I think that was a reasonable style before static typing in python

#

it's just now... def foo(x: some_module.FirstType, y: other_module.SecondType, z: longer_module_name.ThirdType):

#

google's python style guide obviously long predates type hints though and it's enormous so I can see why for them it makes sense to just continue doing the same thing

meager nacelle
#

I'd definitely want to do as shortname at least

#

(Not helped by many of my own libraries being namespaced first)

halcyon trail
#

I think kotlin was smart to disallow importing the "module", fwiw. ends all the discussions, code is more concise, and it's trivial for the editor to tell you where something is from

#

every language that allows both will have to have a style guide that will be endlessly argued about 😛

meager nacelle
#
import ducktools.classbuilder.prefab

@ducktools.classbuilder.prefab.prefab
class Example:
    a: list[str] = ducktools.classbuilder.prefab.attribute(default_factory=list)

Yeah not great

halcyon trail
#

decorators is another place where I really dislike having the module name

#

I admit this is totally irrational

meager nacelle
#

There's a base class version, which is probably actually worse

#

Especially if you start adding things like kw_only and frozen

#

Lazy generation is pretty nice for frozen as hopefully nothing actually triggers the __delattr__ or __setattr__ of a frozen dataclass

swift imp
meager nacelle
#

Most of the import time of the enums module is the enums module, the only things it imports are sys, builtins and types

halcyon trail
swift imp
#

Anyone think match-case will ever be expanded upon?

Been 5 years and nothing. Ive really wanted something more concise than below for checking if anything in a sequence is a specific type.

import numpy as np

def check(t):
    match t:
        case (a, b, c) if any(isinstance(x, np.ndarray) for x in (a, b, c)):
            print("Contains a numpy array")
        case _:
            print("No numpy arrays")
feral island
grave jolt
#

the only expansion I wish for is the ability to refer to constants without requiring attribute access

swift imp
# feral island There haven't been a lot of proposals. Maybe there's room for expansion, but "is...

Theres not much you can do with a sequence other than trying to match some fixed amount of items on either end.

It's really just asking for a way to match if there's at least 1 item in a sequence is a specific type or all the items in a sequence are a specific type without having to rely on a guard.

Some sort of more advanced predicates.

import numpy as np

match value:
    case [*items] if any(isinstance(x, np.ndarray) for x in items):
        print("Contains at least one ndarray")
    case _:
        print("No ndarray")

An example like this would be useful for json parsing, say a schema declared you'd receive an array type and there would be at least 1 item in the array of a specific type.

{
  "type": "array",
  "items": {
    "anyOf": [
      { "type": "number" },
      { "type": "string" }
    ]
  },
  "contains": {
    "type": "string"
  },
  "minContains": 1,
  "maxContains": 1
}

The way id look for that item right now would be like

next(x for x in arr if isinstance(x, str))

A match-case that searched the sequence and allowed binding that a expected type to a name would be useful. Which is really how I'd want to use it. The numpy example was just first thing that came to mind.

Side note:

For that numpy match case example

Something I just realized, doing a sequence check like above doesn't match a string but will match any other kind of sequence

halcyon trail
#

a random thought - in free threaded python, you can easily just use asyncio for CPU parallelism, can you not? Especially if you just raise the number of threads in the default thread pool executor.
You can currently "bridge" between asyncio and cpu parallelism by using run_in_executor and a process pool, it's just more clumsy

halcyon trail
#

with free thread python you can use asyncio.to_thread, which makes it way, way more elegant

halcyon trail
#

I've been dealing with some code that originally used process pool executors, and then also thread pool executors... and now there's asyncio in the mix too. And it's just a mess. there's a "--parallel" option that simply doesn't work because you can't naively mix asyncio and thread pools.
Would be very nice to just be able to use asyncio as a singular abstraction that handles it all

clear hill
#

not quite sure if I follow your full idea, I don’t have much practical experience with asyncio

halcyon trail
#

with free threaded python you can just write code like this

#

and we get parallelism with really minimal syntax and without having to explicitly deal with a process pool or what not

grave jolt
#

maybe we just need cancellation and timeouts for threads

halcyon trail
#

with GIL python you'd have to write this

import asyncio
import time
from concurrent.futures import ProcessPoolExecutor

def work():
    print("start work")
    time.sleep(10)
    print("end work")


async def par():
    loop = asyncio.get_running_loop()
    with ProcessPoolExecutor(10) as e:
        await asyncio.gather(*[loop.run_in_executor(e, work) for _ in range(5)])


if __name__ == "__main__":
    asyncio.run(par())
#

it's just significantly more awkward as you can't use the default/global asyncio executor (since it uses threads)

#

so you have to pass around this separate process pool for the CPU work

clear hill
#

yeah, I think this is an underappreciated bonus of free-threaded Python

#

similarly I’ve found that thread pools are a lot more ergonomic practically for real-world stuff than process pools

#

non-trivial real-world stuff often runs into arcane gotchas around pickleability

halcyon trail
#

Yeah. Or just the fact that you can't pickle a lambda. Performance issues of needing a large amount of read only data in each process. Etc. Certainly a lot of issues. But even compared to thread pools this is quite nice, if you end up using asyncio elsewhere in the program

halcyon trail
#

Random question - is there any particular reason that the asyncio.subprocess stuff is like... almost the same as subprocess, but with various weird annoying differences?

#

Mostly, a lot of convenience API has been removed - e.g. capture=True, text=True was very convenient

#

also, rather than shell=True/False there's two separate functions. Maybe this is because it affects the type of the command arguments I guess? But feels a bit random

#

One of the things I really liked is when subprocess.run came out, the API and convenience functions were good enough that I basically stopped having my own wrappers around subprocess functions

#

feels like now I'm headed back to that

drowsy galleon
#

I doubt they just wanted it to be different from subprocess but yeah

halcyon trail
#

yeah, I think maybe asyncio predates subprocess.run, so that could be part of it

noble terrace
#

I don't nothing about programming. Can anyone suggest a good YouTube playlist or books to learn about programme fundamentals. I meant to learn A,B,C s... Where should I start.......

fallen slateBOT
grave jolt
timber hatch
#

Good afternoon guys, tomorrow is my PCEP test Where can i find practice questions and leaked exams questions?

faint river
quick snow
#

!clban 648479497775218698 scam/malware/piracy

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied ban to @hoary token permanently.

candid violet
#

Hi, everyone

spark magnet
candid violet
#

Okay. I have already complected Pyhon projects. Okay?

drowsy galleon
candid violet
meager nacelle
#

So import statements inside a try/except block are eager even under -Xlazy_imports=all but imports inside those modules are lazy again so if the import error that is being guarded against is actually from a submodule then the import is successful when it would have failed normally.

#

Ran into this trying the mode with pip so it's not entirely hypothetical

#

Well I had to build Python without some optional dependencies but I guess this is a bug?

$ PYTHON_LAZY_IMPORTS=normal ./python -c "import shutil; print(shutil._BZ2_SUPPORTED)"
False
$ PYTHON_LAZY_IMPORTS=all ./python -c "import shutil; print(shutil._BZ2_SUPPORTED)"
True
meager nacelle
#

Technically that one could be fixed by trying _bz2 instead of bz2. I think that's the only one in shutil affected by this as the others use the internal module at top level or have a * import 🤔 .

#

Not sure if there are other cases like this elsewhere in the stdlib though. That one came to mind as I'd seen those try/except checks recently.

feral island
meager nacelle
#

Yeah I'm in the middle of doing so

meager nacelle
#

This is all because I keep trying things with pip under the lazy imports mode

feral island
#

keep them coming 🙂

last estuary
#

I'm looking back at something which bothered me when I first opened the functools.cached_method PR. (Thanks to everyone who has helped me get it this far, btw!)
I see a number of things in functools set __class_getitem__ = classmethod(GenericAlias). Dates back to this commit. I don't quite understand what that does, since I've never been 100% clear on what GenericAlias is/does. Is this something I need to add to cached_method?

#

It would mean that functools.cached_property[int] == GenericAlias(functools.cached_property, (int,))? Is that what we want?

#

Oh, I see now -- asking made me test more stuff -- that this doesn't include lru_cache or cache, since those (like cached_method) are functions. So I guess this is fine? It seems slightly inconsistent to me, but I don't quite grasp what the purpose is of it being possible to write functools.cached_property[int].

clear hill
#

it’s for static typing, see PEP 585

meager nacelle
#

I guess there's the question of what it means for cached_property though? You can't do property[int]

fresh heath
#

ehllo

#

hello

last estuary
#

To the above regarding GenericAlias, I feel like I don't "get it" when I see it outside of the context of builtins, e.g., list[str]. Tracking this through BPO, it seems that functools.cached_property was generic in typeshed, so we made it generic in the stdlib... Maybe it's just a sort of accident of history?

feral island
fallen slateBOT
#

stdlib/functools.pyi line 248

class cached_property(Generic[_T_co]):```
feral island
#

I don't see much of a use case for explicitly writing cached_property[T] but I guess it could make sense if you work with cached_property objects directly

#

I was actually thinking of opening an issue on CPython about documenting better why we make certain things generic. All the docstrings for C-implemented __class_getitem__ method are just "See PEP 585" and that doesn't tell you much. We should list what the expected type parameters are and what they mean.

spark magnet
feral island
last estuary
#

I'm going through these, and finding many things that are generic in typeshed but not in cpython... that subscriptable functions PEP is looking more appealing by the minute.

tidal sorrel
#

I am taking a look at the python lexer and for some reason :

a = 10 #asdasdsa

the newline token has the start at the start of the comment;

[NEWLINE](7 - 17)(start = 0x60eaa7f1b1f7, end = 0x60eaa7f1d1f0): #asdasdsa
merry bramble
last estuary
#

Oh, I was thinking of the other stuff. functools.partial (which is a function) and functools.chain (which is a class but is documented as a function with a classmethod on it 😵‍💫 )

merry bramble
last estuary
#

You're right about partial -- I just checked. I think there are some mixed up cases though.

merry bramble
#
GitHub

Feature or enhancement Right now it is impossible to subscribe map: » ./python.exe Python 3.13.0a0 (heads/main-dirty:79823c103b6, Aug 31 2023, 15:46:08) [Clang 14.0.3 (clang-1403.0.22.14.1)] on dar...

GitHub

Feature or enhancement Proposal: Currently only itertools.chain can be subscripted at runtime. I think most of other iterators should be subscriptable too. Most of these classes are generic in type...

last estuary
#

Thanks for the refs! I was going through things today (doing the docs update discussed above), and saw that enumerate implements class getitem. map and filter feel a bit different.

uneven raptor
#

for those that were involved with PEP 585: why did we add a new dunder instead of just implementing __getitem__ on type?

feral island
#

though then again class getitem doesn't check argument counts either

#

I wasn't involved in the discussion

uneven raptor
#

do we implement it on any non-C types? I was thinking we could have used a type flag

merry bramble
#

Yes, it's implemented on quite a few stdlib pure-Python classes

#

In typeshed we can pretend that these classes inherit from typing.Generic, but we don't want the whole stdlib having a dependency on the typing module at runtime

#

It would create a horrible mess of import cycles

last estuary
#

My way into this as a topic was seeing classes which have __class_getitem__ = classmethod(GenericAlias) -- you can grep for that to find many of the cases

merry bramble
clear hill
#

numpy uses __class_getitem__ for this reason, I think ^

#

the runtime startup cost

boreal umbra
#

inb4

true ridge
crystal pebble
#

So how about that walrus?

boreal umbra
#

In Java, can't you already do assignment within if statements and such just using the regular = operator?

void sonnet
#

well, this is new.

boreal umbra
#

I didn't really get why it had to be a separate thing, but I like it otherwise.

gray mirage
#

4th message in new python language channel: java

crystal pebble
#

Do you mean if (int I =0; ...)?

boreal umbra
#

I don't know, I only use Java when my professors don't give me a choice.

#

but I thought I saw something along those lines. Though I don't think there's ever a semicolon in if conditions.

true ridge
boreal umbra
#

A choice was made to introduce := instead of expand the legal cases for =

#

It might be that the latter would cause ambiguities that haven't occurred to me.

fossil pumice
#

I think it would've been a lot less controversial if they hadn't used the colon.

#

but the thing @true ridge just linked raises a good point

#

not entirely convinced it was worth the trade-off, though.

true ridge
#

I don't know if you folks run into it, but seldomly I write = instead of == which would make the expressions always True (depending on the assigned value)

#

it is nice to have a different operator for this job, it makes the purpose a bit more explicit

fossil pumice
#

yeah, and that case would be a bit insideous.

worldly venture
#

I never fully understood the conflict behind it though, surely if people disliked it they could have just not used it (though I'm sure this was a point raised many times), I personally quite like the := operator (though wish flake8 and co would support it)

fossil pumice
#

flake8 support is out now, ai think?

#

veeery recently

worldly venture
#

ah it might be, it just wasn't when I tried to add it to @fallen slate

#

I know I tried it on the stats PR so that was like April 12th

boreal umbra
#

who is flake8?

fossil pumice
#

a linter

worldly venture
fossil pumice
#

a very nice one

true ridge
#

yep, the maintainer just released it

low lagoon
#

oh snap

fossil pumice
#

anyway sure, := doesn't bother most of us here that much but it fragmented the community at the time and I think it has hurt adoption quite a bit.

peak spoke
#

the = did the same thing until 3.8 so I think changing that instead of including the new walrus could cause some confusion and potentially make a lot of resources outdated

fossil pumice
#

it would still be backwards compatible, it would just fail to give an exception if you confused = for == in a comparison.

#

possibly introducing a silent and deadly problem

fair lynx
#

how do i do like
str = so mething
first_part = #everything before " "
and also
everything after " "

true ridge
#

There are examples of changing a statement to expression, like yield. But because of its limited usage and purpose of it, it didn't hurt anybody.

boreal umbra
#

@fair lynx if you claim a help channel and ping me, I'll answer that.

true ridge
#

For assignments, it would definietly hurt some people and alter behaviors / create bugs that might be hard to spot.

fair lynx
#

okki

fossil pumice
#

@fair lynx not sure what you're asking but this is not a help channel.

fair lynx
#

sorry ;-;

peak spoke
#

it is a common mistake by beginners that could go unnoticed until too late or much frustration, = is fundamental to the language and while it would be backwards compatible it's still a somewhat major change

dawn hill
#

What is this

#

Oh no

#

Am I losing my mind?

peak spoke
#

and there are design decisions to differentiate them like invalid syntax at the top level

boreal umbra
#

@dawn hill You lost your mind long ago.

dawn hill
#

Damn you know too much

#

Is this basically the old python-discussion?

boreal umbra
#

It's python discussion for actual python discussion

fair lynx
#

am good for my question i found arcticles

dawn hill
shy vine
#

Yes but that didn’t happen

dawn hill
#

Fair enough

fossil pumice
#

so now they can use that instead.

fair lynx
#

ohh so its .split

dawn hill
#

Fair enough

fossil pumice
#

we want this channel to be a more intermediate to expert level discussion channel for conversations about the language itself. so this is a pilot test to see if this will help

boreal umbra
#

Speaking of which

#

I'm still interested to know how feasible it would be to have optional compile-time type checking

fossil pumice
#

in the language itself?

boreal umbra
#

My friend who hates Python was complaining that it takes him a long time to debug type errors.

#

Yes

fossil pumice
#

It's probably plenty feasible but they'll never do it.

boreal umbra
#

For example, imagine if python -T my_file.py caused that to happen

fossil pumice
#

the type system is intentionally left open ended and flexible because it's more pythonic.

#

but there are some pretty mature third party solutions for this now

worldly venture
#

mypy is excellent

true ridge
fossil pumice
#

yeah, Guido himself works on mypy

#

well, worked at least

boreal umbra
#

Doesn't mypy turn running your code into a two-step process though?

#

checking it with mypy, and then running it?

true ridge
#

no

#

mypy will only check when you want, possibly somewhere in your development workflow or CI. And when you deploy your code, the type annotations will have no meaning at all

#

or the mypy itself

crystal pebble
#

Your editor likely supports it in some way

#

I get errors as I type (or save?). No need to run it manually

boreal umbra
#

My friend who hates Python doesn't accept IDE-dependent solutions. Not that his objection to how Python is designed necessarily important, since it doesn't look like he's seeking out a career where he'd ever use it.

fossil pumice
#

yeah I've met lots of people just like your friend

#

not sure there's any convincing them. a type error ruined their entire life one time and now they're jaded and broken

boreal umbra
#

lol

crystal pebble
#

:/ I've never had that issue. It's just nice to avoid as many bugs as possible

boreal umbra
#

I've only ever worked on one big project, and I haven't looked at it much since covid started.

crystal pebble
#

Prevention is the best approach, IMO

fossil pumice
#

but I think keeping the actual type checking in third party mostly is a strength of the Python language.

#

it's just more flexible.

boreal umbra
#

but I didn't repeatedly have type issues.

true ridge
#

I agree with @fossil pumice; annotations aren't only for type hints, they are for storing arbitrary data inside of both runtime and compile time

#

so ecosystem is able to create many different tools to process code integrity with them

deft pagoda
#

the true purpose of annotations is creating magical classes with metaclasses using __annotations__

#

i created a class that binds functions to properties through annotations:

class Relay(Dispatcher, default=0):
    width: observer1
    height: (observer1, observer2) = 10
karmic agate
#

Anyone knows how could i melt or self destruct a file after executing?

deft pagoda
#

not very inclined to tell you how

worldly venture
#

yep, doesn't sound like a question for this channel or this server

misty wolf
#

Melt or self destruct? There are two totally separate methods

#

@deft pagoda how does that work? I've been trying to figure it out and I can't tell

karmic agate
#

Self delete from computer?

deft pagoda
#

there's a lot of machinery in the Dispatcher class

worldly venture
#

@karmic agate we're not going to help with that here.

karmic agate
#

Why not?

low lagoon
#

something something

#

!rule 5

fallen slateBOT
#

5. Do not provide or request help on projects that may break laws, breach terms of services, be considered malicious/inappropriate or be for graded coursework/exams.

karmic agate
#

Im just learning python

#

And im experimenting

deft pagoda
#

this is just the meta for it:

class DispatcherMeta(type):
    def __prepare__(*args, **kwargs):
        return DummyDefaultDict()

    def __new__(meta, name, bases, methods, **kwargs):
        methods = dict(methods)

        module = modules[methods['__module__']]
        default = kwargs.get('default')

        for name, attr in tuple(methods.items()):
            if isinstance(attr, Dummy):
                if hasattr(module, name):
                    del methods[name]
                else:
                    methods[name] = Property(default)

        for name, funcs in methods.get('__annotations__', {}).items():
            methods['__annotations__'][name] = tuple(getattr(module, item.name) for item in always_iterable(funcs))

        return super().__new__(meta, name, bases, methods, **kwargs)

but it was mostly an academic exercise

karmic agate
#

Im not into anything malicous tf

worldly venture
#

@karmic agate

  1. this is the wrong channel, no more discussion here
  2. even if you use it with no malicious intent, someone else will, we are not risking it.
karmic agate
#

Bs

boreal umbra
#

You can see from the description of this channel that it isn't for help.

worldly venture
#

Don't push your luck.

#

Now let's get back on topic

karmic agate
#

Yeye bye

unkempt rock
#

so im kinda a beginner in python, I'm coding a pong game and I can't fugure out what my mistake is. Prolly some stupid small mistake but can sum1 skim thru my code and tell me if they can catch what I did wrong?

fallen slateBOT
#

Hey @unkempt rock!

It looks like you tried to attach file type(s) that we do not allow (). We currently allow the following file types: .3gp, .3g2, .avi, .bmp, .gif, .h264, .jpg, .jpeg, .m4v, .mkv, .mov, .mp4, .mpeg, .mpg, .png, .tiff, .wmv, .svg, .psd, .ai, .aep, .xcf, .mp3, .wav, .ogg.

Feel free to ask in #community-meta if you think this is a mistake.

fossil pumice
#

@unkempt rock use a help channel.

misty wolf
#

This channel name might need to change lol

unkempt rock
#

which one

fossil pumice
#

@misty wolf any suggestions for to what?

true ridge
#

maybe we should strip python?

#

just language

fossil pumice
#

hm.

void sonnet
#

then we'll just talk about sanscrit, and what not. 😉

unkempt rock
#

py-lang

#

just by 2c

misty wolf
#

Structure?

#

Nah I don't like that

shy vine
#

python-channel-but-not-a-python-help-channel

void sonnet
#

python-language (not help)?

#

hehe

misty wolf
#

Beautiful, ELA has it

shy vine
#

A bit long

true ridge
#

(not help) python-language

unkempt rock
#

so im kinda a beginner in python, I'm coding a pong game and I can't fugure out what my mistake is. Prolly some stupid small mistake but can sum1 skim thru my code and tell me if they can catch what I did wrong?

#

bruh

misty wolf
#

lmao

fossil pumice
#

hahaha

unkempt rock
#

bruhhhH

#

lmaooo

shy vine
#

Enough

fossil pumice
#

@unkempt rock please, please use a help channel.

unkempt rock
misty wolf
#

language-discussion?

#

No that's just as bad

unkempt rock
#

honestly language is concise

#

we don't need to specify that it's python because we are literally in a python discord

misty wolf
#

I'd be good with language, it's just vague

#

True

fossil pumice
#

language is okay. it's not very precise.

shy vine
#

language-(not-java)

fossil pumice
#

I don't hate it but I don't love it.

unkempt rock
#

that's like having a folder called "School" and then a subfolder called "Algebra in School"

#

you don't need the "in School" part

misty wolf
#

I love naming my variables!

oblique crystal
#

python-channel-but-not-a-python-help-channel
Imo ELA nailed it

unkempt rock
#

-lang is also considered mostly used for programming language stuff

#

rust-lang, etc.

misty wolf
#

But it might have the same problem

misty mulch
#

I love packages that needlessly include "python" in the name, good to see a discord channel doing the same lol

unkempt rock
#

speechless

misty wolf
#

I like the package.py ones cuz it's cute

#

discord.py

unkempt rock
#

the pypackage is also funny

north root
#

name the channel language.py

#

hah

fossil pumice
#

@misty mulch yeah we should've just called this server Discord

unkempt rock
#

pydantic is my favorite

misty wolf
#

:o
I like F1re's idea
I guess we can't do reactions here?

fossil pumice
#

of course dots aren't legal for channel names

#

so it would be like language-py instead

unkempt rock
#

This more belongs in #community-meta but the ✅ isn't a very good emoji for "avaliable"

misty mulch
#

language-dot-py

fossil pumice
#

which is less nice

north root
#

you could use some unicode right?

boreal umbra
#

Do it like how Wikipedia names the article for C# "C sharp"

#

and then the top of the article says that the real name of the article is "C#"

fossil pumice
#

you could use some unicode right?
@north root

it's possible. not aware of a working dot Unicode for discord channel names

#

but maybe.

misty wolf
#

Okay, I think if we keep python-language we also need to create a channel for python-snake
It's only fair

unkempt rock
#

we also need a monty-python channel too

misty wolf
uncut sage
#

flying-circus

unkempt rock
#

and a python-logo

uncut sage
#

(that's what offtopic-0 would be)

fossil pumice
#

I think I will allow this blatant offtopicery since it's a meta conversation about this channel.

unkempt rock
#

and a python-colorscheme

uncut sage
#

haha

fossil pumice
#

but please don't use this channel for this later on.

unkempt rock
#

:D

#

you got it

misty mulch
#

monty-python is redundant, just a monty channel is needed

unkempt rock
#

lmao just #monty

misty wolf
#

I feel like language is the best choice

oblique crystal
misty wolf
#

Since we can't do language.py

oblique crystal
#

use this dot

unkempt rock
#

that didn't age well

misty wolf
#

lol

oblique crystal
#

U+2024 ․

north root
#

ahh lossberg found it first

oblique crystal
#

it has weird name ONE DOT LEADER

misty mulch
#

Let's commit to the langauge misspelling, I like it

unkempt rock
#

I really don't think using a . makes sense

#

it's inconsistent with the rest of the channel names

#

I root for py-language

misty wolf
#

I personally don't mind the inconsistency but that's just me

fossil pumice
#

I like it too. in fact, I'd be open to changing #discord-bots to use the dot, too.

fossil pumice
unkempt rock
#

triggered

#

fair enough 😂

fossil pumice
#

@worldly venture thoughts on dotting channels and language.py for this channel?

oblique crystal
#

Woot Woot my message is pinned 😂

north root
oblique crystal
peak spoke
misty wolf
#

I feel bad for the guy who decides to make a bot that has any interaction with these channels

fossil pumice
#

people interact with channel IDs

#

not names

worldly venture
#

we'll give it a shot

north root
#

nice

misty wolf
#

You'd probably use the name of the channel and fetch the ID with the name, rather than hardcoding the ID tho
Also it was just a joke

fossil pumice
tawdry gulch
#

Oh damn, so name change?

worldly venture
#

hell yeah

#

only thing I don't like it that channel mentions won't work

unkempt rock
#

discord.py makes sense, language.py doesn't because the .py doesn't hold much significance besides "it's python"

fossil pumice
#

like.. at all?

misty wolf
#

They'd work with autocomplete, wouldn't they?

north root
#

it'll autocomplete wouldn't it?

worldly venture
#

if you autocomplete they will yeah

fossil pumice
#

that's probably okay.

worldly venture
#

I do see @unkempt rock's point as well

oblique crystal
#

Who don't use autocomolete tho for channela

worldly venture
#

me

tawdry gulch
#

Wait what channel is being changed?

fossil pumice
#

i usually just do <# and then type the channel ID from memory

oblique crystal
#

Can I just 🤦🏻‍♂️ 😂

worldly venture
#

lol

oblique crystal
#

Idk at who tho full typing name or channel id lol

tawdry gulch
fossil pumice
#

I think language.py is weird enough to maybe keep general questions out of it. I don't like just language

unkempt rock
#

yeah, and it's actually named discord.py

#

unlike the python language

tawdry gulch
#

Also Isn’t there already a channel in this server named “discord-py”

fossil pumice
#

what about #cpython

worldly venture
#

yeah, that is what we are renaming

fossil pumice
#

I wonder if that would work

unkempt rock
#

oh? I thought python-language included other compiles

tawdry gulch
#

Ohh, right

oblique crystal
#

So in future would this be a good place to discuss smth like how useful are type annotations and why people use or don't use Them

fossil pumice
#

fiine, I guess you're right.

unkempt rock
#

I held off on saying #cpython because I thought it also included other implementations

fossil pumice
#

it'd be fine to discuss other pythons here

unkempt rock
#

so is this just about the language?

#

or is it like

#

#python-meta

fossil pumice
#

kinda like that, yes.

unkempt rock
#

python meta?

#

ok

#

well I suggest #python-meta

#

:P

fossil pumice
#

see the topic

unkempt rock
#

I read, that's what prompted me to ask

whole obsidian
#

what are benefits of using programs? they are just browsers in a box... like discord

fossil pumice
#

I don't think #python-meta quite works.

unkempt rock
#

because otherwise python-language is misleading

true ridge
#

I dont think anything that starts with python- would solve the problem

fossil pumice
#

exactly

unkempt rock
#

python-meta is like meta, but for python not the server

oblique crystal
tawdry gulch
#

What about “python-discussion”

#

I don’t see what was wrong with that

unkempt rock
#

that was the original name

slim island
#

language.py would be a pretty cool name

tawdry gulch
#

I know

oblique crystal
#

I was lazy to type

#

😂 Don't judge

misty mulch
#

Rename this channel circulardebateoversemantics since that reflects its content

fossil pumice
#

it people see the word discussion and think general chat

unkempt rock
#

^ I did

fossil pumice
#

@misty mulch thanks for that valuable contribution

willow shore
#

oops that should be in general*

unkempt rock
#

honestly, I don't know why we give the off topic channels numbers if the phrase after it is unique

deft pagoda
#

because the name changes

#

but the numbers don't

unkempt rock
#

but why is that needed

deft pagoda
#

so two days from now i can find the discussion i was having in an ot

slim island
#

Its much easier to link to a channel

unkempt rock
#

I see

oblique crystal
#

Especially if you discus while name is changing and what to refer to the Chanel

slim island
#

I don't want to have to type #cheesey-toes or whatever to link to it. #ot{number}+tab is much nicer

unkempt rock
#

yeah, that makes sense

shy vine
#

!otn a cheesy-toes

fallen slateBOT
#

:ok_hand: Added cheesy-toes to the names list.

fossil pumice
#

hahaha

dire hull
#

Petition to delete all keywords

#

And let user select which set of keywords they want as pre defined

#

Also force var def to specify type

north root
#

hahah that would get rejected so fast

boreal umbra
#

We could infiltrate the steering council

#

with our little Discord cabal

#

I forked cpython a while ago to make my dynamicdict

#

though that got a hard no from the one core dev who responded.

#
>>> my_dyd = dynamicdict(str.upper)
>>> my_dyd['hello'] += ' world'
'HELLO world'
#

The missing key gets passed to the default factory.

#

defaultdict does not support that behavior.

#

This example is useless, of course.

#

I created it because I wanted it for something I was working on

#

I've been meaning to submit it to the pypi

#

performance idk?

#

I mostly wanted to see if I could do it.

#

But I do legitimately think it's worth while.

#

yep

#

I'm not sure why that's not the default implementation of defaultdict, because you could do all the same things if it were

#

defaultdict(lambda x: [])

#

now you have defaultdict(list)

#

less elegant though for those cases, for sure.

#

if defaultdict tried to pass the key to the default factory, but the default factory didn't have any parameters, you'd get an error.

#

so if defaultdict supported key-based generation of missing values, the default factory functions would all need to accept one argument, and ignore it if need be.

#

yes

#

I wanted it to be a separate class

#

but no one liked it

#

😢

#

This can't exist in Java

#

because it's illegal to have an operation in Java that could be done in Python in one line

#

unless it takes at least three lines in Java.

#

I'm just making fun of how verbose Java is.

#

It just seems uncharacteristic of Java to me to abstract away as much work as dynamicdict or even defaultdict do.

#

but I could be way off

shy vine
#

This is pretty neat

deft pagoda
#

i've created some defaultdicts lately that only add some missing keys and not others

#

for metaclasses

#

that would be a neat keyword arg

boreal umbra
#

that is, extend the functionality of defaultdict to support this behavior with a keyword arg?

deft pagoda
#

yeah

#

ignore: cond

boreal umbra
#

hmm

deft pagoda
#

another lambda probably

boreal umbra
#

in what case did you use this?

deft pagoda
#

ignore: lambda key: key.startswith('__')

#

for __prepare__ method of metaclass

#

consider this simple case:

from itertools import count

class IncrDict(dict):
    def __init__(self, start=0, step=1):
        self.counter = count(start, step)

    def __missing__(self, key):
        if key.startswith('__'):
            raise KeyError(key)

        self[key] = next(self.counter)
        return self[key]

class EnumMetaclass(type):
    def __prepare__(*args, **kwargs):
        start = kwargs.get('start', 0)
        step = kwargs.get('step', 1)
        return IncrDict(start, step)

class Enum(metaclass=EnumMetaclass):
    def __init_subclass__(cls, **kwargs):
        """Pull kwargs from class def"""

class Fruit(Enum, start=10, step=15):
    APPLE
    BANANA

print(Fruit.APPLE, Fruit.BANANA)
#
10 25
boreal umbra
#

huh

#

my friend asked me about enums in Python today

#

I didn't know Python had it

deft pagoda
#

it has enums, but this enum is cooler

boreal umbra
#

I'm sure it is pydistrong

deft pagoda
#

i should raise an error on missing

#

oops

boreal umbra
#

also, today is the first time I've seen keyword arguments in class declarations

deft pagoda
#

i've been doing a lot of metaclass stuff recently for my own amusement

misty wolf
#

Oh that's actually cool, I didn't know you could do that :o

boreal umbra
#

I guess this is calling __init_sublcass__ of each class in the new class's MRO?

deft pagoda
#

you can pick up the kwargs in __init_subclass__ or you can grab them in __new__ of the metaclass if you define it there

boreal umbra
#

speaking of which

deft pagoda
#

yeah, __init_subclass__ gets called before any of the subclasses body

boreal umbra
#

__new__ is a class method that actually does the instantiation, right?

deft pagoda
#

so you can do some major surgery there

boreal umbra
#

if you override __new__ in a subclass, how do you ensure that the instantiation still happens?

deft pagoda
#

yeah __new__ will return the instance

north root
#

__new__ of object creates the instance

boreal umbra
#

so you have to access that through super(), or call object.__new__()?

deft pagoda
#

you can use super

boreal umbra
#

but if you do that

#

do you have to do

#
def __new__(cls):
    new_obj = super().__new__()
    new_obj.__class__ = cls
deft pagoda
#
        return super().__new__(meta, name, bases, methods, **kwargs)
boreal umbra
#

😮

north root
#

isn't that just for type salt?

deft pagoda
#

that's for metas

north root
#

for object it's just super().__new__(cls)

#

yeah

boreal umbra
#

hmm

deft pagoda
#

i've been experimenting with automatically binding properties in class defs through metas

#
In [30]: from dispatcher import Dispatcher
    ...: 
    ...: def observer1(instance, name, old, new):
    ...:     print(f'{name} from {instance} changed from {old} to {new}')
    ...: 
    ...: class Relay(Dispatcher, default=0):
    ...:     width: observer1
    ...: 
    ...: relay = Relay()

In [31]: relay.width
Out[31]: 0

In [32]: relay.width = 10
width from width(<width=10, [observer1]>) changed from 0 to 10
north root
#

observers are super cool

#

how's that one work

deft pagoda
#

there's a lot of machinery in Dispatcher

#

the repr is bugging me though

#

i can't figure out what i did for this to happen:

In [60]: Relay.__name__
Out[60]: 'height'
#

oh, i found it

#

i shadowed the name variable in __new__

cinder parrot
#

I had a question, I added mingw 64 bit as my compiler but how do I make a path to it to visual studios

north root
#

that's not related to python, so try one of the off-topic channels

deft pagoda
north root
#

oh nice, that's quite interesting

#

quite a lot of heft under the hood

#

thanks

deft pagoda
#

yeah, it's a pretty deep dive

noble mesa
#

can somebody explain the benefits of using lambda?

#

I keep seeing it in a lot of code practice, and I don't get it.

crystal pebble
#

It's good when you need a small function in one location

#

Something that wouldn't be worth creating a new regular function for

noble mesa
#

That's fair.

north root
#

useful for the key kwarg in sorted/min/max

noble mesa
#

I haven't used args/kwargs yet

#

I need to look into that

boreal umbra
#
from dataclasses import dataclass

@dataclass
class Student:
    name: str
    grade: float

students = [...]  # list of Student objects
# Get student with highest score
best_student = max(students, key=lambda s: s.grade)
print(best_student)
#

@noble mesa

deft pagoda
#

you can make dataclasses comparable so you don't have to provide a lambda function

boreal umbra
#

but

#

then it wouldn't illustrate how lambdas work

#

and I'd have to come up with a new example

noble mesa
#

ahhh

boreal umbra
#

also you might want to alphabetize your students or something

#

and then you'd have sorted(students, key=lambda s: s.name)

deft pagoda
#
from dataclasses import dataclass, field

@dataclass(order=True)
class Student:
    name: str = field(compare=False)
    grade: float
boreal umbra
#

My example is ruined 😦

noble mesa
#

hahahaha

wide shuttle
#

@boreal umbra I can ruin that even more: use operator.attrgetter instead of a lambda

wide shuttle
#

!e

from operator import attrgetter

class Person:
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    def __repr__(self):
        return f"Person(first_name={self.first_name!r}, last_name={self.last_name!r})"

people = [Person("John", "Wick"), Person("Guido", "Rossum, van"), Person("Lemon", "Beardfist"), Person("Joseph", "Posh"), Person("Charlie", "Wick")]
print(sorted(people, key=attrgetter("last_name", "first_name")))
fallen slateBOT
#

@wide shuttle :white_check_mark: Your eval job has completed with return code 0.

[Person(first_name='Lemon', last_name='Beardfist'), Person(first_name='Joseph', last_name='Posh'), Person(first_name='Guido', last_name='Rossum, van'), Person(first_name='Charlie', last_name='Wick'), Person(first_name='John', last_name='Wick')]
undone hare
deft pagoda
#
from dataclasses import dataclass, field

@dataclass(order=True)
class Person:
    first_name: str = field(compare=False)
    last_name: str = field(compare=False)
    last_first: str = field(init=False, repr=False)

    def __post_init__(self):
        self.last_first = self.last_name, self.first_name
fossil pumice
#

@undone hare that's basically the idea, yes.

deft pagoda
#

there's probably some nicer way to switch the order

wide shuttle
#

@deft pagoda Sure, that's if you always know which attributes you're going to compare, and want to preprocess it

#

If you want to combine attributes of existing objects in a comparison or other thing, that's where operator.attrgetter comes in

#

Or things like itemgetter

deft pagoda
#

also why does the discord syntax highlighter break when a ( directly follows a function

#
print (
print(
wide shuttle
#

It does not break, it just supports "print as a statement" from Python 2

deft pagoda
#

i thought it was highlighting builtins

wide shuttle
#

No, just things like statements and operators

#

If you add a ( after return it doesn't change color, as there's no return-function.

#

It's a special change for print, I think, to make "print-as-function" look like other function calls

deft pagoda
#

well, i'm voting for function highlighting at the next discord syntax meeting

undone hare
#

Maybe one day multi-line decorators will not look weird

#

Oh well, I'd prefer to have a mobile highlighting than anything else

fossil pumice
#

I think the syntax highlighter for python should split into py/python/py3 and py2

#

instead of trying to do both

wide shuttle
#

I do see Python 2 being mentioned less and less. It's not gone away, there are people who still need to maintain legacy systems, but I hardly see anyone singing the tune of "I'm never never never going to use Python 3; it will destroy the language!". Probably becuase it's pretty evident that it's not the case.

#

Most of the mentions I see are either from people using outdated (and free) resources and/or universities/educational institutes that got outdated in their teaching materials

unkempt rock
#

hmm ive seen a few people say that python 2.7 is the best

fossil pumice
#

those people were wrong.

wide shuttle
#

It was quite a common sentiment a few years ago

#

When people were still resisting change

#

I'm not talking about the people who's job suddenly got more difficult by having to migrate, I think most yellers were not in such a position

fossil pumice
#

having worked professionally in a py27 codebase, I have no idea why people say that other than because they don't want to migrate

wide shuttle
#

And then there were books like Python, the Hard Way that gave people a bias just because the author was, well, I don't know, antagonistic to change? stuck?

#

A lot of programming languages evolve over time. If you refuse to accept that, your knowledge is going to get outdated

deft pagoda
#

i missed the transition

oblique crystal
#

A yeah and a half ago when I wrote my first line of python I was reading some article on should I learn py2 or 3. And it made case for py2. Luckily for me I only wrote one small program in py2 and abandoned it for another 4-5 months. And after I got some cheap Udemy course teaching 3

#

And now I am annoyed that In production my company has 3.5 and I can not use fstring

wide shuttle
#

Python, the Hard Way was one of the books I picked up when I tried Python again after a few years

#

It was very biased towards Python 2, so I started with that

#

I regret that decision

oblique crystal
#

Ouch. Within 3.* is there much backwards incompatibility?

#

Like from 3. 5 to 37

wide shuttle
#

There was a bit of a jump pre-3.5 to post-3.5 for asynchronous programming

#

3.5 introduced the async def and await syntax that replaced the older decorator-based coroutines

#

I've not had much issues with migrating code after 3.5

flat gazelle
#

In most cases, py3.x code will run in py3.y if x < y.

wide shuttle
#

Sometimes there are subtle differences that may surprise you

#

Such as that CancelledError is now derived from BaseException instead of Exception in 3.8

#

It's probably a change for the best, but it does mean except Exception won't catch CancelledError (which was the point)

#

There are probably other examples of such small changes that could lead to unexpected differences in behavior

#

Reading the changelog for each minor version would tell you that

#

It's unlikely to be introduced within a minor version

deft pagoda
#

when was __init_subclass__ added

#

probably 3.6 like everything else, if i'm guessing

wide shuttle
#

yes

subtle viper
#

what evn is __init__subclass

wide shuttle
#

It's a very useful method for when you're doing metaprogramming. Whenever you create a subclass of a class implementing __init_subclass__, that method is run, just like __init__ is run when you create an object from a class.

#

A lot of the things that used to require meta classes can now be done with __init_subclass__

fossil pumice
#

does it run both of them?

wide shuttle
#

What do you mean?

#

__init_subclass__ runs when you define the subclass

#

Not when you instantiate an object of the subclass

fossil pumice
#

aha

#

interesting

#

it's news to me

#

that's nice

wide shuttle
#

It's one of those methods that helsp you avoid metacalsses

#

__set_name__ is another one

fossil pumice
#

that's new to me, too

wide shuttle
#

Say that you write a descriptor that needs to know the name of the attribute you're assigning it to

#

The usual way of solving that was by using a meta class

#

Now __set_name__ gets run when you assign a name to something

#

So, you get access to it within this dunder

#

!e

class Foo:
    def __set_name__(self, owner, name):
        print(f"I'm assigned to {owner!r} as attribute {name!r}")


class Bar:
    attribute_name = Foo()
fallen slateBOT
#

@wide shuttle :white_check_mark: Your eval job has completed with return code 0.

I'm assigned to <class '__main__.Bar'> as attribute 'attribute_name'
wide shuttle
#

This is useful for instance when a descriptor wants to store the data in the instance's dict using the attribute name

deft pagoda
#

i have a lengthy demonstration of both in a gist somewhere