Closed f62406a5-1c0d-4f0c-8788-796f13394ab1 closed 4 years ago
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?
Thank you for your report
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
Found here: https://docs.python.org/3/reference/datamodel.html#metaclasses
Thank you
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
Ok, I will create a PR soon and update the issue.
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").
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.
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).
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:"
Hey,
Is someone working on this issue? Can I take it?
Ido
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.
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.
Thank you Josh.
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields: ```python assignee = None closed_at =
created_at =
labels = ['3.7', 'type-bug', 'library', 'docs']
title = 'Fix 3.3.3.1 Metaclasses Documentation'
updated_at =
user = 'https://bugs.python.org/NicholasMatthews'
```
bugs.python.org fields:
```python
activity =
actor = 'serhiy.storchaka'
assignee = 'docs@python'
closed = True
closed_date =
closer = 'serhiy.storchaka'
components = ['Documentation', 'Library (Lib)']
creation =
creator = 'Nicholas Matthews'
dependencies = []
files = []
hgrepos = []
issue_num = 36947
keywords = []
message_count = 14.0
messages = ['342723', '342724', '342725', '342726', '342727', '342728', '342730', '342731', '342780', '344105', '352972', '353002', '353134', '353149']
nosy_count = 7.0
nosy_names = ['docs@python', 'serhiy.storchaka', 'matrixise', 'josh.r', 'codevil_2o', 'Nicholas Matthews', 'Ido Michael']
pr_nums = ['15319']
priority = 'normal'
resolution = 'fixed'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue36947'
versions = ['Python 3.7']
```