Conditional Expresion/Statements

Just one more datapoint given the primary argument for this feature is that it is “easier to understand”:

I personally found

        self._lock = lock = RLock() if lock is None

to be much harder to read, parse and reason about than

        if lock is None:
            lock = RLock()
        self._lock = lock

despite already having read the latter first—it reads like a tongue twister to me :slight_smile: And I am someone who is used to seeing

        lock = RLock() if lock is None else lock

Furthermore, perhaps illustrative of that difficulty, it took careful inspection to tell, but if I’m understanding it correctly these two blocks are not equivalent—the first only assigns lock to self._lock if lock is None, but not if a non-None value is passed. Unless I’m misunderstanding the exact effect of this syntax—which would be another issue with it, indeed.

Similarly, to me this:

        self._acquire_restore = lock._acquire_restore if hasattr(lock, '_acquire_restore')

is harder to read, parse and reason about than the existing

        if hasattr(lock, '_acquire_restore'):
            self._acquire_restore = lock._acquire_restore

or the existing alternative with getattr:

        self._acquire_restore = getattr(lock, '_acquire_restore', self._acquire_restore)

So, FWIW, I’d find this a net decrease in overall readability of the language even in the example cases, not to mind the combinatoric complexity with other expressions/statements as others have raised above.

5 Likes
self._lock = lock = RLock() if lock is None

This should work like in standard cases:

  • First the following is evaluated: lock = RLock() if lock is None
  • Then: self._lock = lock

lock already had a value, whatever came as argument (default None or supplied by the user).

In any case it seems most (there is for sure one use who sees it, i.e.: I do) people find the syntax not appropriate and difficult to understand.

I would like to thank you everybody for having a look at it and the discussion.

Best regards

Nit: you reversed the order of the assignments. lock = RLock() if lock is None is not a “substatement” whose result is assigned to self._lock. If lock is None is true, then self._lock should be assigned first, then lock, equivalent to

if lock is None:
    self._lock = lock = RLock()

or with the chained assignment more fully expanded:

if lock is None:
    tmp = RLock()
    self._lock = tmp
    lock = tmp
    del tmp

It’s less of a nit if you expect the assignment self._lock = lock to be made unconditionally, regardless of the current value of lock. That would be a change to the semantics of a chained assignment, as each of the targets is directly assigned the result of the expression on the right.

as each of the targets is directly assigned the result of the expression on the right.

That’s why my interpretation is

if lock is None:
    lock = RLock()

and then

self._lock = lock

But even more to the point, that I obviously am the only one who would perceive and advantage with the notation, which makes it unsuitable for implementation and general adoption.