weakget - Chain multiple `getattr` and `.get` calls into one expression
Project description
weakget - Chaining getattr
and .get
With weakget
, you can write code like:
x = weakget(obj)[5]['key'].attr.method() % 'default'
and x
will be set to 'default'
if:
obj
has just 3 items, orobj[5]
is missing'key'
, orobj[5]['key']
doesn't haveattr
, orobj[5]['key'].attr
didn't definemethod()
Otherwise, x
gets set to obj[5]['key'].attr.method()
. Similar code in pure Python would look like:
try:
x = obj[5]['key'].attr.method()
except (LookupError, AttributeError):
x = 'default'
weakget
is better because:
- it doesn't hide
AttributeError
raised fromobj[5]
orobj[5]['key']
- it doesn't hide
LookupError
raised fromobj[5]['key'].attr
orobj[5]['key'].attr.method
- it doesn't hide any exception raised from calling
obj[5]['key'].attr.method()
- it fits on one line!
Usage
Install from PyPI using pip
:
pip install weakget
Then import into your scripts:
>>> from weakget import weakget
>>> obj = []
>>> weakget(obj)[5]['key'].attr.method() % 'default'
'default'
pep505 - None-aware operations à la PEP 505
But wait, there's more! PEP 505 describes adding None
-aware operators to Python, but you can get that behaviour today from pep505
:
from weakget import pep505
x = pep505(a.attr, b.attr) % 3 # i.e. a.attr ?? b.attr ?? 3
y = pep505(c)['key'].attr % None # i.e. c?.['key']?.attr
Behind-the-scenes, pep505
works in much the same way as weakget
, but where weakget
looks for LookupError
or AttributeError
to be raised, pep505
only looks for None
. Similar code in pure Python would look like:
x = a.attr if a.attr is not None else b.attr if b.attr is not None else 3
y = c['key'].attr if (c is not None and c['key'] is not None) else None
pep505
is better because:
a.attr
,b.attr
, andc['key']
are each evaluated at most once- less typing, which also means...
- less chance for logic errors
FAQs
Q: Why not use getattr
's default instead of catching, and possibly hiding, AttributeError
s?
A: Turns out getattr
also catches AttributeError
:
>>> class A:
... @property
... def b(self):
... return None.badattr
>>> getattr(A(), 'b')
AttributeError: 'NoneType' object has no attribute 'badattr'
>>> getattr(A(), 'b', 'default')
'default'
Q: Why not use .get
's default argument instead of catching LookupError
?
A: .get
is implemented on mapping objects like dict
, but is not available on sequence objects like list
. Catching the LookupError
from obj[key]
is the only way to support both.
Q: Why %
instead of or
, |
, or a method?
A: or
isn't an option as it cannot be directly overloaded. |
is enticing as a | b
reads like "a
or b
", but "or" in Python usually refers to truthiness, which does not distinguish "lack of value" from "false". Adding a method would hide any method of the same name in the underlying object. %
is already overloaded in Python, making it the best option among the remaining operators.
Q: Can't you come up with a better name than pep505
?
A: Well, PP
is currently in the lead as it looks like ??
, but I'm open to suggestions!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for weakget-1.0-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ace5c9a9d2c713c827e10df656c2b12e7f2e85238b8e1d4386c1b9e2d68d06f8 |
|
MD5 | 56cab7678f5aab85ca7bb2c61afa8ae4 |
|
BLAKE2b-256 | b0a7ce45ee606c97351c517a3d8f77d14c273c3b03325350779b539778bbe7f0 |