This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Fix 3.3.3.1 Metaclasses Documentation
Type: behavior Stage: resolved
Components: Documentation, Library (Lib) Versions: Python 3.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Ido Michael, Nicholas Matthews, codevil_2o, docs@python, josh.r, matrixise, serhiy.storchaka
Priority: normal Keywords:

Created on 2019-05-17 14:27 by Nicholas Matthews, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 15319 closed python-dev, 2019-08-17 07:09
Messages (14)
msg342723 - (view) Author: Nicholas Matthews (Nicholas Matthews) Date: 2019-05-17 14:27
Currently the final sentence of the second paragraph reads:
"In the following example, both MyClass and MySubclass are instances of Meta:"
It should read something like:
"In the following example, both MyClass and MySubclass have the metaclass Meta, and new instances will be created using Meta:"

Classes are created by their metaclass, but cannot be said to be instances of their metaclass, correct?
msg342724 - (view) Author: Stéphane Wirtel (matrixise) * (Python committer) Date: 2019-05-17 14:31
Thank you for your report
msg342725 - (view) Author: Stéphane Wirtel (matrixise) * (Python committer) Date: 2019-05-17 14:48
just one question, I don't find the paragraph with this text in the code. Could you share the link of this paragraph? Thank you
msg342726 - (view) Author: Stéphane Wirtel (matrixise) * (Python committer) Date: 2019-05-17 14:49
Found here: https://docs.python.org/3/reference/datamodel.html#metaclasses

Thank you
msg342727 - (view) Author: Stéphane Wirtel (matrixise) * (Python committer) Date: 2019-05-17 14:51
If you want to modify the text, please create a PR for this file: https://github.com/python/cpython/blob/master/Doc/reference/datamodel.rst#metaclasses

Don't forget to sign the CLA, 

Thank you
msg342728 - (view) Author: Nicholas Matthews (Nicholas Matthews) Date: 2019-05-17 14:59
Ok, I will create a PR soon and update the issue.
msg342730 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2019-05-17 15:27
Clarification is fine, but "MyClass and MySubclass are instances of Meta:" is 100% true. Declaring a class to have a metaclass (or inheriting from a class with a metaclass) means that the class itself is an instance of the metaclass.

New instances of the classes with metaclass Meta are not "created using Meta"; Meta modifies the creation of the classes themselves, not instances of the classes.

