generator expressions: performance anomaly?
Steven Bethard
steven.bethard at gmail.com
Wed Jan 19 01:09:57 EST 2005
Bengt Richter wrote:
> On Tue, 18 Jan 2005 17:38:20 -0700, Steven Bethard <steven.bethard at gmail.com> wrote:
>
>
>>Bengt Richter wrote:
>>
>>>Which make me wonder what plans there are for providing a better
>>>mechanism than default arguments as a way of initializing local function
>>>variables. Nested def's to create a closure with initialized values is
>>>pretty crufty for that, IMO.
>>
>>What about using a class? Associating functions with data is pretty
>>much what they're for...
>>
>>
>>>Maybe extending the default argument space
>>>with whatever comes after e.g. a triple star delimiter in the argument list,
>>>but which wouldn't be counted as part of the normal arguments? E.g.,
>>>
>>> def foo(x, y=123, *args, **kw, *** i=1, deftime=time.ctime()):
>>> return x*y, kw.get('which_time')=='now' and time.ctime() or deftime
>>
>>If what you want is to have i=1 and deftime=time.ctime() available
>>within foo, you could do something like (untested):
>>
>>class foo(object):
>> def __init__(self):
>> self.i = 1
>> self.deftime = time.ctime()
>> def __call__(self, x, y=123, *args, **kwds):
>> return x*y, (kw.get('which_time') == 'now'
>> and time.ctime() or self.deftime)
>>foo = foo()
>
> Total: 8 lines, much irrelevant cruft.
>
>
>>Or if you don't like 'foo = foo()', you could probably abuse the __new__
>>method (also untested):
>>
>>class foo(object):
>> i = 1
>> deftime = time.ctime()
>> def __new__(cls, x, y=123, *args, **kwds):
>> return x*y, (kw.get('which_time') == 'now'
>> and time.ctime() or self.deftime)
>
> Total: 6 lines, newbie-unfriendly abuse of __new__ ;-)
>
>
>>I guess my point is that if you want attribute associated with the
>>function, it's often easy enough to write a class instead...
>
> vs. 2 easy lines with minimal irrelevant cruft ;-)
If you're really counting lines, you might compare with the more compact:
class foo(object):
def __init__(self):
self.i, self.deftime = 1, time.ctime()
def __call__(self):
return x*y, kw.get('which_time') == 'now' and time.ctime() or
self.deftime
foo = foo()
and
class foo(object):
i, deftime = 1, time.ctime()
def __new__(cls, x, y=123, *args, **kwds):
return x*y, kw.get('which_time') == 'now' and time.ctime() or
self.deftime
And probably what you want to compare is N lines (function only) versus
N + 2 lines (using __new__) and N + 4 lines (using __call__). If N is
more than 2 lines (which is probably true in most cases), the difference
isn't so dramatic.
Using a class also has the advantage that, assuming one already knows
how classes work (which any Python programmer who wants the kind of
scoping you're talking about should) you don't have to learn how
something new to be able to use it -- that is, *** -> bound locals that
don't contribute to arguments but are listed in the same place as arguments.
If you really want locals that don't contribute to arguments, I'd be
much happier with something like a decorator, e.g.[1]:
@with_consts(i=1, deftime=time.ctime())
def foo(x, y=123, *args, **kw):
return x*y, kw.get('which_time')=='now' and time.ctime() or deftime
Then you don't have to mix parameter declarations with locals definitions.
Steve
[1] I have no idea how implementable such a decorator would be. I'd
just like to see function constants declared separate from arguments
since they mean such different things.
More information about the Python-list
mailing list