Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Feature request: String-inferred names

1 view
Skip to first unread message
Message has been deleted

Chris Rebert

unread,
Nov 25, 2009, 11:49:36 PM11/25/09
to The Music Guy, pytho...@python.org
On Wed, Nov 25, 2009 at 6:35 PM, The Music Guy
<Fearsome...@gmail.com> wrote:
> Hello all,
>
> I just posted to my blog about a feature that I'd like to see added to
> Python. Before I go through the trouble of learning how to write a PEP or
> how to extend the Python interpreter, I want to know what people in the
> community have to say about it.
>
> http://alphaios.blogspot.com/2009/11/python-string-inferred-names-working.html
>
> As far as I know, a feature like this does not appear in any existing PEPs.
> (If it does I would appreciate it if someone could tell me what PEP it is.)
>
> Please give and comments you may have, but I request that you be
> constructive if you must criticize...thank you!

Ugly, Perlish, and as you even admit, entirely unnecessary.
And you'd need to wait at least a year anyway:
http://www.python.org/dev/peps/pep-3003/

Cheers,
Chris
--
http://blog.rebertia.com

Message has been deleted

Gabriel Genellina

unread,
Nov 26, 2009, 1:30:38 AM11/26/09
to pytho...@python.org
En Wed, 25 Nov 2009 23:35:06 -0300, The Music Guy
<Fearsome...@gmail.com> escribi�:

> I just posted to my blog about a feature that I'd like to see added to
> Python. Before I go through the trouble of learning how to write a PEP or
> how to extend the Python interpreter, I want to know what people in the
> community have to say about it.
>
> http://alphaios.blogspot.com/2009/11/python-string-inferred-names-working.html
>
> As far as I know, a feature like this does not appear in any existing
> PEPs.
> (If it does I would appreciate it if someone could tell me what PEP it
> is.)

Already suggested, and rejected; see PEP 363:
http://www.python.org/dev/peps/pep-0363/ and the python-dev discussion.

--
Gabriel Genellina

Lie Ryan

unread,
Nov 26, 2009, 1:44:17 AM11/26/09
to
Brad wrote:

> On Nov 25, 10:49 pm, Chris Rebert <c...@rebertia.com> wrote:
>> On Wed, Nov 25, 2009 at 6:35 PM, The Music Guy
>>
>> <FearsomeDragon...@gmail.com> wrote:
>>> Hello all,
>>> I just posted to my blog about a feature that I'd like to see added to
>>> Python. Before I go through the trouble of learning how to write a PEP or
>>> how to extend the Python interpreter, I want to know what people in the
>>> community have to say about it.
>>> http://alphaios.blogspot.com/2009/11/python-string-inferred-names-wor...

>>> As far as I know, a feature like this does not appear in any existing PEPs.
>>> (If it does I would appreciate it if someone could tell me what PEP it is.)
>>> Please give and comments you may have, but I request that you be
>>> constructive if you must criticize...thank you!
>> Ugly, Perlish, and as you even admit, entirely unnecessary.
>> And you'd need to wait at least a year anyway:http://www.python.org/dev/peps/pep-3003/
>>
>> Cheers,
>> Chris
>> --http://blog.rebertia.com
>
> Like I said, lots of things in Python are "unnecessary," but that
> doesn't make them "useless," and it certainly doesn't mean they
> shouldn't exist. My proposed feature is not useless; I think it would
> make a lot of code easier.

How is it easier than using dictionary with string as keys? setattr,
getattr, and delattr are already sugar for accessing instance.__dict__.

