Syntax across languages

B

bearophileHUGS

This post comes from a boring morning, if you are busy ignore this.
This post is only for relaxed people.

I've found this page, "Syntax Across Languages", it contains many
errors and omissions, but it's interesting.
http://merd.sourceforge.net/pixel/language-study/syntax-across-languages.html

Compared to the other languages Python comes out rather well, in quick
scan only few things look better in other languages (usually all/most
things are possible in all languages, so it's often just a matter of
brevity, elegance, etc):

- Nestable Pascal-like comments (useful): (* ... *)

- Information about the current line and file as Ruby:
__LINE__ __FILE__
Instead of the python version:
inspect.stack()[0][2] inspect.stack()[0][1]

- ~== for approximate FP equality

- comparison returns 4 values (i.e. inferior, equal, superior or not
comparable), as in Pliant:
"compare"

- identity function: "identity" as in Common Lisp (probably of little
use in Python).

- Exception retrying: after catching an exception, tell the snippet to
be re-run
"retry" as in Ruby

- object cloning: obj.copy() obj.deepcopy()

- accessing parent method:
super as in Ruby, instead as in Python:
super(Class, self).meth(args)

- recursive "flatten" as in Ruby (useful)

Probably there are some errors of mine too, there are many things I
don't know aboyt Python yet.

Bye,
bearophile
 
F

Fredrik Lundh

- Information about the current line and file as Ruby:
__LINE__ __FILE__
Instead of the python version:
inspect.stack()[0][2] inspect.stack()[0][1]

(that's (mostly) CPython-dependent, and should be avoided)
- ~== for approximate FP equality

str(a) == str(b)
- comparison returns 4 values (i.e. inferior, equal, superior or not
comparable), as in Pliant: "compare"
Traceback (most recent call last):
File "<stdin>", line 1, in ?
UnicodeDecodeError: 'ascii' codec can't decode byte /.../

sure looks like four possible outcomes.
- identity function: "identity" as in Common Lisp (probably of little
use in Python).
id(a)

- Exception retrying: after catching an exception, tell the snippet to
be re-run "retry" as in Ruby
.... try:
.... x += 1
.... if x <= 5:
.... raise ValueError
.... except ValueError:
.... print "retry"
.... continue
.... else:
.... break
....
retry
retry
retry
retry
retry
- object cloning: obj.copy() obj.deepcopy()

import copy

(cloning is usually a sign of a design problem in python. if you think
you need it, you probably don't. if you really think you need it, import
copy.)
- recursive "flatten" as in Ruby (useful)

if you can define the semantics, it's a few lines of code. if you're not
sure about the semantics, a built-in won't help you...

etc.

</F>
 
B

bearophileHUGS

Thank you for the comments, Fredrik Lundh.
(that's (mostly) CPython-dependent, and should be avoided)<

Then a non CPython-dependent way of doing it can be even more useful.

sure looks like four possible outcomes.<

Right (but to me four explicit answers seem better than three answers
and an exception still).


I think in Python it can be something more like (but it's of little
use):
def identity(x): return x
Or:
identity = lambda x: x

(cloning is usually a sign of a design problem in python. if you think
you need it, you probably don't. if you really think you need it,
import
copy.)<

I agree (importing a module is worse than using a standard copy method,
but I think this can be seen as a way to discourage the use of copy in
Python).

if you can define the semantics, it's a few lines of code. if you're not
sure about the semantics, a built-in won't help you...<

I think the language needs a fast built-in version of it. If something
is both inside Mathematica and Ruby, then probably it can be useful in
Python too :)

Bye and thank you,
bearophile
 
F

Fredrik Lundh

sure about the semantics, a built-in won't help you...<

I think the language needs a fast built-in version of it. If something
is both inside Mathematica and Ruby, then probably it can be useful in
Python too :)

numpy already has one:

http://numeric.scipy.org/numpydoc/numpy-9.html#pgfId-36512

(it's probably there in scipy too, but the scipy docs don't appear to be
freely available. hmm...)

PIL also has one:

http://www.effbot.org/imagingbook/image.htm#image-getdata-method

there's also one in Tkinter:
>>> import Tkinter
>>> Tkinter._flatten(["abc", 1, 2, (3, 4, 5), None, [6, 7, 8, (9,)]])
('abc', 1, 2, 3, 4, 5, 6, 7, 8, 9)

