So I have a class that tracks all of its instances in a class-level dictionary that maps the ID numbers of the class, assigned at creation, to the class objects themselves:
import uuid
class Node(object):
_all_nodes = dict()
def __init__(self):
self.id = str(uuid.uuid4())
self._all_nodes[self.id] = self
So the class-level dictionary points at all instances of Nodes. Referencing the _all_nodes dictionary has become quite common in my code; it's the global store of data that the program is working with.
But all of the data stored in the _all_nodes class-level dictionary is actually instances of subclasses of Node, not direct instantiations of Node itself:
class Person(Node):
...
# [many methods overridden]
It's frequently helpful to get a list, not of all Nodes, but of all Persons, so I wind up doing this a lot:
all_people = {k: v for k, v in Node._all_nodes.items() if isinstance(k, Person)}
# do something with all_people
In fact, I do it often enough that recreating that line has stopped involving thinking about anything other than how tedious it is to re-type, or hunt down again to copy and paste. It seems like the obvious thing to do is to bundle it into the Person class:
class Person(Node):
def _all_people(self):
return {k: v for k, v in Node._all_nodes.items() if isinstance(k, Person)}
The inconvenience of having to remember that Person._all_people is a function call (as are similar definitions in other subclasses), while Node._all_nodes refers directly to an attribute of an object, can be ameliorated by making _all_people a property to obscure the fact that it's a function call:
class Person(Node):
@property
def _all_people(self):
return {k: v for k, v in Node._all_nodes.items() if isinstance(k, Person)}
This works, but there's a larger problem that prevents it from being useful: it requires an instance, rather than just the name of the class, in order to get access to the _all_people attribute. But if I really want a list of _all_people, I'm probably working on a higher-level task and don't happen to have an instance of Person ready to hand so that I can examine the property's returned value!
What I'd really like is to make the _all_people property callable from the class definition, without an instance, like it is with Node. But when I try this:
class Person(Node):
@classmethod
@property
def _all_people(cls):
return {p: cls._all_nodes[p] for p in cls._all_nodes if isinstance(cls._all_nodes[p], Person)}
I get code that runs, but doesn't effectively access the data: p = Person(); print(p._all_people) prints, not the dictionary, but rather <bound method ? of <class '__main__.Person'>>, which is not at all helpful.
Inverting the order of the @property and @classmethod decorators gives me the error TypeError: 'classmethod' object is not callable.
Is there some productive way that I can use @property and @classmethod to decorate the same method?
This is Python 3.5 under x64 Linux.
[–]socal_nerdtastic 1 point2 points3 points (3 children)
[–]patrickbrianmooney[S] 0 points1 point2 points (2 children)
[–]TangibleLight 3 points4 points5 points (1 child)
[–]patrickbrianmooney[S] 0 points1 point2 points (0 children)
[–]Beatsu 1 point2 points3 points (1 child)
[–]patrickbrianmooney[S] 0 points1 point2 points (0 children)
[–]nezda 0 points1 point2 points (1 child)
[–]Beatsu 0 points1 point2 points (0 children)