PEP 318: Can't we all just get along?

M

Michael J. Fromberger

Paul Morrow said:
Actually, it illustrates the importance of proof-reading a post
before posting it, which I didn't (sorry).

Understood, no worries.
I should've also stated that the Python developers would be told that
this is a special version of Python that automatically determines the
type (static|class|instance) of a method. In that light, do you see
how effective the visual convention can be?

Oh, I see it just fine -- but I still disagree with the idea of
including any such implicit magic in the language.

In fact, I don't like some of the magic that is already there -- such
as, for instance, the automatic mangling of class members whose names
begin with a double underscore to get "private" semantics. But that, at
least, is easy to avoid, if one doesn't want to use it.
* If method's first param is 'self', it's an instance method.
* If method's first param is 'cls' or 'klass', it's a class method.
* All other methods are static methods.

Uck. -1 from me.

-M
 
P

Paul Morrow

Michael said:
Oh, I see it just fine -- but I still disagree with the idea of
including any such implicit magic in the language.

In fact, I don't like some of the magic that is already there -- such
as, for instance, the automatic mangling of class members whose names
begin with a double underscore to get "private" semantics. But that, at
least, is easy to avoid, if one doesn't want to use it.

Unless of course you want a method to be private/semi-private. How do
you feel about the way we can create/manipulate lists and dictionaries
using special (magical) syntax? Why is that different (acceptable)?

x = [10, 20, 30]

is shorthand for what would be much more code in other languages. Is
that syntax ok but

def __iAmPrivate(): pass

isn't? Why?
 
A

Anthony Baxter

Unless of course you want a method to be private/semi-private. How do
you feel about the way we can create/manipulate lists and dictionaries
using special (magical) syntax? Why is that different (acceptable)?

Look, name-mangling is horrid, and I don't think anyone's defending it. But
at the same time, "name mangling is there" is not an argument for extending
the horror to a whole new level.

Name mangling only occurs when you create a method with two leading
underscores, and no trailing ones. Your proposal would hit _every_ _single_
'def'. It's nasty, it's unpythonic, and there's approximately _zero_ chance of
it ever going into the language. Having said that, it's perfectly feasible to do
it with a metaclass, and if you want to use it in your code, please, feel free.

Anthony
 
P

Paul Morrow

Anthony said:
Look, name-mangling is horrid, and I don't think anyone's defending it. But
at the same time, "name mangling is there" is not an argument for extending
the horror to a whole new level.

Name mangling only occurs when you create a method with two leading
underscores, and no trailing ones. Your proposal would hit _every_ _single_
'def'. It's nasty, it's unpythonic, and there's approximately _zero_ chance of
it ever going into the language. Having said that, it's perfectly feasible to do
it with a metaclass, and if you want to use it in your code, please, feel free.

Anthony

You didn't follow that one with a smiley either... :)
 
P

Paul Morrow

Anthony said:
Look, name-mangling is horrid, and I don't think anyone's defending it. But
at the same time, "name mangling is there" is not an argument for extending
the horror to a whole new level.

I disagree. It's an effective name-hiding technique. Simple +
Effective = Good.

Name mangling only occurs when you create a method with two leading
underscores, and no trailing ones. Your proposal would hit _every_ _single_
'def'. It's nasty, it's unpythonic, and there's approximately _zero_ chance of
it ever going into the language. Having said that, it's perfectly feasible to do
it with a metaclass, and if you want to use it in your code, please, feel free.

It's not unpythonic, if by that you mean that it's unlike other python
formalisms. And it would *only* hit those defs that were attributes of
classes derived from a new Object (capital 'O') class.
 
M

Michael J. Fromberger

Paul Morrow said:
Michael said:
Oh, I see it just fine -- but I still disagree with the idea of
including any such implicit magic in the language.

In fact, I don't like some of the magic that is already there -- such
as, for instance, the automatic mangling of class members whose names
begin with a double underscore to get "private" semantics. But that, at
least, is easy to avoid, if one doesn't want to use it.

