class Base(object):
colour = "Blue"
def parrot(self):
"""docstring for Base"""
return "Norwegian %s" % self.colour
class SubClass(Base):
colour = "Red"
def parrot(self):
"""docstring for Subclass"""
return super(Subclass, self).parrot()
but that adds an awful lot of boilerplate to my subclasses. Are there any
other good solutions to this problem?
--
Steven
If I've understood, one idea is:
------------------------------
def type_factory(colour):
class Base(object):
def parrot(self):
"""Norwegian %s"""
return 1
parrot.__doc__ %= colour
return Base
class Base(object):
def __new__(cls, *args, **kw):
return type_factory(cls.colour)(*args, **kw)
class A(Base):
colour = "Blue"
class B(Base):
colour = "Red"
a = A()
b = B()
print inspect.getdoc(a.parrot)
Norwegian Blue
print inspect.getdoc(b.parrot)
Norwegian Red
----------------------------------------------
In the more general case, (ie. where you don't know that there is a
method called parrot and an attribute called colour), I imagine you
could do the same thing but at the metaclass level.
HTH
G.F.
Methods don't have docstrings; functions do. So one has to "clone" the
function to set a new docstring.
<code>
def copy_function(fn, docstring):
fn = getattr(fn, "im_func", fn) # accomodate unbound methods in 2.x
function_type = type(lambda:0)
newfn = function_type(fn.__code__, fn.__globals__, fn.__name__,
fn.__defaults__, fn.__closure__)
newfn.__doc__ = docstring
return newfn
class Base(object):
colour = "Blue"
def parrot(self):
"""docstring for Base"""
return "Norwegian %s" % self.colour
class SubClass(Base):
colour = "Red"
parrot = copy_function(Base.parrot, "docstring for Subclass")
</code>
py> x = Base()
py> print(x.parrot())
Norwegian Blue
py> print x.parrot.__doc__
docstring for Base
py> y = SubClass()
py> print(y.parrot())
Norwegian Red
py> print y.parrot.__doc__
docstring for Subclass
--
Gabriel Genellina
Since Steven says he has a series of subclasses, perhaps wrapping those function
calls in a decorator?
<code>
def copy_function(fn, docstring):
# Gabriel Genellina's copy_function
fn = getattr(fn, "im_func", fn) # accomodate unbound methods in 2.x
function_type = type(lambda:0)
newfn = function_type(fn.__code__, fn.__globals__, fn.__name__,
fn.__defaults__, fn.__closure__)
newfn.__doc__ = docstring
return newfn
def docstrings(**kwargs):
def with_altered_docstrings(cls, kwargs=kwargs):
for kwarg in kwargs.items():
func_name = kwarg[0]
docstring = kwarg[1]
original_func = getattr(cls, func_name)
new_func = copy_function(getattr(cls, func_name), docstring)
setattr(cls, func_name, new_func)
return cls
return with_altered_docstrings
class Base(object):
colour = "Blue"
def parrot(self):
"""docstring for Base"""
return "Norwegian %s" % self.colour
@docstrings( parrot = "docstring for Subclass" )
class SubClass(Base):
colour = "Red"
</code>
This is my first decorator ever so it might be Incorect and nonIdiomatic...
Also, neither 'copy_function' nor 'docstrings' seem to work with slots.
Steven: on a personal note, earlier when I saw you (I think it was you) using
the "Norwegian Parrot" example I thought it referred to me because that was the
only sense I could make of it, it followed right after some discussion we had.
Thus my impression of you or or responses in this group was colored by a false
interpretation. But, checking, which is often a good idea!, and *which I should
have done then*, as far as I can see the term was first used in this group in
April 2001, <url:
http://groups.google.com/group/comp.lang.python/browse_thread/thread/12a125ceddd401e2/c021547a1dc14a41>.
It's still a mystery to me what it refers to, though... :-)
Cheers & hth.,
- Alf
>>> print abs.__doc__
abs(number) -> number
Return the absolute value of the argument.
>>>
Perhaps I am misunderstanding "don't have docstrings". This code:
>>> class TheHellOfIt:
... """Classes, of course, as first-class citizens and have
docstrings."""
... def method(self):
... """Discrimination against methods, I call it."""
... pass
...
>>> print TheHellOfIt.method.__doc__
Discrimination against methods, I call it.
>>> import sys
>>> help(sys.modules["__main__"])
Gives:
Help on built-in module __main__:
NAME
__main__
FILE
(built-in)
CLASSES
TheHellOfIt
class TheHellOfIt
| Classes, of course, as first-class citizens and have docstrings.
|
| Methods defined here:
|
| method(self)
| Discrimination against methods, I call it.
So, are the demands of the methods reasonable, or do they already have
what they are so loudly demanding?
regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
PyCon is coming! Atlanta, Feb 2010 http://us.pycon.org/
Holden Web LLC http://www.holdenweb.com/
UPCOMING EVENTS: http://holdenweb.eventbrite.com/
I can't really comment on decorators and subclassing yet (still a
newb) but I am finding this discussion very informative... and lo
there IS something I can comment on.
The Norwegian Blue is a remarkable bird. Beautiful plumage! Though
they do like to lie around on their backs a bit, and seem to spend
their time either resting, or pining for the fjords. Yes lovely
plumage, indeed!
Google the remarkable Norwegian Blue Parrot and you'll fall in love as
I did so long ago :)
--
Marie von Ebner-Eschenbach - "Even a stopped clock is right twice a
day." - http://www.brainyquote.com/quotes/authors/m/marie_von_ebnereschenbac.html
> Steven: on a personal note, earlier when I saw you (I think it was you)
> using the "Norwegian Parrot" example I thought it referred to me because
> that was the only sense I could make of it, it followed right after some
> discussion we had. Thus my impression of you or or responses in this
> group was colored by a false interpretation. But, checking, which is
> often a good idea!, and *which I should have done then*, as far as I can
> see the term was first used in this group in April 2001, <url:
> http://groups.google.com/group/comp.lang.python/browse_thread/
thread/12a125ceddd401e2/c021547a1dc14a41>.
>
> It's still a mystery to me what it refers to, though... :-)
It refers to the famous Monty Python "Dead Parrot Sketch", involving a
Norwegian Blue parrot that definitely isn't dead but merely pining for
the fjords.
http://www.mtholyoke.edu/~ebarnes/python/dead-parrot.htm
http://en.wikipedia.org/wiki/Dead_Parrot
No doubt you'll be able to find it on Youtube.
A little-known FAQ is that Python is named for Monty Python, not the
snake, and that traditionally metasyntactic variables such as foo, bar
etc. are frequently named after Monty Python sketches. E.g. I will
frequently reference the Cheeseshop sketch, the Spanish Inquisition,
Ethel the Aardvark, Spam (the lunch meat, not the email), and similar.
E.g. instead of foo, bar, baz, we frequently use spam, ham, eggs.
http://www.python.org/doc/faq/general/#why-is-it-called-python
--
Steven
>> Methods don't have docstrings; functions do. So one has to "clone" the
>> function to set a new docstring.
>>
> On behalf of all methods I would like to say "We demand the right to
> docstrings".
>
>>>> print abs.__doc__
> abs(number) -> number
>
> Return the absolute value of the argument.
>>>>
>
> Perhaps I am misunderstanding "don't have docstrings". This code:
Sorry, I wasn't clear at all. What I wanted to say is that docstrings are
actually stored as *function* attributes; methods inherit the docstring
from the function they are built on (as a read-only attribute).
py> class Base(object):
... def method(self):
... "my docstring"
...
py> Base.method.__doc__
'my docstring'
py> Base.method.__doc__ = "another docstring"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: attribute '__doc__' of 'instancemethod' objects is not
writable
py> Base.method.im_func.__doc__
'my docstring'
py> Base.method.im_func.__doc__ = "another docstring"
py> Base.method.__doc__
'another docstring'
So, if you want Base.foo and Derived.foo to share the same behavior but
have separate docstrings (what Steven asked for), you have to create
separate functions for both. That's what my already posted code does.
> So, are the demands of the methods reasonable, or do they already have
> what they are so loudly demanding?
Well, they could demand the right to have a docstring of their own. Since
3.x eliminated a whole category of methods (unbound methods are gone),
their ability to press for demands was greatly reduced. I don't think they
could get such right granted in the near future...
--
Gabriel Genellina
>>> return super(self.__class__, self).parrot()
would have made it.
What if Subclass has more than one base class ?
JM
>
>>>> class SubClass(Base):
>>>> colour = "Red"
>>>> def parrot(self):
>>>> """docstring for Subclass"""
>>>> return super(Subclass, self).parrot()
> I'm not a big fan of super, but I'm still wondering if
>
> >>> return super(self.__class__, self).parrot()
>
> would have made it.
No, it wouldn't.
> What if Subclass has more than one base class ?
super() will work in that case provided you specify the current class. It
never works correctly if you specify the class of self.
Consider another level of subclasses and it may be clearer:
>>> class Base(object):
def parrot(self):
print "Base.parrot"
>>> class SubClass(Base):
def parrot(self):
print "SubClass.parrot"
return super(SubClass, self).parrot()
>>> class SubSubClass(SubClass):
def parrot(self):
print "SubSubClass.parrot"
return super(SubSubClass, self).parrot()
>>> SubSubClass().parrot()
SubSubClass.parrot
SubClass.parrot
Base.parrot
>>> class SubClass(Base):
def parrot(self):
print "SubClass.parrot"
return super(self.__class__, self).parrot()
>>> class SubSubClass(SubClass):
def parrot(self):
print "SubSubClass.parrot"
return super(self.__class__, self).parrot()
>>> SubSubClass().parrot()
SubClass.parrot
SubClass.parrot
SubClass.parrot
SubClass.parrot
SubClass.parrot
SubClass.parrot
SubClass.parrot
SubClass.parrot
SubClass.parrot
... (you're in an infinite loop now) ...
Then is there a reason why
>>> return super(Subclass, self).parrot()
would be prefered over the "classic"
>>> return Base.parrot(self)
?
Or is it just a matter of preference ?
JM
[...]
> Then is there a reason why
>>>> return super(Subclass, self).parrot()
> would be prefered over the "classic"
>>>> return Base.parrot(self)
> ?
>
> Or is it just a matter of preference ?
Using super() calls the next method in the class's Method Resolution
Order (mro - to see it on class A, use A.mro()). This guarantees that
ancestor methods won't be called twice when the inheritance graph is not
a tree. Here is a (minimal?) example.
>>> class A(object):
... def foo(self): print 'A'
...
>>> class B(A):
... def foo(self):
... super(B, self).foo()
... print 'B'
...
>>> class C(A):
... def foo(self):
... super(C, self).foo()
... print 'C'
...
>>> class D(B, C):
... def foo(self):
... super(D, self).foo()
... print 'D'
...
>>> d = D()
>>> d.foo()
A
C
B
D
>>> D.mro()
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>]
The reason why super() may be necessary is that if an object is an
instance of say class C, its method resolution order above class C is
not known at compile time.
HTH
--
Arnaud
>>> return super(self.__class__, self).parrot()
>>> would have made it.
>>
>> No, it wouldn't. [...]
>>
> I see.
> Then is there a reason why
> return super(Subclass, self).parrot()
> would be prefered over the "classic"
> return Base.parrot(self)
> ?
> Or is it just a matter of preference ?
For a longer explanation, see:
James Knight: Python's Super Considered Harmful
http://fuhm.net/super-harmful/
Michele Simionato: Things to Know About Python Super
http://www.artima.com/weblogs/viewpost.jsp?thread=236275
http://www.artima.com/weblogs/viewpost.jsp?thread=236278
http://www.artima.com/weblogs/viewpost.jsp?thread=237121
--
Gabriel Genellina
The following is not tested more than you see and will not work for
builtin methods, but it should work in the common cases:
from types import FunctionType, CodeType
def newfunc(func, docstring):
c = func.func_code
nc = CodeType(c.co_argcount, c.co_nlocals, c.co_stacksize,
c.co_flags, c.co_code, c.co_consts, c.co_names,
c.co_varnames, c.co_filename, func.__name__,
c.co_firstlineno, c.co_lnotab, c.co_freevars,
c.co_cellvars)
nf = FunctionType(nc, func.func_globals, func.__name__)
nf.__doc__ = docstring
return nf
def setdocstring(method, docstring):
cls = method.im_class
basefunc = getattr(super(cls, cls), method.__name__).im_func
setattr(cls, method.__name__, newfunc(basefunc, docstring))
# example of use
class B(object):
def m(self):
"base"
return 'ok'
class C(B):
pass
setdocstring(C.m, 'C.m docstring')
print B.m.__doc__ # the base docstring
print C.m.__doc__ # the new docstring
Thanks to all who replied to this thread.
I didn't remember why I didn't want to dive into super in the first
place, now I remember :o)
I'm sure about one thing about super: it has a misleading name.
JM
>> I have a series of subclasses that inherit methods from a base class,
>> but
>> I'd like them to have their own individual docstrings.
>
> from types import FunctionType, CodeType
>
> def newfunc(func, docstring):
> c = func.func_code
> nc = CodeType(c.co_argcount, c.co_nlocals, c.co_stacksize,
> c.co_flags, c.co_code, c.co_consts, c.co_names,
> c.co_varnames, c.co_filename, func.__name__,
> c.co_firstlineno, c.co_lnotab, c.co_freevars,
> c.co_cellvars)
> nf = FunctionType(nc, func.func_globals, func.__name__)
> nf.__doc__ = docstring
> return nf
>
> def setdocstring(method, docstring):
> cls = method.im_class
> basefunc = getattr(super(cls, cls), method.__name__).im_func
> setattr(cls, method.__name__, newfunc(basefunc, docstring))
>
> class B(object):
> def m(self):
> "base"
> return 'ok'
>
> class C(B):
> pass
>
> setdocstring(C.m, 'C.m docstring')
This is basically the same technique as in
<http://permalink.gmane.org/gmane.comp.python.general/651001> but there is
a difference: you clone the function object *and* the code object it is
based on. As I understand it, code objects are immutable and there is no
need to clone them, but I may be wrong. Why did you feel the need to clone
the code object too?
--
Gabriel Genellina
No need. I just had the newfunc utility in my library (I think copied
from a recipe in the Python cookbook by Alex Martelli) so I used it.
In this case it is overkill, though. Also, I had no read your post
when I posted my solution, otherwise I would not have sent it ;)
Anyway, the setdocstring utility to extract the parent method was not
explicit in your post and may be of some use to somebody.
M. Simionato
Ah, ok! I was afraid I missed something -- but reusing code is a perfectly
valid reason!
--
Gabriel Genellina