On Sun, May 19, 2013 at 4:30 PM, Lex Berezhny <[email protected]> wrote:

> You are right, I meant to say anonymous functions.
>
> I think it's a shame that Guido refuses to add this. Almost all modern
> languages have anonymous functions. It's almost a standard when you are
> dealing with frameworks and environments that require callbacks.
>

there really isn't anything about python's impl (or lack thereof, if you
wish) that makes it any more/less useful than what you get from JS/Ruby
etc; the concept of an "anonymous function" is really just that, a function
that does not have an implicit name, but beyond that, it's just a function
like any other.

personally, i would agree with Guido in that python *doesn't* need them --
there is not one significant difference between an explicit definition:

>>> def anon_A(x):
>>>    """FUNC"""
>>>    return x*x
>>> anon_A.__name__ = 'anonymous'

...and the binding of a function object to a identifier:

>>> anon_B = lambda x: x*x
>>> anon_B.__name__ = 'anonymous'
>>> anon_B.__doc__  = 'FUNC'

...aside from the fact that their internal code objects have different
names:

>>> anon_A.func_code.co_name
'anon_A'

>>> anon_B.func_code.co_name
'<lambda>'

...but that's irrelevant, as their code objects, and all
cellvars/locals/etc are IDENTICAL:

>>> dis.dis(anon_A)
  3           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                0 (x)
              6 BINARY_MULTIPLY
              7 RETURN_VALUE

>>> dis.dis(anon_B)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                0 (x)
              6 BINARY_MULTIPLY
              7 RETURN_VALUE

...you may notice A and B do actually differ by offset 2, where A=3 and
B=1...  this arises from from the fact that the explicit definition
(anon_A) records line numbers/offsets, whereas the lambda version does not
(since it's all on one line).  aside from that, there is only one other
slight difference, as seen here:

>>> [m for m in inspect.getmembers(anon_A.func_code) if m[0][0]=='c']
[('co_argcount', 1),
 ('co_cellvars', ()),
 ('co_code', '|\x00\x00|\x00\x00\x14S'),
 ('co_consts', ('FUNC',)),
 ('co_filename', '<ipython-input-76-b07173e47ae4>'),
 ('co_firstlineno', 1),
 ('co_flags', 67),
 ('co_freevars', ()),
 ('co_lnotab', '\x00\x02'),
 ('co_name', 'anon_A'),
 ('co_names', ()),
 ('co_nlocals', 1),
 ('co_stacksize', 2),
 ('co_varnames', ('x',))]

>>> [m for m in inspect.getmembers(anon_B.func_code) if m[0][0]=='c']
[('co_argcount', 1),
 ('co_cellvars', ()),
 ('co_code', '|\x00\x00|\x00\x00\x14S'),
 ('co_consts', (None,)),
 ('co_filename', '<ipython-input-77-9a4a0444163c>'),
 ('co_firstlineno', 1),
 ('co_flags', 67),
 ('co_freevars', ()),
 ('co_lnotab', ''),
 ('co_name', '<lambda>'),
 ('co_names', ()),
 ('co_nlocals', 1),
 ('co_stacksize', 2),
 ('co_varnames', ('x',))]

...anon_A stores the __doc__ string within co_const, and anon_B does not,
storing instead the const `None` (since the __doc__ IS None at the moment
the lambda is created)

if you wanted to get fancy, you could construct code objects manually and
assign to function objects, and actually assign the same code object to
DIFFERENT functions, thereby separating the implementation (code, ie.
procedures) from the concrete definition (function, ie. name, arg defaults):

>>> anon_B.func_code = anon_A.func_code
>>> anon_A(10), anon_B(10)
(100, 100)
>>> anon_A.func_code is anon_B.func_code
True

>>> [anon_A, anon_A.func_code, anon_B, anon_B.func_code]
[<function __main__.anonymous>,
 <code object anon_A at 0x279ab30, file "<ipython-{snip}>", line 1>,
 <function __main__.anonymous>,
 <code object anon_A at 0x279ab30, file "<ipython-{snip}>", line 1>]

...but ....WHY? if you want "anonymous" functions, simply rebind/reuse the
same *initial* name, over any over again:

>>> anon = dict()
>>> \
... for i, char in enumerate(('A', 'B'), start=2):
...     def __(x=i):
...         return x*x
...     anon[char] = __

>>> anon
{'A': <function __main__.__>, 'B': <function __main__.__>}
>>> anon['A'](), anon['B']()
(4, 9)

...it's all the same in the end :) that was an extremely long winded way of
saying "python can handle it just fine".

anyways, back to Dart, it's interesting you brought it all up because i was
just thinking about this exact this not 2 days... how/if Dart was replacing
GWT at Google, what that would mean for us, and how we fit in to it all...
my take is this: we still fit in, but i think it would be wise to focus on
python3 syntax, specifically because of the `nonlocal` keyword; this is the
only significant difference i am aware of that make python2 "different-y"
 compared to, say, JS -- when assigning an identifier NOT declared by
`var`, JS will walk up the stack and bind against the first frame with the
same identifier, eventually teminating on the global object (`window` in a
browser, sometimes different)... python2, however, will only affect the
non-local identifier if it is a mutable object (and this is really just a
side-effect/hack of python semantics) python ASSIGNMENT doesn't bother too
much with scope, and knows how to BIND only two: global, and local. it is
unable to REBIND anything but that

python3 changes this, and brings it inline with other langs.

i am intrigued by the Dart idea though, it's definately worth exploring, or
at the very least watching closely.

-- 

C Anthony

-- 

--- 
You received this message because you are subscribed to the Google Groups 
"Pyjs.org Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to