to create a generic version, you have to decide which sequences to
treat like sequences, and which sequences you don't want to treat
like sequences...

</F>
 
F

Fredrik Lundh

Right (but to me four explicit answers seem better than three answers
and an exception still).

def cmp4(a, b):
try:
return cmp(a, b)
except:
return None

</F>
 
B

bearophileHUGS

Thank you Fredrik Lundh for showing everybody that indeed lot of people
feel the need of such function in Python too.
to create a generic version, you have to decide which sequences to treat like sequences<

In my version I give the function some parameter(s) to define what I
want to flatten. I'll probably put it in the cookbook...

Bye,
Bearophile
 
F

Fredrik Lundh

Thank you Fredrik Lundh for showing everybody that indeed lot of people
feel the need of such function in Python too.

you seem to be missing the point: all those versions are highly optimized,
and tuned for the specific use-cases. a generic flatten would be useless
in all three cases.

</F>
 
B

beza1e1

id("blub")
-1210548288

This is not identity in a mathematical view.

def identity(x): return x

It has is uses. I had some kind of parser and had a dict like this:
{case: function, ...} It had to be a dict, because i wanted to
dynamically add and remove cases. In some cases nothing had to be done.
To represent this in the dict a identity function is needed. There
surely are other ways, but identity was the most expressive in my eyes.

Nice read, by the way. Thanks for sharing ;)
 
B

bonono

just curious, how can this identity function be used ? In haskell,
because all functions are curried, I can sort of visualize/understand
how id is used. Not quite understand how it can be used in python.
 
F

Fredrik Lundh

beza1e1 said:
It has is uses. I had some kind of parser and had a dict like this:
{case: function, ...} It had to be a dict, because i wanted to
dynamically add and remove cases. In some cases nothing had to be done.
To represent this in the dict a identity function is needed.

in Python, that's spelled "lambda x: x" (or "None", in some contexts)

</F>
 
G

garabik-news-2005-05

Fredrik Lundh said:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
UnicodeDecodeError: 'ascii' codec can't decode byte /.../

that is not because of the comparison, but because of the coercion:
Traceback (most recent call last):
sure looks like four possible outcomes.
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cannot compare complex numbers using <, <=, >, >=


a fifth one :)


--
-----------------------------------------------------------
| Radovan Garabík http://kassiopeia.juls.savba.sk/~garabik/ |
| __..--^^^--..__ garabik @ kassiopeia.juls.savba.sk |
-----------------------------------------------------------
Antivirus alert: file .signature infected by signature virus.
Hi! I'm a signature virus! Copy me into your signature file to help me spread!
 
A

Alex Martelli

- Information about the current line and file as Ruby:
__LINE__ __FILE__
Instead of the python version:
inspect.stack()[0][2] inspect.stack()[0][1]

__file__ is around in Python, too, but there's no __line__ (directly).
- identity function: "identity" as in Common Lisp (probably of little
use in Python).

I've seen enough occurrences of "lambda x: x" in Python code with a
generally functional style that I'd love to have operator.identity (and
a few more trivial functions like that) for readability;-)
- object cloning: obj.copy() obj.deepcopy()

Like (say) container.length() versus len(container), I'm perfectly
comfortable relying on functions rather than methods. It even makes it
easier to allow several alternative ways for an object to provide such
functionality (e.g. by implementing __getstate__ and maybe __setstate__
as opposed to __copy__ and maybe __deepcopy__) -- which would be
feasible even with a method, of course (Template Method DP), but IS
easier when relying on functions (and operators).
- accessing parent method:
super as in Ruby, instead as in Python:
super(Class, self).meth(args)

Ruby's syntax may be better for a single-inheritance language, but
Python's, while less elegant, may be more appropriate in the presence of
multiple inheritance.
- recursive "flatten" as in Ruby (useful)

Usage too rare to deserve a built-in method, IMHO, considering the ease
of coding the equivalent:

def flatten(x):
if not isinstance(x, list): yield x
for y in x: yield flatten(y)

What I _do_ envy Ruby's syntax, a little, is the convention of ending
methodnames with exclamation mark to indicate "modifies in-place" (and,
secondarily, question mark to indicate predicates). The distinction
between, e.g.,
y = x.sort()
and
x.sort!()
in Ruby is much clearer, IMHO, than that between, say,
y = sorted(x)
and
x.sort()
in Python...


Alex
 
A

Alex Martelli

