The readability issue isn't just a matter of a new set of symbols to learn. It isn't even that the symbols are used in a non-intuitive way (though that doesn't help). It's not even that the question mark, unlike the dot, is very visually obtrusive (which also doesn't help). It also screws with the grammar in an unexpected way. I would be fine with something like:
def func(data=None):
data ?= []
...If there were some corresponding dunder method to implement that behavior, but it's not clear to me that such a thing is possible. If it isn't, that would make `?=` (or '??=' though I don't see the need for double '?'s) a special statement, a special case that someone who's familiar with how other in-place operators work, would be thrown for a loop. The other use cases look like they break down in a different manner than they actually do:
person?.namelooks like it would break down similar to
person().namebut it doesn't because '?' by itself is not an operator.
similarly:
person?[0]looks like it would break down similar to
person()[0]but again, the operator is '?[...]' not '?'
This also raises the question of other operators that could be made null aware. Why not:
func?()
?-num
?~num
num ?+ otherWhy not other reflective operators?
num ?+= otherI think this could be helped by simply making '?' an operator with a very high order of operations, so that pretty-much any expression on the LHS is guarded for 'NoneType' AttributeErrors:
val = person[0]?
val = person.name?That has the double benefit of making multiple '?.' or '?[]' operations unnecessary. I mean the following expression would almost never make sense under the current proposal:
instead of:
val = person?.name?[0]?.lower()you could write:
val = person.name[0].lower()?That also aligns a little better with common usage of '?' in natural language.
But again; there doesn't seem to be a reasonable way to implement a corresponding dunder method for those operators because they're special.
I also disagree with the idea that None is special enough to warrant such special behavior. There are other special None-like objects (as David Mertz pointed out) like NaN and custom place-holders for cases where None is a valid argument.
Yet another possibility is to make '?' signify a parameter who's default value is an expression that should be evaluated when necessary:
def func(data: List = []?):
...
That gets closer to another often requested feature: delayed expression evaluation (as Steve D'Aprano pointed out).
So there are other, possibly better uses for the '?' symbol. It's something that needs to be carefully considered.