Double underscores -- ugly?

B

Ben Finney

Ivan Illarionov said:
I would like to see something like %init or &init to be converted to
__init__ behind the scenes.

I would prefer that the names I create and see in the code are the
names actually used by the Python runtime, with no magic name
conversion "behind the scenes".
 
B

benhoyt

You must be looking at different code from the rest of us. A single
leading underscore on the name *is* the convention for "this attribute
is not part of the external interface", which is about as "private" as
Python normally gets.

Yeah, I understand that. I meant -- and I could be wrong -- that I
haven't seen people creating a method called "init" with a single
leading underscore. It's too similar to "__init__", so they would use
some other name.

In other words, defining _init to mean what __init__ now means
probably wouldn't cause name conflicts.

-Ben
 
B

Ben Finney

Please preserve attribution lines on the quoted material, so we can
see who wrote what at each level.

benhoyt said:
Yeah, I understand that. I meant -- and I could be wrong -- that I
haven't seen people creating a method called "init" with a single
leading underscore. It's too similar to "__init__", so they would
use some other name.

In other words, defining _init to mean what __init__ now means
probably wouldn't cause name conflicts.

But it would conflict with the existing conventions. '_init' as a name
indicates that it's *not* treated specially, because it's not named
with double-underscores. Since it *is* treated specially by Python, it
would be confusing not to follow the convention for naming such
attributes.
 
J

Jorge Godoy

Ivan said:
I would like to see something like %init or &init to be converted to
__init__ behind the scenes. And $something to be converted to
self.something. But, unfortunately, most Python people would consider
this ugly just because Perl uses too much syntactic sugar and anything
Perl-like is considered ugly in Python community. So, unless Perl die,
I believe that Python will remain sugar-free.

A good text editor allows you to replace text. Some of them can even do
that for you with macros when you save a document or open it for editing
(making it possible to go from "$" to "self" and vice-versa).

Maybe using another tool would solve your problem.
 
B

Bruno Desthuilliers

Jason a écrit :
(snip)
Hmm. I must be the only person who doesn't think the double
underscores are ugly.

As far as I'm concerned, I just don't care if they are "ugly" or not -
FWIW, I never ever think of them in terms of "beauty" or "ugliness".

What I do care about is that they simply and clearly convey a special
meaning (just like the _single_leading_underscore names), and make sure
you won't accidentaly override such a name.
 
B

Bruno Desthuilliers

benhoyt a écrit :
(snip)
Then again, what's stopping us just using a single leading underscore?
Nobody calls their own private methods _init or _add

I do.
 
B

Bruno Desthuilliers

benhoyt a écrit :
Yeah, I understand that. I meant -- and I could be wrong -- that I
haven't seen people creating a method called "init" with a single
leading underscore.

Can you see me ?
It's too similar to "__init__", so they would use
some other name.

Nope. It's perfect for a template method that is supposed to be called
from the parent's class __init__.
In other words, defining _init to mean what __init__ now means
probably wouldn't cause name conflicts.

It would.

What you obviously fail to understand is that the __magic_name__
convention is here to clearly separate language implementation space
from user space. Your suggestion would break this.
 
C

cokofreedom

So people's problem with __word__ is that it is not very readable?

How so, it stands out on page, it clearly is different from other
objects and doesn't abuse other symbols that generally have a meaning
based on their use.

I haven't seen a single alternative that really stands out as much as
__word__ does.
 
S

Steven D'Aprano

So people's problem with __word__ is that it is not very readable?

How so, it stands out on page, it clearly is different from other
objects and doesn't abuse other symbols that generally have a meaning
based on their use.

I haven't seen a single alternative that really stands out as much as
__word__ does.

My only two gripes about double underscore names are that:

(1) My news reader interprets _X_ as "underline X", which leads to ugly
display. I could turn that feature off, but that would mean losing *X*
"bold X", which I like.

(2) Two underscores __ is insufficiently visually different from a single
underscore _. Choosing a good font reduces the problem, but doesn't make
it go away.

However, these are minor gripes. On a scale of 0 to -9, where 0 is "it
doesn't upset me or please me at all" and -9 is "I'd rather die than live
with this one more minute", these gripes are both about a -2, and far out-
weighed by the advantages. Taking the advantages and the disadvantages
both into account, I give it a total score of about +4.
 