just curious, how can this identity function be used ? In haskell,
because all functions are curried, I can sort of visualize/understand
how id is used. Not quite understand how it can be used in python.

There was a very recent example posted to this group (by Robin Becker, I
believe, looking for ways to "override property"), something like:
def __init__(self, validate=None):
if not validate: validate = lambda x: x
self.validate = validate
and later on, self.validate is always unconditionally called to extract
a valid value from an input argument to another method -- a nicer style,
arguably, than assigning self.validate unconditionally and then having
to test each and every time in the other method. Such subcases of the
well-known "Null Object" design pattern, where you don't want to store
None to mean "no such object" but, to avoid repeated testing, rather
want to store an object which "reliably does nothing", are reasonably
common. In an abstract way, they're somewhat akin to having the 'pass'
statement in the language itself;-).


Alex
 
S

skip

Alex> I've seen enough occurrences of "lambda x: x" in Python code with
Alex> a generally functional style that I'd love to have
Alex> operator.identity (and a few more trivial functions like that) for
Alex> readability;-)

But, but, but [Skip gets momentarily apoplectic, then recovers...]
"operator.identity" is way more to type than "lambda x: x". Plus you have
to remember to import the operator module. <0.5 wink>

Not to mention which (from "pydoc operator"):

[The operator module] exports a set of functions implemented in C
corresponding to the intrinsic operators of Python.

Last time I checked, Python didn't have an intrinsic "identity" operator.

For which reason, I'd be -1 on the idea of an identity function, certainly
in the operator module.

Skip
 
A

Alex Martelli

Alex> I've seen enough occurrences of "lambda x: x" in Python code with
Alex> a generally functional style that I'd love to have
Alex> operator.identity (and a few more trivial functions like that) for
Alex> readability;-)

But, but, but [Skip gets momentarily apoplectic, then recovers...]
"operator.identity" is way more to type than "lambda x: x". Plus you have
to remember to import the operator module. <0.5 wink>

But, it's way more readable, IMHO.

Not to mention which (from "pydoc operator"):

[The operator module] exports a set of functions implemented in C
corresponding to the intrinsic operators of Python.

Last time I checked, Python didn't have an intrinsic "identity" operator.

attrgetter and itemgetter don't exactly correspond to "intrinsic
operators", either (getitem, and the built-in getattr, are more like
that)... yet module operator exports them today, offering more readable
(and faster) alternatives to "lambda x: x[y]" and "lambda x: getattr(x,
y)".

For which reason, I'd be -1 on the idea of an identity function, certainly
in the operator module.

I'm not at all wedded to having 'identity' in the operator module (which
may arguably be the wrong placement for 'attrgetter' and 'itemgetter'
too). But identity is a useful primitive for a functional style of
Python programming, so having it SOMEwhere would be nice, IMHO.


Alex
 
T

Tom Anderson

str(a) == str(b)

This is taken from the AIEEEEEEEE 754 standard, i take it? :)

Seriously, that's horrible. Fredrik, you are a bad man, and run a bad
railway.

However, looking at the page the OP cites, the only mention of that
operator i can find is in Dylan, and in Dylan, it's nothing to do with
approximate FP equality - it means 'not identical', which we can spell "is
not".

What would approximate FP equality even mean? How approximate?
... try:
... x += 1
... if x <= 5:
... raise ValueError
... except ValueError:
... print "retry"
... continue
... else:
... break
...
retry
retry
retry
retry
retry

That works well for trivial cases, and not at all for anything complex. If
you have this sort of structure:

def reverse_the_polarity_of_the_neutron_flow():
five_hundred_lines_of_code()
and_dozens_of_layers_of_nesting_and_indirection()
interrossitor.activate() # can raise InterrossitorError
do_what_we_came_here_to_do()

try:
reverse_the_polarity_of_the_neutron_flow()
except InterrossitorError:
degausser.degauss(interrossitor)
interrossitor.activate()
RETRY # how do you implement this?

You're in trouble. I realise that this snippet is not a hugely compelling
example, but the point is that there could be some corrective action that
you can take in an exception handler which, for some reason, you can't
write close enough to the source of the exception that control can carry
on flowing in the right direction.

What you can do - and this is fairly high-grade evil of a different sort -
is package the exception-handling specifics in a function, and pass that
in, to be applied at the appropriate point:

