selective (inheriting?) dir()?

S

Skip Montanaro

Before I get up to my neck in gators over this, I was hoping perhaps
someone already had a solution. Suppose I have two classes, A and B,
the latter inheriting from the former:

class A:
def __init__(self):
self.x = 0

class B(A):
def __init__(self):
A.__init__(self)
self.y = 1

inst_b = B()

Now, dir(inst_b) will list both 'x' and 'y' as attributes (along with
the various under under attributes). Without examining the source, is
it possible to define some kind of "selective" dir, with a API like

def selective_dir(inst, class_): pass

which will list only those attributes of inst which were first defined
in (some method defined by) class_? The output of calls with different
class_ args would yield different lists:

selective_dir(inst_b, B) -> ['y']

selective_dir(inst_b, A) -> ['x']

I'm thinking some sort of gymnastics with inspect might do the trick,
but after a quick skim of that module's functions nothing leapt out at
me. OTOH, working through the code objects for the methods looks
potentially promising:
('x',)

Thx,

Skip
 
S

Steven D'Aprano

On Mon, 21 Apr 2014 09:06:14 -0500, Skip Montanaro wrote:

[...]
Now, dir(inst_b) will list both 'x' and 'y' as attributes (along with
the various under under attributes). Without examining the source, is it
possible to define some kind of "selective" dir, with a API like

def selective_dir(inst, class_): pass

which will list only those attributes of inst which were first defined
in (some method defined by) class_? The output of calls with different
class_ args would yield different lists:

selective_dir(inst_b, B) -> ['y']

selective_dir(inst_b, A) -> ['x']

In general, no. There's no way of telling what method added an attribute
after the event has taken place: given that instance.__dict__ has a key
"x", how do you know how it got there?

You may be able to do this cooperatively: have both A and B define a
__dir__ method which lists only the attributes they contribute, then call
dir(A) or dir(B) as necessary.

Or, if you find yourself in the position of having an instance of both A
and B, say, a and b, you can compare dir(a) and dir(b). Anything in the
later but not in the former probably was added by B not A.

I say "probably" because one might have things like this:

class A:
def __init__(self):
if type(self) is not A:
self.y = "Surprise!"
self.x = "something"

and of course don't forget that attributes can be added by external
entities too:

instance = A()
instance.z = "bet you forgot about this"

I'm thinking some sort of gymnastics with inspect might do the trick,
but after a quick skim of that module's functions nothing leapt out at
me. OTOH, working through the code objects for the methods looks
potentially promising:

('x',)


You may have a bit of difficulty with classes that write directly to the
__dict__, or use setattr, or eval.
 
S

Skip Montanaro

Thanks for the responses. I'm not really interested in perfection
here. I do most of my programming in a mature internally developed
platform written in Python. As the platform has grown and approaches
to different problems have changed 12-15 year period, some of the
classes which are instantiated have grown quite a few attributes which
are not interesting on a day-to-day basis. As I often query my objects
at runtime and use dir() to jog my memory about what's changing, it
would be nice to eliminate most attributes defined by and only used by
base classes.

Thanks for the suggestion of writing a custom __dir__ method. I hadn't
considered that. It was fairly straightforward to build its attribute
list on-the-fly, taking a snapshot of attributes just after
the base class __init__ method was call, and again after
initialization was complete. The only trick was to leave __dir__
undefined until after that little dance was complete.

Skip


On Mon, 21 Apr 2014 09:06:14 -0500, Skip Montanaro wrote:

[...]
Now, dir(inst_b) will list both 'x' and 'y' as attributes (along with
the various under under attributes). Without examining the source, is it
possible to define some kind of "selective" dir, with a API like

def selective_dir(inst, class_): pass

which will list only those attributes of inst which were first defined
in (some method defined by) class_? The output of calls with different
class_ args would yield different lists:

selective_dir(inst_b, B) -> ['y']

selective_dir(inst_b, A) -> ['x']

In general, no. There's no way of telling what method added an attribute
after the event has taken place: given that instance.__dict__ has a key
"x", how do you know how it got there?

You may be able to do this cooperatively: have both A and B define a
__dir__ method which lists only the attributes they contribute, then call
dir(A) or dir(B) as necessary.

Or, if you find yourself in the position of having an instance of both A
and B, say, a and b, you can compare dir(a) and dir(b). Anything in the
later but not in the former probably was added by B not A.

I say "probably" because one might have things like this:

class A:
def __init__(self):
if type(self) is not A:
self.y = "Surprise!"
self.x = "something"

and of course don't forget that attributes can be added by external
entities too:

instance = A()
instance.z = "bet you forgot about this"

I'm thinking some sort of gymnastics with inspect might do the trick,
but after a quick skim of that module's functions nothing leapt out at
me. OTOH, working through the code objects for the methods looks
potentially promising:

('x',)


You may have a bit of difficulty with classes that write directly to the
__dict__, or use setattr, or eval.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top