Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #111017
| Path | csiph.com!fu-berlin.de!uni-berlin.de!not-for-mail |
|---|---|
| From | eryk sun <eryksun@gmail.com> |
| Newsgroups | comp.lang.python |
| Subject | Re: Special attributes added to classes on creation |
| Date | Sun, 3 Jul 2016 23:07:53 +0000 |
| Lines | 151 |
| Message-ID | <mailman.48.1467587322.2295.python-list@python.org> (permalink) |
| References | <57793711$0$1611$c3e8da3$5496439d@news.astraweb.com> <CACL+1aurqm3bihszW9Kvq6TnkjxEmtWMpwpZoUTLF=Jwo52eYg@mail.gmail.com> |
| Mime-Version | 1.0 |
| Content-Type | text/plain; charset=UTF-8 |
| X-Trace | news.uni-berlin.de fAwwnbQBD+QU4yXoZW0G+QZWz+LHGNNOdECamyMfIblg== |
| Return-Path | <eryksun@gmail.com> |
| X-Original-To | python-list@python.org |
| Delivered-To | python-list@mail.python.org |
| X-Spam-Status | OK 0.000 |
| X-Spam-Evidence | '*H*': 1.00; '*S*': 0.00; 'cpython': 0.05; 'defaults': 0.05; 'method.': 0.05; '__name__': 0.07; 'attributes': 0.07; 'defines': 0.07; 'implements': 0.07; 'method,': 0.07; 'present,': 0.07; 'remaining': 0.07; '__init__': 0.09; 'defined,': 0.09; 'dict': 0.09; 'namespace': 0.09; 'none.': 0.09; 'positional': 0.09; 'example:': 0.10; 'def': 0.13; 'skip:f 30': 0.15; 'variables': 0.15; "'c'": 0.16; '2016': 0.16; '@classmethod': 0.16; '__new__': 0.16; 'argument.': 0.16; 'arguments:': 0.16; 'attributes.': 0.16; 'bases,': 0.16; 'bytecode': 0.16; 'descriptors': 0.16; 'descriptors.': 0.16; 'globals.': 0.16; 'metaclass': 0.16; 'optionally': 0.16; 'preamble': 0.16; 'received:io': 0.16; 'received:psf.io': 0.16; 'set,': 0.16; 'when?': 0.16; 'wrote:': 0.16; 'documented': 0.18; '>>>': 0.20; '3.x': 0.22; 'arguments': 0.22; 'keys': 0.22; 'defined': 0.23; 'implemented': 0.24; 'written': 0.24; 'header:In- Reply-To:1': 0.24; 'rest': 0.26; 'message-id:@mail.gmail.com': 0.27; 'defining': 0.27; 'executing': 0.27; 'object,': 0.27; 'function': 0.28; "skip:' 10": 0.28; 'values': 0.28; 'initial': 0.28; 'arguments,': 0.29; 'initialized': 0.29; 'referenced': 0.29; 'instruction': 0.29; 'allows': 0.30; 'classes': 0.30; 'code': 0.30; "can't": 0.32; 'skip:_ 10': 0.32; 'statement': 0.32; 'class': 0.33; 'url:python': 0.33; "d'aprano": 0.33; 'steven': 0.33; 'add': 0.34; 'gets': 0.35; 'received:google.com': 0.35; 'mapping': 0.35; 'returning': 0.35; 'but': 0.36; 'should': 0.36; 'there': 0.36; 'url:org': 0.36; 'keyword': 0.36; 'skip:{ 10': 0.36; 'to:addr:python-list': 0.36; 'pm,': 0.36; 'subject:: ': 0.37; 'two': 0.37; 'method': 0.37; 'starting': 0.37; 'creation': 0.38; '(1)': 0.38; 'names': 0.38; 'skip:p 20': 0.38; 'whatever': 0.39; 'takes': 0.39; 'to:addr:python.org': 0.40; 'called': 0.40; 'body': 0.61; 'default': 0.61; 'bases': 0.63; 'respect': 0.65; 'statement,': 0.66; "they're": 0.66; 'url:6': 0.66; 'potentially': 0.67; 'jul': 0.72; 'present.': 0.72; 'body:': 0.84; 'compiles': 0.84; 'dict.': 0.84; 'etc,': 0.84; 'locals': 0.84; 'url:cpython': 0.84; 'subject:Special': 0.91 |
| DKIM-Signature | v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=3Sxq/nOU1jdZdyWJyx3se9g0t7nleh9fvo5DT3KKz7w=; b=dfZ3eY6ZDr6soNP1yKWjj3hTZ9T53aplrHj/Nme+efJ8bR8fSTX/nKFhZoLbUBqXMo bBtgtbJAK40+oxxE0llo0JBpF2hlco6sRe0HzKbV4UHk80AvXe0bMItdcRNr0mziU61o mt0ZXjQK1WcFAqjqhBA4x8NHOuh2IfjCnbQIqm8V9HvdGv8v2Oxte2GG2qlafsV/AFGl v9SCTOkpvOAKvSHbJeVDPLdYmuQ1Rc1POmgp3O8aLr96Jm/ZZ+EZxm/E2SkP0y7iibPr IVKcyneVoiKkaPoO/MYZZ/pEGBziQQtZR199RH2SZiINlwgW91bapm8rKrjHWgJaKSq5 NUAw== |
| X-Google-DKIM-Signature | v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=3Sxq/nOU1jdZdyWJyx3se9g0t7nleh9fvo5DT3KKz7w=; b=gVIDqGQ8PERddn/+x/0vGfg9l2IKqJ/T5Apn5ASd25KjfLrcMlpsQdNWfNtuubmPzn vvGlPk4MgVp8xQikb4Jf8SD2IypxRScaJrZrx58+/eAX1PWyvsQQaY11kXZKffx07kvV yjG5N/zIBycwJ0v3/xrAa6Dpsny+MnylwcC0/7NW4uJ3t8xodRbr1LJ2vEyw1ZYZdrdZ lb0SgtQGN7VeCbYKeCJN8GCk+gF6ZeS/jr40Og3/q0GYZZrYtK5OEK4UdRMS/CRhcgAQ fvJWR1GboiT9Mw6e2jVMyiv6l3KnmhKkLhrVkYncPLnPvHqFMg0I3SWgidY54qfq/j4F L2cA== |
| X-Gm-Message-State | ALyK8tIW3IZd/te69F2bWTdZvqRdpRQvd/J5n1RDVjL1MTFfCRu08dAYis0u0GZ2FBUIV1Bl0ZqoUqLfJt/v8A== |
| X-Received | by 10.36.141.196 with SMTP id w187mr6934063itd.87.1467587313479; Sun, 03 Jul 2016 16:08:33 -0700 (PDT) |
| In-Reply-To | <57793711$0$1611$c3e8da3$5496439d@news.astraweb.com> |
| X-BeenThere | python-list@python.org |
| X-Mailman-Version | 2.1.22 |
| Precedence | list |
| List-Id | General discussion list for the Python programming language <python-list.python.org> |
| List-Unsubscribe | <https://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe> |
| List-Archive | <http://mail.python.org/pipermail/python-list/> |
| List-Post | <mailto:python-list@python.org> |
| List-Help | <mailto:python-list-request@python.org?subject=help> |
| List-Subscribe | <https://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe> |
| X-Mailman-Original-Message-ID | <CACL+1aurqm3bihszW9Kvq6TnkjxEmtWMpwpZoUTLF=Jwo52eYg@mail.gmail.com> |
| X-Mailman-Original-References | <57793711$0$1611$c3e8da3$5496439d@news.astraweb.com> |
| Xref | csiph.com comp.lang.python:111017 |
Show key headers only | View raw
On Sun, Jul 3, 2016 at 4:02 PM, Steven D'Aprano <steve@pearwood.info> wrote:
> Is there any documentation for exactly what keys are added to classes when?
It should be documented that the namespace that's passed to the
metaclass contains __module__ and __qualname__, and optionally __doc__
if the class has a docstring.
These names are also available as local variables while executing the
class body:
>>> class C:
... 'eggs and spam'
... print('__module__:', __module__)
... print('__qualname__:', __qualname__)
... print('__doc__:', __doc__)
...
__module__: __main__
__qualname__: C
__doc__: eggs and spam
This is potentially an (unlikely) issue because the class body
preamble overwrites whatever custom values of these attributes were
added by the metaclass __prepare__ method. For example:
class Meta(type):
@classmethod
def __prepare__(mcls, name, bases, **kwds):
return {'__module__': 'spam',
'__qualname__': 'eggs.spam.' + name,
'__doc__': 'spam spam spam',
'x': 42}
class C(metaclass=Meta):
'docstring'
>>> C.__module__
'__main__'
>>> C.__qualname__
'C'
>>> C.__doc__
'docstring'
>>> C.x
42
I don't think additional documentation is required for the __dict__
and __weakref__ descriptors. They're described with respect to
__slots__. They can't be added until after the metaclass processes
__slots__, if present.
You can begin unraveling how CPython 3.x class creation works by
disassembling the bytecode for the following example:
def f():
class Q(Base, metaclass=Meta):
'example class'
x = 1
def method(self):
__class__ # or use super()
The initial work of defining a class is implemented via
builtins.__build_class__, which is referenced by the bytecode
instruction LOAD_BUILD_CLASS. This built-in function takes two
required positional arguments: the argumentless function that
implements the class body and the class name. Optionally, the base
class(es) are passed as the remaining positional arguments, and the
metaclass is passed as a keyword argument. Additional keyword
arguments can be passed in the class statement, but this requires a
custom metaclass with __new__ and __init__ methods that accept the
extra arguments. The metaclass __prepare__ method also gets passed the
name, bases and extra keyword arguments.
Here's the bytecode setup to call __build_class__ for the above example:
>>> dis.dis(f)
2 0 LOAD_BUILD_CLASS
2 LOAD_CONST 1 (<code object Q ...>)
4 LOAD_CONST 2 ('Q')
6 MAKE_FUNCTION 0
8 LOAD_CONST 2 ('Q')
10 LOAD_GLOBAL 0 (Base)
12 LOAD_CONST 3 ('metaclass')
14 LOAD_GLOBAL 1 (Meta)
16 EXTENDED_ARG 1
18 CALL_FUNCTION 259 (3 positional,
1 keyword pair)
20 STORE_FAST 0 (Q)
22 LOAD_CONST 0 (None)
24 RETURN_VALUE
The locals mapping for the class body comes from the metaclass
__prepare__ method, if defined, and is otherwise an empty dict.
There's a default type.__prepare__, which returns an empty dict:
>>> type.__prepare__(1, 2, 3, spam='whatever')
{}
The code for the class body defines the __module__, __qualname__, and
__doc__ attributes. It also defines the __class__ closure when a class
has methods that use super() or reference __class__.
The return value of the class body is either the __class__ cell
object, if defined, or None. Returning the __class__ closure cell
allows __build_class__ to set the new class as the value of the cell.
Here's the bytecode for the body of class Q:
>>> dis.dis(f.__code__.co_consts[1])
2 0 LOAD_NAME 0 (__name__)
2 STORE_NAME 1 (__module__)
4 LOAD_CONST 0 ('f.<locals>.Q')
6 STORE_NAME 2 (__qualname__)
3 8 LOAD_CONST 1 ('example class')
10 STORE_NAME 3 (__doc__)
4 12 LOAD_CONST 2 (1)
14 STORE_NAME 4 (x)
5 16 LOAD_CLOSURE 0 (__class__)
18 BUILD_TUPLE 1
20 LOAD_CONST 3 (<code object method ...>)
22 LOAD_CONST 4 ('f.<locals>.Q.method')
24 MAKE_FUNCTION 8
26 STORE_NAME 5 (method)
28 LOAD_CLOSURE 0 (__class__)
30 RETURN_VALUE
>>> f.__code__.co_consts[1].co_cellvars
('__class__',)
The rest of the process is all written in C.
compiler_class, which compiles a class statement to the above bytecode:
https://hg.python.org/cpython/file/v3.6.0a2/Python/compile.c#l1809
builtins.__build_class__:
https://hg.python.org/cpython/file/v3.6.0a2/Python/bltinmodule.c#l53
type.__new__:
https://hg.python.org/cpython/file/v3.6.0a2/Objects/typeobject.c#l2268
In type_new, the class dict gets initialized starting on line 2516.
__module__, if not already set, is the value of __name__ in the
current globals. __qualname__, if not already set, defaults to the
class name.
The getset descriptors for __dict__ and __wreakref__, if present, are
added to the class on line 2625, but they're not added to the class
dict until the type is made ready via PyType_Ready. On line 4886,
add_getset is called to add them. The names "__dict__" and
"__weakref__" are defined by subtype_getsets_full, etc, starting on
line 2154. Also in PyType_Ready, on line 4937, __doc__ is added if
it's not already present in the class dict.
Back to comp.lang.python | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
Special attributes added to classes on creation Steven D'Aprano <steve@pearwood.info> - 2016-07-04 02:02 +1000 Re: Special attributes added to classes on creation Ian Kelly <ian.g.kelly@gmail.com> - 2016-07-03 10:58 -0600 Re: Special attributes added to classes on creation eryk sun <eryksun@gmail.com> - 2016-07-03 23:07 +0000 Re: Special attributes added to classes on creation Xiang Zhang <zhangyangyu0614@gmail.com> - 2016-07-04 03:22 -0700
csiph-web