[Python-Dev] PEP 318 - generality of list; restrictions on elements

Greg Ewing greg at cosc.canterbury.ac.nz
Mon Mar 8 18:52:39 EST 2004


"Jewett, Jim J" <jim.jewett at eds.com>:

> Right now, the variable portion of the syntax is:
> 
> 	'[' wrapper (, wrapper)* ']'
> 
> What else should be accepted, to avoid surprises?

Whatever else happens, I think the square brackets should always be
present. They do *not* denote list construction; they are the
syntactic elements which say "here is a parenthetical note concerning
qualities which this function is to have".

> What are the restrictions on list items?
> 
> 	Only a function?
> 	Only a code object?  (I assume so)

Any callable object should be acceptable as a wrapper. I don't
see any need to restrict them to functions.

To allow for dynamic insertion of a sequence of wrappers, I can
think of two possibilities:

(A) Allow a list or tuple of further items to be used as an item.

(B) Allow a '*' before an item to mean that the item is to
be treated as a sequence of items to be iterated over.

I think I prefer (B) because it eliminates any need for type
testing, and allows any iterable to be used as the items sequence
rather than being restricted to certain sequence types.

> 	Must the code return the original function?
> 	Must the code return a code object?

The wrapper can return any object it likes, as long as it makes sense
to insert it into the class dict as the result of the def, or pass it
on to further wrappers. (In most cases it probably *won't* return the
original function -- that's the whole point of wrapping!)

> 1.	# fail, integer not a callable?  (Don't try to slice the args!)
> 	def name(args)[0]:

Yes, fail.


> 2.	# fail, as w[0] is itself a (non-callable) list?
> 	w = [wrapper]
> 	def name(args) [w]:

Under suggestion (A) above, recurse into the list. Under (B),
fail (item non-callable).

> 3.	# fail, not a list?
> 	def name(args) classmethod:

Syntax error.

> 4.	# ??? lambda would be OK, except for the second ":"
> 	def name(args)[lambda x: x]:

Accepted. I can't see any reason why the second ':' should be
an issue, any more than the multiple ':' in nested lambdas
causes any problem.

> 5.	# should succeed?
> 	def name(args)[x for x in decorators if x in active]:	

On the understanding that there is a generator expression
between the [...]:

  Under (A): Fail, item is not callable and is not a list or tuple
             (it's a generator-iterator).

  Under (B): Fail, item is not callable. This would succeed, however:

     def name(args)[*x for x in decorators if x in active]:

> 6.	# ??? wrapper does not return a callable.
> 	y = lambda x: None
> 	def name(args) [y]:

Succeeds, but leaves 'name' defined as 'None' in the target
namespace, which probably isn't very useful.

> 7.	# a list, but no '[]'.  either surprises.
> 	def name(args) list((wrap1, wrap2)):

Syntax error.

> 8.	# a list, but no '[]'.  either surprises.
> 	w = [wrapper]
> 	def name(args) w:		

Syntax error.

> 9.	# a list, but no '[]'.  either surprises.
> 	def w(): return [y,y,y]
> 	def name(args) w():

Syntax error.

> Do the wrappers have to be defined when the definition starts?

The wrapper expressions are evaluated when the def is executed (same
as with default argument values).

> def outer():
>     # w not defined at module load, but defined before any call
>     def inner(x)[w]:
>         print x
>     return inner

Okay.

But if that is OK, then which w would be used in the next example?

> def w(fn): 
>     print "outside w"
>     return fn
> 
> def outer():
>     # w not defined yet, but defined in this
>     def inner(x)[w]:
>         print x
>     def w(fn):
>         return fn
>     inner(5)

The w in def inner(x)[w]: refers to the local w, which is not
bound when the inner def is executed, so a NameError results
when outer() is called.

> How about this?  There is no guarantee that othermod
> will finish loading first, though I suppose that 
> already causes problems today.
> 
> import othermod
> def fn()[othermod.wrap]:
>     pass

You take your chances. Okay if othermod gets as far as
binding othermod.wrap by the time def fn() is executed
(which presumably it will as long as nothing goes wrong).

Greg Ewing, Computer Science Dept, +--------------------------------------+
University of Canterbury,	   | A citizen of NewZealandCorp, a	  |
Christchurch, New Zealand	   | wholly-owned subsidiary of USA Inc.  |
greg at cosc.canterbury.ac.nz	   +--------------------------------------+





More information about the Python-Dev mailing list