You make a comparison with decorators; even if it's unnecessary it does
eliminate a DRY case (don't repeat yourself):
def foo(self): pass
foo = property(foo)

there you repeat foo three times unnecessarily, instead of:
@property
def foo(self): pass

people already bashed decorator syntax because it is ungoogleable; a
non-python programmer reading a python code can't google "python @" to
find out that it's a decorator. $ has very similar problem; and we don't
want to add more of this wart.

You also make with iterators and generators. Iterator and generator is
an implication of the core design of python; because python chose not to
have a for-loop (python's "for-loop" is actually a for-each-loop).
Without the iterator protocol, it is not possible to make an iterable
class and people would have to use "for x in range(len(foo)):" every so
often. Iterator protocol also makes it possible to have infinite
iterable (e.g. for x in primegenerator(): produces prime numbers
indefinitely).

A list comprehension is space saver; it saves a lot of lines for the
very common operation:

a = []
for x in orig:
if test(x):
a.append(transform(x))

into one concise line:
a = [transform(x) for x in orig if test(x)]

Also a generator comprehension can be passed around without being evaluated.

As you see, these "unnecessary features" does have significant benefits
to it. Decorators reduced DRY, iterators/generators eliminates the need
of range-len for-loop, list comprehension is huge space saver.

The proposed syntax only saves a few character, does not eliminate any
DRY, is ungoogleable, and looks confusing to me. Is there any
significant benefit from it?

Gregory Ewing

unread,
Nov 26, 2009, 2:28:06 AM11/26/09
to
> On Wed, 25 Nov 2009 20:44:36 -0600, The Music Guy
> <musi...@alphaios.net> declaimed the following in
> gmane.comp.python.general:

>
>>I just posted to my blog about a feature that I'd like to see added to
>>Python.
>>
>>http://alphaios.blogspot.com/2009/11/python-string-inferred-names-working.html

I don't think getattr and setattr are used anywhere near
frequently enough to justify special syntax.

To warrant having its own synax, a feature needs to be
used *all the time*. If you find yourself using getattr
and setattr that much, it's probably a symptom that
you're abusing namespaces for things that would be
better done using dictionaries.

(A frequent question asked by newcomers from certain
other kinds of languages is something like "How do I
assign to a variable whose name is in another variable?"
The answer is almost always "Don't do that, use a
dictionary.")

--
Greg

Bruno Desthuilliers

unread,
Nov 26, 2009, 3:58:09 AM11/26/09
to
Lie Ryan a �crit :

(snip)


> setattr, getattr, and delattr are already sugar for accessing
instance.__dict__.

They are actually much more than that - else descriptors and inheritance
wouldn't work.

Terry Reedy

unread,
Nov 26, 2009, 1:21:49 PM11/26/09
to pytho...@python.org
Gregory Ewing wrote:
>> On Wed, 25 Nov 2009 20:44:36 -0600, The Music Guy
>> <musi...@alphaios.net> declaimed the following in
>> gmane.comp.python.general:
>>
>>> I just posted to my blog about a feature that I'd like to see added to
>>> Python.
>>>
>>> http://alphaios.blogspot.com/2009/11/python-string-inferred-names-working.html
>>>
>
> I don't think getattr and setattr are used anywhere near
> frequently enough to justify special syntax.

This was my response too.

The Music Guy

unread,
Nov 26, 2009, 6:43:04 PM11/26/09
to
On Nov 26, 12:30 am, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:

> En Wed, 25 Nov 2009 23:35:06 -0300, The Music Guy  
> <FearsomeDragon...@gmail.com> escribió:

>
> > I just posted to my blog about a feature that I'd like to see added to
> > Python. Before I go through the trouble of learning how to write a PEP or
> > how to extend the Python interpreter, I want to know what people in the
> > community have to say about it.
>
> >http://alphaios.blogspot.com/2009/11/python-string-inferred-names-wor...

>
> > As far as I know, a feature like this does not appear in any existing  
> > PEPs.
> > (If it does I would appreciate it if someone could tell me what PEP it  
> > is.)
>
> Already suggested, and rejected; see PEP 363:  http://www.python.org/dev/peps/pep-0363/and the python-dev discussion.
>
> --
> Gabriel Genellina

Thank you for pointing that out. The PEP actually proposed some code
that I can use in my current project to help make it more readable:

class attrs:
def __init__(self, obj):
self.obj = obj
def __getitem__(self, name):
return getattr(self.obj, name)
def __setitem__(self, name, value):
return setattr(self.obj, name, value)
def __delitem__(self, name):
return delattr(self, name)
def __contains__(self, name):
return hasattr(self, name)

That aside, I still feel that a new syntax would be a better solution
than a new class. And, anyway, what I'm proposing isn't *quite* the
same as what Ben North proposed. Ben's idea was *strictly* to create
shorthand syntax to the getattr/setattr/delattr in the context of
specific objects. What I'm suggesting could be more accurately
described as a namespace-neutral transformation of the value of an
expression into a name. So if "bar" is the value of foo, then when the
interpreter sees $foo, it reads bar. And when the interpreter sees
obj.$foo, it reads obj.bar. It can effectively be used in the same way
as Ben's proposal, but also for names in the current scope.

Next thing is, I can't see logically how the path of the discussion of
the proposal lead to the proposal being rejected. It looked like a lot
of people really liked the idea--including Guido himself--and several
examples were given about how it could be useful. The final verdict on
the matter just doesn't make logical sense in the context of the
discussions.

The main problem that people had with it was more to do with the
syntactical form than with the feature itself, but that's easily
adjusted. Not to sound pompous (ahem), but the syntax that I propose
does not suffer from the problems that people had with other
suggestions, i.e. it looks less like a typo (how often do you
accidentally type a "$" when you meant to type a "(" or a "." ?), it
does not get easily confused as a function call, or indexing syntax,
or an ordinary member lookup, because none of those things rely on the
$ as an operator. Nothing does.

As for it not being useful enough to justify new syntax, well, I think
Ben showed pretty well that it actually is. Approximately 600 uses of
the get*r functions were used in the Python 2.5 standard library
alone. Now 2.7 is around the corner and that number has probably
grown, if only a little bit. Besides that, as I already stated in the
blog, a feature like this would make metaclassing code that generates
properties and methods much easier to write and understand.

Nonetheless, the fact remains that the feature I'm proposing closely
resembles one that has already been rejected... Well, it's been a few
years since then. Maybe its about time for another PEP to be proposed?

John Machin

unread,
Nov 26, 2009, 7:48:44 PM11/26/09
to
On Nov 27, 10:43 am, The Music Guy <music...@alphaios.net> wrote:
[snip]

> Nonetheless, the fact remains that the feature I'm proposing closely
> resembles one that has already been rejected... Well, it's been a few
> years since then. Maybe its about time for another PEP to be proposed?

Judging by the response you've got from about half-a-dozen sensible
people, I say maybe it's NOT about time.

Ben Finney

unread,
Nov 26, 2009, 7:58:53 PM11/26/09
to
The Music Guy <musi...@alphaios.net> writes:

> Nonetheless, the fact remains that the feature I'm proposing closely
> resembles one that has already been rejected... Well, it's been a few
> years since then.

The passage of time is insufficient. The idea also needs to have greater
merit now than before. You haven't demonstrated that it does.

> Maybe its about time for another PEP to be proposed?

Before that happens, you might like to know that Guido (like many
others) far prefers to communicate with people who use their real name,
as one might use to introduce oneself face-to-face.

--
\ “I call him Governor Bush because that's the only political |
`\ office he's ever held legally.” —George Carlin, 2008 |
_o__) |
Ben Finney

Cameron Simpson

unread,
Nov 26, 2009, 8:16:53 PM11/26/09
to Brad, pytho...@python.org
On 25Nov2009 21:45, Brad <themusi...@gmail.com> wrote:
| On Nov 25, 10:49 pm, Chris Rebert <c...@rebertia.com> wrote:
| > On Wed, Nov 25, 2009 at 6:35 PM, The Music Guy
| > <FearsomeDragon...@gmail.com> wrote:
| > > I just posted to my blog about a feature that I'd like to see added to
| > > Python. Before I go through the trouble of learning how to write a PEP or
| > > how to extend the Python interpreter, I want to know what people in the
| > > community have to say about it.
| > >http://alphaios.blogspot.com/2009/11/python-string-inferred-names-wor...
[...]

| > Ugly, Perlish, and as you even admit, entirely unnecessary.
| > And you'd need to wait at least a year anyway:http://www.python.org/dev/peps/pep-3003/
|
| Like I said, lots of things in Python are "unnecessary," but that
| doesn't make them "useless," and it certainly doesn't mean they
| shouldn't exist. My proposed feature is not useless; I think it would
| make a lot of code easier.

The Zen promotes the guideline that there should be only one (obvious)
way to do most things and that's a surprisingly effective design rule.

For your idea the obvious ways already exist.

If you really want this you can achieve nearly the same conciseness by
defining __setitem__ and __getitem__ so that:

obj[attrname] = foo

does what you want.
--
Cameron Simpson <c...@zip.com.au> DoD#743
http://www.cskk.ezoshosting.com/cs/

For reading rec.moto, I use one of those carbon-fiber Logitech mice w/a
little 'No Fear' sticker on it. - Mike Hardcore DoD#5010 <mo...@netcom.com>
Apologies to Primus

Ben Finney

unread,
Nov 26, 2009, 8:25:43 PM11/26/09
to
Cameron Simpson <c...@zip.com.au> writes:

> The Zen promotes the guideline that there should be only one (obvious)
> way to do most things and that's a surprisingly effective design rule.

It's also important to realise that the Zen places the “preferably only
one” in a parenthetical, and note that “preferably” qualifier. That is,
it's:

There should be one obvious way to do it.

without that parenthetical. I think that “obvious” is the important part
there, and seems to be to be the design principle that (far more than
“only one”) is guiding in Python's development.

--
\ “Too many pieces of music finish too long after the end.” —Igor |
`\ Stravinskey |
_o__) |
Ben Finney

Gregory Ewing

unread,
Nov 26, 2009, 8:49:54 PM11/26/09
to
The Music Guy wrote:

> As for it not being useful enough to justify new syntax, well, I think
> Ben showed pretty well that it actually is. Approximately 600 uses of
> the get*r functions were used in the Python 2.5 standard library
> alone.

The standard library isn't necessarily representative of
Python code in general. I just looked at three of my
projects, and out of a total of 45954 lines (about half
the size of the stdlib) I found only 37 uses of getattr
and setattr.

Also, many of the uses of getattr in the std lib appear
to be of the 3-argument form, which your suggested syntax
doesn't cover. If I exclude those from my code, I'm left
with only 18 uses.

So I would only be able to use your syntax in about
0.04% of the lines of code that I typically write.

--
Greg

Gabriel Genellina

unread,
Nov 26, 2009, 10:10:20 PM11/26/09
to pytho...@python.org
En Thu, 26 Nov 2009 20:43:04 -0300, The Music Guy <musi...@alphaios.net>
escribi�:

> Nonetheless, the fact remains that the feature I'm proposing closely
> resembles one that has already been rejected... Well, it's been a few
> years since then. Maybe its about time for another PEP to be proposed?

You'll have to wait a few more years; in case you missed the previous
reference to PEP 3003 up in the thread, the language syntax is frozen by
now [1]


[1] http://www.python.org/dev/peps/pep-3003/

--
Gabriel Genellina

Message has been deleted

The Music Guy

unread,
Nov 27, 2009, 11:02:31 PM11/27/09
to
On Nov 26, 9:10 pm, "Gabriel Genellina" <gagsl-...@yahoo.com.ar>
wrote:
> En Thu, 26 Nov 2009 20:43:04 -0300, The Music Guy <music...@alphaios.net>  
> escribió:

>
> > Nonetheless, the fact remains that the feature I'm proposing closely
> > resembles one that has already been rejected... Well, it's been a few
> > years since then. Maybe its about time for another PEP to be proposed?
>
> You'll have to wait a few more years; in case you missed the previous  
> reference to PEP 3003 up in the thread, the language syntax is frozen by  
> now [1]
>
> [1]http://www.python.org/dev/peps/pep-3003/
>
> --
> Gabriel Genellina

That PEP seems to pretty clearly state that it applies only to the 3.x
branch and not to the 2.x branch. Is there maybe a slim chance of
getting my idea added to 2.7, or even 2.8? :D

The Music Guy

unread,
Nov 27, 2009, 11:08:10 PM11/27/09
to
Gred, thanks for your comments.

On Nov 26, 7:49 pm, Gregory Ewing <greg.ew...@canterbury.ac.nz> wrote:
>
> [...] Also, many of the uses of getattr in the std lib appear


> to be of the 3-argument form, which your suggested syntax

> doesn't cover. [...]

Good point. After excluding those, only ~435 uses would work for my
proposed syntax. Still seems fairly significant to me, though.

Also, please keep in mind that I never suggested that the get*r
functions should be removed from the language precisely because they
DO work in ways that my proposed syntax does not, and that removing
them would make a lot of existing code fail. For the purpose of the 3-
argument form, I would still prefer using getattr or even a
defaultdict depending on the task. (For the record, I disagree with
the 2-argument form of Ben's proposed syntax; that's confusing and
hard to read.)

As for your code, I haven't seen it, so it would be hard for me to say
exactly how the new syntax would come into play. What I can tell you,
however, is that the parts of your code that would use it would
probably be easier to read and change to anyone with a firm grasp of
the proposed syntax.

Quantity of code is definitely important, but I don't want to
underwrite the importance of quality, either. Even if only 30 lines of
code--rounding down--out of 40,000 would use it, those 40 lines would
probably be easier to read and understand. (Off-handedly, you might
also find that the availability of the new syntax makes new solutions
to some task obvious which previously were not, so the number could
rise.)

The discussion of PEP 363 presented some good examples of what I'm
talking about. Consider this code, which is a paraphrase of code that
appeared in the discussion:

setattr(obj, ("my_%s" % foo), getattr(obj, ("my_%s" % foo)) + 3)

That could be written much more readably as:

obj.$("my_%s" % foo) += 3

Or, if you don't like that exact syntax for it, why not any of these:

obj.?("my_%s" % foo) += 3
obj.${"my_%s" % foo} += 3
obj.?{"my_%s" % foo} += 3
obj.<"my_%s" % foo> += 3
(and so on)

Even if this sort of thing only needed to happen a few times in an
entire project, the project as a whole could only benefit from it. My
projects rely on a lot of metaclassing for the automatic generation of
properties and methods, which saves tremendous amounts of coding.
However, the code for the metaclasses is confusing because it relies
heavily on the getattr and setattr functions for accessing not only
the classes being created but also the instances of those classes. The
code for the metaclasses themselves only constitute a small percentage
of the overall code for the projects, but that doesn't mean the code
doesn't need to be easy to read and understand. Dynamic attribute
access via a syntactical construct would be very beneficial for me.

Back to PEP 3003, I understand the odds of getting the feature in
right now are slim. I get it. But that doesn't mean the idea of the
feature is a bad one. There are other things that can be done in the
mean time until the moratorium is lifted, like perfecting the syntax
and implementation details, or whatever.

--Brad Harms

Lie Ryan

unread,
Nov 28, 2009, 4:07:27 AM11/28/09
to
On 11/28/2009 3:08 PM, The Music Guy wrote:
> As for your code, I haven't seen it, so it would be hard for me to say
> exactly how the new syntax would come into play. What I can tell you,
> however, is that the parts of your code that would use it would
> probably be easier to read and change to anyone with a firm grasp of
> the proposed syntax.

Isn't this much easier to read and grasp?

obj.d["my_%s" % foo] += 3

doesn't need new syntax as well.

> Even if this sort of thing only needed to happen a few times in an
> entire project, the project as a whole could only benefit from it. My
> projects rely on a lot of metaclassing for the automatic generation of
> properties and methods, which saves tremendous amounts of coding.

If you use it a lot, it is likely 1) you have abused class syntax for
what should have been a dict or 2) what you need is to override
__getattr__/__getattribute__ and __setattr__

