The (ab)use seems endless :)
The (ab)use seems endless :)
Dozens of operators in Python have been overloadable and open for abuse for decades now, and yet I don't see much abuse, unlike the C++ and Scala communities. This says a lot about the Python community's ability to avoid pitfalls over the years.
I think the only real (ab)use of @ is to echo its use in another language. For example, @ means something in XPath, so X@Y could be used as a short-hand for X.attrib[Y] in an ElementTree-like API:
tree = load_xml_tree(...)
for node in tree.select("//item[@price > 2*@discount]"):
print(node @ "price", node @ "discount")Maybe passing objects with 'argument @ resource' would be interesting...
I guess you could torture @ for similar purposes in an email library or something.
As I said, there is DSL potential. As it stands, it's just something that is not possible.
class object:
def __matmul__(self, dict):
return self in dict.values()
a = {'asdf': 1}
if 1 @ a: # Evaluates to True.
print('Lovely!')I've always thought that maps and a matching __maps__ would have been a nicer way of referring to the keys of a mapping with in/__in__ referring to the values. Although the semantics are a bit odd in that case. Technically the mapping maps a key, but the language semantic to to have it the other way around as in key is mapped by mapping.
foo = {'bar': 42}
assert 42 in foo
but which makes more sense below? assert 42 maps foo
assert foo maps 42
or even assert 42 mapped by foo
The benefits of including by in the grammar could be of consequence here too. if 42 in d.values(): passWhat bugs me is the implicitness of __in__ defaulting to keys for a mapping. We have .keys() and .values() which are nice and clear since they explicitly grab an object which has an unambiguous definition for __in__.
Double Edit: It's an implementation decision that had to be made and I'm not aware of the rationale or debate behind the original choice. It's directly attributable to the decision to make __iter__ return the keys for a mapping which is the root of my issue. It's presumably useful and convenient (from a language writer's perspective) for iteration of a mapping to be along the keys in whatever order they may be traversed but if that's all it comes down to, why should a mapping be iterable at all when there is obvious ambiguity in what may be iterated? Maybe there is some history I'm not aware of where the .keys(), .values() and .items() methods were introduced post-hoc and the previous behaviour was such due to their non-existence and the need to iterate and then index to get all values in the object.
If you want to efficiently look for values, use a set() or store a second dict that goes from values to keynames.
If you're not worried about the efficiency, do the "in d.values()" you've suggested.
Using "in d.keys()" takes a quick hash lookup and turns it into a slower iterative list lookup.
The more reasonable (I think) problem I have is one of language semantics which is introduced by in being applicable to a mapping in the first place - why should a mapping be iterable at all if it is ambiguous (as I believe) as to what it should return? Members should be key:val pairs but membership checks refer only to keys and it's probably not unreasonable for a user to want any of .keys(), .values() or .items() when iterating. That's obviously why they're made available so why should __iter__ special case one of them?
I assume this is to match semantics introduced by the membership check and probably historical because without a .values() method, key iteration and lookups would be the usual way to get all values out of a mapping. This just seems like the kind of thing that could have been changed in Python3 (although 2to3 would probably not have been able to handle the syntax changes automatically).
map[key]==value
Which is a weak reason in support of the use of containment testing for something else.Its iterable at all because early python didn't have generators, so iterating over dict.keys() would be inefficient for large dictionaries (since you would create an intermediate list just to iterate over.)
> Maybe there is some history I'm not aware of where the .keys(), .values() and .items() methods were introduced post-hoc and the previous behaviour was such due to their non-existence and the need to iterate and then index to get all values in the object.
Prior to Python 3.x, .keys(), .values(), and .items() returned lists (rather than generators providing a view on the underlying dict), which would generally be inefficient if the only purpose was to iterate over them once.
'a' in {'a':1}
which will evaluate True. But that's for keys. GP post wants to know about values, if I understand properly.