Unless of course you want a method to be private/semi-private. How do
you feel about the way we can create/manipulate lists and dictionaries
using special (magical) syntax? Why is that different (acceptable)?

x = [10, 20, 30]

is shorthand for what would be much more code in other languages. Is
that syntax ok but

def __iAmPrivate(): pass

isn't? Why?

I'm glad you asked this question -- you have highlighted an important
distinction we should all heed. In short: The special syntax for list
construction (to use your example) is "explicit magic" rather than
"implicit magic."

Use of a square-bracketed tuple for list construction is almost
completely orthogonal to other language features (modulo indexing), it
correlates well to other familiar notations for lists, and it improves
the readability of the code without obscuring anything. These are some
key hallmarks of good syntax.

By contrast, the special leading-double-underscore convention for class
members and the idea to identify instance, static, or class methods
based on the name of their first parameter, are not even a visibly
syntactic change. Each of these ideas specially overloads the single
most common programming-language operation -- interpretation of a
variable name -- under particular circumstances. This technique is (as
far as I know) nearly unprecedented in other languages, so it would be
surprising to most programmers. Furthermore, I think it makes code less
readable, by hiding important facts inside an implicit assumption about
the content of non-keyword identifiers, which are otherwise never
special.

Many people respond to this by saying, "The programmer has to be careful
anyway, so what is one more thing?" You could ask the same question
about drivers and beer. Little distractions add up to big mistakes.

Let me add that I do not intend to assert that all syntactic sugar is
bad (even if, as Alan Perlis suggested, "syntactic sugar causes cancer
of the semi-colon" :) However, the simple fact is, unless there is a
really good reason, we shouldn't make programmers (i.e., ourselves)
memorize more special cases. Going back to your example: There is an
excellent case for a compact and orthogonal list construction notation.
There is no good case for magically overloading non-keyword identifiers
in certain contexts -- especially when there is a better and more
explicit way to do it.

Thank you for your good example, Paul.

Cheers,
-M
 
R

Roy Smith

Paul Morrow said:
I disagree. It's an effective name-hiding technique. Simple +
Effective = Good.

I disagree with your disagreement :)

I find a mix of text and puctuation difficult to read. Human brains
don't read letters, they read whole words. That's why, for example,
it's so easy to make a typo and not notice it. I find "word.word" easy
to parse, but "word.__word" much more difficult. I don't know if it's
the switching back and forth between letters and symbols, or the
juxtaposition of the two symbols down on the baseline (i.e. ".__") that
makes it hard to read.

This is true of the __name__ convention for internal names too, but
somehow I don't find that as bad. Maybe because it's symmetric? Maybe
because my brain recognizes the whole __name__ as a unit, with the
"name" part of it being what I really recognize?

Even worse is when mix them. Stuff like "__myPrivateFunc.__name__" is
total gibberish to me.

Oh my god, I just realized (Ob decorator comment here) that if we start
having people write private decorators, we'll have things like:

@__decorator

which really makes me barf.
 
J

John Roth

Kevin Smith said:
For what it's worth, I wrote the original PEP 318. I probably wasn't
qualified, but I just wanted a nice simple way to declare class methods
without having to repeat the function name. After submitting it to BDFL
for approval, more work was needed and the discussion of PEP 318 on
python-dev increased rapidly. It was evident that I was in over my head,
so I asked more someone more experienced to take over.

I guess others had bigger plans for my proposal that I had planned. It
has turned into the "solution" to many problems: type checking (both
arguments and returned values), metaclasses, metadata, interfaces,
function attributes, etc.). Unfortunately, in the process, this simple
request for syntactical sugar has turned into a monstrosity. In my
opinion, none of the proposed syntaxes really seem Pythonic. This PEP
just seems to be trying to solve too many problems.

I don't think that is the case. What is actually going on has to do
with the mechanics of the classmethod and staticmethod functions.
They wrap the actual function in a special purpose descriptor.