Steven D'Aprano

unread,
Nov 28, 2009, 4:19:53 AM11/28/09
to
On Fri, 27 Nov 2009 20:02:31 -0800, The Music Guy wrote:

> That PEP seems to pretty clearly state that it applies only to the 3.x
> branch and not to the 2.x branch. Is there maybe a slim chance of
> getting my idea added to 2.7, or even 2.8? :D


The only new features being added to 2.7 are features which are also
being added to 3.x. There is no chance at all of having new features
added to 2.7 which isn't added to 3, unless that feature is specifically
to make it easier to migrate from 2 to 3.

--
Steven

The Music Guy

unread,
Nov 28, 2009, 6:38:38 AM11/28/09
to
On Nov 28, 3:07 am, Lie Ryan <lie.1...@gmail.com> wrote:
> On 11/28/2009 3:08 PM, The Music Guy wrote:
>
> > As for your code, I haven't seen it, so it would be hard for me to say
> > exactly how the new syntax would come into play. What I can tell you,
> > however, is that the parts of your code that would use it would
> > probably be easier to read and change to anyone with a firm grasp of
> > the proposed syntax.
>
> Isn't this much easier to read and grasp?
>
> obj.d["my_%s" % foo] += 3
>
> doesn't need new syntax as well.

Actually, that's similar to my backup solution, which is a variant of
the "attrs" class that PEP 363 provides. It does make things easier to
read, but a new syntax would still be better because:

1.) A new syntax would apply to _everything_ as it would be a hook to
the very mechanism that gets the value of a member from an object and
does not rely on an object defining the magic "d" property. I suppose
you could argue that an enhancement could be made to the language that
says that all objects must define the magic "d" (so the builins
"object" and "type" would have to define it). That also has the added
benefit of not conflicting with PEP 3003, which says it is fine to add
new methods (and I would assume properties as well) to existing
classes.

2.) Ben's patch for his proposed syntax generated an aproximate 1%
performance hit for the interpreter overall versus a >40% increase
where code that used the getattr/settattr functions was modified to
use the proposed syntax. The magic "d" MIGHT have a performance
increase over the getattr/setattr functions, but a syntax would still
be significantly faster because there would be less function
dereferencing/calling. For the purposes that I had intended for the
syntax to be used, that would definitely matter.

> If you use it a lot, it is likely 1) you have abused class syntax for
> what should have been a dict or 2) what you need is to override
> __getattr__/__getattribute__ and __setattr__

Oh boy...here we go. :|

