Re: [Python-Dev] One-line abstractmethod function?

On Thu, Dec 05, 2013 at 01:33:00PM -0800, Guido van Rossum wrote:
The only two alternatives are doing nothing/pass/return None or having actual code in the method.
The former is only useful to silently ignore blind super() calling, the latter you would define and decorate the method normally.
Actually if you want to support multiple inheritance of your ABC, your abstract methods *must* be no-ops (or have some kind of default behavior that can always be done last).
I must respectfully disagree with this. If your ABCs aren't meant to be in the MRO, then you should be @registering them as virtual classes and not inheriting them. The trick with Python multiple inheritance and super() (from personal experience) is to not think of it as multiple inheritance (a tree with cycles), but as building the MRO (linear, the same as single inheritance).

On 12/05/2013 06:08 PM, Allen Li wrote:
On Thu, Dec 05, 2013 at 01:33:00PM -0800, Guido van Rossum wrote:
Actually if you want to support multiple inheritance of your ABC, your abstract methods *must* be no-ops (or have some kind of default behavior that can always be done last).
Done last or first really depends on what the default behavior is, doesn't it? Using __new__ as an example, the chain of calls for that has the most ancestorish (yeah, I just made that word up ;) method doing the work first, with each less-ancestorish method building on to that as the call chain unwinds.
I must respectfully disagree with this. If your ABCs aren't meant to be in the MRO, then you should be @registering them as virtual classes and not inheriting them.
Why would you think they are not meant to be in the MRO? When dealing with multiple-inheritance, there must be a base class that does not try to call super() (object does not work for this) -- what better class to use than the base abstract class?
The trick with Python multiple inheritance and super() (from personal experience) is to not think of it as multiple inheritance (a tree with cycles), but as building the MRO (linear, the same as single inheritance).
-- ~Ethan~

On Thu, Dec 5, 2013 at 6:31 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
On Thu, Dec 05, 2013 at 01:33:00PM -0800, Guido van Rossum wrote:
Actually if you want to support multiple inheritance of your ABC, your abstract methods *must* be no-ops (or have some kind of default behavior that can always be done last).
Done last or first really depends on what the default behavior is, doesn't it? Using __new__ as an example, the chain of calls for that has the most ancestorish (yeah, I just made that word up ;) method doing the work first, with each less-ancestorish method building on to that as the call chain unwinds.
If you count which call *starts* first, the base class is always called later than the subclass (even if it finishes earlier :-). -- --Guido van Rossum (python.org/~guido)

Hi, maybe a syntax like that can correspond: class MyObject(metaclass=ObjectSpec): ''' MyObject doc''' 'attr1 contains something' attr1 = None 'attr2 contains something' attr2 = str 'method1 do something' method1 = NotImplementedMethod('self', 'arg1', kwarg1=str) Metaclass "ObjectSpec" would extend ABCMeta to search class source code for comments before members assignement, and replace NotImplementedMethod objects by a corresponding method wich signature can simply be given by arguments or by ArgSpec, FullArgSpec, Signature... with factories like these of "Signature" (from_function, from_builtins...). 2013/12/6 Guido van Rossum <guido@python.org>
On Thu, Dec 5, 2013 at 6:31 PM, Ethan Furman <ethan@stoneleaf.us> wrote:
On Thu, Dec 05, 2013 at 01:33:00PM -0800, Guido van Rossum wrote:
Actually if you want to support multiple inheritance of your ABC, your abstract methods *must* be no-ops (or have some kind of default behavior that can always be done last).
Done last or first really depends on what the default behavior is, doesn't it? Using __new__ as an example, the chain of calls for that has the most ancestorish (yeah, I just made that word up ;) method doing the work first, with each less-ancestorish method building on to that as the call chain unwinds.
If you count which call *starts* first, the base class is always called later than the subclass (even if it finishes earlier :-).
-- --Guido van Rossum (python.org/~guido) _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/apieum%40gmail.com