The current approach is simply to allow running any wrapping
function, not just classmethod and staticmethod. That is, in a
very real sense, realistic because if they put in a special purpose
hack for just those two descriptors, then you'd get a huge backlash
from people who will still complain that it doesn't support, for
example, properties.

All the other stuff you're seeing isn't something that the proposal
has to support explicitly. You can wrap a function in any kind
of a descriptor you want. They are simply use cases, and IMHO,
some of them are not very well founded. However, none of them
involves one line of code more or less than the basic "allow
any descriptor anyone cares to write as a wrapper" approach.

The arguement is, and always has been, about syntax. Everyone
agrees that the current situation is not ideal; putting the wrapping
assignment statement after the method is a very poor way of
declaring intent.

In other words, forget the use cases. They're irrelevant. The
sticking point on syntax has to be solved first. If it is, then
I doubt if you're going to get a special purpose, just those
two specific descriptors and no others, solution. I just don't
see it happening.

There is, by the way, one syntax that hasn't to my knowledge
been proposed that is straightforward, natural, doesn't
make it begin to look like line noise and is completely
consistent with existing syntax. Just use the '.' operator
on the name and be done with it. For example:

def classmethod.fubar(self, widget, wadget, boff):
pass

I'm not seriously proposing it because I'd like to reserve
that idea to be able to insert a method into an instance
or existing class without either having to do an extra
assignment, or having to pollute the module namespace
in passing.

John Roth
 
M

marduk

Oh my god, I just realized (Ob decorator comment here) that if we start
having people write private decorators, we'll have things like:

@__decorator

I wish to have a private decorator. My apartment looks boring.

-m
 
C

Colin J. Williams

Roy said:
I disagree with your disagreement :)

I find a mix of text and puctuation difficult to read. Human brains
don't read letters, they read whole words. That's why, for example,
it's so easy to make a typo and not notice it. I find "word.word" easy
to parse, but "word.__word" much more difficult.

I agree, but see this as similar to the naming convention:
long_symbolic_representation at first glance,
this looks like
three names
why not:
longSymbolicRepresentation? this makes the oneness
clearer

Returning to the subject line - When will the final decision be handed
down?

My own preferences are: (1) transform or transformer not decorator
(2) the transforms should follow the thing
being
transformed. i.e. after the script has
declared the name.
(3) a list of transforms.
(4) the list should have one entry per line,
to make reading easier.

Colin W.
I don't know if it's
 
M

Michael J. Fromberger

"John Roth said:
Kevin Smith said:
For what it's worth, I wrote the original PEP 318. [...]

In my opinion, none of the proposed syntaxes really seem Pythonic.
This PEP just seems to be trying to solve too many problems.

The arguement is, and always has been, about syntax. Everyone agrees
that the current situation is not ideal; putting the wrapping
assignment statement after the method is a very poor way of declaring
intent.

I agree that the current situation is not ideal. However, I would also
argue that many of the proposed replacements are even worse. Kevin
In other words, forget the use cases. They're irrelevant.

On this point, I strongly disagree. If you don't have a use case, there
is no point whatsoever in arguing about the syntax of a feature.

Now, if you want to argue about general syntactic design principles,
maybe that is an interesting topic -- but it is one level removed from
what PEP-318 is all about, and therefore (in my opinion) not really
germane to the present discussion.

-M
 
A

Anthony Baxter

You didn't follow that one with a smiley either... :)

That's because I wasn't joking, at all. Look, your idea is a _bad_ one. Numerous
people have pointed out why. Let it die.
 
J

John Roth

Michael J. Fromberger said:
John Roth said:
Kevin Smith said:
For what it's worth, I wrote the original PEP 318. [...]

In my opinion, none of the proposed syntaxes really seem Pythonic.
This PEP just seems to be trying to solve too many problems.

The arguement is, and always has been, about syntax. Everyone agrees
that the current situation is not ideal; putting the wrapping
assignment statement after the method is a very poor way of declaring
intent.