Please listen. In all the time I've spent in the coding community
(that's at least 7 years) and especially since I started paying
attention to the Python community (2 years), I have noticed a trend:
When one coder does something that another cannot understand,
frequently the other will assume the former is not only doing things
wrong, but is doing them _blatantly_ wrong. I have caught myself
making that very assumption many times in the past, and I've tried
hard to build up an immunity against the impulse to make that
assumption. At this point, I don't even believe in such a thing as a
universal "wrong way" and a "right way" to code that applies to every
circumstance. The way to solve a problem depends on the problem. When
it comes to coding, there is not an absolute "right" way or "wrong"
way--unless we're talking about, say, stealing closed source code
without permission, or deliberately coding in a way that will cause
problems for the end user (like causing memory clogs or buffer
overflows and whatnot).

All of this can be determined through common sense. And yet I continue
to see the attitude of "my solution is the ONLY solution to your
problem, and it doesn't matter if I don't even actually understand the
problem." Not everyone does this, but it is a frequent enough
occurence to be worth noting. If I had to pull a number out of my
magic bag, I would say 4 out of 10 resposes have at least a hint of
this attitude, and 2.5/10 where it is very obvious.

But I digress. I've already gone over other possible solutions and the
one I am using seems to fit the bill better than any other yet
presented to me, including the ones you just suggested. In fact, I'm
fairly certain that __getattr__ and friends even apply to the
situation, or if they do, they're certainly inferior alternatives to
the use of getattr/setattr. Not that I'm calling you inferior--I'm
just saying that if you had a better understanding of the problem you
would not see __getatrr__ et al. as parts of a possible solution
because they don't really make logical sense given the circumstances.

...and I have one last thing to say. I feel very strongly that
metaclassing is a fiercely underestimated and largely untapped source
of good coding solutions. I hope that many coders will see this and
help to make it more adoptable by the masses; at present it is seen as
a big, scary beast that is hard to tame and even harder to drive. It
is portrayed as something dangerous that should only be used in
relatively rare situations. I disagree with this view. It is the view
itself which makes it seem so dangerous (in other words, it is self-
perpetuating).

Well, that's about enough yakking for 5:30 in the morning...time to
give my noggin a rest.

-- Brad Harms

The Music Guy

unread,
Nov 28, 2009, 6:44:50 AM11/28/09
to
P.S., not trying to start a flame war. It's just that I can't stand to
keep silent on the matter any longer.

-- Brad Harms

Ben Finney

unread,
Nov 28, 2009, 7:12:09 AM11/28/09
to
The Music Guy <fearsome...@gmail.com> writes:

> Please listen. In all the time I've spent in the coding community
> (that's at least 7 years) and especially since I started paying
> attention to the Python community (2 years), I have noticed a trend:
> When one coder does something that another cannot understand,
> frequently the other will assume the former is not only doing things
> wrong, but is doing them _blatantly_ wrong.

I think you may be misinterpreting the message.

> At this point, I don't even believe in such a thing as a universal
> "wrong way" and a "right way" to code that applies to every
> circumstance. The way to solve a problem depends on the problem.

You'll find firm agreement on that in this group.

> When it comes to coding, there is not an absolute "right" way or
> "wrong" way--unless we're talking about, say, stealing closed source
> code without permission, or deliberately coding in a way that will
> cause problems for the end user (like causing memory clogs or buffer
> overflows and whatnot).

However, when it comes to a *specific*, mature programming language,
there *are* right and wrong ways. Or, at least, there are ways
encouraged or discouraged by the language, its interfaces, its style
guides, and its community.

Which is very important: it's the rare program that is only ever read by
one person in one context. Far more often, the same program needs to be
read multiple times, by multiple people, in multiple contexts, over
multiple iterations of maintenance. And for that to be feasible, it's
very important to write the program the right way *for that language*.

Sticking to local conventions has a great deal of practical merit in the
medium of human-to-human communication that we call “programming”.
Progress depends on doing things differently; but maintainability
depends on keeping unexpected differences to a minimum.

--
\ “The truth is the most valuable thing we have. Let us economize |
`\ it.” —Mark Twain, _Following the Equator_ |
_o__) |
Ben Finney

Lie Ryan

unread,
Nov 28, 2009, 7:10:50 AM11/28/09
to
On 11/28/2009 10:38 PM, The Music Guy wrote:
>> If you use it a lot, it is likely 1) you have abused class syntax for
>> what should have been a dict or 2) what you need is to override
>> __getattr__/__getattribute__ and __setattr__
>
> Oh boy...here we go. :|
> <sniprant>

ok, then what's your use case, AFAICT in the discussion here and
previous ones, nobody has yet described a realistic and compelling
situation where setattr/getattr is the best solution. That's why the
discussion tended to end with "not used frequently enough"; simply
because nobody can turn up with a use case to justify a new syntax,
especially since all the proposed syntax are ugly (the most acceptable
one, for me, is obj.[foo], still ugly but not as ugly as the others).

Message has been deleted

Steven D'Aprano

unread,
Nov 28, 2009, 8:23:18 PM11/28/09
to
On Sat, 28 Nov 2009 03:38:38 -0800, The Music Guy wrote:

> Please listen. In all the time I've spent in the coding community
> (that's at least 7 years) and especially since I started paying
> attention to the Python community (2 years), I have noticed a trend:
> When one coder does something that another cannot understand, frequently
> the other will assume the former is not only doing things wrong, but is
> doing them _blatantly_ wrong.

That's because most of the time that assumption is correct.

50% of all coders are worse than average -- and in fact since the
distribution of coding skill is unlikely to be normally distributed, it
may very well be true that *more* than 50% of all coders are worse than
average. Which means that, when faced with a coder you know nothing about
except that he is trying to do something you can't understand, merely by
playing the odds you have at least a 50:50 chance that he's doing
something silly.

The coders who hang around forums casting judgement are more likely like
to better than average -- they're not just code monkeys putting in their
eight hours days cranking out boilerplate code. They usually know what
they're doing. They are skillful and knowledgeable -- those who aren't
don't last long: they either leave, or they learn and become
knowledgeable. So when people on forums suggest something is a bad idea,
statistics is on their side, to say nothing of reasoned judgement.

Most new ideas are bad ideas. Pure statistics again -- if an idea is any
good, somebody has probably already had it, and it has become a standard
tool that everyone uses. Breaking code up into subroutines is such a good
idea, and nearly every programming language has some way of breaking code
up into subroutines. But bad ideas keep coming up over and over again, as
they're thought of, then rejected, then somebody else comes along and
thinks of it again. The same old bad ideas keep being raised again and
again.

> I have caught myself making that very
> assumption many times in the past, and I've tried hard to build up an
> immunity against the impulse to make that assumption.

Doing so reduces your chances of making uncommon false negatives at the
cost of increasing your chances of making common false positives.
Personally, I think it's a bad strategy, but that depends on just how
much effort you put into giving every new idea a fair shake.


> At this point, I
> don't even believe in such a thing as a universal "wrong way" and a
> "right way" to code that applies to every circumstance.

Well duh :)


> The way to solve a problem depends on the problem.

Well duh again :D

But there are certain "standard", common, types of problems. Most
problems are just variations on other problems. Very few problems are
unique.


> When it comes to coding, there is not
> an absolute "right" way or "wrong" way--unless we're talking about, say,
> stealing closed source code without permission, or deliberately coding
> in a way that will cause problems for the end user (like causing memory
> clogs or buffer overflows and whatnot).

There is no need for "deliberately" in that sentence. If you cause
problems like buffer overflows, you're doing it wrong. It's wrong whether
you did so maliciously or through ignorance. Even if you document that it
is subject to this failure mode ("don't do this"), it's still wrong.

Sometimes we do the wrong thing because sometimes it's more important to
get a 99% solution today than a 100% solution next month, but it's still
objectively buggy.


> All of this can be determined through common sense. And yet I continue
> to see the attitude of "my solution is the ONLY solution to your
> problem, and it doesn't matter if I don't even actually understand the
> problem." Not everyone does this, but it is a frequent enough occurence
> to be worth noting. If I had to pull a number out of my magic bag, I
> would say 4 out of 10 resposes have at least a hint of this attitude,
> and 2.5/10 where it is very obvious.

You say that as if it's a bad thing. I think it's a good thing -- most
solutions are tried and tested, and conservatively sticking to solutions
that are known to work is a successful solution:

* if you write code which took a lot of effort to understand, it will
take a lot of effort to maintain;

* if you write code which only the creator understands, then if something
happens to the creator, nobody will understand the code;

* debugging is harder than writing code in the first place, so if you
write the cleverest code you possibly can, then you aren't clever enough
to debug it.

[...]


> ...and I have one last thing to say. I feel very strongly that
> metaclassing is a fiercely underestimated and largely untapped source of
> good coding solutions.

There's a reason for that -- metaclasses are *clever*. Good solutions
should be dumb enough that even the 50% of below-average coders can use
them. Metaclasses are hard, and because they're hard, they're
underutilized, and consequently people are unfamiliar with them. Because
they're unfamiliar, that makes them even harder to understand, and so
people avoid metaclasses -- a vicious circle, as you pointed out.


--
Steven

The Music Guy

unread,
Nov 28, 2009, 8:24:09 PM11/28/09
to

Alright, I'm not sure if my last message about this came through, so
I'm going to assume it didn't.

When I first started seeing @ show up in Python code, I said "what the
heck is that? It looks so weird and _ugly_. I would never try to mess
with that." But I started seeing it more and more, so I asked #python
what it was. They told me about decorators, so I looked it up in the
docs, and I thought the idea was interesting. It took me a while to
figure out exactly how they worked--and judging from messages I've
seen in #python a number of people have the same trouble understanding
them.

My point is that any particular syntax would look ugly to you only
because you haven't seen it in use enough, and haven't used it enough
yourself. But of course you haven't--it's not currently a valid
syntax. However, the ugliness would seem to go away after the syntax
had been in use for a while. And again, the EXACT syntax of the
feature can be adjusted until its "just right".

As for my specific use case, it's somewhat difficult to explain. The
general idea was to isolate a pattern that I spotted repeated in
several unrelated parts of my project. The pattern manifested itself
as a set of 4-5 methods and/or properties on a class whose objects
were designed to work in conjunction with other objects that fit a
particular behavior. These other objects had methods and properties
that were designed to interact with the first type of object in a
similar but--how should I say--"inverted" fashion.

This pattern showed up in many different classes throughout the
project, and not only that, but the code was very similar. I decided
to try to eliminate some of the code redundancy by creating a base
class for all the classes to derive from. That didn't worked out okay
for some things, but not for others. I can't remember the exact
details of the problem at this point, but I believe it had to do with
the keying/indexing protocol (ie. __getitem__, __setitem__, etc.). I
decided to keep the base class (and have since extended it), but
decided that it wasn't enough--that's when I decided to try
metaclassing. After some work I managed to recreate the object-to-
object relationship pattern that kept showing up everywhere, but in a
generic way that allowed for the names of methods and properties that
composed the pattern to vary in name and in the names that they
referenced from other objects. The code worked very well, and allowed
for the pattern to be added to any class by using a single, short line
of code (something along the lines of __class_attr = { key: value }).
Not only that, but the metaclass code itself was comprised of less
than a screenful of code after docstrings and comments had been
removed. However, the code was (and still is) very difficult to follow
simply because of the way getters and setters had to be used to
generate the methods and properties.

P.s. Ben Finney, I appreciate your response, and I will get back to
you,
but I want to make sure I reply under the right circumstances or I'll
end up putting my foot in my mouth. ^_^

Steven D'Aprano

unread,
Nov 28, 2009, 10:39:56 PM11/28/09
to
On Sat, 28 Nov 2009 17:22:27 -0800, The Music Guy wrote:

> As for my specific use case, it's somewhat difficult to explain. The
> general idea was to isolate a pattern that I spotted repeated in several
> unrelated parts of my project. The pattern manifested itself as a set of
> 4-5 methods and/or properties on a class whose objects were designed to
> work in conjunction with other objects that fit a particular behavior.
> These other objects had methods and properties that were designed to
> interact with the first type of object in a similar but--how should I
> say--"inverted" fashion.
>
> This pattern showed up in many different classes throughout the project,
> and not only that, but the code was very similar. I decided to try to
> eliminate some of the code redundancy by creating a base class for all
> the classes to derive from. That didn't worked out okay for some things,
> but not for others. I can't remember the exact details of the problem at
> this point, but I believe it had to do with the keying/indexing protocol
> (ie. __getitem__, __setitem__, etc.). I decided to keep the base class
> (and have since extended it), but decided that it wasn't enough--that's
> when I decided to try metaclassing. After some work I managed to
> recreate the object-to- object relationship pattern that kept showing up
> everywhere, but in a generic way that allowed for the names of methods
> and properties that composed the pattern to vary in name and in the
> names that they referenced from other objects.

Removing code redundancy is all very well, but beware of turning into an
architecture astronaut:

http://www.joelonsoftware.com/articles/fog0000000018.html

There is such a thing as over-generalisation -- if you're having to
struggle to get the abstract code working abstractly enough, you're
probably over-generalising.


> The code worked very
> well, and allowed for the pattern to be added to any class by using a
> single, short line of code (something along the lines of __class_attr =
> { key: value }). Not only that, but the metaclass code itself was
> comprised of less than a screenful of code after docstrings and comments
> had been removed. However, the code was (and still is) very difficult to
> follow simply because of the way getters and setters had to be used to
> generate the methods and properties.

That's good evidence that you've over-generalised.

--
Steven

The Music Guy

unread,
Nov 29, 2009, 5:15:25 AM11/29/09
to
Okay, I'm having a really hard time telling which messages are getting
on to the list and which ones aren't. Some of the messages I send show
up in the comp.lang.python mirror in Google Groups, and some aren't.
Others show up on the Groups mirror, but don't show up in Gmail, or
show up in a different order. It seems the only way I can guarantee
anything showing up on Groups is to post on Groups, but that makes it
difficult because I can't see the messages in the thread that only
appear in my inbox. Is there a quick fix for this, because it's
getting pretty aggravating trying to figure out who heard what. I
don't like mailing lists. :P

David Robinow

unread,
Nov 29, 2009, 9:58:57 AM11/29/09
to pytho...@python.org
On Sun, Nov 29, 2009 at 6:58 AM, inhahe <inh...@gmail.com> wrote:
> Did you say you were using gmail to post?  I think mailing lists tend to
> have issues with gmail because it puts html in the message or something like
> that.  Btw I recently set up this mailing list to send me a message back
> when I successfully posted something.  oddly enough, i only remember getting
> one such message, so maybe none of my other messages got through. :P
> i think there's a way to disable html when sending a gmail message, but
> don't quote me on that.
I wasn't aware it was possible to Enable html but apparently it is.
Let me know if you see any html in this post.

Terry Reedy

unread,
Nov 29, 2009, 8:10:12 PM11/29/09
to pytho...@python.org
The Music Guy wrote:

> When I first started seeing @ show up in Python code, I said "what the
> heck is that?

For future reference, PySymbols.html at
http://code.google.com/p/xploro/downloads/list
answers all such symbol questions.

Lie Ryan

unread,
Nov 29, 2009, 8:49:40 PM11/29/09
to
On 11/29/2009 12:22 PM, The Music Guy wrote:
> When I first started seeing @ show up in Python code, I said "what the
> heck is that? It looks so weird and _ugly_.I would never try to mess

> with that." But I started seeing it more and more, so I asked #python
> what it was. They told me about decorators, so I looked it up in the
> docs, and I thought the idea was interesting. It took me a while to
> figure out exactly how they worked--and judging from messages I've
> seen in #python a number of people have the same trouble understanding
> them.

And we don't want a second flood of users asking about foo.$bar.

> My point is that any particular syntax would look ugly to you only
> because you haven't seen it in use enough, and haven't used it enough
> yourself.

You're absolutely right, and I have *never needed* to use the plain
getattr/setattr/delattr enough to even bother considering a syntax that
already looks ugly at first sight. For @decorators, everyone used it
*often enough* BEFORE it turned into a syntax that the ugly syntax is
justified and become "acceptable". If you can find a syntax that doesn't
look ugly at first sight +0, fine by me; otherwise -1, I don't want to
be forced to read an ugly syntax for a feature that I don't use often
enough. It's not just the syntax, the necessity+syntax don't add up well.

> But of course you haven't--it's not currently a valid
> syntax. However, the ugliness would seem to go away after the syntax
> had been in use for a while. And again, the EXACT syntax of the
> feature can be adjusted until its "just right".

In so far, your definition of adjusting only means something around
"[a-zA-Z0-9_]+\.[^a-zA-Z0-9_][<{(\[]?[a-zA-Z0-9_]+[>})\]]?"

that class of syntax is ugly; some are more acceptable (e.g. obj.[arg])
the old thread have spawned better alternatives than that class of syntax.

> As for my specific use case, it's somewhat difficult to explain.

You know that:
If the implementation is hard to explain it's a bad idea.
-- Zen of Python --

right?

> The
> general idea was to isolate a pattern that I spotted repeated in
> several unrelated parts of my project. The pattern manifested itself
> as a set of 4-5 methods and/or properties on a class whose objects
> were designed to work in conjunction with other objects that fit a
> particular behavior. These other objects had methods and properties
> that were designed to interact with the first type of object in a
> similar but--how should I say--"inverted" fashion.

Do you mean something like this?

class A(object):
@property
def the_b(self):
return self._b
@the_b
def the_b(self, new_b):
self._b = new_b
self._b._a = self

class B(object):
@property
def the_a(self):
return self._a
@the_a
def the_a(self, new_a):
self._a = new_a
self._a._b = self

am I getting you right? If not, please elaborate and give an example of
what you actually meant.

Carl Banks

unread,
Nov 29, 2009, 10:52:44 PM11/29/09
to
On Nov 26, 3:43 pm, The Music Guy <music...@alphaios.net> wrote:
> That aside, I still feel that a new syntax would be a better solution
> than a new class. And, anyway, what I'm proposing isn't *quite* the
> same as what Ben North proposed. Ben's idea was *strictly* to create
> shorthand syntax to the getattr/setattr/delattr in the context of
> specific objects. What I'm suggesting could be more accurately
> described as a namespace-neutral transformation of the value of an
> expression into a name. So if "bar" is the value of foo, then when the
> interpreter sees  $foo, it reads bar.

This transformation isn't possible in Python. Python has seperate
compile and run times, and the value of a variable (like foo) isn't
known at compile time, but it would have to be known at compile time
for the interpreter to "see" the value of that variable ("bar" in this
example).

Therefore, to get the effect you want, the evaluation of foo would
have to be delayed until run time. The interpreter would "see" $foo,
and explicitly change it to bar. But that leads to another problem.

Local variables (in CPython at least) are converted to index lookups
during the compile phase, for efficiency reasons. Python doesn't use
the name of a the local variable at run time at all, and you can't
dynamically create local variables. Thus, to use your syntax proposal
with local variables you would have to accept two concessions:

1. You could not use $foo to dynamically create a new local variable;
foo would have to evaluate to the name of a local variable that
already exists.

2. You would take a significant performance hit.

Furthermore, this would introduce a bad analogical inconsistency into
the language. If you can write foo.$bar=1 to create a new attribute,
you'd expect to be able to write $bar=1 to create a new local
variable, but you can't.

These issues are significant, and given that a proposal for just
computed attributes that didn't have these issues was already
rejected, I would say your proposal would have absolutely no chance,
even if there hadn't been a moratorium on new syntax.


Carl Banks

Carl Banks

unread,
Nov 29, 2009, 10:59:52 PM11/29/09
to
On Nov 28, 3:38 am, The Music Guy <fearsomedragon...@gmail.com> wrote:
> On Nov 28, 3:07 am, Lie Ryan <lie.1...@gmail.com> wrote:
> > If you use it a lot, it is likely 1) you have abused class syntax for
> > what should have been a dict or 2) what you need is to override
> > __getattr__/__getattribute__ and __setattr__
>
> Oh boy...here we go. :|
>
> Please listen. In all the time I've spent in the coding community
> (that's at least 7 years) and especially since I started paying
> attention to the Python community (2 years), I have noticed a trend:
> When one coder does something that another cannot understand,
> frequently the other will assume the former is not only doing things
> wrong, but is doing them _blatantly_ wrong. I have caught myself
> making that very assumption many times in the past, and I've tried
> hard to build up an immunity against the impulse to make that
> assumption. At this point, I don't even believe in such a thing as a
> universal "wrong way" and a "right way" to code that applies to every
> circumstance. The way to solve a problem depends on the problem. When
> it comes to coding, there is not an absolute "right" way or "wrong"
> way--unless we're talking about, say, stealing closed source code
> without permission, or deliberately coding in a way that will cause
> problems for the end user (like causing memory clogs or buffer
> overflows and whatnot).
>
> All of this can be determined through common sense.

Another thing that can be determined through common sense is that if
you have object that you are calling getattr and setattr on so much
that you think you need special syntax, you should have been using a
dict.


Carl Banks

Bruno Desthuilliers

unread,
Nov 30, 2009, 11:35:24 AM11/30/09
to
Lie Ryan a �crit :

> On 11/28/2009 3:08 PM, The Music Guy wrote:

(snip the part about the proposed feature - which I don't like but
that's not the point)

>> My
>> projects rely on a lot of metaclassing for the automatic generation of
>> properties and methods, which saves tremendous amounts of coding.
>
> If you use it a lot, it is likely 1) you have abused class syntax for
> what should have been a dict or 2) what you need is to override
> __getattr__/__getattribute__ and __setattr__

I have to totally disagree here. The way the OP uses metaprogramming is
a really common and handy solution in lots of frameworks, and
drastically reduces the need for boilerplate (and the potential for
bugs). It's *WAY* cleaner (readability, introspection, doc etc) and far
less error-prone than going the __getattr(ibute)__ / __setattr__, and
also way more efficient (from execution time POV).

Using __getattr__ and __setattr__ to emulate attributes (usually
descriptors) that can be built at class creation time is IMHO what
should be labeled as an "abuse" (at best).

Lie Ryan

unread,
Nov 30, 2009, 1:07:36 PM11/30/09
to
On 12/1/2009 3:35 AM, Bruno Desthuilliers wrote:
> Lie Ryan a �crit :
>> On 11/28/2009 3:08 PM, The Music Guy wrote:
>
> (snip the part about the proposed feature - which I don't like but
> that's not the point)
>
>>> My
>>> projects rely on a lot of metaclassing for the automatic generation of
>>> properties and methods, which saves tremendous amounts of coding.
>>
>> If you use it a lot, it is likely 1) you have abused class syntax for
>> what should have been a dict or 2) what you need is to override
>> __getattr__/__getattribute__ and __setattr__
>
> I have to totally disagree here. The way the OP uses metaprogramming is
> a really common and handy solution in lots of frameworks, and
> drastically reduces the need for boilerplate (and the potential for
> bugs). It's *WAY* cleaner (readability, introspection, doc etc) and far
> less error-prone than going the __getattr(ibute)__ / __setattr__, and
> also way more efficient (from execution time POV).

I won't argue with the usefulness of metaclass, I agree that metaclass
is the cleanest way to implement certain things; but the main point is
the OP's use of getattr/setattr while he got full control of the
namespace dictionary.

Terry Reedy

unread,
Nov 30, 2009, 4:35:12 PM11/30/09
to pytho...@python.org
Brad Harms wrote:

> Well, yes, the names would have to be determined at run time. That's
> what getattr and setattr do, except that that do it in the context of an
> object rather than the local scope. However, I was under the impression
> that python's mechanism for looking up local names was the same as the
> mechanism used to look up attributes because names and attributes seem
> to function pretty much the same way. This I assumed because of the
> functionality of the locals() and globals() functions, which seem to act
> like the __dict__ attribute on objects except that the work on the
> current scope.

The definition of locals() allows it to just be a dict *copy* of the
local namespace, rather than the local namespace itself. Within
functions, (at least for CPython, and probably for other
implementations), locals() is just a copy, and changes to locals() are
*not* propagated back to the local namespace. Within functions, local
name 'lookup' has nothing to do with dict lookup. (It is more like list
indexing.)


The Music Guy

unread,
Nov 30, 2009, 9:55:46 PM11/30/09
to
> Brad Harms FearsomeDragonfly at gmail.com
> Mon Nov 30 05:04:37 CET 2009
>
> That was a relatively simple example; classes as simple as the ones
> generated by the It is more likely that the class generation could would
> appear in a metaclass's class constructor or decorator function, and there
> would be more than just the three attributes given.

Bwa ha ha! Well, I managed to screw up that paragraph pretty badly. (I
code better than I write, honest.) Let me try again:

That was a relatively simple example; classes as simple as the ones
generated by the factory function example given are not needed very
often. It is more likely that the class generation would appear in a
metaclass's class constructor or decorator function, and there would
be more than just the three attributes. That way it could be possible
to ADD those properties and methods to a class in the process of being
built rather than make a class with just those attributes.

Lie Ryan, I think I see what you're saying about using __dict__ to add
members to a class, but it's not quite the same. __dict__ is only for
attributes, NOT properties, methods, etc. which all come from the
class of an object rather than the object's __dict__. Adding things to
__dict__ would only work halfway; it wouldn't be very extensible.
That's (one of the reasons) why the members have to be accessed as
attributes rather than dict items.

Steven D'Aprano

unread,
Dec 1, 2009, 9:38:01 AM12/1/09
to
On Mon, 30 Nov 2009 18:55:46 -0800, The Music Guy wrote:

> Lie Ryan, I think I see what you're saying about using __dict__ to add
> members to a class, but it's not quite the same. __dict__ is only for
> attributes, NOT properties, methods, etc. which all come from the class
> of an object rather than the object's __dict__.

Almost but not quite.

It's just special double-underscore methods like __init__ __add__ etc
that have to be in the class rather than the instance. (To be precise,
you can add such a method to the instance, but it won't be called
automatically.) Likewise staticmethods and classmethods won't work
correctly unless they are in the class. But ordinary methods work fine:
the only tricky bit is creating them in the first place.

>>> class K(object):
... pass
...
>>> k = K()
>>> import types
>>> k.method = types.MethodType(lambda self: "I am %s" % self, k)
>>> k.method()
'I am <__main__.K object at 0xb7cc7d4c>'

--
Steven

Bruno Desthuilliers

unread,
Dec 1, 2009, 10:58:00 AM12/1/09
to
The Music Guy a �crit :
(snip)

> Lie Ryan, I think I see what you're saying about using __dict__ to add
> members

No "members" in Python - only attributes.

> to a class, but it's not quite the same. __dict__ is only for
> attributes, NOT properties, methods, etc. which all come from the
> class of an object rather than the object's __dict__.

properties and methods (well, functions actually) ARE attributes... of
the class object. And you can of course access the obj.__class__.__dict__

Just for the record...

Raymond Hettinger

unread,
Dec 1, 2009, 1:21:03 PM12/1/09
to
[Gregory Ewing]
> >>I just posted to my blog about a feature that I'd like to see added to
> >>Python.
>
> >>http://alphaios.blogspot.com/2009/11/python-string-inferred-names-wor...
>
> I don't think getattr and setattr are used anywhere near
> frequently enough to justify special syntax.

Perhaps that would change if we had the proposed syntax.
I would expect that powerful and expressive idioms would emerge.


> (A frequent question asked by newcomers from certain
> other kinds of languages is something like "How do I
> assign to a variable whose name is in another variable?"
> The answer is almost always "Don't do that, use a
> dictionary.")

The proposed syntax works better with class namespaces
which automatically provide inheritance logic and
method binding. Dictionaries don't provide equivalent
support.


Raymond

Carl Banks

unread,
Dec 1, 2009, 3:52:19 PM12/1/09
to
On Dec 1, 10:21 am, Raymond Hettinger <pyt...@rcn.com> wrote:
> [Gregory Ewing]
>
> > >>I just posted to my blog about a feature that I'd like to see added to
> > >>Python.
>
> > >>http://alphaios.blogspot.com/2009/11/python-string-inferred-names-wor...
>
> > I don't think getattr and setattr are used anywhere near
> > frequently enough to justify special syntax.
>
> Perhaps that would change if we had the proposed syntax.
> I would expect that powerful and expressive idioms would emerge.

I doubt it. Such expressive idioms haven't emerged in languages that
do this (e.g., Javascript, Matlab) as far as I can tell. The objects
end up being used as nothing more than a poor replacement for
dictionaries.


> > (A frequent question asked by newcomers from certain
> > other kinds of languages is something like "How do I
> > assign to a variable whose name is in another variable?"
> > The answer is almost always "Don't do that, use a
> > dictionary.")
>
> The proposed syntax works better with class namespaces
> which automatically provide inheritance logic and
> method binding.  Dictionaries don't provide equivalent
> support.

The right approach to having "inheritance-like behavior" AND
"typically don't know the name of the thing being accessed at compile
time" in the same object--and I doubt that would be widely useful--is
to add an option to dictionaries to support inheritance.


Carl Banks

Brad Harms

unread,
Dec 4, 2009, 12:12:39 AM12/4/09
to pytho...@python.org

...I'm not sure I follow your logic.

Yes, you can create an instancemethod out of a function and assign it to
an instance after (or during) its instantiation, which is what Python's
class/instance model provides automatically. However, to do so manually
in this manner completely disregards the fundamentals of object-oriented
programming, not to mention the basic guiding principles of nearly all
Python code in existence. It totally breaks inheritance and
polymorphism. Maybe I'm missing something, but I can't see how that line
of thought helps anything.

Message has been deleted

Bradley K. Harms

unread,
Dec 4, 2009, 1:35:28 AM12/4/09
to pytho...@python.org
On Tue, 2009-12-01 at 14:38 +0000, Steven D'Aprano wrote:

> Yes, you can create an instancemethod out of a function and assign it to


> an instance after (or during) its instantiation, which is what Python's

> class/instance model provides automatically. [...]

...Hmm, let me clarify that statement as I think it could be misunderstood:

When I say "which is what [Python] does automatically", I mean that Python
automatically creates a BOUND instancemethod object from the UNBOUND
instancemethod whenever you try to access the unbound instancemethod as an
attribute of the instance _at the moment that you try to access it_. I did
NOT mean to imply that the bound instancemethod objects are created and
assigned to the instance at the time of its instantiation (because Python
obviously doesn't do that).

Sorry for the rapid-fire posting.

Ben Finney

unread,
Dec 4, 2009, 2:05:03 AM12/4/09
to
Brad Harms <fearsome...@gmail.com> writes:

> Anyway, it looks like the docs agree with you
> (http://docs.python.org/glossary.html#term-attribute), so I'm not
> going to argue.

That's good, because the terms are quite well established in Python
terminology.

> However, for the purpose of clean communication, I'd still like to
> have terms that refer specifically to:
>
> 1.) "Regular" attributes, ie. those that are shortcuts to items in the
> directly associated object's __dict__,

I don't know what you mean by “shortcuts to items”. The names are looked
up in dictionaries; where do shortcuts play a part?

Try “instance attribute”, as distinct from “class attribute”.

> 2.) Attributes whose values are determined or assigned dynamically by
> indirectly calling a function (like properties and instancemethods)

Yes, the term “property” seems to do what you want.

The value of an instance method is *not* determined dynamically: its
value is a function, and that value is no more dynamic than any other
attribute of the instance.

> 3.) Attributes that are read from an object with regular .dot syntax,
> but are actually attributes (in the sense of #1 above) of the __dict__
> of the object's class.

This is a “class attribute” as distinct from an “instance attribute”.

The distinction isn't often worth knowing, though, so you'll probably
still have to explain it when you use it.

--
\ “‘Did you sleep well?’ ‘No, I made a couple of mistakes.’” |
`\ —Steven Wright |
_o__) |
Ben Finney

Steven D'Aprano

unread,
Dec 4, 2009, 4:00:42 AM12/4/09
to
On Fri, 04 Dec 2009 18:05:03 +1100, Ben Finney wrote:

> Brad Harms <fearsome...@gmail.com> writes:
...


>> 1.) "Regular" attributes, ie. those that are shortcuts to items in the
>> directly associated object's __dict__,
>
> I don't know what you mean by “shortcuts to items”. The names are looked
> up in dictionaries; where do shortcuts play a part?
>
> Try “instance attribute”, as distinct from “class attribute”.