On Fri, Dec 06, 2013 at 07:28:57AM +0100, Gregory Salvan wrote:
Hi, maybe a syntax like that can correspond:
class MyObject(metaclass=ObjectSpec): ''' MyObject doc''' 'attr1 contains something' attr1 = None 'attr2 contains something' attr2 = str 'method1 do something' method1 = NotImplementedMethod('self', 'arg1', kwarg1=str)
I really don't like the idea of extending the docstring syntax to arbitrary objects. Docstrings are just the right amount of magic to be useful, without being so much as to be confusing. If you extend them to arbitrary objects, that crosses the line. I really don't like the look of the above, I'd rather see: class MyObject(metaclass=ObjectSpec): ''' MyObject doc attr1 contains something attr2 contains something ''' attr1 = None attr2 = str @NotImplementedMethod def method1(self, arg1, kwarg1=str): '''method1 do something''' One-liners are over-rated, especially since there isn't that much that you can fit in 80 or even 100 chars on a single line. Toy examples, like "method1 do something", sure. But real methods that do real things? Not so often. Besides, this suggestion changes the semantics of code, and therefore would need to go through a "from __future__ import docstring_everywhere" phase. Currently, bare strings can be used for multiline comments, as the compiler discards them at compile-time: fe() fi() fo() fum() """At this point, we can smell the blood of any Englishmen in the vicinity.""" bread = grind_bones(englishman) Another issue is that many objects (particularly built-ins) cannot take additional attributes. So where are you going to attach the docstrings? What are you going to do with singletons like None? "Amount of spam.""" spam = None "Amount of eggs.""" eggs = None print(spam.__doc__) => 'Amount of eggs.'
Metaclass "ObjectSpec" would extend ABCMeta to search class source code for comments before members assignement,
What do you expect to happen when the source code is not available? The behaviour of code should not depend on whether it is pre-compiled or not. -- Steven

We might adopt the conventions promoted by the Sphinx autodoc extension: http://sphinx-doc.org/ext/autodoc.html#directive-autofunction Example: class Foo: """Docstring for class Foo.""" #: Doc comment for class attribute Foo.bar. #: It can have multiple lines. bar = 1 flox = 1.5 #: Doc comment for Foo.flox. One line only. baz = 2 """Docstring for class attribute Foo.baz.""" def __init__(self): #: Doc comment for instance attribute qux. self.qux = 3 self.spam = 4 """Docstring for instance attribute spam.""" -- --Guido van Rossum (python.org/~guido)

On 12/6/2013 5:46 AM, Steven D'Aprano wrote:
On Fri, Dec 06, 2013 at 07:28:57AM +0100, Gregory Salvan wrote:
class MyObject(metaclass=ObjectSpec): ''' MyObject doc''' 'attr1 contains something' attr1 = None 'attr2 contains something' attr2 = str 'method1 do something' method1 = NotImplementedMethod('self', 'arg1', kwarg1=str)
I really don't like the idea of extending the docstring syntax to arbitrary objects. ... Another issue is that many objects (particularly built-ins) cannot take additional attributes. So where are you going to attach the docstrings?
For data attributes, which are usually mutable, it should be attached to the attribute *concept*, which is represented by the name, rather than the current but usually changeable value. Values are usually already documented either by a value representation or a docstring. This could be done with a string subclass that is used as needed. For methods, the value is nearly always constant. When multiple methods share the same function, they usually also share the same name, and represent the same concept. A half-way measure would be to extend help() (pydoc, I guess) to recognize the same attribute comment conventions as Sphinx autodoc when source is available, as it usually is. If we do this, I think the conventions should be 'blessed' in an info pep. Docstrings are seldom needed for runtime execution, which is why we have an option to remove them. -- Terry Jan Reedy

Reply-To set to python-ideas@python.org. Terry Reedy writes:
For data attributes, which are usually mutable, it should be attached to the attribute *concept*, which is represented by the name, rather than the current but usually changeable value. Values are usually already documented either by a value representation or a docstring. This could be done with a string subclass that is used as needed.
For methods, the value is nearly always constant. When multiple methods share the same function, they usually also share the same name, and represent the same concept.
Aside: Properties are which? Data, or method? It's also not clear to me that "def first (self): return self.values[0]" is unlikely to be used for completely different purposes than getting the head of a list. I conclude the considerations above are mostly red herrings. The important thing, I suppose, is that the names of attributes defined in a class are not mutable. This means that their docstrings can be kept in a completely separate dict (or other string -> string mapping), which could even be stored in a separate file. (Emacs Lisp uses this to good effect. The DOC file for XEmacs is 1.6MB; for GNU Emacs it's 2.4MB.) Of course it has its problems, but they're pretty minor.

I just wanted to sum up this thread of discussion. Proposal: A function in abc to provide a default abstract method implementation. foo = make_abstractmethod('foo', ['self']) is the same as @abc.abstractmethod def foo(self): pass Details: Default behavior, if implemented, should probably be empty/pass/return None. How to handle docstrings? Either attribute docstring (a separate discussion) or a parameter in the function call. Pros: Save a lot of lines defining interface-like ABCs, especially in small scripts without docstrings (bad practice, but I do it often =)) Cons: Do we need it?

On 12/09/2013 11:52 AM, Allen Li wrote:
Pros: Save a lot of lines defining interface-like ABCs, especially in small scripts without docstrings (bad practice, but I do it often =))
If the only pro is encouraging bad practice, it's not going to happen. ;)
Cons: Do we need it?
In my opinion, no. -- ~Ethan~

On Thu, Dec 5, 2013 at 6:08 PM, Allen Li <cyberdupo56@gmail.com> wrote:
On Thu, Dec 05, 2013 at 01:33:00PM -0800, Guido van Rossum wrote:
The only two alternatives are doing nothing/pass/return None or having actual code in the method.
The former is only useful to silently ignore blind super() calling, the latter you would define and decorate the method normally.
Actually if you want to support multiple inheritance of your ABC, your abstract methods *must* be no-ops (or have some kind of default behavior that can always be done last).
I must respectfully disagree with this. If your ABCs aren't meant to be in the MRO, then you should be @registering them as virtual classes and not inheriting them.
Registering is meant to be a method of last resort; it is implemented for cases where an ABC is introduced after implementations already exist (IOW, formalizing duck typing). When the ABC *is* actually used as a base class, when the standard M.I. patterns are used, the abstract methods must be no-ops, because they will be called (last).
The trick with Python multiple inheritance and super() (from personal experience) is to not think of it as multiple inheritance (a tree with cycles), but as building the MRO (linear, the same as single inheritance).
I'm not sure I understand -- or maybe I disagree. "A tree with cycles" seems a really poor way to describe what is usually referred to as a "diamond inheritance diagram". The right patterns require that you design your class to be unaware of the exact MRO. But we're getting off-topic. You should probably read one of the standard tutorials on the topic to refresh your use of the terminology. -- --Guido van Rossum (python.org/~guido)
participants (7)
-
Allen Li
-
Ethan Furman
-
Gregory Salvan
-
Guido van Rossum
-
Stephen J. Turnbull
-
Steven D'Aprano
-
Terry Reedy