blhsing
(Ben Hsing)
December 19, 2024, 7:10am
74
Carl Meyer:
Is it, though? Where is the evidence that this is such a common pattern that it needs syntax-level support? The case I hear mentioned is working with unstructured data, eg from an API, but isn’t such data typically in lists and dictionaries? Unless you anre doing something (in my experience) unusual, class instances have a relatively fixed set of attributes that are always available. If I see attribute access style for data from an API, I would assume it’s already been validated to a known schema via something like Pydantic. Of course it’s possible to have exceptions, but do we want the language to encourage this style?
I personally prefer accessing items via dot notation over subscript so I use the wrapper from dict2dot · PyPI to access dict keys as attributes. Although you are right that a predefined validation schema is the right thing to do for the long term we often don’t do that for smaller projects just to get things working quickly.
CPython itself also has a data model where certain attributes are optional for some data types due to dynamic initializers, duck typing or backwards compatibility. Below are a few examples that can benefit from Guido’s generalization:
# return a filename found in the linecache even if it doesn't exist on disk
if filename in linecache.cache:
return filename
if os.path.exists(filename):
return filename
# only return a non-existent filename if the module has a PEP 302 loader
module = getmodule(object, filename)
if getattr(module, '__loader__', None) is not None:
return filename
elif getattr(getattr(module, "__spec__", None), "loader", None) is not None:
return filename
def getabsfile(object, _filename=None):
"""Return an absolute path to the source or compiled file for an object.
The idea is for each object to have a unique origin, so this routine
normalizes the result as much as possible."""
if _filename is None:
_filename = getsourcefile(object) or getfile(object)
return os.path.normcase(os.path.abspath(_filename))
except AttributeError:
continue
if doc is not None:
return doc
return None
if ismethod(obj):
name = obj.__func__.__name__
self = obj.__self__
if (isclass(self) and
getattr(getattr(self, name, None), '__func__') is obj.__func__):
# classmethod
cls = self
else:
cls = self.__class__
elif isfunction(obj):
name = obj.__name__
cls = _findclass(obj)
if cls is None or getattr(cls, name) is not obj:
return None
elif isbuiltin(obj):
_NEEDS_LOADING = object()
def _find_and_load(name, import_):
"""Find and load the module."""
# Optimization: we avoid unneeded module locking if the module
# already exists in sys.modules and is fully initialized.
module = sys.modules.get(name, _NEEDS_LOADING)
if (module is _NEEDS_LOADING or
getattr(getattr(module, "__spec__", None), "_initializing", False)):
with _ModuleLockManager(name):
module = sys.modules.get(name, _NEEDS_LOADING)
if module is _NEEDS_LOADING:
return _find_and_load_unlocked(name, import_)
# Optimization: only call _bootstrap._lock_unlock_module() if
# module.__spec__._initializing is True.
# NOTE: because of this, initializing must be set *before*
# putting the new module in sys.modules.
_lock_unlock_module(name)
And here are the dozens of other instances of getattr(obj, "attr", None)
in CPython where certain attributes are optional in the data model.
5 Likes