Not all such attributes are actually found in instance.__dict__.


>>> class Example(object):
... __slots__ = 'spam'
...
>>> x = Example()
>>> y = Example()
>>> x.spam = 23
>>>
>>> x.__dict__['spam']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Example' object has no attribute '__dict__'
>>> x.spam
23
>>> y.spam
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: spam


So it is possible to have per-instance attributes that don't live inside
the instance __dict__.

>> 2.) Attributes whose values are determined or assigned dynamically by
>> indirectly calling a function (like properties and instancemethods)
>
> Yes, the term “property” seems to do what you want.

Or dynamic attributes returned by __getattr__ or __getattribute__.

--
Steven

Brad Harms

unread,
Dec 4, 2009, 4:34:00 AM12/4/09
to
On Fri, 04 Dec 2009 18:05:03 +1100, Ben Finney wrote:

> Brad Harms <fearsome...@gmail.com> writes:
>
>> Anyway, it looks like the docs agree with you
>> (http://docs.python.org/glossary.html#term-attribute), so I'm not going
>> to argue.
>
> That's good, because the terms are quite well established in Python
> terminology.

I'm just saying, if the official documentation defines the term
"attribute" thusly, it would be silly of me to continue using my own made-
up term that means pretty much the same thing.

>
>> However, for the purpose of clean communication, I'd still like to have
>> terms that refer specifically to:
>>
>> 1.) "Regular" attributes, ie. those that are shortcuts to items in the
>> directly associated object's __dict__,
>
> I don't know what you mean by “shortcuts to items”. The names are looked
> up in dictionaries; where do shortcuts play a part?
>
> Try “instance attribute”, as distinct from “class attribute”.
>
>> 2.) Attributes whose values are determined or assigned dynamically by
>> indirectly calling a function (like properties and instancemethods)
>
> Yes, the term “property” seems to do what you want.

