Just to add. I haven’t thought about evaluation. Thus, to prevent evaluation of 
unnecessary code, introduction of C-style expression is needed anyways:
> 1. result = bar is None ? default : bar

The below would have to evaluate all arguments, thus not achieving benefits of 
PEP505.
> 2. result = ifelse(bar is None, default, bar)


So I would vote for something similar to:
> result = bar is None ? default : bar


Where default and bar is only evaluated if needed. Although not to the extent 
as initially intended, it would offer satisfiable solutions to several 
proposals.


> On 15 Jul 2023, at 22:37, Dom Grigonis <dom.grigo...@gmail.com> wrote:
> 
> def fu(bar, default=1):
>     bar = bar or default
>     return bar
> 
> print(fu(None))       # 1 - as expected
> print(fu(2))          # 2 - as expected
> print(fu(0))          # 1 - not as expected
> 
> class A:
>     def __bool__(self):
>         return False
> 
> print(fu(A())         # 1 - not as expected
> 
> So it only works if ALL possible bar values are limited to those that 
> evaluate to True on truth test. And even if I have such cases, when this is 
> the case, I restrain from doing this for the sake of consistency of coding 
> style and to eliminate risk if I ever decide to introduce new input options 
> that do not comply with this restriction. Just to be on the safe side.
> 
> Obviously, one could do:
> def fu(bar, default=1):
>     bar = bar if bar is not None else default
>     return bar
> But not having lengthy, hard to read expressions to do such a simple thing is 
> the key here isn’t it?
> 
> So my latest resolve for such cases is simply:
> def fu(bar, default=1):
>     if bar is None:
>         bar = default
>     return bar
> So 2 lines instead of 1, but easy to read, risk-free simple code.
> 
> In case of class construction, I suffer 1 extra assignment here:
> def __init__(self, bar, default=1):
>     self.bar = bar
>     if bar is None:
>         self.bar = default
> Which I don’t like! Extra assignment is not ideal. Of course I could use:
> def __init__(self, bar, default=1):
>     if bar is None:
>         self.bar = default
>     else:
>         self.bar = bar
> Or the 1-line if-else, but (to repeat myself) these 2 don’t read nicely and 
> lack aesthetics for such a simple case as this.
> 
> IMO, what could probably be a good (time tested and convenient) solution is 
> to introduce something similar to C-style, low-level `ifelse` expression.
> 
> string result = (time < 18) ? "Good day." : "Good evening.”;
> 
> My personal opinion is that 1-line pythonic if-else expression lacks pythonic 
> aesthetics.
> 
> The PEP505 looks nice, but it is mostly concerned with `None`, which I IMO is 
> the reason it didn’t go through. It’s the same as with sentinels: 
> https://peps.python.org/pep-0661/ <https://peps.python.org/pep-0661/>
> 
> The proposal is too narrow and specific, to be implemented in core python. In 
> other words, it only solves one corner case, but not the root issue. My 
> solution to PEP661 was to use `unittest.sentinel` so I can define my own 
> `None` alternatives.
> 
> Now, if PEP505 was accepted, then it would only work for `None`, but not for 
> user-defined sentinels, meaning it is not a good solution either - something 
> more general is needed. What I think could potentially be optimal is either:
> 1. result = bar is None ? default : bar
>       However, in this case, new operator had to be introduced instead of 
> “:”, which I am sure would arise many discussions. Although, I think this is 
> a very elegant expression
> 2. result = ifelse(bar is None, default, bar)
>       Having such well-optimised builtin in core python, would also be a good 
> solution without introduction of any new operators.
> 
> Now, this doesn’t directly solve your initial proposal:
> ifelse(dict.get('key') is None, {}, dict.get('key')).get('child_key')
> However, then it could be easier to define a new method when subclassing 
> `dict` or `UserDict`
> from unittest.sentinel import Sentinel
> NotGiven = Sentinel.NotGiven
> 
> class PlayDict(dict):
>     def get_or(self, key, default=NotGiven, arbitrary=None):
>         value = self.get(key, default)
>         return value is NotGiven ? arbitrary : value
>         # OR
>         return ifelse(value is NotGiven, arbitrary, value)
> Whether this is included in core-python or not is another matter. It is not 
> as elegant as proposal in PEP505, but it is not limited to `None` sentinel, 
> while making use of nicely-read 1-liner.
> 
> So IMO, a more elegant if-else 1-liner is potentially a happy middle, which 
> would cover many different cases, although not as elegantly as PEP505.
> 
> 
>> On 15 Jul 2023, at 21:07, Jothir Adithyan <adithyanjot...@gmail.com 
>> <mailto:adithyanjot...@gmail.com>> wrote:
>> 
>> Dom Grigonis wrote:
>>> I like this. Something that I would use for sure.
>>> I have used a lot of:
>>> ```
>>> (value: None | object ) or default
>>> ```
>>> , but I stopped for obvious reasons. However, I miss those days, when I was 
>>> ignorant that this is not a good idea.
>>>> On 11 Jul 2023, at 01:17, David Mertz, Ph.D. david.me...@gmail.com 
>>>> <mailto:david.me...@gmail.com> wrote:
>>>> This is basically PEP 505 – None-aware operators 
>>>> (https://peps.python.org/pep-0505/ <https://peps.python.org/pep-0505/> 
>>>> https://peps.python.org/pep-0505/ <https://peps.python.org/pep-0505/>).
>>>> I've generally been opposed to that, but clearly some serious and smart 
>>>> Pythonistas have supported it.  That PEP is a bigger lift than your 
>>>> suggestion,  but correspondingly more general.
>>>> On Mon, Jul 10, 2023, 6:04 PM Jothir Adithyan <adithyanjot...@gmail.com 
>>>> <mailto:adithyanjot...@gmail.com> mailto:adithyanjot...@gmail.com 
>>>> <mailto:adithyanjot...@gmail.com>> wrote:
>>>> Hi everyone,
>>>> I would like to briefly present my idea regarding the `get` function 
>>>> commonly used with dictionaries. When working with large amounts of JSON 
>>>> data, I often encounter code that doesn't feel very Pythonic to me.
>>>> Problem Statement:
>>>> The `get` function allows chaining of method calls, which is quite useful 
>>>> when working with dictionaries. It also has a convenient `default` 
>>>> parameter that returns a default value if the key is not found in the 
>>>> dictionary. This feature makes it safe and easy to use. However, problems 
>>>> arise when the dictionary contains the key we are accessing, but the 
>>>> corresponding value is `None`. In such cases, subsequent `get` calls fail 
>>>> because the `get` method belongs to objects of type `dict` and not `None`. 
>>>> To address this, I propose adding a new parameter to the `get` function or 
>>>> introducing a new function called `get_or` that swiftly handles this 
>>>> issue. This new parameter, called `arbitrary`, would accept an arbitrary 
>>>> value to be returned by subsequent `get` calls in case the retrieved value 
>>>> of the key is `None`.
>>>> Assumptions:
>>>> The problem statement is based on a few assumptions:
>>>> 
>>>> You prefer chaining `get` statements for cleaner code.
>>>> You expect at least some of the `get` methods to return `None`.
>>>> You want to avoid the hassle of using `try` and `except` for every `get` 
>>>> chain.
>>>> 
>>>> If you fall into the category of people who wish for a simpler way to work 
>>>> with dictionaries and handle large amounts of data, I hope you can 
>>>> empathise with this proposal.
>>>> I have made a simple implementation by modifying the `get` method, which 
>>>> is below this thread. I would appreciate your valuable input on this 
>>>> feature. Before diving into coding, I want to make sure this is not a bad 
>>>> idea waiting to reveal itself in the dark.
>>>> Thank you for taking the time to read this thread. Your feedback is 
>>>> greatly appreciated.
>>>> Best regards,  
>>>> Jothir Adithyan
>>>> **Runnable Version**  
>>>> https://replit.com/@Adithyan71/GetOr 
>>>> <https://replit.com/@Adithyan71/GetOr> 
>>>> https://replit.com/@Adithyan71/GetOr <https://replit.com/@Adithyan71/GetOr>
>>>> **Code Samples.**
>>>> class PlayDict(dict):  
>>>>    def get_or(self, key, arbitrary=None, default=None):  
>>>>        if not self.__contains__(  
>>>>            key  
>>>>        ):  # case 1 the key does not exist hence the default value  
>>>>            return default  
>>>>        elif (  
>>>>            self[key] is None  
>>>>        ):  # case 2 key does exist but the value is None return the arb 
>>>> value  
>>>>            return arbitrary  
>>>>        return self[key]  # case 3 the key is present and the value is not 
>>>> None  
>>>> 
>>>> 
>>>> import contextlib  
>>>> parent_dict = PlayDict()  
>>>> parent_dict['k1'] = None  
>>>> parent_dict['k2'] = {"child_key": "val"} # Parent dict can contain nested 
>>>> dicts  
>>>> 
>>>> with contextlib.suppress(AttributeError):  
>>>>    result = parent_dict.get("k1", {}).get("child_key") # This will raise 
>>>> AttributeError  
>>>> 
>>>> result = parent_dict.get_or("k1", default={}, 
>>>> arbitrary={}).get("child_key") # This will work  
>>>> 
>>>> print(result)  
>>>> 
>>>> 
>>>> Python-ideas mailing list -- python-ideas@python.org 
>>>> <mailto:python-ideas@python.org> mailto:python-ideas@python.org 
>>>> <mailto:python-ideas@python.org>
>>>> To unsubscribe send an email to python-ideas-le...@python.org 
>>>> <mailto:python-ideas-le...@python.org> 
>>>> mailto:python-ideas-le...@python.org <mailto:python-ideas-le...@python.org>
>>>> https://mail.python.org/mailman3/lists/python-ideas.python.org/ 
>>>> <https://mail.python.org/mailman3/lists/python-ideas.python.org/> 
>>>> https://mail.python.org/mailman3/lists/python-ideas.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/IELDCU
>>>>  
>>>> <https://mail.python.org/archives/list/python-ideas@python.org/message/IELDCU>...
>>>>  
>>>> https://mail.python.org/archives/list/python-ideas@python.org/message/IELDCURRVQXCPGD4EPPLL7MYWJT4XHKV/
>>>>  
>>>> <https://mail.python.org/archives/list/python-ideas@python.org/message/IELDCURRVQXCPGD4EPPLL7MYWJT4XHKV/>
>>>> Code of Conduct: http://python.org/psf/codeofconduct/ 
>>>> <http://python.org/psf/codeofconduct/> 
>>>> http://python.org/psf/codeofconduct/ <http://python.org/psf/codeofconduct/>
>>>> _______________________________________________
>>>> Python-ideas mailing list -- python-ideas@python.org 
>>>> <mailto:python-ideas@python.org>
>>>> To unsubscribe send an email to python-ideas-le...@python.org 
>>>> <mailto:python-ideas-le...@python.org>
>>>> https://mail.python.org/mailman3/lists/python-ideas.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/4BCGPZ...
>>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>> 
>> Hey Dom, thank you for your time.
>> 
>> Could you please provide a couple of reasons why this idea might not be 
>> favorable? I would like to have a clear understanding and ensure my 
>> assumptions are correct.
>> 
>> Regards,
>> Jothir Adithyan
>> _______________________________________________
>> Python-ideas mailing list -- python-ideas@python.org 
>> <mailto:python-ideas@python.org>
>> To unsubscribe send an email to python-ideas-le...@python.org 
>> <mailto:python-ideas-le...@python.org>
>> https://mail.python.org/mailman3/lists/python-ideas.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/4DZXMGL4UZ7HBGJB5MC2SCMLVSGVTQCW/
>> 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/4X5XXPUB5B5PKAR4HUWMWF45ZNYQ4GKX/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to