Two syntax questions (newbie)

S

Szabolcs

I used Mathematica for data processing a lot and I got spoiled by its
functional programming possibilities.
I was drawn to Python because it also allows for a similar programming
style (and, more importantly, it has an interactive shell, ipython,
and a lot of libraries that are useful to me, like scipy).
I am still learning the language, so please be gentle :)

And here comes the first question:

Mathematica allows writing
result = processData@Reverse@Sort@data
or even
result = data//Sort//Reverse//processData
instead of
result = processData[Reverse[Sort[data]]]

In Python this would be something like
result = processData(list(reversed(sorted(data))))

The first two Mma alternatives are both easier to read (especially
when part of a bigger expression) and easier to type (an re-type, if
working interactively) because I don't have to jump with the cursor to
the beginning and end of the expression to insert the brackets when
adding another function call.

Is there a way to avoid typing all the parentheses in Python? Is it
possible to define a different syntax for function calls or define a
function composition operator for functions that take a single
argument?

The second question:

Of course Python is not Mathematica and not as friendly with this
style as Mma is. Sometimes it forces me to use some temporary
variables (e.g. because lines get too long and breaking lines with a
backslash is ugly). I like to get rid of these variables as soon as
they aren't needed, e.g.:

temp = data[:]
temp.sort()
temp.reverse()
result = processData(temp)
del temp

Is it possible to avoid the explicit del temp? In C/C++ I would simply
enclose the piece of code in curly brackets. Is it possible to somehow
separate a block of code from the rest of the program and make
variables local to it?

Of course none of these two things would allow me do to something that
I can not already do, but they would make work easier. And I am
curious if they are possible.

Thanks for your replies in advance,
Szabolcs
 
G

Gabriel Genellina

Mathematica allows writing
result = processData@Reverse@Sort@data
or even
result = data//Sort//Reverse//processData
instead of
result = processData[Reverse[Sort[data]]]

In Python this would be something like
result = processData(list(reversed(sorted(data))))

The first two Mma alternatives are both easier to read (especially
when part of a bigger expression) and easier to type (an re-type, if
working interactively) because I don't have to jump with the cursor to
the beginning and end of the expression to insert the brackets when
adding another function call.

Is there a way to avoid typing all the parentheses in Python? Is it
possible to define a different syntax for function calls

Not a different syntax.
or define a
function composition operator for functions that take a single
argument?

You could use this:

def chain(*args):
"""Compose functions (assoc right).
last argument (args[-1]): argument to last function
args[0] .. args[-2]: functions taking a single argument
Returns args[0](args[1](...(args[-2]))(args[-1])
"""
args = list(args)
data = args.pop(-1)
while args:
fn = args.pop(-1)
data = fn(data)
return data

import random
items = [random.randrange(100) for _ in range(20)]
print chain(list, reversed, sorted, items)

Of course Python is not Mathematica and not as friendly with this
style as Mma is. Sometimes it forces me to use some temporary
variables (e.g. because lines get too long and breaking lines with a
backslash is ugly).

I almost never use backslashes for line continuation. If you have an open
(,[,{ continuation is implicit. If not, usually adding a heading ( is
enough.
That is, instead of

x = a + b + \
c - d

I'd use:

x = (a + b +
c - d)
I like to get rid of these variables as soon as
they aren't needed, e.g.:

temp = data[:]
temp.sort()
temp.reverse()
result = processData(temp)
del temp

Is it possible to avoid the explicit del temp? In C/C++ I would simply
enclose the piece of code in curly brackets. Is it possible to somehow
separate a block of code from the rest of the program and make
variables local to it?

Python does not have block scope; use a function instead. (It's hard to
define block scopes without variable declarations). Anyway that would make
any difference if you are using huge structures.
 
S

Szabolcs

Thanks for the reply!

or define a
function composition operator for functions that take a single
argument?

You could use this:

def chain(*args):
"""Compose functions (assoc right).
last argument (args[-1]): argument to last function
args[0] .. args[-2]: functions taking a single argument
Returns args[0](args[1](...(args[-2]))(args[-1])
"""
args = list(args)
data = args.pop(-1)
while args:
fn = args.pop(-1)
data = fn(data)
return data

import random
items = [random.randrange(100) for _ in range(20)]
print chain(list, reversed, sorted, items)

This is already better. Is it possible to define function composition
as an operator and have something like (list@reversed@sorted)(items)
or (list*reversed*sorted)(items) ?
I almost never use backslashes for line continuation. If you have an open
(,[,{ continuation is implicit. If not, usually adding a heading ( is
enough.
That is, instead of

x = a + b + \
c - d

I'd use:

x = (a + b +
c - d)

Thanks! This is very useful.

Szabolcs
 
D

Diez B. Roggisch

This is already better. Is it possible to define function composition
as an operator and have something like (list@reversed@sorted)(items)
or (list*reversed*sorted)(items) ?

Not on functions, but on classes/instances. So something like this might
work for you (untested):

class FunctionComposer(object):
def __init__(self, f=None):
if f is None:
f = lambda x: x
self._f = f

def __call__(self, *args, **kwargs):
return self._f(*args, **kwargs)

def __mul__(self, other):
def combined(*args, **kwargs):
return other(self._f(*args, **kwargs))
return FunctionComposer(combined)

fc = FunctionComposer

Then you can write

(fc() * list * reversed * sorted)(items)

Diez
 
D

Duncan Booth

Szabolcs said:
In Python this would be something like
result = processData(list(reversed(sorted(data))))

I know that is only intended as an example, but by trying to use
Mathematica idioms in Python you are perhaps blinding yourself to using
Python's own idioms. A more Pythonic way to write your example in Python
would be:

result = processData(sorted(data, reverse=True))

sorted already returns a list, and giving it 'reverse=True' is almost
always identical to sorting and then reversing (and in the rare cases
where it matters the reverse parameter is probably what you want).

The second question:

Of course Python is not Mathematica and not as friendly with this
style as Mma is. Sometimes it forces me to use some temporary
variables (e.g. because lines get too long and breaking lines with a
backslash is ugly). I like to get rid of these variables as soon as
they aren't needed, e.g.:

temp = data[:]
temp.sort()
temp.reverse()
result = processData(temp)
del temp

Is it possible to avoid the explicit del temp? In C/C++ I would simply
enclose the piece of code in curly brackets. Is it possible to somehow
separate a block of code from the rest of the program and make
variables local to it?

Move the code using the temporary variable into a function and it will
disappear as soon as the function returns. If you find you want to
delete the temporary before the function returns then your function is
too long.

As always there are caveats on this: don't depend on either 'del' or a
return from a function actually destroying objects immediately as any
surviving references to the value will prolong its life. Also, while the
current C-Python implementation deletes values immediately if they have
no references other Python implementations do not.

In this case the obvious fix is to use a function which copies, sorts
and reverses a sequence and then you don't need the temporary. Since
that function already exists you don't even need to write it.
 
M

Michael Hoffman

Diez said:
Not on functions, but on classes/instances. So something like this might
work for you (untested):

class FunctionComposer(object):
def __init__(self, f=None):
if f is None:
f = lambda x: x
self._f = f

def __call__(self, *args, **kwargs):
return self._f(*args, **kwargs)

def __mul__(self, other):
def combined(*args, **kwargs):
return other(self._f(*args, **kwargs))
return FunctionComposer(combined)

fc = FunctionComposer

Then you can write

(fc() * list * reversed * sorted)(items)

A clever little hack, but please don't do this. Anyone else who will
read your code will thank you.
 

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,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top