I agree that the current situation is not ideal. However, I would also
argue that many of the proposed replacements are even worse. Kevin
In other words, forget the use cases. They're irrelevant.

On this point, I strongly disagree. If you don't have a use case, there
is no point whatsoever in arguing about the syntax of a feature.

There is a use case. If you go back and read the original
post I was replying to, it contains the sentence:

[begin quote]
I guess others had bigger plans for my proposal that I had planned. It
has turned into the "solution" to many problems: type checking (both
arguments and returned values), metaclasses, metadata, interfaces,
function attributes, etc.).
[end quote]

This is the context in which you should have taken my comment
to "forget the use cases." The original use case (classmethod
and staticmethod) is clearly still there, as my comments
in the post you reply to should have made clear.

John Roth
 
M

Michael J. Fromberger

"John Roth said:
Michael J. Fromberger said:
On this point, I strongly disagree. If you don't have a use case, there
is no point whatsoever in arguing about the syntax of a feature.

There is a use case. If you go back and read the original
post I was replying to, it contains the sentence:

[begin quote]
I guess others had bigger plans for my proposal that I had planned. It
has turned into the "solution" to many problems: type checking (both
arguments and returned values), metaclasses, metadata, interfaces,
function attributes, etc.).
[end quote]

Ah, I see. I misunderstood your intent. My apologies.

Nevertheless, I think it's clear the Python community at large ought to
have a clearer idea of exactly what the use cases ARE (and, more
importantly, what they're not) before deciding on a syntax. It's not
clear to me that there's consensus on purpose yet (as witness the wildly
divergent ideas that have accumulated on the wiki, comp.lang.python, and
python-dev).

Cheers,
-M
 
N

Neil Zanella

Ville Vainio said:
Kevin> Bear with me, but I'd like to propose one more syntax that
Kevin> is simple, easy for newbies to understand, and nowhere near
Kevin> as powerful as the current PEP's syntax. However, it
Kevin> doesn't add incoherent, arbitrary syntax either.

Kevin> def classmethod foo(x, y, z):
Kevin> pass
I don't even use static/classmethods, but I can imagine several
frameworks can use parametrized decorators to their advantage.

Well, allow me to contribute my thoughts on staticmethod and classmethod:
I am barely starting out with Python and my class objects are already
loaded with so many

foo = staticmethod(foo)

statements. In other words these are very useful: they should be part of
Python's syntax. Other than the above proposal, which I think is the most
obvious thing that could be done, I would also like to contribute yet another
syntax:

class Foo:
# stuff
classmethods:
# classmethods here
staticmethods:
# staticmethods here

In the spirit of Python, this scheme would lead to even less typing
on average than would be required with Kevin's solution, although I
must admit that Kevin's solution was the very first thing that came
to mind when I was looking for classmethods/staticmethods.

staticmethods are very useful: you can pack related methods in a class
and use them as getters for class objects which need not be differentiated
among instances. It may even be, that due to python's class objects feature
the user never cares to instantiate certain types of classes anyways. For
instance, a class object with staticmethods can simply be used as a
singleton object: very convenient, if it were not for this ugly
staticmethod syntax. And you may ask, what are the advantages
of using staticmethod inside a class as opposed to using
plain methods? The answer to that question is polymorphism:
Imagine a hierarchy of singleton classes derived from a base
class with a common interface. The singleton class objects
can then be processed polymorphically. Class objects, unlike
class instances, are singletons by nature: what a convenient
means of using singletons pythons offers us!

class Person:
def name():
return "Sorry, I'm just an abstract class."
name = staticmethod(name)
def favoMovie():
return "Monty Python's Flying Circus"
favMovie = staticmethod(FavMovie)
def favFood():
return "SPAM!"
favFood = staticmethod(favFood)

class JoeDoe(Person):
def name():
return "Joe Doe"
name = staticmethod(name)

class JaneDoe(Person):
def name():
return "Jane Doe"
name = staticmethod(name)
def favFood():
return "Eggs"
favFood = staticmethod(FavFood)