def reverse_the_polarity_of_the_neutron_flow(ie_hdlr):
five_hundred_lines_of_code()
and_dozens_of_layers_of_nesting_and_indirection()
try:
interrossitor.activate() # can raise InterrossitorError
except InterrossitorError, e:
ie_hdlr(e)
do_what_we_came_here_to_do()

def handle_interrossitor_error(e):
degausser.degauss(interrossitor)
interrossitor.activate()
reverse_the_polarity_of_the_neutron_flow(handle_interrossitor_error)

You can even do extra bonus higher-order-functioning:

def reverse_the_polarity_of_the_neutron_flow(ie_hdlr):
five_hundred_lines_of_code()
and_dozens_of_layers_of_nesting_and_indirection()
ie_hdlr(interrossitor.activate)
do_what_we_came_here_to_do()

def handle_interrossitor_error(fn):
try:
fn()
except InterrossitorError, e:
degausser.degauss(interrossitor)
interrossitor.activate()
reverse_the_polarity_of_the_neutron_flow(handle_interrossitor_error)

Although i can't see any reason why you'd want to.
if you can define the semantics, it's a few lines of code. if you're
not sure about the semantics, a built-in won't help you...

While we're on the subject, we had a big recursive flatten bake-off round
here a few months back: look for a thread called "flatten(), [was Re:
map/filter/reduce/lambda opinions andbackground unscientific
mini-survey]", and filter out the posts with code from the posts with
rants. There are all sorts of solutions, coming at the problem from
different angles, but the end of it is more or less here:

http://groups.google.co.uk/group/comp.lang.python/msg/0832db53bd2700db

Looking at the code now, i can see a couple of points where i could tweak
my flatten even more, but i think the few microseconds it might save
aren't really worth it!

tom
 
A

Alex Martelli

Tom Anderson said:
What would approximate FP equality even mean? How approximate?

In APL, it meant "to within [a certain quad-global whose name I don't
recall] in terms of relative distance", i.e., if I recall correctly,
"a=b" meant something like "abs(a-b)/(abs(a)+abs(b)) < quadEpsilon" or
thereabouts. Not too different from Numeric.allclose, except the latter
is "richer" (it takes both absolute and relative "epsilons", and also
implies an "and-reduce" if the objects being compared are arrays).


Alex
 
M

Mike Meyer

Tom Anderson said:
This is taken from the AIEEEEEEEE 754 standard, i take it? :)

Seriously, that's horrible. Fredrik, you are a bad man, and run a bad
railway.

However, looking at the page the OP cites, the only mention of that
operator i can find is in Dylan, and in Dylan, it's nothing to do with
approximate FP equality - it means 'not identical', which we can spell
"is not".

What would approximate FP equality even mean? How approximate?

Hopefully user defined. Rexx has a global control that lets you set
the number of digits to be considered significant in doing an FP
equality test.

<mike
 
D

Dennis Lee Bieber

Hopefully user defined. Rexx has a global control that lets you set
the number of digits to be considered significant in doing an FP
equality test.
That's the good part about the REXX model...

The bad part? It's based on the number of significant digits...
Rather than a true epsilon.
--
 
B

bearophileHUGS

Thank you for all the answers, some people have already answered for me
about most details I don't agree :)

Mike Meyer>Rexx has a global control that lets you set the number of
digits to be considered significant in doing an FP equality test.<

Mathematica too, I think.


Tom Anderson>There are all sorts of solutions, coming at the problem
from different angles, but the end of it is more or less here:<

Interesting, but I think in Python the recursive solutions cannot be
used, because they are too much fragile (they break with not much
nested levels), an iterative solution (using a stack) can manage enough
levels before finishing the memory ("not much" and "enough" are
relative things, I know... but there is probably a difference of 10**4
times still). Note that statistically most real-life structures to
flatten are probably quite flat (the most common are probably of depth
2), so probably the non recursive solution is the better again :)
Another problem with such solutions is that they don't allow to define
what to iterate over and what to not consider a sequence. This is
probably easy to define with an input parameter. (A compromise solution
is probably enough, without a fully general solution for this problem).
Another interesting possibility (suggested from Mathematica Flatten[]
syntax) is to add another parameter to specify how much levels to
flatten (all levels, only the first k levels, or all levels but the
last n levels), but maybe this last parameter can be a bit less easy to
remember, and Python functions are designed to be very easy to
remember.

Bye,
bearophile
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top