S

Steven D'Aprano

I would like to see something like %init or &init to be converted to
__init__ behind the scenes.

Unfortunately -- or perhaps fortunately -- % clashes with the already
established uses of % as the modulus operator for numbers and the
interpolation operator for strings.
'hello world'


The last thing I want is to have to study code carefully to try to work
out whether %name means __name__ or %name.

Similarly for &, the bitwise and operator:
8



And $something to be converted to self.something.

Well, at least $ is unused in Python at the moment. That's a point in the
idea's favour. It's a tiny point, but a point.

But, unfortunately, most Python people would consider
this ugly
Yes.

just because Perl uses too much syntactic sugar

No. It's because Perl uses too much *line noise*, punctuation characters
instead of syntax.

and anything
Perl-like is considered ugly in Python community. So, unless Perl die, I
believe that Python will remain sugar-free.

Python has lots of syntactic sugar. Some examples:

"class Foo" is syntactic sugar for a call to the new.classobj() function.

Both "def foo():" and "lambda :" are syntactic sugar for a call to the
new.function() function.

Double-underscore method names are syntactic sugar.

Decorators are syntactic sugar.

Generator expressions and list comprehensions are syntactic sugar.

Dict, tuple and list literals {a: b} (a, b) [a, b] are syntactic sugar.

Method calls and method definitions are syntactic sugar.

The trinary if operator "x if flag else y" is syntactic sugar.

Most of these have been part of Python since the earliest days. Some of
them, like method calls, are so established in Python and other languages
that it's hard to remember that they could be done another way, without
syntax support, but of course they could be:

# instance.method(arg)
getattr(instance, 'method')(arg)


Python uses relatively little punctuation. That's one of the strengths of
the language, and why its very unlikely that your suggestions will be
implemented in Python.
 
C

castironpi

If you're taking programming advice from a bartender your postings
suddenly start to make sense (though not, unfortunately, as comments
about programming). Do you think perhaps yo might be trying just a
little too hard?

regards
  Steve
--
Steve Holden        +1 571 484 6266   +1 800 494 3119
Holden Web LLC              http://www.holdenweb.com/- Hide quoted text -

- Show quoted text -

It's definitely possible. I've been hacking the code for some time,
and so far, the furthest I've gotten is:
Traceback (most recent call last):

Any ideas?
 
C

cokofreedom

It's definitely possible. I've been hacking the code for some time,
and so far, the furthest I've gotten is:


Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Bartender' object has no attribute 'think'



Any ideas?

You need to pass it a parameter for .drink() which in turn calls
the .pay() function, before it can .think()
 
G

grflanagan

That ugliness has long been my biggest bugbear with python, too. The
__name__ == '__main__' thing is something I always have to look up,
every time I use it, too ... awkward.
I'd settle for:
hidden def init(self): # which could be extended to work
for everything "hidden x=3"
...
And for __name__ == '__main__' how about:
if sys.main():
...

Or even:

@hidden
def init(self): ...

@main
def mymainfunc():
...

The first of those probably wants some metaclass support to make it work
cleanly, but here's a sample implementation for the second one:

import sys, atexit
def main(f):
"""Decorator for main function"""
def runner():
sys.exit(f())
if f.func_globals['__name__']=='__main__':
atexit.register(runner)
return f

print "define mymainfunc"
@main
def mymainfunc(args=sys.argv):
print "Got args", args
return 3
print "end of script"

If you have multiple functions marked as main that will run them in
reverse order, so it might be better to put them on a list and use a
single runner to clear the list. Also, I have no idea what happens to
the exit code if you use this decorator more than once.

BTW, should anyone be wondering, you can still use atexit inside a
function called from atexit and any registered functions are then called
when the first one returns.

I liked the idea, thanks. But I also wanted to be able to pass options
to the decorator, for example optparser.OptionParser instances, so
(after wrestling with nested functions for half a day!) I ended up
with the class below, FWIW.

