Runtime-accessible attribute docstrings
![](https://secure.gravatar.com/avatar/bd9e10e866605b0bdf9c48d6c0565d74.jpg?s=120&d=mm&r=g)
Hi all, I have seen discussion of docstrings for class attributes before on this list, but not with this exact proposal. My motivation is that I have a dataclass for which I want to write docstrings that can be accessed at runtime. In my specific case, the docstrings would be used to create a help message. Sphinx supports a syntax to document class attributes. It looks like this: @dataclass class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True "Docstring for y" It is a bit awkward that the docstring is *below* the definition of the attribute, but it can't be put above because it could be confused for the class docstring. My proposal would be to just enshrine this syntax as the syntax for attribute docstring, and to make them available at runtime. They would be stored in a dictionary like the type annotations. For example like this: A.__attrdoc__ == {"x": "Docstring for x", "y": "Docstring for y"} Best, Thomas
![](https://secure.gravatar.com/avatar/5615a372d9866f203a22b2c437527bbb.jpg?s=120&d=mm&r=g)
On Wed, Nov 17, 2021 at 02:26:16PM -0000, tmkehrenberg@gmail.com wrote:
@dataclass class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True "Docstring for y"
It is a bit awkward that the docstring is *below* the definition of the attribute, but it can't be put above because it could be confused for the class docstring.
Function and class docstrings follow *below* the function/class signature, so I don't think that's a problem. However a real problem is that bare strings like that are already legal, although only as a no-op. People sometimes use them as multiline comments. So we would have no real way of distinguishing between these cases: class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True """Just a comment.""" Making such strings syntactically meaningful would be a breaking change, although one with a very small impact. (Some strings which were previously ignored by the interpreter will now be kept in memory as docstrings.)
My proposal would be to just enshrine this syntax as the syntax for attribute docstring, and to make them available at runtime. They would be stored in a dictionary like the type annotations. For example like this:
A.__attrdoc__ == {"x": "Docstring for x", "y": "Docstring for y"}
You could get that same effect with a decorator: @attrdoc(x="Doctring for x", y="Doctring for y") class A: """Class docstring.""" x: int y: bool = True There's some duplication of the names, which is sad, but otherwise I don't mind it. -- Steve
![](https://secure.gravatar.com/avatar/8da339f04438d3fcc438e898cfe73c47.jpg?s=120&d=mm&r=g)
Steven D'Aprano writes:
On Wed, Nov 17, 2021 at 02:26:16PM -0000, tmkehrenberg@gmail.com wrote:
@dataclass class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True "Docstring for y"
However a real problem is that bare strings like that are already legal, although only as a no-op. People sometimes use them as multiline comments.
I agree it's a real problem. But I don't think it's a show-stopper. That is, the proposal as written also seems to be a near no-op from the point of view of backwards compatibility (I guess if you list the attributes of the class you would discover the new dunder).
So we would have no real way of distinguishing between these cases:
class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True """Just a comment."""
True, but why would one want to, except to save the space? And for that, there's -OO.
A.__attrdoc__ == {"x": "Docstring for x", "y": "Docstring for y"}
You could get that same effect with a decorator:
@attrdoc(x="Doctring for x", y="Doctring for y") class A: """Class docstring.""" x: int y: bool = True
Such a decorator moves the documentation even farther from its subjects? And doesn't simply class A: """Class docstring.""" __attrdoc__ == {"x": "Docstring for x", "y": "Docstring for y"} x: int y: bool = True do the trick? Or if you just like decorating (bear with me now, this is revolutionary): @standard_class_docstring_parser class A: """ Class docstring. x: Docstring for x y: Docstring for y """ x: int y: bool = True which must exist somewhere already (I'm sure Sphinx has a nice fancy function for this). I guess that brings me all the way to -1 on the proposal as is; the "below the attribute" syntax isn't sufficiently attractive to justify syntax. Steve
![](https://secure.gravatar.com/avatar/d67ab5d94c2fed8ab6b727b62dc1b213.jpg?s=120&d=mm&r=g)
On Thu, Nov 18, 2021 at 7:44 PM Stephen J. Turnbull <stephenjturnbull@gmail.com> wrote:
Steven D'Aprano writes:
On Wed, Nov 17, 2021 at 02:26:16PM -0000, tmkehrenberg@gmail.com wrote:
@dataclass class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True "Docstring for y"
However a real problem is that bare strings like that are already legal, although only as a no-op. People sometimes use them as multiline comments.
I agree it's a real problem. But I don't think it's a show-stopper. That is, the proposal as written also seems to be a near no-op from the point of view of backwards compatibility (I guess if you list the attributes of the class you would discover the new dunder).
So we would have no real way of distinguishing between these cases:
class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True """Just a comment."""
True, but why would one want to, except to save the space? And for that, there's -OO.
Possible wrinkle: What if a string literal immediately follows something that isn't an attribute declaration? class A: "Class docstring" x: int "x docstring" y: bool; True "y docstring?" print("Hello, world?") "print docstring??" def spam(self): ... "spam docstring???" I presume it would have to be permitted and ignored, as per current behaviour (otherwise it'd create bizarre errors in currently-legal code). But that may make for some hard-to-track-down bugs when there's an error in a declaration, or when something technically breaks the declaration from the docstring (like the presumably-unintended semicolon in the y line). I'm personally -0 on this - I don't declare class level type annotations enough to want to use this, but if it existed, I'd probably find a way to use it for a DSL or something. It's of minimal value, but it should also be of minimal disruption. ChrisA
![](https://secure.gravatar.com/avatar/bd9e10e866605b0bdf9c48d6c0565d74.jpg?s=120&d=mm&r=g)
Stephen J. Turnbull wrote:
@standard_class_docstring_parser class A: """ Class docstring. x: Docstring for x y: Docstring for y """ x: int y: bool = True
Oh, this is actually a nice idea. You could have a decorator that parses reST and then according to some conventions extracts the attribute docstrings. I think I will try to write something like that. Thomas
![](https://secure.gravatar.com/avatar/9ea64fa01ed0d8529e4ae1b8873bb930.jpg?s=120&d=mm&r=g)
Could this be a use case for typing.Annotated? In [6]: from dataclasses import dataclass In [7]: from typing import Annotated In [8]: class A: ...: """Docstring for class A.""" ...: x: Annotated[int, "Docstring for x"] ...: y: Annotated[bool, "Docstring for y"] = True In [9]: A.__annotations__ Out[9]: {'x': typing.Annotated[int, 'Docstring for x'], 'y': typing.Annotated[bool, 'Docstring for y']} The syntax is a bit arduous; I'd be in favor of thinking through ways to make it easier to write. But the basic functionality already exists; there's no reason to duplicate it with another language feature. Rick. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler On Thu, Nov 18, 2021 at 5:50 AM <tmkehrenberg@gmail.com> wrote:
Stephen J. Turnbull wrote:
@standard_class_docstring_parser class A: """ Class docstring. x: Docstring for x y: Docstring for y """ x: int y: bool = True
Oh, this is actually a nice idea. You could have a decorator that parses reST and then according to some conventions extracts the attribute docstrings. I think I will try to write something like that.
Thomas _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/F2QJ3Q... Code of Conduct: http://python.org/psf/codeofconduct/
![](https://secure.gravatar.com/avatar/9ea64fa01ed0d8529e4ae1b8873bb930.jpg?s=120&d=mm&r=g)
On Thu, Nov 18, 2021 at 10:28 AM Ricky Teachey <ricky@teachey.org> wrote:
Could this be a use case for typing.Annotated?
...
The syntax is a bit arduous; I'd be in favor of thinking through ways to make it easier to write. But the basic functionality already exists; there's no reason to duplicate it with another language feature.
Rick.
Whoops sorry, forgot the @dataclass decoration: In [10]: @dataclass ...: class A: ...: """Docstring for class A.""" ...: x: Annotated[int, "Docstring for x"] ...: y: Annotated[bool, "Docstring for y"] = True ...: --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler
![](https://secure.gravatar.com/avatar/bd9e10e866605b0bdf9c48d6c0565d74.jpg?s=120&d=mm&r=g)
I've seen this proposed before, but it is, as you said, a bit arduous. For dataclasses specifically, there is also another possibility: add a `doc` argument to dataclasses.field. Like this: from dataclasses import dataclass, field @dataclass class A: x: int = field(doc="Docstring for x.") y: bool = field(default=False, doc="Docstring for y.") And then it would be retrievable with dataclasses.fields(A). Thomas
![](https://secure.gravatar.com/avatar/05917fed26d7519fae8318f78d14592a.jpg?s=120&d=mm&r=g)
Ricky Teachey wrote:
Could this be a use case for typing.Annotated? In [6]: from dataclasses import dataclass In [7]: from typing import Annotated In [8]: class A: ...: """Docstring for class A.""" ...: x: Annotated[int, "Docstring for x"] ...: y: Annotated[bool, "Docstring for y"] = True In [9]: A.__annotations__ Out[9]: {'x': typing.Annotated[int, 'Docstring for x'], 'y': typing.Annotated[bool, 'Docstring for y']} The syntax is a bit arduous; I'd be in favor of thinking through ways to make it easier to write. But the basic functionality already exists; there's no reason to duplicate it with another language feature. Rick. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler On Thu, Nov 18, 2021 at 5:50 AM tmkehrenberg@gmail.com wrote:
Stephen J. Turnbull wrote: @standard_class_docstring_parser class A: """ Class docstring. x: Docstring for x y: Docstring for y """ x: int y: bool = True Oh, this is actually a nice idea. You could have a decorator that parses reST and then according to some conventions extracts the attribute docstrings. I think I will try to write something like that. Thomas _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/F2QJ3Q... Code of Conduct: http://python.org/psf/codeofconduct/
I think you need to use another type rather than a plain string here eg: ``` @dataclasses.dataclass(frozen=True) class Doc: v: str @dataclasses.dataclass class A: """docstring for class A.""" x: typing.Annotated[int, Doc("docstring for x")] ```
![](https://secure.gravatar.com/avatar/9ea64fa01ed0d8529e4ae1b8873bb930.jpg?s=120&d=mm&r=g)
On Thu, Nov 18, 2021 at 1:39 PM Thomas Grainger <tagrain@gmail.com> wrote:
Ricky Teachey wrote:
Could this be a use case for typing.Annotated? In [6]: from dataclasses import dataclass In [7]: from typing import Annotated In [8]: class A: ...: """Docstring for class A.""" ...: x: Annotated[int, "Docstring for x"] ...: y: Annotated[bool, "Docstring for y"] = True In [9]: A.__annotations__ Out[9]: {'x': typing.Annotated[int, 'Docstring for x'], 'y': typing.Annotated[bool, 'Docstring for y']} The syntax is a bit arduous; I'd be in favor of thinking through ways to make it easier to write. But the basic functionality already exists; there's no reason to duplicate it with another language feature. Rick. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler On Thu, Nov 18, 2021 at 5:50 AM tmkehrenberg@gmail.com wrote:
Stephen J. Turnbull wrote: @standard_class_docstring_parser class A: """ Class docstring. x: Docstring for x y: Docstring for y """ x: int y: bool = True Oh, this is actually a nice idea. You could have a decorator that parses reST and then according to some conventions extracts the attribute docstrings. I think I will try to write something like that. Thomas _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at
https://mail.python.org/archives/list/python-ideas@python.org/message/F2QJ3Q. ..
Code of Conduct: http://python.org/psf/codeofconduct/
I think you need to use another type rather than a plain string here eg:
``` @dataclasses.dataclass(frozen=True) class Doc: v: str
@dataclasses.dataclass class A: """docstring for class A.""" x: typing.Annotated[int, Doc("docstring for x")] ```
I don't know why you would? It seems to work just fine with a plain string? One thing that is bad about it: the class member "docstrings" (actually the annotations) are repeated all over the place (look like 4 times total?) in the help() output-- example is below:
help(A) Help on class A in module __main__:
class A(builtins.object) | A(x: *typing.Annotated[int, 'docstring for x']*) -> None | | docstring for class A. | | Methods defined here: | | __eq__(self, other) | | __init__(self, x: *typing.Annotated[int, 'docstring for x']*) -> None | | __repr__(self) | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) | | ---------------------------------------------------------------------- | Data and other attributes defined here: | | __annotations__ = {'x': *typing.Annotated[int, 'docstring for x']*} | | __dataclass_fields__ = {'x': Field(name='x',type= *typing.Annotated[int,..*. | | __dataclass_params__ = _DataclassParams(init=True,repr=True,eq=True,or... | | __hash__ = None --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler
![](https://secure.gravatar.com/avatar/833c1ef94aebf738851577a5cb0b71e7.jpg?s=120&d=mm&r=g)
I too have used plain strings in Annotated[...] to document fields in dataclasses. On Thu, 2021-11-18 at 13:51 -0500, Ricky Teachey wrote:
On Thu, Nov 18, 2021 at 1:39 PM Thomas Grainger <tagrain@gmail.com> wrote:
Ricky Teachey wrote:
Could this be a use case for typing.Annotated? In [6]: from dataclasses import dataclass In [7]: from typing import Annotated In [8]: class A: ...: """Docstring for class A.""" ...: x: Annotated[int, "Docstring for x"] ...: y: Annotated[bool, "Docstring for y"] = True In [9]: A.__annotations__ Out[9]: {'x': typing.Annotated[int, 'Docstring for x'], 'y': typing.Annotated[bool, 'Docstring for y']} The syntax is a bit arduous; I'd be in favor of thinking through ways to make it easier to write. But the basic functionality already exists; there's no reason to duplicate it with another language feature. Rick. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler On Thu, Nov 18, 2021 at 5:50 AM tmkehrenberg@gmail.com wrote:
Stephen J. Turnbull wrote: @standard_class_docstring_parser class A: """ Class docstring. x: Docstring for x y: Docstring for y """ x: int y: bool = True Oh, this is actually a nice idea. You could have a decorator that parses reST and then according to some conventions extracts the attribute docstrings. I think I will try to write something like that. Thomas _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at
https://mail.python.org/archives/list/python-ideas@python.org/message/F2QJ3Q. ..
Code of Conduct: http://python.org/psf/codeofconduct/
I think you need to use another type rather than a plain string here eg:
``` @dataclasses.dataclass(frozen=True) class Doc: v: str
@dataclasses.dataclass class A: """docstring for class A.""" x: typing.Annotated[int, Doc("docstring for x")] ```
I don't know why you would? It seems to work just fine with a plain string?
One thing that is bad about it: the class member "docstrings" (actually the annotations) are repeated all over the place (look like 4 times total?) in the help() output-- example is below:
help(A) Help on class A in module __main__:
class A(builtins.object) | A(x: typing.Annotated[int, 'docstring for x']) -> None | | docstring for class A. | | Methods defined here: | | __eq__(self, other) | | __init__(self, x: typing.Annotated[int, 'docstring for x']) -> None | | __repr__(self) | | ----------------------------------------------------------------- ----- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) | | ----------------------------------------------------------------- ----- | Data and other attributes defined here: | | __annotations__ = {'x': typing.Annotated[int, 'docstring for x']} | | __dataclass_fields__ = {'x': Field(name='x',type=typing.Annotated[int,... | | __dataclass_params__ = _DataclassParams(init=True,repr=True,eq=True,or... | | __hash__ = None
--- Ricky.
"I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/BXCEE4... Code of Conduct: http://python.org/psf/codeofconduct/
![](https://secure.gravatar.com/avatar/133b712423066c858d82f5d285a6867a.jpg?s=120&d=mm&r=g)
On Thu, 18 Nov 2021 at 04:38, Steven D'Aprano <steve@pearwood.info> wrote:
On Wed, Nov 17, 2021 at 02:26:16PM -0000, tmkehrenberg@gmail.com wrote:
@dataclass class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True "Docstring for y"
It is a bit awkward that the docstring is *below* the definition of the attribute, but it can't be put above because it could be confused for the class docstring.
Function and class docstrings follow *below* the function/class signature, so I don't think that's a problem.
However a real problem is that bare strings like that are already legal, although only as a no-op. People sometimes use them as multiline comments.
So we would have no real way of distinguishing between these cases:
class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True """Just a comment."""
Making such strings syntactically meaningful would be a breaking change, although one with a very small impact. (Some strings which were previously ignored by the interpreter will now be kept in memory as docstrings.)
It wouldn't be a breaking change, there's no compatibility issue as nothing could break from this. It's a new feature so you'd have an unexpected attribute docstring that you're not using. Michael
My proposal would be to just enshrine this syntax as the syntax for attribute docstring, and to make them available at runtime. They would be stored in a dictionary like the type annotations. For example like this:
A.__attrdoc__ == {"x": "Docstring for x", "y": "Docstring for y"}
You could get that same effect with a decorator:
@attrdoc(x="Doctring for x", y="Doctring for y") class A: """Class docstring.""" x: int y: bool = True
There's some duplication of the names, which is sad, but otherwise I don't mind it.
-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/2F7CZR... Code of Conduct: http://python.org/psf/codeofconduct/
-- Michael Foord Python Consultant, Contractor and Trainer https://agileabstractions.com/
![](https://secure.gravatar.com/avatar/047f2332cde3730f1ed661eebb0c5686.jpg?s=120&d=mm&r=g)
+1 On Thu, Nov 18, 2021 at 09:31 Michael Foord <fuzzyman@gmail.com> wrote:
On Thu, 18 Nov 2021 at 04:38, Steven D'Aprano <steve@pearwood.info> wrote:
On Wed, Nov 17, 2021 at 02:26:16PM -0000, tmkehrenberg@gmail.com wrote:
@dataclass class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True "Docstring for y"
It is a bit awkward that the docstring is *below* the definition of the attribute, but it can't be put above because it could be confused for the class docstring.
Function and class docstrings follow *below* the function/class signature, so I don't think that's a problem.
However a real problem is that bare strings like that are already legal, although only as a no-op. People sometimes use them as multiline comments.
So we would have no real way of distinguishing between these cases:
class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True """Just a comment."""
Making such strings syntactically meaningful would be a breaking change, although one with a very small impact. (Some strings which were previously ignored by the interpreter will now be kept in memory as docstrings.)
It wouldn't be a breaking change, there's no compatibility issue as nothing could break from this. It's a new feature so you'd have an unexpected attribute docstring that you're not using.
Michael
My proposal would be to just enshrine this syntax as the syntax for attribute docstring, and to make them available at runtime. They would be stored in a dictionary like the type annotations. For example like this:
A.__attrdoc__ == {"x": "Docstring for x", "y": "Docstring for y"}
You could get that same effect with a decorator:
@attrdoc(x="Doctring for x", y="Doctring for y") class A: """Class docstring.""" x: int y: bool = True
There's some duplication of the names, which is sad, but otherwise I don't mind it.
-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/2F7CZR... Code of Conduct: http://python.org/psf/codeofconduct/
--
Michael Foord
Python Consultant, Contractor and Trainer
https://agileabstractions.com/
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/OGSJU4... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido (mobile)
![](https://secure.gravatar.com/avatar/0a2191a85455df6d2efdb22c7463c304.jpg?s=120&d=mm&r=g)
On 17.11.2021 15:26, tmkehrenberg@gmail.com wrote:
Hi all,
I have seen discussion of docstrings for class attributes before on this list, but not with this exact proposal.
My motivation is that I have a dataclass for which I want to write docstrings that can be accessed at runtime. In my specific case, the docstrings would be used to create a help message.
Sphinx supports a syntax to document class attributes. It looks like this:
@dataclass class A: """Docstring for class A.""" x: int """Docstring for x""" y: bool = True "Docstring for y"
See https://www.python.org/dev/peps/pep-0224/ Perhaps it's time to revive the idea for its 20th anniversary :-)
It is a bit awkward that the docstring is *below* the definition of the attribute, but it can't be put above because it could be confused for the class docstring.
My proposal would be to just enshrine this syntax as the syntax for attribute docstring, and to make them available at runtime. They would be stored in a dictionary like the type annotations. For example like this:
A.__attrdoc__ == {"x": "Docstring for x", "y": "Docstring for y"} -- Marc-Andre Lemburg eGenix.com
Professional Python Services directly from the Experts (#1, Nov 18 2021)
Python Projects, Coaching and Support ... https://www.egenix.com/ Python Product Development ... https://consulting.egenix.com/
::: We implement business ideas - efficiently in both time and costs ::: eGenix.com Software, Skills and Services GmbH Pastor-Loeh-Str.48 D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg Registered at Amtsgericht Duesseldorf: HRB 46611 https://www.egenix.com/company/contact/ https://www.malemburg.com/
![](https://secure.gravatar.com/avatar/b9a638a8d681d7825361d61be005280e.jpg?s=120&d=mm&r=g)
I feel like we could possible use the slots being a dict here, this is already a supported feature and is able to document attributes indivually, and dataclasses does have a slots argument now in 3.10 class Foo: """docstring for Foo""" __slots__ = {"bar": "docstring for bar"} def __init__(self, bar): self.bar = bar
![](https://secure.gravatar.com/avatar/9ea64fa01ed0d8529e4ae1b8873bb930.jpg?s=120&d=mm&r=g)
This might be a weird idea but I think it looks nice, is backward compatible, and flexible. It could be a convention to have the type hint syntax location (ie, the syntax location after the colon that usually contains type hints only today) do double duty. It could be used for documentation as long as it is provided FIRST. Then, optionally provide the type hint information on a later line: @dataclass class A: """Docstring for class A.""" x: "Docstring for x" x: int y: "Docstring for y" y: bool = True In this way one could provide the docstrings in all together in a separate section of code, as long as the docstrings came before the final type hint and any default values: @dataclass class A: """Docstring for class A.""" x: "Docstring for x" y: "Docstring for y" x: int y: bool = True People that have no interest in type hinting their code and don't intend for it to run through a type checker can use the same convention without any issues: class A: """Docstring for class A.""" x: "Docstring for x" y: "Docstring for y" If desired and if it became a popular idea, language support could later be provided to make use of these docstrings- saving them in a useful place- and bring them into help() output in a proper looking way. I am unsure if this would be backwards compatible with mypy. __________ WARNING: half baked idea ahead! ahoy there be dragons here probably, etc etc ___________ Expanding on that idea: if language support for making use of this documentation convention is indeed later wanted but it were deemed too problematic, and potentially backwards incompatible, to differentiate docstrings from regular typing information, there could be a docstring literal d"", similar to f string literal: @dataclass class A: """Docstring for class A.""" x: d"Docstring for x" y: d"Docstring for y" x: int y: bool = True To be clear there is nothing magical about the d"" string itself. It's just a regular string. The d"" moniker merely causes the string contents to be stored away for safe keeping in a class or module dunder, storing all the info for the created docstrings in a dictionary:
print(A.__member_docstrings__) {'x': 'Docstring for x', 'y': 'Docstring for y'}
Using only convention, you could do all sorts of fancy shenanigans with these docstrings. You could provide format fields in the docstring.... such as using a convention for identifying the variable name on the LHS inside the docstring, or its type hint (type hint maybe defaulting to Any if there isn't a type hint?): class A: """Docstring for class A.""" x: d"{var} is of type {hint}" y: d"{var} is of type {hint}" Documentation tools line help() could know about __member_docstrings__ and these conventions, properly parse them using the format() method:
help(A.x) x is of type Any
In this way the help function or other documentation tools wouldn't require type hint information, and a type hint could even be defined/changed later (such as in a child class). class B(A): """Docstring for class B.""" x: int
help(A.x) x is of type int
I'm unsure how the help() function, or other similar documentation tools, could know where to look (ie, in the parent class) for the docstring information. Seems like this could be solved in some way, though. On Fri, Nov 19, 2021, 6:23 PM Angelo Kontaxis <angelokontaxis@hotmail.com> wrote:
I feel like we could possible use the slots being a dict here, this is already a supported feature and is able to document attributes indivually, and dataclasses does have a slots argument now in 3.10
class Foo: """docstring for Foo""" __slots__ = {"bar": "docstring for bar"} def __init__(self, bar): self.bar = bar _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/DC5JBX... Code of Conduct: http://python.org/psf/codeofconduct/
![](https://secure.gravatar.com/avatar/5615a372d9866f203a22b2c437527bbb.jpg?s=120&d=mm&r=g)
On Fri, Nov 19, 2021 at 11:23:02PM -0000, Angelo Kontaxis wrote:
I feel like we could possible use the slots being a dict here, this is already a supported feature and is able to document attributes indivually, and dataclasses does have a slots argument now in 3.10
That doesn't help classes which don't use slots. -- Steve
participants (11)
-
Angelo Kontaxis
-
Chris Angelico
-
Guido van Rossum
-
Marc-Andre Lemburg
-
Michael Foord
-
Paul Bryan
-
Ricky Teachey
-
Stephen J. Turnbull
-
Steven D'Aprano
-
Thomas Grainger
-
tmkehrenberg@gmail.com