I wasn't asking what you call any object or any /kind/ of object. I was
asking for a term (noun?) that describes the WAY the object is accessed
as an attribute of an instance, with the connotation that the value of
the attribute would be calculated dynamically (by calling a function) at
the time the attribute was accessed. Note that the value does not have to
exist in ANY __dict__ anywhere, it could, for example, be calculated by
object.__getattribute__.

Example:

>>> obj.attr

Without knowing what "obj" is or what "attr" is as it pertains to obj,
but knowing that "attr" does not actually a key in obj.__dict_,_ and that
its value has to be determined by some other means, what do you call the
thing on the code line above? That is what I'm trying to find out. (HINT:
Don't think about how the Python interpreter parses it or how the value
is eventually determined. That's not relevant. Just understand that the
value does not come directly from obj.__dict__.)

By the way, a "property" is an object of type __builtin__.property. A
property with a reference in an attribute of a class /does/ call a
function when you try to access that property as an attribute of the
class's instances. However, properties are not the only objects that have
this behavior, so calling objects that behave in this way is ambiguous. I
think the actual, general term for such an object is "data descriptor,"
or just "descriptor." (http://docs.python.org/glossary.html#term-
descriptor)

>
> The value of an instance method is *not* determined dynamically: its
> value is a function, and that value is no more dynamic than any other
> attribute of the instance.

