Why can function definitions only use identifiers, and not attributereferences or any other primarie

J

Jeremy Banks

Hi. I'm sure there've been debates about this before, but I can't seem
to figure out what to search for to pull them up, so I'm asking here.

It seems to me that a lot of things could be made much easier if you
could use primaries other than basic identifiers for the target of
function definitions. For example, if attribute references were
allowed I'd be able to do:

def foo.bar():
return("I'm a method!")

If we wanted to get even more liberal (which I don't see as a bad
thing, but I could see being found more objectionable by some), we
could allow the use of anything that's a valid assignment target. For
example:

def foo["bar']():
return("I'm a function referenced in a mapping object!")


In this case I could see there being a problem in that there's nothing
to get the function's __name__ from, but that doesn't apply for the
first example.

Many uses of this may not be Pythonic, but I'm sure there are many
that are. It just feels like an arbitrary restriction, preventing
users from doing something that may be useful.

Any feedback or direction to previous discussion on the subject would
be appreciated. Thanks!
 
G

Gary Herron

Jeremy said:
Hi. I'm sure there've been debates about this before, but I can't seem
to figure out what to search for to pull them up, so I'm asking here.

It seems to me that a lot of things could be made much easier if you
could use primaries other than basic identifiers for the target of
function definitions. For example, if attribute references were
allowed I'd be able to do:

def foo.bar():
return("I'm a method!")

There's no need for a specific addition to the syntax to do this.

Try this:

def foo_bar():
return(...)
foo.bar = foo_bar
If we wanted to get even more liberal (which I don't see as a bad
thing, but I could see being found more objectionable by some), we
could allow the use of anything that's a valid assignment target. For
example:

def foo["bar']():
return("I'm a function referenced in a mapping object!")

and this:

def foo_bar():
return(...)
foo["bar"] = foo_bar


In this case I could see there being a problem in that there's nothing
to get the function's __name__ from, but that doesn't apply for the
first example.

Not sure what you mean here.
 
A

Alan Franzoni

Jeremy Banks was kind enough to say:
Hi. I'm sure there've been debates about this before, but I can't seem
to figure out what to search for to pull them up, so I'm asking here.

I'm not exactly sure what you mean... if you want to add functions to
another fuction, just do it this way:

def foo():
return "i'm the main function."

foo.bar = lambda: "i'm the bar attr"

print foo()
print foo.bar()
def foo.bar():
return("I'm a method!")

So you'd just like some "syntactic sugar" to let function declarations to
be "shorter"?

I think this wouldn't make the language that clear. In order to accomplish
what you want, you could just use a class and the __call__ method for the
"main" function.

I think that what you really mean is that you would like an "improved
lambda" or "different def". E.g., that could you write anonymous functions
( or ruby-like code blocks ) in a different way. Something like this:

d["func"] = def pippo(a, b, c):
...
...
...

I suppose the reason behind this is that it's not really needed. There're
plenty of ways to do this sort of things in python; if you just declare
methods in a class you can just use the plain def in order to achieve this,
and you can inherit from your container and specialize some methods in
order to achieve results which are similar to those you want.



--
Alan Franzoni <[email protected]>
-
Remove .xyzz from my email in order to contact me.
-
GPG Key Fingerprint:
5C77 9DC3 BD5B 3A28 E7BC 921A 0255 42AA FE06 8F3E
 
J

Jeremy Banks

Thanks for your comments.


There's no need for a specific addition to the syntax to do this.

Try this:

  def foo_bar():
      return(...)
  foo.bar = foo_bar

and this:

  def foo_bar():
      return(...)
  foo["bar"] = foo_bar

I understand that this is possible now, but I just don't see why it's
necessary to do it at all.
Not sure what you mean here.

>>> def foo(): pass
...
>>> bar = foo
>>> bar.__name__
'foo'
>>>

If I defined foo.bar it would know that the method name was "bar", but
if I defined foo["bar"] there's be no clear identifier to use for the
function's name. I don't see this as a great problem, since anonymous
functions already exist, but I thought it was worth acknowledging.

To be clear, I don't see this as a serious fault in the language, but
as an unnecessary restriction that makes code a little less direct
than it could be.
 
G

Gary Herron

Jeremy said:
Thanks for your comments.

There's no need for a specific addition to the syntax to do this.

Try this:

def foo_bar():
return(...)
foo.bar = foo_bar

and this:

def foo_bar():
return(...)
foo["bar"] = foo_bar

I understand that this is possible now, but I just don't see why it's
necessary to do it at all.

Not sure what you mean here.

>>> def foo(): pass
...
>>> bar = foo
>>> bar.__name__
'foo'
>>>

If I defined foo.bar it would know that the method name was "bar", but
if I defined foo["bar"] there's be no clear identifier to use for the
function's name. I don't see this as a great problem, since anonymous
functions already exist, but I thought it was worth acknowledging.

To be clear, I don't see this as a serious fault in the language, but
as an unnecessary restriction that makes code a little less direct
than it could be.


Things like your suggestion are called "syntactic-sugar" -- syntax that
adds a convenience, but *no* new functionality. Python has plenty of
"syntactic-sugar"s, and more will be added in the future. To make an
argument for such an addition, one would have to describe some
compelling (and general) use cases in a well-argued PEP. You're welcome
to try, but be forewarned, most PEP's (especially syntax changing PEPs)
don't fly far.

 
J

Jeremy Banks

Things like your suggestion are called "syntactic-sugar"  -- syntax that
adds a convenience, but *no* new functionality.  Python has plenty of
"syntactic-sugar"s, and more will be added in the future.  To make an
argument for such an addition, one would have to describe some compelling
(and general) use cases in a well-argued PEP.  You're welcome to try, but be
forewarned, most PEP's (especially syntax changing PEPs) don't fly far.

Thank you very much for the feedback. I might throw something at
Python-Ideas if I think I can come up with an adequate justification
and don't come accross a previous similar propsition (though if I do
miss it I'm sure it will be pointed out to me fairly quickly). I fully
appreciate the small chance of success, but it certainly couldn't hurt
to give it a try.
 
J

John Krukoff

Thank you very much for the feedback. I might throw something at
Python-Ideas if I think I can come up with an adequate justification
and don't come accross a previous similar propsition (though if I do
miss it I'm sure it will be pointed out to me fairly quickly). I fully
appreciate the small chance of success, but it certainly couldn't hurt
to give it a try.

You probably want to be searching for multi-line lambda to find the past
decade or so of this argument, as that's where most people who argued
for this came from. But, if you'd just like a bit of discouragement,
here's GvR arguing that there's just no good way to mix statements and
expressions in python:
http://www.artima.com/weblogs/viewpost.jsp?thread=147358
 
J

Jeremy Banks

You probably want to be searching for multi-line lambda to find the past
decade or so of this argument, as that's where most people who argued
for this came from. But, if you'd just like a bit of discouragement,
here's GvR arguing that there's just no good way to mix statements and
expressions in python:
http://www.artima.com/weblogs/viewpost.jsp?thread=147358

I've read those discussion before, but somehow never made the
connection between those and this. I'll give that article a read, it
probably details exactly the perspective I'm looking for. Thank you!
 
M

Marco Mariani

Jeremy said:
I've read those discussion before, but somehow never made the
connection between those and this. I'll give that article a read, it
probably details exactly the perspective I'm looking for. Thank you!

You could also read this:

http://unlimitednovelty.com/2009/03/indentation-sensitivity-post-mortem.html

The author is writing a language for the Erlang VM inspired by Python
and Ruby. He had some trouble (at the grammar level) in keeping both
"indentation working like in python" (dear to Guido and many of us) and
"anonymous blocks" (dear to functional languages).
So he got braces and was happy :)
 
T

Terry Reedy

Jeremy said:
Hi. I'm sure there've been debates about this before, but I can't seem
to figure out what to search for to pull them up, so I'm asking here.

It seems to me that a lot of things could be made much easier if you
could use primaries other than basic identifiers for the target of
function definitions. For example, if attribute references were
allowed I'd be able to do:

def foo.bar():
return("I'm a method!")

If we wanted to get even more liberal (which I don't see as a bad
thing, but I could see being found more objectionable by some), we
could allow the use of anything that's a valid assignment target. For
example:

def foo["bar']():
return("I'm a function referenced in a mapping object!")


In this case I could see there being a problem in that there's nothing
to get the function's __name__ from, but that doesn't apply for the
first example.

Many uses of this may not be Pythonic, but I'm sure there are many
that are. It just feels like an arbitrary restriction, preventing
users from doing something that may be useful.

Any feedback or direction to previous discussion on the subject would
be appreciated. Thanks!

There has been some discussion on py-dev and perhaps python-ideas, but I
cannot remember any specifics as to why Guido was unpersuaded/negative.

If one regards

def name(params): body

as syntantic sugar for a (somewhat hypothetical) assignment statement

name = make_func('name', "params", "body")

(there is a function_maker function in the new module, though with a
more complicated interface), then generalizing the target would seem
reasonable. The function's __name__ does not seem like an issue:
"foo.bar" and "foo['bar']" both direct one to the proper definition code.

Counter-argument: class and import are also implied assignments, and
they also subject to the same limitation.

Counter-counter-argument: a) doing actual assignments with name =
type('name', bases, dict) and name = __import__('name',...) is more
feasible, and b) the need for qualified names is less for class and
probably for import and c) the restriction *could* also be lifted for
those two statements also.

