By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,446 Members | 1,566 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,446 IT Pros & Developers. It's quick & easy.

PEP 318 : Def and Class in expressions

P: n/a
PF

Hello,

I'm pleased to see activity on this topic as it pains me to write
"classmethod" two pages of code after the method definition. However I
find the decorators to obfuscate the syntax and lessen the expressivity
(ie. they restrain what can be done).

All these problems come from the fact that the execution of the
"foo=staticmethod(foo)" must be delayed after the execution of the "def"
statement because it must act on the function after it has been defined.

Normal program execution thus flow forces it to be placed after the
"def", while readability would require it to be placed *before* the 'def'.

How to reverse the execution order ? One method would be to use an
expression, but that would get very ugly soon, and Python's indented
syntax does not lend itself well to such twistings. To mix a few previous
postings :

mymethod = staticmethod( def (args):
method code...
)

is just plain ugly.

mymethod = staticmethod( def (args) ):
method code...

is also quite ugly.

I don't like the decorators either.

So the root of the problem is the fact that the source code executes from
top to bottom. I see two solutions.
1. Use a text editor which can fold functions, hiding the code between
the def and the staticmethod call
2. Reverse the flow of code.

Ha.
I'm gonna propose a flame bait, read on. It's about code blocks.

Say we introduce a new keyword : 'block'. Here is the syntax :

block (block-class,block-name):
some code
some code
some code

A block of code is thus an object, deriving from a base class (say,
'CodeBlock'). It can have children too (other blocks of code), which can
have names.
If omitted, block-class defaults to CodeBlock, and block-name to None.
(block-class,block-name) is a tuple, so the following are equivalent :

block-class => (block-class,None)
block-class,block-name => (block-class,block-name)
(,block-name) => (CodeBlock,block-name)

Example in the classmethod thingie :

block InvertingCodeBlock:
block:
mymethod = staticmethod(mymethod):
block:
def mymethod(arg1, arg2):
some code

where InvertingCodeBlock: is a block class which executes its children in
inverted order. This object has two children, both of class CodeBlock.

I invented the syntax as it came, it sucks, but it's just so you get the
idea. Feel free to propose something better. But first look at the
following.

Now, this has other, more interesting, things into it.
Example :

def crapthread( params ):
acquire_lock( global_lock )
do something
release_lock( global_lock )

This example sucks because any exception happening in "do something" will
not release the lock, and the lock must be manually released before every
return.

Now, CodeBlock can have children. What if CodeBlock decides the children
could be executed in a certain order ?
For instance, we could have children names "init", "run", "cleanup" which
would run in this order.
We could then write :

def crapthread( params ):
block:
block (,'init'):
acquire_lock( global_lock )
block (,'run'):
do something
block (,'cleanup'):
release_lock( global_lock )

I expect anyone will understand how this works. The parent block would
execute 'init', then 'run', then 'cleanup', then pass anu return'ed value
or exceptions.

If the 'def' statement implies creation of a code block, we could omit
the first 'block:'

The classmethod example cound be rewritten as :
block:
block (,'init'):
mymethod = staticmethod(mymethod):
block (,'run'):
def mymethod(arg1, arg2):
some code

We could define other types of children too, like a version of cleanup
which is executed oly when no exceptions occur in "run".

Now let's add the __currentblock__ which gives us a reference to the
block we're in, and give the block object a way to add children of a
certain type. We could thus register cleanup actions to be executed at the
end of a function when needed.

try-except-finally could also be done with blocks.

All this is very preliminary thinking. I hope it fuels your inspiration.
I feel this could be powerful, and also pythonic. What do you think ?

Thanks for your time,

Pierre
Jul 18 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
"PF" <pe****@free.fr> wrote in message news:op**************@news.free.fr...

Hello,

I'm pleased to see activity on this topic as it pains me to write
"classmethod" two pages of code after the method definition. However I
find the decorators to obfuscate the syntax and lessen the expressivity
(ie. they restrain what can be done).

All these problems come from the fact that the execution of the
"foo=staticmethod(foo)" must be delayed after the execution of the "def"
statement because it must act on the function after it has been defined.

Normal program execution thus flow forces it to be placed after the
"def", while readability would require it to be placed *before* the 'def'.

