Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!feeder.erje.net!eu.feeder.erje.net!newsfeed.xs4all.nl!newsfeed2.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'python.': 0.02; 'source,': 0.04; 'output': 0.05; 'say,': 0.05; '21,': 0.07; 'args': 0.07; 'attribute': 0.07; 'method.': 0.07; '__init__': 0.09; 'attributes': 0.09; 'classes.': 0.09; 'runtime': 0.09; 'undefined': 0.09; 'api': 0.11; 'cc:addr:python-list': 0.11; 'def': 0.12; 'a()': 0.16; 'attributes).': 0.16; 'from:addr:pobox.com': 0.16; 'from:addr:skip': 0.16; 'inst': 0.16; 'instantiated': 0.16; 'internally': 0.16; "module's": 0.16; 'otoh,': 0.16; 'responses.': 0.16; 'self.y': 0.16; 'setattr,': 0.16; 'there?': 0.16; 'to:addr:pearwood.info': 0.16; 'to:addr:steve+comp.lang.python': 0.16; "to:name:steven d'aprano": 0.16; 'sender:addr:gmail.com': 0.17; 'wrote:': 0.18; 'bit': 0.19; 'later': 0.20; 'written': 0.21; 'memory': 0.22; 'programming': 0.22; 'cc:addr:python.org': 0.22; 'necessary.': 0.24; 'skip': 0.24; 'fairly': 0.24; 'mon,': 0.24; 'looks': 0.24; 'cc:2**0': 0.24; 'sort': 0.25; 'compare': 0.26; 'define': 0.26; 'query': 0.26; 'this:': 0.26; 'pass': 0.26; 'defined': 0.27; 'header:In- Reply-To:1': 0.27; 'external': 0.29; 'leave': 0.29; 'am,': 0.29; 'forgot': 0.30; 'message-id:@mail.gmail.com': 0.30; "i'm": 0.30; 'url:mailman': 0.30; 'code': 0.31; 'that.': 0.31; "d'aprano": 0.31; 'inspect': 0.31; 'steven': 0.31; 'class': 0.32; 'lists': 0.32; 'probably': 0.32; 'quite': 0.32; 'url:python': 0.33; 'skip:b 30': 0.33; 'skip:_ 10': 0.34; 'subject: (': 0.35; 'classes': 0.35; 'objects': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'really': 0.36; 'complete.': 0.36; 'dance': 0.36; 'yield': 0.36; 'url:listinfo': 0.36; 'method': 0.36; 'thanks': 0.36; 'possible': 0.36; 'url:org': 0.36; 'list': 0.37; 'problems': 0.38; 'basis.': 0.38; 'little': 0.38; 'anything': 0.39; 'changed': 0.39; 'url:mail': 0.40; 'how': 0.40; 'most': 0.60; 'skip:a 30': 0.61; 'no.': 0.61; 'course': 0.61; 'first': 0.61; 'developed': 0.63; 'kind': 0.63; 'telling': 0.64; 'different': 0.65; 'taking': 0.65; 'approaches': 0.68; 'difficulty': 0.68; 'yourself': 0.78; 'potentially': 0.81; 'examining': 0.84; 'jog': 0.84; 'mature': 0.84; 'snapshot': 0.84; 'trick,': 0.84; 'lists:': 0.91 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date:message-id:subject :from:to:cc:content-type; bh=w6rD8eZRliMD26fJTzd9acO0TAoKhbcfkUMJE1xGaho=; b=cw65NjqQOmrzfb1OE+17gczMIC18qBOkcqBEk9MJ2gyppv0F9AoQGHu6cn7NuV0vgx N5TA206z9mTH17W50ZqHPCRON9SZg2wHttRBwXFbLZgBFWJ6YeD+8NJPGJFg0+Fk960D WRqvbd96X/M1metYJe9hPCAx7hCwNofo1KCq+n/yG0uJPaU7D81SHlehjtf3+agUnN6Q KyEE1fQFQu4D9oSor5g3wCSVAkuDWss4AskuNGzTYPB7C7pLxEOvEeZKoi6YSMC5WFlg VG0oQjI0TMzOjXjGzbWcr/j7feKySpnI/nO0Px+Hm/HoMB3JTx94+AXyM1KHvR5h/P6f Z6Gw== MIME-Version: 1.0 X-Received: by 10.50.60.72 with SMTP id f8mr23050207igr.20.1398095569892; Mon, 21 Apr 2014 08:52:49 -0700 (PDT) Sender: skip.montanaro@gmail.com In-Reply-To: <53553933$0$29993$c3e8da3$5496439d@news.astraweb.com> References: <53553933$0$29993$c3e8da3$5496439d@news.astraweb.com> Date: Mon, 21 Apr 2014 10:52:49 -0500 X-Google-Sender-Auth: 1l5J6Nv3JqeGKvY6hOYWxhjsMWk Subject: Re: selective (inheriting?) dir()? From: Skip Montanaro To: "Steven D'Aprano" Content-Type: text/plain; charset=UTF-8 Cc: Python X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 87 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1398095572 news.xs4all.nl 2854 [2001:888:2000:d::a6]:34740 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:70468 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 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