For some, a plus for this proposal is that is directly binds the
function to the target without introducing a spurious name into the
local scope. It would thus reduce the perceived need for and hence
pressure for generalized function expressions. I believe Guido would
consider this last point a plus if so stated.

I do not believe this recurring idea has been the subject of a PEP. If
not, writing one might be a service, should you choose to do so, even if
rejected.

Terry Jan Reedy
 
J

Jeremy Banks

Jeremy said:
Hi. I'm sure there've been debates about this before, but I can't seem
to figure out what to search for to pull them up, so I'm asking here.
It seems to me that a lot of things could be made much easier if you
could use primaries other than basic identifiers for the target of
function definitions. For example, if attribute references were
allowed I'd be able to do:
    def foo.bar():
        return("I'm a method!")
If we wanted to get even more liberal (which I don't see as a bad
thing, but I could see being found more objectionable by some), we
could allow the use of anything that's a valid assignment target. For
example:
    def foo["bar']():
        return("I'm a function referenced in a mapping object!")
In this case I could see there being a problem in that there's nothing
to get the function's __name__ from, but that doesn't apply for the
first example.
Many uses of this may not be Pythonic, but I'm sure there are many
that are. It just feels like an arbitrary restriction, preventing
users from doing something that may be useful.
Any feedback or direction to previous discussion on the subject would
be appreciated. Thanks!

There has been some discussion on py-dev and perhaps python-ideas, but I
cannot remember any specifics as to why Guido was unpersuaded/negative.

If one regards

def name(params): body

as syntantic sugar for a (somewhat hypothetical) assignment statement

name = make_func('name', "params", "body")

(there is a function_maker function in the new module, though with a
more complicated interface), then generalizing the target would seem
reasonable.  The function's __name__ does not seem like an issue:
"foo.bar" and "foo['bar']" both direct one to the proper definition code.

Counter-argument: class and import are also implied assignments, and
they also subject to the same limitation.

Counter-counter-argument: a) doing actual assignments with name =
type('name', bases, dict) and name = __import__('name',...) is more
feasible, and b) the need for qualified names is less for class and
probably for import and c) the restriction *could* also be lifted for
those two statements also.