The other alternative is to attach methods to instances of a common class
after they are created, which is also something that can be done in Python
but not in most other languages.

Note that the getters I have coded, in general may involve more complex
logic than shown here, so that we really do need methods and not palin
variables in such cases.

Overall, allow me to say that OO stuff seems to be much more flexible in an
interpreted environment such as Python than it is in compiled languages.

Feedback welcome,

Regards,

Neil
 
J

John Roth

Michael J. Fromberger said:
John Roth said:
in message news:Michael.J.Fromberger-D24476.14010119082004@localhost...
In other words, forget the use cases. They're irrelevant.

On this point, I strongly disagree. If you don't have a use case, there
is no point whatsoever in arguing about the syntax of a feature.

There is a use case. If you go back and read the original
post I was replying to, it contains the sentence:

[begin quote]
I guess others had bigger plans for my proposal that I had planned. It
has turned into the "solution" to many problems: type checking (both
arguments and returned values), metaclasses, metadata, interfaces,
function attributes, etc.).
[end quote]

Ah, I see. I misunderstood your intent. My apologies.

Nevertheless, I think it's clear the Python community at large ought to
have a clearer idea of exactly what the use cases ARE (and, more
importantly, what they're not) before deciding on a syntax. It's not
clear to me that there's consensus on purpose yet (as witness the wildly
divergent ideas that have accumulated on the wiki, comp.lang.python, and
python-dev).

I don't think they're particularly related. Functionally, whatever happens
as the result of a decorator will be the return of an object which
will be bound to the class or module (or serve as the input to another
decorator, of course.) In most cases, this will either be the original input
or a descriptor that has the original input as an attribute.

This is a very generic mechanism of amazing simplicity. It can be put
to as many uses as one wishes. There are currently implementations
of just about everything that has been suggested, including Design
by Contract, Aspects and several forms of type checking.

The whole question of syntax is simply orthogonal. The current
syntax works perfectly well; it's just very poor from an intention revealing
standpoint.

John Roth
 
P

Paul Morrow

Anthony said:
That's because I wasn't joking, at all. Look, your idea is a _bad_ one. Numerous
people have pointed out why. Let it die.

I know you weren't Anthony (that was a joke). I understand that you
don't like this idea, but that doesn't make it a _bad_ one. Numerous
people have *not* effectively pointed out the problems with it (and
neither have you, sir).

Don't use it, if you don't want to. Make your code as hard to
understand as you like. Python gives you that freedom.
 
A

Anthony Baxter

I know you weren't Anthony (that was a joke). I understand that you
don't like this idea, but that doesn't make it a _bad_ one. Numerous
people have *not* effectively pointed out the problems with it (and
neither have you, sir).

Err, what? Have you bothered to read the replies I sent to you? This
is _bad_ magic behaviour. Python does not care about argument lists
now, and adding this is icky. Your behaviour when _adding_ methods
to classes is extremely undefined, particularly in the presence of
descriptors. Explaining this to new users would be complex. It's a
messy interference in the way Python's OO builds classes and objects,
which is currently very clear and easy to follow[1]. It's not explicit, but
implicit. How many ways do I have to spell this out?

[1] with the double-underscore mangling put to one side, or preferably,
off a bridge.

The only argument _for_ this that you've offered is that it's just like the
double-underscores. This is a losing argument (with me, anyway) as
I regard the double-underscore mangling as awful - that sort of "data
hiding" just ends up being a pain in the arse when you want to poke
with a class's internals. Python regards everyone as an adult in that
respect, unlike the "protecting you from yourself" C++ nightmare. In
addition, the double-underscore is just random magic that occurs when
a class is created, not subsequently:
.... __foo = 1
....
dir(A) ['_A__foo', '__doc__', '__module__']
A.__bar = 2
dir(A)
['_A__foo', '__bar', '__doc__', '__module__']

for the same reasons, your idea would lead to inconsistencies.

Anthony
 
P