That is incorrect. Indirectly accessing an instancemethod of a class
through an instance of that class will trigger the descriptor behavior of
the instancemethod type. This produces a new object, another
instancemethod, that is bound to the instance through which it was
accessed. It's a mouthful to say, but it is sufficiently accurate.

Heck, just look at this:

>>> class Foo(object):
... def spam(self): pass
...
>>> foo = Foo()
>>> foo.spam
<bound method Foo.spam of <__main__.Foo object at 0x931c46c>>
>>> Foo.spam
<unbound method Foo.spam>
>>> foo.spam is Foo.spam
False
>>> foo.spam == Foo.spam
False
>>> Foo.spam.__get__(foo, Foo)
<bound method Foo.spam of <__main__.Foo object at 0x931c46c>>
>>> Foo.__dict__["spam"].__get__(foo, Foo)
<bound method Foo.spam of <__main__.Foo object at 0x931c46c>>
>>> Foo.__dict__["spam"].__get__(foo, Foo) is foo.spam
False
>>> Foo.__dict__["spam"].__get__(foo, Foo) == foo.spam
True

Also note the fact that Foo.spam is an _instancemethod_ object and not
just a function, even though it was defined as "just a function" in the
class body. That's because function objects are descriptors as well; it
lets them produce unbound instancemethods. I'm not precisely sure how
this works, though. I think it only happens when the metaclass of a class
processes the functions in the class block.