For some, a plus for this proposal is that is directly binds the
function to the target without introducing a spurious name into the
local scope.  It would thus reduce the perceived need for and hence
pressure for generalized function expressions.  I believe Guido would
consider this last point a plus if so stated.

I do not believe this recurring idea has been the subject of a PEP.  If
not, writing one might be a service, should you choose to do so, even if
rejected.

Terry Jan Reedy

Interesting, thank you very much for your suggestions. I'll try to put
together a draft.
 
M

Marco Mariani

Scott said:
I am afraid it will make it too easy to define functions in other
modules remotely, a tempting sharp stick to poke your eye out with.

It's not very hard at the moment, and I don't see lots of eyes flying
by. I don't know about Ruby where monkeypatching seems to be common
practice, though.
Imagine debugging a pile of code that includes a module with:
import random
def random.random():
return .42

No need to imagine. I can do the same, one line shorter:
 
S

Steven D'Aprano

I am afraid it will make it too easy to define functions in other
modules remotely, a tempting sharp stick to poke your eye out with.

It's not terribly difficult to do so already:
.... return "spam spam spam"
....'spam spam spam'

Note
also, that it will not be so easy to find the definition of a function
provided as a argument to a failing function. Right now you can get the
function name and (with a bit more effort) its module. Imagine debugging
a pile of code that includes a module with:
import random
def random.random():
return .42
Easy-peasy.
'__main__'


Sure, if somebody wants to really work at it, they could create a
function that looks exactly like the original, including claiming to come
from the same module, but that's possible now anyway.

I don't think the proposed syntax is useful because it doesn't actually
gain us anything. Currently, you add a function to a class at class
creation time:

class Spam(object):
def spam(self):
return "spam spam spam"

Adding functions to a class after the class already exists is rare, but
not unheard of. Currently you can do this:

def ham(self):
return "ham is not spam"

Spam.ham = ham
del ham # if you can be bothered


And you're done. The proposal gives us this:

class Spam(object):
pass # Need to have a class before you can add methods to it.

def Spam.spam(self):
return "spam spam spam"

def Spam.ham(self):
return "ham is not spam"



Whatever benefit there might be from doing this, it's so minor I don't
think it's worth the effort to implement it. Unlike decorators, I'd be
surprised if it opens the door to bigger and better things.
 

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,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top