Paul Morrow

Anthony said:
Err, what? Have you bothered to read the replies I sent to you?

Yes of course I have. You can tell because I've replied to everything
you've said, directly (as best I could) addressing your 'points'. Have
you noticed my replies? Did you bother to read them?
This is _bad_ magic behaviour. Python does not care about argument lists
now, and adding this is icky.

Python doesn't do this now. Check. You think that it's "icky". Check.
Your behaviour when _adding_ methods to classes is extremely undefined,
particularly in the presence of
descriptors.

If you're talking about dynamically adding methods to classes (at
runtime), we've discussed this in general. You have to have the first
parm name correct before you add the method.

But we haven't talked about descriptor issues yet, have we? What's the
problem with them?
Explaining this to new users would be complex.

We discussed this before too (didn't we?). It will be *less* complex
for new users. Well, you tell me. Here's the only part of the
classmethod documentation that would change (from
http://docs.python.org/lib/built-in-funcs.html)...

"""
A class method receives the class as implicit first argument, just like
an instance method receives the instance. To declare a class method, use
this idiom:

class C:
def f(cls, arg1, arg2, ...): ...
f = classmethod(f)
"""

....it would be changed to (something like) this...

"""
A class method receives the class as its first argument 'cls', just like
an instance method receives the instance as its first argument 'self'.
To declare a class method, use this idiom:

class C:
def f(cls, arg1, arg2, ...): ...

Note that the first argument of each class method must be named 'cls'.
"""

It's a
messy interference in the way Python's OO builds classes and objects,
which is currently very clear and easy to follow[1].

We haven't discussed this, have we? What do you mean?

It's not explicit, but implicit.

True. But then so is dynamic typing, a powerful feature of Python that
differentiates it from languages like Java, C++. Therefore, you aren't
saying enough here for that point to be valid.

How many ways do I have to spell this out?

One valid spelling would be a good start.

The only argument _for_ this that you've offered is that it's just like the
double-underscores.

Oh my... <sigh> Have you been reading *my* posts? If so, I must be
doing a terrible job of communicating here (my apologies). Here are
four reasons in favor of it. Rip them apart to your satisfaction.

1. It make formal a convention widely used by others and therefore would
have an obvious interpretation to readers of your code.

2. It doesn't require as much typing as the current technique nor any
proposed decorator technique.

3. It is less error prone (because it is WYSIWYG) than the current
technique.

4. It is easier to understand than the current technique.

double-underscores. This is a losing argument (with me, anyway) as
I regard the double-underscore mangling as awful - that sort of "data
hiding" just ends up being a pain in the arse when you want to poke
with a class's internals. Python regards everyone as an adult in that
respect, unlike the "protecting you from yourself" C++ nightmare. In
addition, the double-underscore is just random magic that occurs when
a class is created, not subsequently:


... __foo = 1
...

['_A__foo', '__doc__', '__module__']

['_A__foo', '__bar', '__doc__', '__module__']

for the same reasons, your idea would lead to inconsistencies.

That's an interesting point. The behavior you illustrate is apparently
a Python bug wrt private attributes. If it was consistent...

A.__bar = 2

would work, but a subsequent

print A.__bar

would generate an attribute error.

But of course its easy to make Python work that way (as I show below).
Likewise, I'm sure similar inconsistencies in 'my' (for lack of a better
word --- I didn't actually come up with it) idea could be as easily
resolved.

#############################################################
class M(type):
def __setattr__(metacls, attrName, value):
if attrName.startswith('__'):
attrName = '_%s%s' % (metacls.__name__, attrName)
type.__setattr__(metacls, attrName, value)

class A:
__metaclass__ = M
__foo = 1

print [x for x in dir(A) if x.startswith('_A')] # 1.
A.__bar = 2
print [x for x in dir(A) if x.startswith('_A')] # 2.

"""Footnotes:
1. prints ['_A__foo']
2. prints ['_A__bar', '_A__foo']
"""
#############################################################
 

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,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top