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']
"""
#############################################################