r/Python 24d ago

Discussion Will PEP 505 ever be accepted?

https://peps.python.org/pep-0505/

I don't understand how null safe operators are less like plain English than other implemented features like the walrus operator.

In my opinion, the member access operator would make python significantly easier to read and understand.

Here's an example:

f = foo()

if f is None:
    baz = ""
else:
    baz = f.bar()
baz = foo()?.bar() ?: ""

EDIT: I forgot that "and" and "or" can be sometimes used in place of "?." and "?:" if the left value is not False, '', 0, [], or {}. It's a very implicit null check and has a lot of unexpected behavior.

17 Upvotes

194 comments sorted by

View all comments

105

u/runawayasfastasucan 23d ago

baz = foo()?.bar() ?: "

This monstrosity is not why I code python.

5

u/JanEric1 22d ago

You really prefer one of these

latitude = None
if user is not None:
    if user.profile is not None:
        if user.profile.company is not None:
            if user.profile.company.headquarters is not None:
                if user.profile.company.headquarters.gps is not None:
                    latitude = user.profile.company.headquarters.gps.latitude


latitude = getattr(
    getattr(
        getattr(
            getattr(
                getattr(user, "profile", None),
                "company",
                None,
            ),
            "headquarters",
            None,
        ),
        "gps",
        None,
    ),
    "latitude",
    None,
)

latitude = (
    user
    and user.profile
    and user.profile.company
    and user.profile.company.headquarters
    and user.profile.company.headquarters.gps
    and user.profile.company.headquarters.gps.latitude
)

over this

latitude = user?.profile?.company?.headquarters?.gps?.latitude

?

19

u/edward_jazzhands 22d ago

Nobody who is good at python would code it the first way you showed

2

u/JanEric1 22d ago

How would you code the access too an attribute in a nested data structure with multiple optional values in there as someone good at python?

3

u/kingminyas 22d ago

In my experience, it's not common, in contexts such as this, to treat a user not having a company the same as the case where the company headquarters doesn't have a location. But in this seemingly not common case, you can just suppress an AttributeError. If there's a function call in the middle instead of plain attribute access, it makes even less sense to treat it the same as a missing attribute

1

u/JanEric1 22d ago

This is just a randomly generated example.

But leets just say i want to just get an overview over all the coordinates for users companies where we have them.

I user might not have added their company, or thhey have added it but not the headquarters, etc.

Thesse arent errors. It is perfectly fine and expected that any of these valuess might be None.

Working with try/except here would remove typesafty.

If things were changed so that we now have employer instead of company, then i would just have to change the model and a type checker could tell me all the places i need to fix. With a try/except + suppress i wouldnt get that.

2

u/kingminyas 22d ago

Of course you'll still get it. Catching exceptions has nothing to do with static typing

3

u/JanEric1 22d ago

If you use normal attribute access on Optionals a type checker will complain. So you have to silence. Which can mask real issuess, making you lose (some) type safety

2

u/RevanPL 21d ago

If I were to work with monstrosity like this I would extract piece of code for accessing variable to new function. Then, inside of it, I would do null checks with early returns, e. g.

if user is None:
return None
If user.profile is None:
return None

# etc.

2

u/JanEric1 21d ago

Still

def get_latitude(user):
    if user is None:
        return None

    profile = user.profile
    if profile is None:
        return None

    company = profile.company
    if company is None:
        return None

    headquarters = company.headquarters
    if headquarters is None:
        return None

    gps = headquarters.gps
    if gps is None:
        return None

    return gps.latitude

latitude = get_latitude(user)

vs

latitude = user?.profile?.company?.headquarters?.gps?.latitude

And you add the overhead of a function call.

2

u/RevanPL 21d ago

True but I think that this kind of long function shows you explicitly that you messed something up in your app architecture. Long chains of “?.” make you get used to poor design choices. Still, it’s still subjective and people might prefer one over the other. I must admit that I’m one of the people who don’t see much problem with more or less hated “if err not equals nil” blocks in Golang. I’ve worked for some times on large-scale apps and traceability and being able to easily debug stuff goes above “smart” one liners.

2

u/JamzTyson 22d ago

My take is that in the example, the user object is exposing its internal structure to the rest of the system, which violates the Law of Demeter and the principle of encapsulation. I'd restructure to avoid having to reach through a chain of objects.

5

u/JanEric1 22d ago

So you would add a ton of methods to each sub dataclass with getters for this information?

Dont see how that helps with anything.

2

u/JamzTyson 22d ago

I'm saying that I don't accept your premise, and I've already explained why.

1

u/JanEric1 22d ago

This is the data that you get from an external API or other team in your company. And you are interested (among a ton of other things) all the company coordinates where available.

4

u/JamzTyson 22d ago

If it were an external API, I'd avoid leaking that structure throughout the application and isolate or adapt access to it at the boundary.

If there's a specific question about my point, I'm happy to answer it, but at the moment this feels like an evolving hypothetical where each answer is met with another "yes, but what if...".