> def frobnicate(data, verbose=os.environ.get('LEVEL')==loglevel.DEBUG): ...
Is there any value in not putting that into a global constant?
Probably not. I was just inventing an ad hoc example to show what I meant. I didn't search any actual repos I work on for real-life examples.
Regardless, the @ operator is now available *everywhere* in Python. Does it quadratically increase cognitive load?
Yeah, probably about that much. Other than NumPy or closely related array libraries, I don't know that many other uses. I think I saw something on PyPI that used it as an email thing, where obviously it has some familiarity. But in that case, the lines it occurs on probably have no more than one or two other sigils.
In the numeric stuff, if I have:
newarray = (A @ B) | (C / D) + (E - F)
That's @, |, /, +, and -. So 5 operators, and 25 "complexity points". If I added one more operator, 36 "complexity points" seems reasonable. And if I removed one of those operators, 16 "complexity points" feels about right.
In a function signature "def bisect(stuff, lo=0, hi=None)", you don't
know what the hi value actually defaults to. Even if it's obvious that
it is late-bound
Sure, knowing what `hi` defaults to *could be useful*. I'm sure if I used that function I would often want to know... and also often just assume the default is "something sensible." I just don't think that "could be useful" as a benefit is nearly as valuable as the cost of a new sigil and a new semantics adding to the cognitive load of Python.
For example, it also "could be useful" to have syntax that indicated the (expected) big-O complexity of that function. But whatever that syntax was, I really doubt it would be worth the extra complexity in the language vs. just putting that info in the docstring.
Let's look at a function that has a lot of late-bound default arguments:
pd.read_csv(
filepath_or_buffer: 'FilePath | ReadCsvBuffer[bytes] | ReadCsvBuffer[str]',
sep=<no_default>,
delimiter=None,
header='infer',
names=<no_default>,
index_col=None,
usecols=None,
squeeze=None,
prefix=<no_default>,
mangle_dupe_cols=True,
dtype: 'DtypeArg | None' = None,
engine: 'CSVEngine | None' = None,
converters=None,
true_values=None,
false_values=None,
skipinitialspace=False,
skiprows=None,
skipfooter=0,
nrows=None,
na_values=None,
keep_default_na=True,
na_filter=True,
verbose=False,
skip_blank_lines=True,
parse_dates=None,
infer_datetime_format=False,
keep_date_col=False,
date_parser=None,
dayfirst=False,
cache_dates=True,
iterator=False,
chunksize=None,
compression: 'CompressionOptions' = 'infer',
thousands=None,
decimal: 'str' = '.',
lineterminator=None,
quotechar='"',
quoting=0,
doublequote=True,
escapechar=None,
comment=None,
encoding=None,
encoding_errors: 'str | None' = 'strict',
dialect=None,
error_bad_lines=None,
warn_bad_lines=None,
on_bad_lines=None,
delim_whitespace=False,
low_memory=True,
memory_map=False,
float_precision=None,
storage_options: 'StorageOptions' = None,
I'd have to look through the implementation, but my guess is that quite a few of the 25 late-bound defaults require calculations to set that take more than one line of code. I really don't WANT to know more than "this parameter is calculated according to some logic, perhaps complex logic" ... well, unless I think it pertains to something I genuinely want to configure, in which case I'll read the docs.
--
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons. Intellectual property is
to the 21st century what the slave trade was to the 16th.