Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #70463 > unrolled thread

selective (inheriting?) dir()?

Started bySkip Montanaro <skip@pobox.com>
First post2014-04-21 09:06 -0500
Last post2014-04-21 10:52 -0500
Articles 3 — 2 participants

Back to article view | Back to comp.lang.python


Contents

  selective (inheriting?) dir()? Skip Montanaro <skip@pobox.com> - 2014-04-21 09:06 -0500
    Re: selective (inheriting?) dir()? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2014-04-21 15:28 +0000
      Re: selective (inheriting?) dir()? Skip Montanaro <skip@pobox.com> - 2014-04-21 10:52 -0500

#70463 — selective (inheriting?) dir()?

FromSkip Montanaro <skip@pobox.com>
Date2014-04-21 09:06 -0500
Subjectselective (inheriting?) dir()?
Message-ID<mailman.9408.1398089649.18130.python-list@python.org>
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:

>>> B.__init__.im_func.func_code.co_names
('A', '__init__', 'y')
>>> A.__init__.im_func.func_code.co_names
('x',)

Thx,

Skip

[toc] | [next] | [standalone]


#70466

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2014-04-21 15:28 +0000
Message-ID<53553933$0$29993$c3e8da3$5496439d@news.astraweb.com>
In reply to#70463
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:
> 
>>>> B.__init__.im_func.func_code.co_names
> ('A', '__init__', 'y')
>>>> A.__init__.im_func.func_code.co_names
> ('x',)


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



-- 
Steven D'Aprano
http://import-that.dreamwidth.org/

[toc] | [prev] | [next] | [standalone]


#70468

FromSkip Montanaro <skip@pobox.com>
Date2014-04-21 10:52 -0500
Message-ID<mailman.9412.1398095572.18130.python-list@python.org>
In reply to#70466
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, Apr 21, 2014 at 10:28 AM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> 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:
>>
>>>>> B.__init__.im_func.func_code.co_names
>> ('A', '__init__', 'y')
>>>>> A.__init__.im_func.func_code.co_names
>> ('x',)
>
>
> You may have a bit of difficulty with classes that write directly to the
> __dict__, or use setattr, or eval.
>
>
>
> --
> Steven D'Aprano
> http://import-that.dreamwidth.org/
> --
> https://mail.python.org/mailman/listinfo/python-list

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web