How to reverse the execution order ? One method would be to use an
expression, but that would get very ugly soon, and Python's indented
syntax does not lend itself well to such twistings. To mix a few previous
postings :

mymethod = staticmethod( def (args):
method code...
)

is just plain ugly.

mymethod = staticmethod( def (args) ):
method code...

is also quite ugly.

I don't like the decorators either.

So the root of the problem is the fact that the source code executes from
top to bottom. I see two solutions.

Check out "Re: Meta-class fun with PEP 318 [was Re: PEP 318 - posting
draft]", for another solution, but only for methods.

decorate("g", staticmethod)
def g():
return "G"

Sean
Jul 18 '05 #2

P: n/a

"PF" <pe****@free.fr> wrote in message news:op**************@news.free.fr...

Hello,

I'm pleased to see activity on this topic as it pains me to write
"classmethod" two pages of code after the method definition. However I
find the decorators to obfuscate the syntax and lessen the expressivity
(ie. they restrain what can be done).
Why are you writing methods that long? (That's rhetorical -
I'd break it up so I could understand it)

All these problems come from the fact that the execution of the
"foo=staticmethod(foo)" must be delayed after the execution of the "def"
statement because it must act on the function after it has been defined.
That isn't the only problem, but it's the one most often cited.
Normal program execution thus flow forces it to be placed after the
"def", while readability would require it to be placed *before* the 'def'.
I'd prefer it as part of the same expression as the 'def'. That makes it
quite clear, and eliminates any possible confusion from having two
assignments where one should be sufficient.
How to reverse the execution order ? One method would be to use an
expression, but that would get very ugly soon, and Python's indented
syntax does not lend itself well to such twistings. To mix a few previous
postings :

mymethod = staticmethod(def(args):
method code...
)

is just plain ugly.
Agreed. I don't like the trailing parenthesis on another line.
Avoiding that is part of the joy of Python. (Notice that
I've reworked your example to conform to Guido's style
rules.)
mymethod = staticmethod(def(args)):
method code... is also quite ugly.
Why? Except for the ':', which I would eliminate (although
there are arguements for keeping it) I think it reads quite well.

I don't like the decorators either.
Neither do I. I don't find that any version of the syntax flows.
So the root of the problem is the fact that the source code executes from
top to bottom. I see two solutions.
1. Use a text editor which can fold functions, hiding the code between
the def and the staticmethod call
That doesn't fix it; there's still two statements where there should
be only one.
2. Reverse the flow of code.
I'm going to stop here and go off in another direction...
[snip rest of post]

As I said above, I find:

aMethod = staticmethod(def(parms))
statements

to be quite readable. The indentation says everything I need
said to understand it while scanning without having to resort
to studying the syntax (which I would have to do with brace-
bound languages.)

Multiple decorators fall out without any effort. There are
really only two issues:

1. The lack of a ":" at the end.

2. How to handle multiple blocks in one expression.

On item 1. There are two good reasons for the ":":
readability and the fact that most Python aware editors
use it for automatic indentation.

Regardless of what happens, readability is going to take
a hit, and the editors can be patched.

The way to handle item 2 is with the following set of
indentation rules:

1. There may be at most one 'def' on a line (*not* in a
statement!)

2. If the expression containing the def does not end naturally
on the same line as the ')' at the end of the def, parsing of
the expression is suspended at the end of that line (*not*
immediately after the ')'. The reason for this rule is to allow
the containing statement to end in the most readable fashion,
if possible.

3. The statements for the def follow immediately
on the next line and following lines, indented either 1 or 2
levels depending on whether the containing expression ended
or was suspended.

4. The body of the function/method ends, as usual, when
any line is indented less (that is, farther to the left) than the
body of the function/method.

5. A suspended expression continues on the line immediately
after the end of the function body. It must be indented to the
left of the function body, and to the right of the indentation for
the statement containing the expression.

In looking at this, I see one other problem: a multi-line
statement that contains several lines after the last one that
contains a 'def'. My personal preference is that I can finish
out the statement before writing the function body, but I
don't see a way of managing both multiple blocks in one
expression and doing this.

Finally, I have another reason for liking this particular
syntax. It lets me stick methods into instances quite
directly, without having to invent yet another syntax, or
leaving them bound at the module level to both be bound
into the instance and also cleaned up from the module.
That's something that I need for certain kinds of programs
that are more easily expressed with a proto-type based
language, such as interactive fiction.

John Roth

Pierre

Jul 18 '05 #3

P: n/a
On Sat, 27 Mar 2004 15:56:18 -0500, "John Roth"
<ne********@jhrothjr.com> wrote:

"PF" <pe****@free.fr> wrote in message news:op**************@news.free.fr...

Hello,

I'm pleased to see activity on this topic as it pains me to write
"classmethod" two pages of code after the method definition. However I
find the decorators to obfuscate the syntax and lessen the expressivity
(ie. they restrain what can be done).
Why are you writing methods that long? (That's rhetorical -
I'd break it up so I could understand it)


While readable methods tend to be short methods, breaking up a method
without good reason can also damage readability. Also, having many
simple units doesn't remove complexity - it merely means that the
complexity is in the interaction between units. And if readers can
only understand the units one or two at a time, and don't understand
how the units interact, it follows that the code as a whole isn't
readable.

I've seen this problem more times than I care to mention. You look at
module A and it all makes sense and looks fine. You look at module B
and it all makes sense and looks fine. You look at modules A and B
together and you can spot the incompatibility - the difference in the
assumptions made in each module about the interactions between them.
But when there are 100 much simpler modules, and a dozen or more play
some role in the incompatibility, suddenly its much harder to
understand how the incompatibility arises.

Keeping related code and definitions together is a good principle. But
that applies just as much to two pieces of related function body code
as it does to a function definition and its wrapper. If you routinely
split long functions purely for reasons like keeping the wrapping
statement close to the definition of the function it wraps, or out of
the principle that methods should be short, then that's fine. But
don't expect me to read it.

All things are a balance in programming, as in life. Strong principles
can get you only so far - if you impose absolute principles on
everyone and in every case, often they will do more damage than good.
mymethod = staticmethod(def(args)):
method code...

is also quite ugly.


Why? Except for the ':', which I would eliminate (although
there are arguements for keeping it) I think it reads quite well.


Mainly because the method code appears to be associated with the
assignment, or the assigned variable, rather than the def. It's hard
(maybe impossible?) to name a block structure in any language that
doesn't start with a word that identifies the type of block. Probably
the only common statements of any type that don't start with an
identifying keyword are assignments. That isn't a fluke.

Anyone pointing out the streaming operators in C++ gets half a point.
Strictly they're just operators in an expression, but they get used in
such an imperitive way that I half count them as statements.
I don't like the decorators either.


Neither do I. I don't find that any version of the syntax flows.


There is a certain lack of beauty, I agree. But while there is beauty
in simplicity, there is pragmatism in realising that not all
complexity can be avoided.

2. How to handle multiple blocks in one expression. <snip>The way to handle item 2 is with the following set of
indentation rules:
I disagree.

There are two common cases I can think of where names are used before
they are defined. One is mathematics (y = mx + c, where x is ...) and
the other is Haskell, working on much the same principle.

There is a certain similarity of purpose in the Pascal 'with' block,
in that the Haskell 'where', like the Pascal 'with', is mainly used
for abbreviation - though the means is rather different.

Messing around with these principles, I came up with...

with x :
x = staticmethod(x)
where def x (args) :
...

But virtually the only suggestion I prefer this to is yours, I'm
afraid :-(
5. A suspended expression continues on the line immediately
after the end of the function body. It must be indented to the
left of the function body, and to the right of the indentation for
the statement containing the expression.


This suggestion is IMO close to insane.

You are breaking up a statement and putting potentially quite large
chunks of body code in the middle of it - maybe several function
bodies. And you are doing this to avoid having code between the
function definition and its wrapping assignment.

In other words, you are deliberately splitting up closely related code
in order to avoid splitting up closely related code. And making the
lexical structure and layout of Python code more complex in order to
do it.

If you limit it to the case where a single statement containing a
single def can be followed by the body code, then it isn't actually
insane (though I'm still strongly against it) but if you have two
functions being manipulated by the same wrapping code (I don't see the
need, but lets go with it anyway) then one way or another the wrapping
code is going to be separated from at least one functions body. In
this case, referring to the functions by name is the only thing that
makes sense. We don't need any new syntax to do that.
--
Steve Horne

steve at ninereeds dot fsnet dot co dot uk
Jul 18 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.