Point is, your suggested change is half wrong (new instances of MyClass and MySubclass aren't directly created using Meta), and half misunderstanding the current documentation ("MyClass is an instance of Meta" already means "MyClass has the metaclass Meta").
msg342731 - (view) Author: Nicholas Matthews (Nicholas Matthews) Date: 2019-05-17 15:35
Thanks for the clarification. For the first point on the correctness of the original text, that makes sense, could you link me to any relevant documentation for further reading?

On the second point "Meta modifies the creation of the classes themselves, not instances of the classes." I think this is not 100% correct. When you create an instance of a class via "instance = MyClass()", the `__call__` method of the metaclass is invoked, so metaclasses can control both class definition and instance creation.
msg342780 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2019-05-18 00:56
Ah, you're right on __call__; I've never bothered to override it on a metaclass, but yes, since a class using a metaclass is an instance of the metaclass, like all instances, calling it invokes the __call__ of its type (it's just that the default metaclass, type, has a __call__ that turns around and calls the __new__ and __init__ of the "instance", which is a class). The nomenclature is hard here.

In any event, yes, overriding __call__ will let you hook into the construction of each individual instance of the classes using the metaclass. That's not generally true of all uses of metaclasses (if __call__ is inherited from type, then while new instances are technically created using the metaclass, the metaclass is just letting the normal __new__/__init__ calls take place without interference).

There is very little in the way of Python official documentation on metaclasses; the line you proposed to change is one of the few places it's mentioned (most references to metaclasses are on that Data Model page). There are a couple of mentions in the PEPs, and a lot of off-site tutorials, but it's a poorly documented feature in general.

It's pretty easy to demonstrate the current wording is correct though:

>>> class Meta(type):
...     pass
...
>>> class MyMeta(metaclass=Meta):
...     pass
...
>>> isinstance(MyMeta, Meta)
True

Note that we're using isinstance, not issubclass, and we're not constructing a MyMeta instance. MyMeta itself is an instance of Meta.

I really think the problem here is that the documentation is correct, but so bare it's easy to miss the implications of "MyClass and MySubclass are instances of Meta"; since the classes are instances of another class, the metaclass has the same power over them that normal classes have over their instances. That's why __call__ can hook the creation of instances, __new__ can hook the creation of the class itself, __getitem__ can be used to perform lookups on the child class (in at least of the few iterations of the typing framework, that's how List[int] and the like worked; not sure if it's still that way), and properties defined on the metaclass can be accessed on classes that use it, but not their instances. It's enormously powerful, but so complex that the Python docs tend to encourage simpler, more targeted ways of tweaking classes (e.g. decorators).
msg344105 - (view) Author: Chirag Garg (codevil_2o) Date: 2019-05-31 18:52
It should be written like "In the following example, both MyClass and MySubclass are instances of Meta and the type of MyClass is of metaclass Meta and type of MySubclass is MyClass:"
msg352972 - (view) Author: Ido Michael (Ido Michael) * Date: 2019-09-22 12:06
Hey,

Is someone working on this issue? 
Can I take it?

Ido
msg353002 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-23 10:05
It is not good first issue. The referred documentation is complex and needs deep knowledge of Python for changing.

The original report was wrong. The original documentation is correct. Josh, do you think the documentation needs other changes, and if yes, do you mind to create a PR? If no, I am inclined to close this issue.
msg353134 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2019-09-25 03:24
The existing documentation is correct, just hard to understand if you don't already understand the point of metaclasses (metaclasses are hard, the language to describe them will be inherently a little klunky).

At some point, it might be nice to write a proper metaclass tutorial, even if it's only targeted at advanced users (the only people who should really be considering writing their own metaclasses or even directly using existing ones; everyone else should be using more targeted tools and/or inheriting from classes that already implement the desired metaclass).

The Data model docs aren't concerned with tutorials and examples though; they're just dry description, and they're doing their job here, so I think this issue can be closed.
msg353149 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-25 06:57
Thank you Josh.
History
Date User Action Args
2022-04-11 14:59:15adminsetgithub: 81128
2019-09-25 06:57:03serhiy.storchakasetstatus: open -> closed
resolution: fixed
messages: + msg353149

stage: patch review -> resolved
2019-09-25 03:24:19josh.rsetmessages: + msg353134
2019-09-23 10:05:32serhiy.storchakasetstatus: pending -> open
title: [Good first issue] Fix 3.3.3.1 Metaclasses Documentation -> Fix 3.3.3.1 Metaclasses Documentation
2019-09-23 10:05:19serhiy.storchakasetstatus: open -> pending

nosy: + serhiy.storchaka
messages: + msg353002

keywords: - patch, easy
2019-09-22 12:06:23Ido Michaelsetnosy: + Ido Michael
messages: + msg352972
2019-08-17 07:09:09python-devsetkeywords: + patch
stage: patch review
pull_requests: + pull_request15037
2019-05-31 18:52:04codevil_2osetnosy: + codevil_2o
messages: + msg344105
2019-05-18 00:56:43josh.rsetmessages: + msg342780
2019-05-17 15:35:13Nicholas Matthewssetmessages: + msg342731
2019-05-17 15:27:24josh.rsetnosy: + josh.r
messages: + msg342730
2019-05-17 14:59:21Nicholas Matthewssetmessages: + msg342728
2019-05-17 14:51:04matrixisesetmessages: + msg342727
2019-05-17 14:49:42matrixisesetstatus: pending -> open

messages: + msg342726
2019-05-17 14:48:35matrixisesetstatus: open -> pending

messages: + msg342725
2019-05-17 14:38:56matrixisesetkeywords: + easy
title: Fix 3.3.3.1 Metaclasses Documentation -> [Good first issue] Fix 3.3.3.1 Metaclasses Documentation
2019-05-17 14:31:52matrixisesetnosy: + docs@python, matrixise
messages: + msg342724

assignee: docs@python
components: + Documentation
2019-05-17 14:27:51Nicholas Matthewscreate