>
>> 3.) Attributes that are read from an object with regular .dot syntax,
>> but are actually attributes (in the sense of #1 above) of the __dict__
>> of the object's class.
>
> This is a “class attribute” as distinct from an “instance attribute”.
>

I know it's called that, but I was talking more about the fact of it
being accessed through an instance of the class rather than


> The distinction isn't often worth knowing, though, so you'll probably
> still have to explain it when you use it.

I beg to differ. For one thing, it affects descriptors.


Anyway, these metadiscussions are starting to give me headaches. Let's
talk about something more interesting...


PS. I'm truly sorry once again for using email addresses and names
inconsistently. I really am trying to solve the problem. I'm going to try
accessing the list via comp.lang.python and Pan (newsreader for Gnome)
for a while. Hopefully it will help.

--
Brad Harms -- http://alphaios.net

Brad Harms

unread,
Dec 4, 2009, 4:40:04 AM12/4/09
to
On Fri, 04 Dec 2009 09:00:42 +0000, Steven D'Aprano wrote:
> Not all such attributes are actually found in instance.__dict__.

...I hadn't even considered __slots__ yet. Hm...

> Or dynamic attributes returned by __getattr__ or __getattribute__.

I'm looking for a generic term, because it's too cumbersome to say
"properties or dynamic attributes using __getattr__ or __getattribute__"
all the time.

That will be my last message for a while...good night, c.p.l.

Steven D'Aprano

unread,
Dec 4, 2009, 7:58:09 AM12/4/09
to
On Thu, 03 Dec 2009 23:12:39 -0600, Brad Harms wrote:

> On Tue, 2009-12-01 at 14:38 +0000, Steven D'Aprano wrote:

[...]


>> It's just special double-underscore methods like __init__ __add__ etc
>> that have to be in the class rather than the instance. (To be precise,
>> you can add such a method to the instance, but it won't be called
>> automatically.) Likewise staticmethods and classmethods won't work
>> correctly unless they are in the class. But ordinary methods work fine:
>> the only tricky bit is creating them in the first place.
>>
>> >>> class K(object):
>> ... pass
>> ...
>> >>> k = K()
>> >>> import types
>> >>> k.method = types.MethodType(lambda self: "I am %s" % self, k)
>> >>> k.method()
>> 'I am <__main__.K object at 0xb7cc7d4c>'
>
> ...I'm not sure I follow your logic.
>
> Yes, you can create an instancemethod out of a function and assign it to
> an instance after (or during) its instantiation, which is what Python's
> class/instance model provides automatically. However, to do so manually
> in this manner completely disregards the fundamentals of object-oriented
> programming, not to mention the basic guiding principles of nearly all
> Python code in existence. It totally breaks inheritance and
> polymorphism. Maybe I'm missing something, but I can't see how that line
> of thought helps anything.

I'm not recommending it as a standard technique instead of defining
methods via the usual class statement. But it does work, and can be handy
for the odd occasion where you want per-instance behaviour of some class.
I'm not saying this is a common occurrence, but it does happen -- it's
particularly handy if you have a standard behaviour which you want to
override, e.g. monkey-patching specific instances. Instead of this:

class K:
marker = None
def method(self):
if self.marker:
return "special"
return "normal"

k = K()
k.marker = 1

you can do this:

class K:
def method(self):
return "normal"

k = K()
k.method = type(k.method)(lambda self: "special", k)

So although unusual, it is useful.

As for breaking inheritance and polymorphism, not at all. Inheritance
still works, and polymorphism is irrelevant: methods are, or aren't,
polymorphic regardless of whether they are per instance or shared.
Fundamentally, per-instance methods are nothing more than as per-instance
attributes which happen to be callable.

It is "magic methods" like __len__ and friends that break the usual rules
of inheritance. The normal lookup chain for instance.name, whether name
is a callable method or a non-callable attribute, is:

instance
class
base class(es)

but for magic methods, the chain skips the instance step. That's done as
an optimization, and given how rare it is to have per-instance methods,
that's quite reasonable.

--
Steven

Message has been deleted

Bruno Desthuilliers

unread,
Dec 4, 2009, 10:14:42 AM12/4/09
to
Ben Finney a écrit :
> Brad Harms <fearsome...@gmail.com> writes:
(snip)

>> 2.) Attributes whose values are determined or assigned dynamically by
>> indirectly calling a function (like properties and instancemethods)
>
> Yes, the term “property” seems to do what you want.

The property type is just one possible application of the descriptor
protocol which provides most of the support for computed attributes in
Python, so it might be way too restrictive.

> The value of an instance method is *not* determined dynamically:

It is, actually. The function type implements the protocol descriptor,
with the __get__ method returning an instancemethod object.

Bruno Desthuilliers

unread,
Dec 4, 2009, 10:24:42 AM12/4/09
to
Brad Harms a écrit :

> On Fri, 04 Dec 2009 18:05:03 +1100, Ben Finney wrote:
(snip)

>>> 2.) Attributes whose values are determined or assigned dynamically by
>>> indirectly calling a function (like properties and instancemethods)
>> Yes, the term “property” seems to do what you want.
>
> I wasn't asking what you call any object or any /kind/ of object. I was
> asking for a term (noun?) that describes the WAY the object is accessed
> as an attribute of an instance, with the connotation that the value of
> the attribute would be calculated dynamically (by calling a function) at
> the time the attribute was accessed.

Then you definitly want "computed attribute" - which is quite standard
OO terminology FWIW.

(snip - Ben, I think you shouldn't have tred to teach your grandmother
how to suck eggs <g>)

> Also note the fact that Foo.spam is an _instancemethod_ object and not
> just a function, even though it was defined as "just a function" in the
> class body. That's because function objects are descriptors as well; it
> lets them produce unbound instancemethods. I'm not precisely sure how
> this works,

class function(object):
def __get__(self, instance, cls):
if instance:
assert isinstance(instance, cls)
return boundmethod(instance, cls)
else
return unboundmethod(cls)


> though. I think it only happens when the metaclass of a class
> processes the functions in the class block.

Nope, this is totally unrelated.

class Foo(object):
def __init__(self, bar):
self.bar = 42

def baaz(obj, whatever):
print obj.bar, whatever

Foo.baaz = baaz

f= Foo()
f.baaz("is the answer")


>>> 3.) Attributes that are read from an object with regular .dot syntax,
>>> but are actually attributes (in the sense of #1 above) of the __dict__
>>> of the object's class.
>> This is a “class attribute” as distinct from an “instance attribute”.
>>
>
> I know it's called that, but I was talking more about the fact of it
> being accessed through an instance of the class rather than

Except for descriptors, this doesn't make much difference difference.


0 new messages