[Python-ideas] Re: mro and super don't feel so pythonic
On Wed, 13 Apr 2022 at 15:02, Ganesh B wrote: > > I hope nicer on the code text please. Sure. Sorry about that. malmiteria's "lib" code is ``` class HighGobelin: def scream(self): print("raAaaaAar") class CorruptedGobelin(HighGobelin): def scream(self): print("my corrupted soul makes me wanna scream") super().scream() class ProudGobelin(HighGobelin): def scream(self): print("I ... can't ... contain my scream!") super().scream() ``` Best regards, Takuo Matsuoka > > On Wed, Apr 13, 2022 at 9:21 AM Matsuoka Takuo wrote: >> >> On Wed, 13 Apr 2022 at 04:28, malmiteria wrote: >> > >> > Idk, what do you think? >> >> I would need to see more examples to determine the limit of the >> current strategy for method resolution and super. For the example at >> hand, I can be happy with the following code as a lib user (using your >> lib code). >> >> ``` >> class Proud_base(HighGobelin): >> scream = HighGobelin.scream >> >> class ProudGobelin_floating(ProudGobelin, Proud_base): >> pass >> >> class HalfBreed(ProudGobelin_floating, CorrupteGobelin): >> def scream(self): >> if random.choices([True, False]): >> super(HalfBreed, self).scream() >> else: >> super(Proud_base, self).scream() >> ``` >> >> Best regards, >> Takuo >> ___ >> Python-ideas mailing list -- python-ideas@python.org >> To unsubscribe send an email to python-ideas-le...@python.org >> https://mail.python.org/mailman3/lists/python-ideas.python.org/ >> Message archived at >> https://mail.python.org/archives/list/python-ideas@python.org/message/K63MS6XAS3OXGYDU4N47VIFMPNAWX2Z7/ >> Code of Conduct: http://python.org/psf/codeofconduct/ ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/PX3LKNVFKHIE2MH7BYHC4JZT2E24TQQN/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Wed, 13 Apr 2022 at 04:28, malmiteria wrote: > > Idk, what do you think? I would need to see more examples to determine the limit of the current strategy for method resolution and super. For the example at hand, I can be happy with the following code as a lib user (using your lib code). ``` class Proud_base(HighGobelin): scream = HighGobelin.scream class ProudGobelin_floating(ProudGobelin, Proud_base): pass class HalfBreed(ProudGobelin_floating, CorrupteGobelin): def scream(self): if random.choices([True, False]): super(HalfBreed, self).scream() else: super(Proud_base, self).scream() ``` Best regards, Takuo ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/K63MS6XAS3OXGYDU4N47VIFMPNAWX2Z7/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 4/12/2022 12:57 PM, malmiteria wrote: So the amount of actual breakings left shouldn't be enough to justify denying this feature IMO. Again, we'll have a clearer view on that once we get experimental data. What's to look for is usage of super in MI cases, since each super call in MI today should be replaced by one super call per parent, in my proposal. If this turns out to be an issue, we can try to imagine solution for it. Maybe a solution such as : super calls implicitely run a super call to each parent when there's multiple parent, and super isn't given arguments. This i think would behave strictly as today's super + MRO, except for cases where one class appears multiple time in an inheritance tree. The last breaking change would be that scenario, class appearing multiple time in an inheritance tree. And we're getting on even rarer occasions here, but again, we can think of solutions here. I have code in a non-public repository that your proposed change will break. I'm sure I'm not the only one. It is not realistic to implement a change like this that will break code and then say "there's a workaround that you'll need to implement". Especially for library code that needs to run across multiple python versions. As much as i understand we don't want breaking change, i don't think it is *that* strong an argument, in this case. And, on its own, breaking changes aren't a strict veto, there's been some, and there's gonna be more. As a long-time core developer, I can assure you that this is one of those cases where a breaking change will not be allowed. I'm trying to save you some time here, but if you're committed to continuing this, then you can't say you weren't warned when it's ultimately rejected. My suggestion is to rework your proposal to not break any existing code. It's a constraint we've all had to live with at one time or another, as much as we don't like it. Eric ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/KWXDZBGZBX3LLCP3FQ33T27YUXDKXXL5/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Tue, Apr 12, 2022, 4:31 PM Steven D'Aprano > Except the most important one: why are you using multiple inheritence when > you clearly don't want multiple inheritence, instead you want delegation? > I'll note that hundreds of posts ago, I made the FIRST reply to this silliness, and that it 100% explained every single needless digression that followed: > If you want to explicitly delegate a method to a class, you should explicitly delegate a method to a class. > This is exactly why a lot of folks feel composition is better than inheritance (at least often so). > You don't need `super()` to call `SomeSpecificClass.method(self, other, args)` I also co-authored a widely read article on then-new C3 linearization in Python with Michele Simianato before he wrote his really great explanation of it in the Python docs, and his also great 15+ year old pieces on traits ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/T3TAQ46HJ2LATLPYEP36LRLEZEA5YYCH/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 2022-04-12 11:02, malmiteria wrote: My proposal would completely detach method resolution from calls to super. essentially: ``` class A: val = 1 class B: val = 2 class C(A,B): pass C.val # raises an explicitness required error ``` If you think you can come up with code that would break under my proposal, hit me. I wanna have the least amount of breaking change. You just showed an example in your own message. The behavior of `C.val` is already defined in that case (it evaluates to 1). If you change it so it now raises an error, that's a breaking change. -- Brendan Barnwell "Do not follow where the path may lead. Go, instead, where there is no path, and leave a trail." --author unknown ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/DE5NY7GLE6TPITTF7DW4ASQMKOSYT7JK/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Tue, Apr 12, 2022 at 11:17:27AM -, malmiteria wrote: > Steven D'Aprano writes: > > > So in the general case, order matters. We have to linearize the > > superclasses, and call them in that linear order, and the best way to do > > that is with the MRO and super. > Why would we *have* to do that? Because if you don't, you aren't doing multiple inheritence. If you don't want MI, if you want delegation or composition, then of course you can do something else. But if you want MI in its full generality, that's really the only thing you can do. > When multiple parent provide candidate to a method resolution, raise an error. Then you aren't doing full MI any more, just a limited, restricted version known as traits. > The child class now has to redefine the method, and in the body of that > method, can decide which parent method call, or in what order call them. > That's essentially the basic idea of my proposal. > What makes this impossible for you? Its not impossible, I have been telling you about traits since my earliest posts in this thread. Maybe you need to stop thinking you have invented some brilliant idea which has solved a problem nobody else has noticed, and read some of the Artima links I have days ago. > I think i've adressed most if not all problems i had raised against it. Except the most important one: why are you using multiple inheritence when you clearly don't want multiple inheritence, instead you want delegation? > Linearisation is litterally an operation that consist into converting > a multiple inheritance tree into a simple inheritance tree. That is absolutely not what linearization does. > That's bound to lose some info, No, the point of linearization is to avoid losing info. > and can't cover all cases. Correct, there are inconsistent inheritence hierarchy which are impossible to linearise because they are inconsistent. It is better to get an error when you try to define the inconsistent hierarchy, rather than pretend it is consistent and then wonder why inheritence is not working and methods are called in inconsistent order. -- Steve ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/A3V2OYAD4USX64BAL7JMRDIFYUM2KLWD/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Eric V. Smith writes: > I've said this before, but I'll repeat it here: if your proposal is to > have super().something raise an error if "something" exists on more than > one parent class (via the MRO), then that's a breaking change and it > will not be accepted. The expliciteness required error should be raise at attribute / method access, not through super. My proposal would completely detach method resolution from calls to super. essentially: ``` class A: val = 1 class B: val = 2 class C(A,B): pass C.val # raises an explicitness required error ``` It's fair to assume super would need to know what parent class it should target however, especially since part of my proposal is to make it so that super can take as an argument the class it targets, instead of the previous in MRO order, but that is not something i consider an "active" part of my proposal (the idea that super needs to be passed a parent as argument in case of MI). As i was answering Ronald Oussoren, i figured that in case of MI, a call to super with no argument could simply loop over call to super with each parent, one after the other. That would keep it a nice way to tell "go fetch all parents behaviors" without having to write down one line per parent. I think it would behave 'strictly' as today's super calls, except in cases where one class appears multiple time in the inheritance tree (and is visited through calls to super). For those scenarios, i have a dedicated answer. Your exemple actually is one of those cases, since calls to super do visit the object parent class. Let's start with super() implicitelly calling super on all parents one after the other. ``` class A: def foo(self): print("A") try: super().foo() except AttributeError: print('no parent defines foo') class B: def foo(self): print("B") try: super().foo() except AttributeError: print('no parent defines foo') class C(A, B): def foo(self): print("C") super().foo() C().foo() ``` This would output (not accounting for the parent appearing multiple time proposal) : ``` C A no parent defines foo B no parent defines foo ``` in this case, C would be equivalent to, (but not require any rewrites): ``` class C(A, B): def foo(self): print("C") super(A, self).foo() super(B, self).foo() # keep in mind, in my proposal, the class passed as an argument is the one we target. ``` I occasionally write it down without the self, or with self.__as_parent__(..) but overall, i'm fine with super(class, self), as long as the class is the target, not the previous to the target in MRO order. You get the idea. If accounting for the parent appearing multiple time (i'll just call it the diamond case for now) my proposal for those is to have a module strats, that would allow to decide what occurence of a reoccuring parent should be visited or not. the default strat would be 'last', as to match the current behavior. Idk exactly what API is the better for this proposal, but since the goal is for it to default to today's behavior, we wouldn't need to write down anything related to it in this scenario, we would get that output ``` C A B no parent defines foo ``` Which is the one you want. TLDR: with my full proposal, the code you presented me won't break. It won't even change behavior at all. Or in other term, I acknowledge breaking changes are bad, but they're not impossible to cover for. And i think i have covered for it fairly extensively. If you think you can come up with code that would break under my proposal, hit me. I wanna have the least amount of breaking change. And as much as possible, i wanna cover for those breaking changes, to find a way to update my proposal, so those aren't breaking changes anymore. One thing i can think of rn is that calls to super in classes without parent would turn out to break with my proposal, since they would now refer to object anytime. That needs covering up too, and i'll be thinking on that one too. Like i've done for every scenario i've been opposed with so far, i think. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/SV4F7I2XNX3A2YCQ747TJW3XJF5CS2LF/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Tue, Apr 12, 2022 at 1:59 PM malmiteria wrote: > Ronald Oussoren writes: > > > To be blunt: That’s not going to happen because this is big backward > compatibility break. Either that, or this adds a > > second way to define classes. Both are good reasons to keep the status > quo. > > the breaking is limited MI with name collision, so likely rare enough, and > i've already mentionned that i'm perfectly willing to implement my proposal > and run it against whatever selection of python repos, to check for real > life exemple of breakings, so we can measure how bad it would actually be. > Sorry. I thought we were past this point and you had understood and agreed that any change in this respect would not change the current behavior of MRO and super, requiring either a different call than super, and/or a different metaclass for all the hierarchy, to start with. TL;DR: ***Changing the current behavior of super itself or the MRO formula is just not going to happen.*** And it is not me saying this. If you won't spare replying on the list, you can spare yourself from checking "whether this would break things". It would. But even if it does not break a particular project, that is not negotiable. And I am not saying that these changes,even as "add-ons" to the language are being considered either - IMHO you failed so far in presenting any evidence of your point or more people that would ask for the features you are proposing. The playful example you brought here with the Gobelin hierarchy, for example, could be addressed with a multitude of approaches, including custom-metaclases and even `__init_subclass__` methods, that would collect the methods with "name collision" and allow one to select a strategy when calling them. So, a custom base class or custom metaclass could attend your needs - and that does not need to live in the language core. > The most common case of breaking would be the django style mixins, which i > propose a dedicated feature for, adoption. > Essentially a way to declare more than your parent, but their parents too, > recursively. > would look like that: > ``` > class A(B(C)): ... > ``` > the adoption syntax is non breaking, as it's simply an addition to the > language, and has values on its own. > I'll make a dedicated post, but i'm a bit out of time for that now, > especially since i'm getting the survey ready. > I'll add some question to get infos that could help debate this feature > too, so i guess i'll wait for the survey result. > > Once adoption is ... adopted, and start getting used, the more it goes on, > the less breaking change will occur. > > And, on top of that, the actual change needed to switch from today's > solution to adoption is extremly simple. > replace > ``` > class A(B,C): ... > ``` > with > ``` > class A(B(C)): ... > ``` > That's it. > > So the amount of actual breakings left shouldn't be enough to justify > denying this feature IMO. Again, we'll have a clearer view on that once we > get experimental data. > What's to look for is usage of super in MI cases, since each super call in > MI today should be replaced by one super call per parent, in my proposal. > If this turns out to be an issue, we can try to imagine solution for it. > Maybe a solution such as : super calls implicitely run a super call to each > parent when there's multiple parent, and super isn't given arguments. This > i think would behave strictly as today's super + MRO, except for cases > where one class appears multiple time in an inheritance tree. > The last breaking change would be that scenario, class appearing multiple > time in an inheritance tree. > And we're getting on even rarer occasions here, but again, we can think of > solutions here. > > As much as i understand we don't want breaking change, i don't think it is > *that* strong an argument, in this case. > And, on its own, breaking changes aren't a strict veto, there's been some, > and there's gonna be more. > Overall, they are an upgrade cost we really wanna make as less expensive > as possible, but an worthwhile upgrade overcomes the upgrade costs. And, if > it improves something, the longer we wait, the more the current behavior > can deal its damage, it should be considered in the balance too. > Breaking changes are an momentary cost, while not upgrading might have a > smaller, but constant cost. > ___ > Python-ideas mailing list -- python-ideas@python.org > To unsubscribe send an email to python-ideas-le...@python.org > https://mail.python.org/mailman3/lists/python-ideas.python.org/ > Message archived at > https://mail.python.org/archives/list/python-ideas@python.org/message/LP22REU3YWWLRDOTKAZMTCC5EMHYP53A/ > Code of Conduct: http://python.org/psf/codeofconduct/ > ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org
[Python-ideas] Re: mro and super don't feel so pythonic
A general note on breaking changes: On Wed, 13 Apr 2022 at 03:01, malmiteria wrote: > > Ronald Oussoren writes: > > > To be blunt: That’s not going to happen because this is big backward > > compatibility break. Either that, or this adds a > > second way to define classes. Both are good reasons to keep the status quo. > > the breaking is limited MI with name collision, so likely rare enough, and > i've already mentionned that i'm perfectly willing to implement my proposal > and run it against whatever selection of python repos, to check for real life > exemple of breakings, so we can measure how bad it would actually be. > The most common case of breaking would be the django style mixins, which i > propose a dedicated feature for, adoption. > Essentially a way to declare more than your parent, but their parents too, > recursively. > would look like that: > ``` > class A(B(C)): ... > ``` > the adoption syntax is non breaking, as it's simply an addition to the > language, and has values on its own. > I'll make a dedicated post, but i'm a bit out of time for that now, > especially since i'm getting the survey ready. > I'll add some question to get infos that could help debate this feature too, > so i guess i'll wait for the survey result. > > Once adoption is ... adopted, and start getting used, the more it goes on, > the less breaking change will occur. > > And, on top of that, the actual change needed to switch from today's solution > to adoption is extremly simple. > replace > ``` > class A(B,C): ... > ``` > with > ``` > class A(B(C)): ... > ``` > That's it. This is a major problem for cross-version compatibility. If you make a breaking change in Python 3.42, the question must be: How should code be written that supports both 3.41 and 3.42? A breaking change that is supported by the older version is annoying, but can be acceptable if it's worth it. For example, this code works on Python 3.9, but not on Python 3.10: >>> import traceback >>> traceback.format_exception(etype=None, value=Exception(), tb=None) ['Exception\n'] But if this is a problem to your code, you can simply switch to positional arguments, and it will work on both versions: >>> traceback.format_exception(None, Exception(), None) ['Exception\n'] A proposal that breaks existing code, and which introduces a new way to do things, will usually require multiple versions of deprecation time in order to be accepted. Taking another example from exception handling, Python 2.5 and older use this syntax: try: spam() except Exception, e: print("Got an exception") print(e) Python 3.0 and later use this syntax: try: spam() except Exception as e: print("Got an exception") print(e) But in between, Python 2.6 and 2.7 are able to accept both forms. > As much as i understand we don't want breaking change, i don't think it is > *that* strong an argument, in this case. > And, on its own, breaking changes aren't a strict veto, there's been some, > and there's gonna be more. It is a VERY strong argument, but it can be answered by showing that the breakage can be managed. That usually means either a compatibility period, or a means of continuing to use the older syntax. > Overall, they are an upgrade cost we really wanna make as less expensive as > possible, but an worthwhile upgrade overcomes the upgrade costs. And, if it > improves something, the longer we wait, the more the current behavior can > deal its damage, it should be considered in the balance too. > Breaking changes are an momentary cost, while not upgrading might have a > smaller, but constant cost. > No, they are not a momentary cost; they are an ongoing cost for as long as any application or library needs to support both pre-change and post-change Python interpreters. Backward incompatibility demands a high justification. In the case of the "except Exception, e:" syntax, the justification is that it is confusingly similar to "except (Exception1, Exception2):" in a way that causes hard-to-debug problems. Don't simply dismiss the concern; answer it by showing the need that justifies it. ChrisA ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/PE5P4FLYWC3B3D5RP7YCCMN5P7ZNNFXI/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Matsuoka Takuo writes: > I don't think this is better than the failing code in any way. It > will fail in the same way. Yeah! i completely forgot that :p I've been redoing this exemple so many times now, it's hard to always keep the brain turned on when writing it. Thanks for pointing it out. > I think she should have done as follows, and > that's close to the solution I shared with you first. I understand that this solution works, as in, it provides a way for the lib user's to make HalfBreed work as intended. But i think that it requires way too much efforts, and essentially hints at a flaw of today's design. With my proposal, you wouldn't have to change the lib at all: ``` class HighGobelin: def scream(self): print("raAaaaAar") class CorruptedGobelin(HighGobelin): def scream(self): print("my corrupted soul makes me wanna scream") super().scream() class ProudGobelin(HighGobelin): def scream(self): print("I ... can't ... contain my scream!") super().scream() ``` would be enough. A lib user could write : ``` class HalfBreed(ProudGobelin, CorruptedGobelin): def scream(self): if random.choice([True, False]): super(ProudGobelin, self).scream() # OR : super(ProudGobelin).scream() # OR : self.__as_parent__(ProudGobelin).scream(), in the toy implementation i made here : https://github.com/malmiteria/super-alternative-to-super/blob/master/parent.py else: super(CorruptedGobelin, self).scream() ``` This would work like intended. Of course the question now is, how do we limit the breaking changes, and how to we leave open the option to have a class appearing multiple time in an inheritance tree called only once through super, as it is today's behavior, and is sometimes what we want. That's what i'm most unclear on, maybe we could have a class attribute, or a method decorator. Maybe we could add an argument to super, idk. The point would be to be able to specify somewhere the strategy we wanna use for parent appearing multiple times. maybe something like that would work fine: ``` import strat class HalfBreed(ProudGobelin, CorruptedGobelin): __visit_reoccuring_parents__ = strat.last def scream(self): ... (same as before) ``` or ``` import strat class HalfBreed(ProudGobelin, CorruptedGobelin): @visit_reoccuring_parents(strat.last) def scream(self): ... (same as before) ``` where available strats would be "last", "all", and maybe "only_after", where we would be able to specify which occurence should be visited. the decorator allows a method specific selection, the class attribute doesn't, so maybe the decorator is better. Idk, what do you think? Overall what matters to me is that we can chose the strat in case a parent appears multiple time in an inheritance tree, and that we can set the default strat to match today's strat. The implementation details, and overall API, i don't know exactly what they should look like. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/BDKMW6ICH47WQONXXNZQBCHKPSA2BBGR/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Native support for units
On 4/12/22 00:57, Stephen J. Turnbull wrote: Ethan Furman writes: 15mpg * 7l == how many miles? Now it's my turn to not understand the point of this example. My point is that when an object is instantiated it can normalize its arguments, and that that normalization should happen with the original value (7 above, not 105), so when I put the above into the REPL I get `27 miles` instead of `105 l*mpg`. Now, it could easily be that more advanced uses of units (torque vs force? or whatever was mentioned some time ago) would work better with the intermediate results being more in flux (quantum mechanics, anyone? heh) with the final units being selected later (perhaps somebody wants kilometers instead of miles in the above example). To rephrase my original point: `7_litres` is a different thing than `105_litres_mpg` -- is that a meaningless difference? I don't know. -- ~Ethan~ ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/R2QPBEEXQHSST2OH4KTTHJVVGFGGQDPS/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Ronald Oussoren writes: > To be blunt: That’s not going to happen because this is big backward > compatibility break. Either that, or this adds a > second way to define classes. Both are good reasons to keep the status quo. the breaking is limited MI with name collision, so likely rare enough, and i've already mentionned that i'm perfectly willing to implement my proposal and run it against whatever selection of python repos, to check for real life exemple of breakings, so we can measure how bad it would actually be. The most common case of breaking would be the django style mixins, which i propose a dedicated feature for, adoption. Essentially a way to declare more than your parent, but their parents too, recursively. would look like that: ``` class A(B(C)): ... ``` the adoption syntax is non breaking, as it's simply an addition to the language, and has values on its own. I'll make a dedicated post, but i'm a bit out of time for that now, especially since i'm getting the survey ready. I'll add some question to get infos that could help debate this feature too, so i guess i'll wait for the survey result. Once adoption is ... adopted, and start getting used, the more it goes on, the less breaking change will occur. And, on top of that, the actual change needed to switch from today's solution to adoption is extremly simple. replace ``` class A(B,C): ... ``` with ``` class A(B(C)): ... ``` That's it. So the amount of actual breakings left shouldn't be enough to justify denying this feature IMO. Again, we'll have a clearer view on that once we get experimental data. What's to look for is usage of super in MI cases, since each super call in MI today should be replaced by one super call per parent, in my proposal. If this turns out to be an issue, we can try to imagine solution for it. Maybe a solution such as : super calls implicitely run a super call to each parent when there's multiple parent, and super isn't given arguments. This i think would behave strictly as today's super + MRO, except for cases where one class appears multiple time in an inheritance tree. The last breaking change would be that scenario, class appearing multiple time in an inheritance tree. And we're getting on even rarer occasions here, but again, we can think of solutions here. As much as i understand we don't want breaking change, i don't think it is *that* strong an argument, in this case. And, on its own, breaking changes aren't a strict veto, there's been some, and there's gonna be more. Overall, they are an upgrade cost we really wanna make as less expensive as possible, but an worthwhile upgrade overcomes the upgrade costs. And, if it improves something, the longer we wait, the more the current behavior can deal its damage, it should be considered in the balance too. Breaking changes are an momentary cost, while not upgrading might have a smaller, but constant cost. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/LP22REU3YWWLRDOTKAZMTCC5EMHYP53A/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On Wed, 13 Apr 2022 at 02:00, Matsuoka Takuo wrote: > > Thanks for your answer. > > On Mon, 11 Apr 2022 at 00:46, malmiteria wrote: > > > > There's a few problems, mainly, if you provide ProudGobelin and > > CorruptedGobelin as a lib author, you're very likely not to think of the > > HalfBreed use case, so the lib users wanting to create the HalfBreed class > > is bared from this solution, as it requires some work on ProudGobelin and > > CorruptedGobelin classes. Actually, now I see. It's the lib author's fault. She went against DRY in defining CorruptedGobelin and ProudGobelin as unrelated subclasses of HighGobelin when they had a common structure, unless she intended to make things like the "failing" version of HalfBreed easier to create. Otherwise, I think she should have done as follows, and that's close to the solution I shared with you first. ``` class HighGobelin: def scream(self): print("raAaaaAar") class SpeakingGobelin(HighGobelin): def scream(self): self._speak() super().scream() def _speak(self): return class CorruptedGobelin(SpeakingGobelin): def _speak(self): print("my corrupted soul makes me wanna scream") class ProudGobelin(SpeakingGobelin): def _speak(self): print("I ... can't ... contain my scream!") ``` Best regards, Takuo ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/KTXAPEKGLCP5LS3FJYQXBZIF7ZM5AERI/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Native support for units [was: custom literals]
On Tue, Apr 12, 2022 at 11:27 AM Christopher Barker wrote: > > > I guess you could call the associative law of multiplication "dumb >> > > luck", but most mathematicians will consider that hate speech. >> > >> > My apologies for not understanding your example. The counter >> > example I had in my head, and should have written down, >> > was something like: >> > >> >15mpg * 7l == how many miles? >> > > Using pint: > > In [76]: U = pint.UnitRegistry() > > In [77]: (15 * U.miles / U.gallons * 7 * U.liter).to('miles') > Out[77]: 27.7380654976056 > > A bit verbose, perhaps, but to me clear, and the operator precedence rules > seem to "just work". > > And it you want it a tad less verbose, you can give some of those units > names: > > In [78]: mpg = U.miles / U.gallons > In [79]: l = U.liter > > In [80]: (15 * mpg * 7 * l).to('miles') > Out[80]: 27.7380654976056 > > My question for the folks that want units built in to Python is "what's so > hard about that? > > Ricky wrote: > > "Python is so painful to use for units I've actually avoided it," > > Really? have you tried pint? or anything else? what is so painful about > this? > > -CHB > > -- > Christopher Barker, PhD (Chris) > I will try to finish my email about this I started writing a week ago! --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/SO456QXMDO6TSCIFYVOX4AHGECFLCMAB/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Native support for units [was: custom literals]
> > > > I guess you could call the associative law of multiplication "dumb > > > luck", but most mathematicians will consider that hate speech. > > > > My apologies for not understanding your example. The counter > > example I had in my head, and should have written down, > > was something like: > > > >15mpg * 7l == how many miles? > Using pint: In [76]: U = pint.UnitRegistry() In [77]: (15 * U.miles / U.gallons * 7 * U.liter).to('miles') Out[77]: 27.7380654976056 A bit verbose, perhaps, but to me clear, and the operator precedence rules seem to "just work". And it you want it a tad less verbose, you can give some of those units names: In [78]: mpg = U.miles / U.gallons In [79]: l = U.liter In [80]: (15 * mpg * 7 * l).to('miles') Out[80]: 27.7380654976056 My question for the folks that want units built in to Python is "what's so hard about that? Ricky wrote: "Python is so painful to use for units I've actually avoided it," Really? have you tried pint? or anything else? what is so painful about this? -CHB -- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/4UB6TGEPEKJTXPPXZ7ZH2OHTWJWMEZ3X/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
On 4/12/2022 7:43 AM, malmiteria wrote: Brendan Barnwell writes: You seem to be envisioning a system in which multiple inheritance gives a subclass a "menu" of behaviors from which it may explicitly choose, but does not actually combine the superclasses' behaviors into a single, definite behavior of the subclass. In that scheme, order of multiple inheritance would not matter, because the superclasses don't need to be "integrated" into the subclass; they just sit there waiting for the subclass to explicitly decide which superclass it wants to delegate to. not sure i had time to answer this one yet, so here we are. I do not want any change in case of simple inheritance, nor do i want any change in case of MI where there's no name collision. The integration of parent class would be the exact same in those cases. And if you doubt it, my proposal, about method resolution, is that if there's only one candidate for resolution, we select it, if there's none, we raise the standard attribute error, and if there's multiple, we raise an explicitness required error. In case of MI where there's no name collision, aka, there's never more than one candidate for resolution, the behavior would be the exact same. Expliciteness is required only in case there's multiple candidates for resolution. I've said this before, but I'll repeat it here: if your proposal is to have super().something raise an error if "something" exists on more than one parent class (via the MRO), then that's a breaking change and it will not be accepted. This code: ``` class A: def foo(self): print("A") try: super().foo() except AttributeError: print('no parent defines foo') class B: def foo(self): print("B") try: super().foo() except AttributeError: print('no parent defines foo') class C(A, B): def foo(self): print("C") super().foo() C().foo() ``` Must continue to output: ``` C A B no parent defines foo ``` Eric ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/RM4HPZV7MAQTKDMEDZSVAD7K2JIPKMXI/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
> On 12 Apr 2022, at 13:17, malmiteria wrote: > > Steven D'Aprano writes: > >> So in the general case, order matters. We have to linearize the >> superclasses, and call them in that linear order, and the best way to do >> that is with the MRO and super. > Why would we *have* to do that? > When multiple parent provide candidate to a method resolution, raise an error. > The child class now has to redefine the method, and in the body of that > method, can decide which parent method call, or in what order call them. > That's essentially the basic idea of my proposal. To be blunt: That’s not going to happen because this is big backward compatibility break. Either that, or this adds a second way to define classes. Both are good reasons to keep the status quo. You’re of course free to create a library that checks for this at runtime, or as a lint tool. Ronald — Twitter / micro.blog: @ronaldoussoren Blog: https://blog.ronaldoussoren.net/ ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/K4L3SQGKZX2IUKXTSJQLYO53WIQZJJZB/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Thanks for your answer. On Mon, 11 Apr 2022 at 00:46, malmiteria wrote: > > There's a few problems, mainly, if you provide ProudGobelin and > CorruptedGobelin as a lib author, you're very likely not to think of the > HalfBreed use case, so the lib users wanting to create the HalfBreed class is > bared from this solution, as it requires some work on ProudGobelin and > CorruptedGobelin classes. Starting from the "lib" definitions of HighGobelin, CorruptedGobelin and ProudGobelin you originally wrote, the lib user can surely have a similar solution, but, it will take many more (though straightforward) steps. So, if the lib code was that, MRO doesn't seem to be the most helpful thing for the lib user. (I assume, with your solution, the other behaviour of HalfBreed, that is, the original behaviour of it with the "failing" code, can also be achieved as easily in the case where that is what the lib user wants. Does this hold?) By the way, On Mon, 4 Apr 2022 at 02:11, malmiteria wrote: > > Getting the correct behavior requires to let go of super, in such a way: > > > ``` > class HalfBreed(ProudGobelin, CorrupteGobelin): > def scream(self): > if random.choices([True, False]): > ProudGobelin.scream(self) > else: > CorrupteGobelin.scream(self) > ``` I don't think this is better than the failing code in any way. It will fail in the same way. If you stopped using super in ProudGobelin.scream, then you would have been good, even though that's not necessary as I already said. The lib user can't complain the use of super when it does the job for the lib author, but what I felt from the example is there might be some notion of abuse of super, perhaps. Best regards, Takuo Matsuoka ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/L5CEOFISOPJDMPUPE6KQDT7OBDT3LPQ5/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Steven D'Aprano writes: > Do you think that the order of arguments in func(a, b) doesn't matter? Actually it doesn't: ``` def func(a, b): print(a) print(b) func(b=10, a=5) ``` would print 5, then 10 But i get what you mean, and i know very much it matters here. > One of the reasons why this discussion isn't going anywhere is that we > agree that MI is difficult, but your "solution" to that is to make > super() even more complex, with even more to learn, so that people can > use MI in even more cases of problems which are better solved with > another technique. I disagree, assuming all my proposal passes, super would be completely untied from MRO, which is the toughest nut to crack, it would allow to target the class you pass as an argument, which makes it much more straightforward to use than today. If we only add a kwarg target to super for example, then maybe it complexifies the design of super, but not it's uses. They would be able to use it in more cases, sure, but the actual uses cases of today would also be easier to deal with. if today some cases are hard to solve with MI, and tomorrow those same cases are hard to solve with MI, but the other cases got simpler, isn't that an improvment? perhaps it's way to abstract now, would we benefit in this discussion from having some toy implementation of it so we could compare before / after? > It is like you only have one tool in your toolbox, super, and you want > to solve every problem with it. It's more like you're given only one tool, and you realise it doesn't work well. But not everyone knows where to look for better tools. And we're here to design the toolbox, so let's adress this problem. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/2VMDN7ISEXP7ARHZ6B3V25SBS36WTEXI/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Brendan Barnwell writes: > You seem to be envisioning a system in which multiple inheritance > gives a subclass a "menu" of behaviors from which it may explicitly choose, > but does not actually combine the superclasses' behaviors into a single, > definite behavior of the subclass. In that scheme, order of multiple > inheritance would not matter, because the superclasses don't need to be > "integrated" into the subclass; they just sit there waiting for the > subclass to explicitly decide which superclass it wants to delegate to. not sure i had time to answer this one yet, so here we are. I do not want any change in case of simple inheritance, nor do i want any change in case of MI where there's no name collision. The integration of parent class would be the exact same in those cases. And if you doubt it, my proposal, about method resolution, is that if there's only one candidate for resolution, we select it, if there's none, we raise the standard attribute error, and if there's multiple, we raise an explicitness required error. In case of MI where there's no name collision, aka, there's never more than one candidate for resolution, the behavior would be the exact same. Expliciteness is required only in case there's multiple candidates for resolution. Also, super, or the equivalent i named __as_parent__ in my poc, would be able to target the parent class it's given as an argument, as well as implicitely chose the only parent, when there's only one parent. Order of the parent doesn't matter, because we just don't need it anymore. Not because we're not integrating the parents. > they just sit there waiting for the > subclass to explicitly decide which superclass it wants to delegate to. Implicitness would still be the overall norm. > When a subclass inherits from multiple superclasses, the > superclass behaviors are *combined* into a *single* set of behaviors for > the subclass. They're not "held separate" somehow as alternative > inheritance hierarchies; they are joined into one. Demonstrably false: ``` class Dad: age = 65 class Mom: age = 61 class Son(Dad, Mom): pass ``` Son.age is definitely not a combination of Dad's and Mom's age Same apply for methods, they only "combine" assuming Dad's method calls super. Which it's likely not to if it's meant to run independant instances, as it doesn't have parent itself. But it is possible to have those behavior combine, yeah. > They're not "held separate" somehow as alternative > inheritance hierarchies; they are joined into one. All but one are ignored, and that one has the responsibility to care about the others. The design i propose would make the responsibility of "caring" about all its parent to the class inheriting from them. Which localises the responsibility a bit better i think, and definitely allows for actual integration of multiple class into one, at least as well as today's solution. There's probably a joke about parents ignoring conflict so much it leads to divorce somewhere in there. > I don't want to sound harsh, but if `class A(B, > C)` doesn't "feel" different to you from `class(C, B)` then I think you > need to adjust your feelings rather than expect Python to adjust its > behavior. You're absolutely not harsh, you're actually quite respectful. Disagrement is not an insult. I think that python is (at least know to be) a language that cares about making it the easiest to program. Or that it's made to be easy to learn. Essentially, that it always cared about having a very reliable UX design, not that it named it UX design, but that's at the core of python values. I believe the change i propose goes very well with those values / goals of python, and wouldn't be out of place in python. I don't believe it's as clear cut as you say it is, honestly. As much as i understand the feeling 'perhaps its time you learn', i don't believe it applies here, since it's a commonly misunderstood feature. If i were the actual only one guy who didn't understand it, sure. But that's not the case. And at some point, we gotta look at the feature itself. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/G7EEFAWMODTAUZKW63VRJANEG2CU5B7B/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Steven D'Aprano writes: > So in the general case, order matters. We have to linearize the > superclasses, and call them in that linear order, and the best way to do > that is with the MRO and super. Why would we *have* to do that? When multiple parent provide candidate to a method resolution, raise an error. The child class now has to redefine the method, and in the body of that method, can decide which parent method call, or in what order call them. That's essentially the basic idea of my proposal. What makes this impossible for you? I think i've adressed most if not all problems i had raised against it. This gives much more power to python users, clarifies possible missed name collisions and changes absolutely nothing on SI. And why do you say MRO and super is the best way to do that? If you mean it's the best way to do linearisation fine, but if you're saying it's the best way to do method / attribute resolution, i disagree. Linearisation is litterally an operation that consist into converting a multiple inheritance tree into a simple inheritance tree. That's bound to lose some info, and can't cover all cases. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/QESYIA72COVSP4YIJEZJH6SJMALV566U/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: mro and super don't feel so pythonic
Steven D'Aprano writes: > In any case, how do you know what "most people" think? Have you done a > survey, or are you just guessing? I haven't done a survey, but I'm getting one ready, I also wanna let you all have a read at it before running it, so we can all agree the data we would get from it are meaningful, if that's okay with you. I am not guessing either however, knowledge is formed in a somewhat deterministic way, and UX design to some extent plays a role in it. You are very likely to form knowledge coherent with what you experience, and the most experience in case of use of super is simple inheritance, which means you're likely to learn a lot about super and SI before you face a MI case, in which, you'd have only the SI experience to build off of an expectation. > Actually, we are defining arguments to be passed: the listed > superclasses are passed on to the class metaclass as a tuple, which > preserves order, and the MRO is generated from that ordered tuple. Same problem as before, this is definitely not obvious to most python users, they never have to dive in those metaclasses logics, and therefore, it can't play a role in their understanding of what's happening at class definition. So again, the most common intuition on what happens at class definition would would be very different from the most common intuition about method definition / calls. Essentially, I'm saying that most people intuition is something, and you're answering that this thing almost no one knows about shows otherwise. It doesn't, since they don't know about it. You get my point. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/NH57FNMP3WS3PDS32GJPGKT7ICC53WFQ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Custom literals, a la C++
On Mon, Apr 11, 2022 at 12:22 PM Chris Angelico wrote: > > as oped what I understand was being proposed via a "global registry", > which is that code: > > > > distance = 500[miles] > > > > would work even if there were no name "miles" in that namespace(s) -- > and it would, instead go look for it in the global registry -- which could > have been manipulated by the application to mean nautical miles, or statute > miles, or whatever. > > > > And THAT I think is a bad idea. > > It's a good thing we don't have a mutable builtins module, then. Oh right. > :) > Python is a highly dynamic, you can monkey patch the heck out of almost anything -- you surely don't think is a good programming practice to alter the behavior of builtins at the "program" level ? > > > use my_units_system's definition of miles in that module without having > explicitly imported the name. > > > > The trouble is, you now force everyone to do bulk imports - almost > certainly star imports. How are you going to populate the namespace > appropriately if not with a star import? What happens if you don't > want the entire contents of the module? > 1) if you really want really easy to write units, then user, use star imports. But most code is going to use what, a half a dozen (or less) units? is it so bad to write: from my_unit_system import miles, ft, kg, lbs, gallons or: import my_unit_sytem as U and go from there -- frankly, it's how most of PYthon already works. If you want a quick and easy uit-aware calculator -- then write an application or pre-processor for the code. > Having a registry means you can get finer granularity with > registration functions, without a massively complex module and > submodule system, or heaps of manual imports. > if there were a way to use a module level registry that sure -- I'm not sure that's possible or easy, but please don't make it global so that when I write code in a library, I have no idea what context I'll be working in. But honestly, I don't think I like the idea -- but no one has actually fleshed out exactly how it would work -- so maybe I would like the actual proposal -- who knows? But I would hope that if anyone does come up with a proposal, they will address the core issue I'm harping on here: when I write code that may be run in the context of someone else's "application" (or my own, two years later :-) ) -- I want to know exactly what the unit calculations will mean, and that they won't be messed with at run time by a standard recommended practice. -CHB -- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/6GDVZ3NXYAF75EO7OWMIHOMKDXQDVWEZ/ Code of Conduct: http://python.org/psf/codeofconduct/
[Python-ideas] Re: Native support for units [was: custom literals]
Ethan Furman writes: > On 4/10/22 21:33, Stephen J. Turnbull wrote: > > > I guess you could call the associative law of multiplication "dumb > > luck", but most mathematicians will consider that hate speech. > > My apologies for not understanding your example. The counter > example I had in my head, and should have written down, > was something like: > >15mpg * 7l == how many miles? Now it's my turn to not understand the point of this example. Are you arguing Chris A's point that in some applications you want those conversions done automagically[1], and in other applications you want to get a YouSureYouMeanThatBoss? Exception[2]. :-) Footnotes: [1] American you just bought a car in Detroit MI and it still has the EPA sticker "15mpg" on the window, and now you're in Windsor ON (Canada) looking at the cost of the 7l you put in and wondering if you can get back home to Ann Arbor MI on that. [2] Building a Mars lander for NASA. ___ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/355ZIXMMVMCPPWB6M4D3TVR7R236Z4UF/ Code of Conduct: http://python.org/psf/codeofconduct/