Getting the interplay between __new__, __init__ and __call__ was
somewhat trial-and-error, and maybe I just painted myself into a
corner, but (slightly academic question) is it the case that if you
want to be able to use a decorator both with and without options, ie.
like this:

@mainmethod
def main(...)

and like this:

@mainmethod(parser=myparser)
def main(...)

then you cannot use that decorator for a function that expects or
allows a function as its first argument? Because how and when can you
decide whether that function is the decorated one or the function
parameter?

Anyway, thanks again.

Code:
class mainmethod(object):

    _parser = None
    kwargs = {}
    args =()

    def _getparser(self):
        if self._parser is None:
            self._parser = CommonOptionParser()
        return self._parser
    parser = property(_getparser)

    def __new__(cls, *args, **kw):
        obj = super(mainmethod, cls).__new__(cls, *args, **kw)
        if len(args) == 1 and inspect.isfunction(args[0]):
            #we assume that the decorator has been declared with no
arguments,
            #so go to straight to __call__, don't need __init__
            #if it's the case that the wrapped 'main' method allows or
            #expects a function as its first (and only) positional
argument
            #then you can't use this decorator
            return obj(args[0])
        else:
            return obj

    def __init__(self, *args, **kw):
        self.args = args
        self._parser = kw.pop('parser', None)
        self.kwargs = kw

    def _updatekwargs(self, dict):
        #don't want default null values of parser to overwrite
anything
        #passed to `mainmethod` itself
        for k,v in dict.iteritems():
            #can't do 'if v: ...' because empty configobj evaluates
False
            if v is None or v == '':
                continue
            self.kwargs[k] = v

    def exit(self):
        try:
            log.end()
        except:
            pass

    def run(self):
        options, args = self.parser.parse_args()
        #the following so that command line options are made available
        #to the decorated function as **kwargs
        self._updatekwargs(self.parser.values.__dict__)
        logargs = (
                self.kwargs.get(OPTLOGFILE, None),
                self.kwargs.get(OPTLOGDIR, None),
                self.kwargs.get(OPTLOGPREFIX, ''),
                )
        self.kwargs[OPTLOGFILE] = logstart(*logargs)
        log.info("SCRIPT: " + sys.argv[0])
        conf = self.kwargs.get(OPTCONFIG, None)
        if conf:
            log.info("%s: %s" % (OPTCONFIG.upper(), conf.filename))
        for k,v in self.kwargs.iteritems():
            if v and k not in COMMONOPTS:
                log.info("%s = %s" % (k, v))
        log.divider()
        return sys.exit(self.func(*self.args, **self.kwargs))

    def __call__(self, f):
        if f.func_globals['__name__'] == '__main__':
            self.func = f
            import atexit
            atexit.register(self.exit)
            atexit.register(self.run)
        return f

Gerard
 
B

benhoyt

Has anyone thought about alternatives? Is there a previous discussion
on this I can look up?

Okay, I just emailed the BDFL and asked if he could tell me the origin
of the double underscore syntax for __special__ methods, and what he
said I'm pretty sure he won't mind me posting here:
[Guido van Rossum said:]
The specific naming convention was borrowed from the C standard, which
reserves names like __FILE__ and __LINE__. The reason for needing a
convention for "system-assigned" names was that I didn't want users to
be surprised by the system giving a special meaning to methods or
variables they had defined without intending that special meaning,
while at the same time not wanting to introduce a physically separate
namespace (e.g. a separate dict) for system names. I have no regrets.

After that and this thread, I'm pretty good with it, I guess. :)

Cheers,
Ben.
 
C

castironpi

@mainmethod
def main(...)

and like this:

@mainmethod(parser=myparser)
def main(...)

then you cannot use that decorator for a function that expects or
allows a function as its first argument? Because how and

If it's called with only one non-keyword parameter, then the language
might have done it; if not, guaranteed not. (More succintly, if it's
not, the language didn't.)

So, to get:
@mainmethod
def main(...)
you'll have to check the parameter counts, and you can never invoke
with just one callable parameter, pretty easy; bulky; your choice
between:

@mainmethod()
def main(...)

Note: 'Non-keyword' -and- callable!
 

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,780
Messages
2,569,611
Members
45,280
Latest member
BGBBrock56

Latest Threads

Top