From: Stephen Hansen on 3 Apr 2010 15:03 On 2010-04-02 20:24:46 -0700, Patrick Maupin said: > On Apr 2, 10:11�pm, Stephen Hansen <apt.shan...(a)gmail.invalid> wrote: >> >> I don't know if properties are really faster or slower then a >> __getattr__, but I find them a lot cleaner if I want to delay some >> calculation until needed like that. > > Well, the relative speed of properties vs. __getattr__ can become > irrelevant in at least two ways: > > 1) If the __getattr__ only calculates the value one time and then > stuffs it into the instance dictionary, now you are really comparing > the relative speed of properties vs. lookup of an attribute in the > instance dict. If you're at all concerned about speed, I think there > is a clear winner here. I concede it would probably be notably faster, but there's a big difference between "at all concerned about speed" and "optimizing a profiled bottleneck". The speed difference between direct attribute lookup and properties may be notable, but that doesn't make a clear winner here. Now that I have (with either method) optimized the expensive value-calculation operation such that it only happens on-demand and once, I now have to weigh further optimization. Is the difference in speed between a standard attribute lookup and a property fetch worth losing the clarity the property brings over the __getattr__ solution, especially considering the __getattr__ creates a fuzzy 'sometimes this code is responsible, othertimes the dict is' situation that someone may down the road miss in maintenance? For me, usually not-- unless profiling pushes me to reconsider. But everyone makes these calls differently. > 2) There is a single __getattr__ function, vs. one property for every > attribute that needs a property. In cases where you can somehow > easily compute the attribute names as well as the attribute values, > __getattr__ can be a *lot* less code than defining dozens of > properties. I don't really mind a lot of properties, if they're simple. Then again, I often prefer regular ol' attributes where possible :) However, if I'm doing a dispatching sort of mechanism, or a situation where the "name" isn't something static, set in stone or pre-defined-- then certainly, __getattr__ is a fine solution. I don't mind it where its the clearest way to accomplish a goal. -- --S .... p.s: change the ".invalid" to ".com" in email address to reply privately.
From: John Nagle on 4 Apr 2010 14:57 kj wrote: > When coding C I have often found static local variables useful for > doing once-only run-time initializations. If you want functions with state, use an object. That's what they're for. Don't muck with the internal representation of functions. John Nagle
From: Patrick Maupin on 4 Apr 2010 16:35 On Apr 4, 1:57 pm, John Nagle <na...(a)animats.com> wrote: > If you want functions with state, use an object. That's what they're > for. Don't muck with the internal representation of functions. > While "Don't muck with the internal representation of functions" is excellent advice over 99% of the time, it is also true that it is often possible, sometimes even encouraged, to have "functions with state." This is done without "mucking" and without explicitly declaring a class or a class instance. See, e.g. closures and generator functions. Regards, Pat
From: Lee Harr on 5 Apr 2010 17:04 > Another approach would be to stuff the static values in the function's > __dict__. That's how I did it when I wanted something similar. I created this decorator: def static(**kw): ��� ''' ��� Used to create a decorator function that will add an ��� attribute to a function and initialize it. ���>>> @static(foo=5) ��� ... def bar(): ��� ...���� print bar.foo ��� ...���� bar.foo += 1 ��� ... ���>>> bar() ��� 5 ���>>> bar() ��� 6 ��� ''' ��� def decorator(f): ������� f.__dict__.update(kw) ������� return f ��� return decorator _________________________________________________________________ Hotmail: Trusted email with Microsoft�s powerful SPAM protection. https://signup.live.com/signup.aspx?id=60969
From: Ethan Furman on 5 Apr 2010 19:50
Ethan Furman wrote: > Steven D'Aprano wrote: >> On Fri, 02 Apr 2010 19:48:59 -0700, Ethan Furman wrote: >> >> >>>> The heuristic I use is, if I expect the try block to raise an exception >>>> more than about one time in ten, I change to an explicit test. In this >>>> case, since the exception should only be raised once, and then never >>>> again, I would use a try...except block. >>> >>> That was my reasoning as well, but when I timed it for one million runs >>> (so 1 instantiation, 999,999 simple calls), the __getattr__ time was .5 >>> seconds, the try...execpt block was .6; at ten million it was 5 and 6. >> >> >> Care to share your timing code? Not that I don't trust your results, >> but timings are very sensitive to the exact thing you do, and I'd like >> to see what that is. > > Happy to do so -- if I made a mistake I'd like to know about it and learn. > > It'll have to wait two days 'til I get back to work, though... I'll post > it asap. Well, so much for asap, but here's what I used (with one correction: in the 'if' code I had forgotten to actually reference the missing attribute, so the __getattr__ look up never happened; now the try...except block is /slightly/ faster, as opposed to 20% slower). class spam_except(object): def __call__(self, x, y, z): try: mongo = self.mongo except AttributeError: mongo = self.mongo = 1 return class spam_if(object): def __getattr__(self, name): if name != 'mongo': raise AttributeError self.mongo = 1 return self.mongo def __call__(self, x, y, z): self.mongo # didn't have this line before. d'oh! return --> timeit.Timer('spammer(1,2,3)','from spam import spam_except; spammer=spam_except()').timeit() 0.65764130543749388 --> timeit.Timer('spammer(1,2,3)','from spam import spam_if; spammer=spam_if()').timeit() 0.66972877235545525 ~Ethan~ |