Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
7fc570a5
Commit
7fc570a5
authored
May 20, 2012
by
Nick Coghlan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Close #14588: added a PEP 3115 compliant dynamic type creation mechanism
parent
7c5ba513
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
486 additions
and
51 deletions
+486
-51
Doc/library/functions.rst
Doc/library/functions.rst
+6
-4
Doc/library/types.rst
Doc/library/types.rst
+58
-9
Doc/reference/datamodel.rst
Doc/reference/datamodel.rst
+99
-37
Doc/whatsnew/3.3.rst
Doc/whatsnew/3.3.rst
+4
-0
Lib/test/test_types.py
Lib/test/test_types.py
+250
-1
Lib/types.py
Lib/types.py
+58
-0
Misc/NEWS
Misc/NEWS
+11
-0
No files found.
Doc/library/functions.rst
View file @
7fc570a5
...
@@ -1324,10 +1324,12 @@ are always available. They are listed here in alphabetical order.
...
@@ -1324,10 +1324,12 @@ are always available. They are listed here in alphabetical order.
Accordingly, :func:`super` is undefined for implicit lookups using statements or
Accordingly, :func:`super` is undefined for implicit lookups using statements or
operators such as ``super()[name]``.
operators such as ``super()[name]``.
Also note that :func:`super` is not limited to use inside methods. The two
Also note that, aside from the zero argument form, :func:`super` is not
argument form specifies the arguments exactly and makes the appropriate
limited to use inside methods. The two argument form specifies the
references. The zero argument form automatically searches the stack frame
arguments exactly and makes the appropriate references. The zero
for the class (``__class__``) and the first argument.
argument form only works inside a class definition, as the compiler fills
in the necessary details to correctly retrieve the class being defined,
as well as accessing the current instance for ordinary methods.
For practical suggestions on how to design cooperative classes using
For practical suggestions on how to design cooperative classes using
:func:`super`, see `guide to using super()
:func:`super`, see `guide to using super()
...
...
Doc/library/types.rst
View file @
7fc570a5
:mod:`types` ---
N
ames for built-in types
:mod:`types` ---
Dynamic type creation and n
ames for built-in types
=========================================
=========================================
==========================
.. module:: types
.. module:: types
:synopsis: Names for built-in types.
:synopsis: Names for built-in types.
...
@@ -8,20 +8,69 @@
...
@@ -8,20 +8,69 @@
--------------
--------------
This module defines names for some object types that are used by the standard
This module defines utility function to assist in dynamic creation of
new types.
It also defines names for some object types that are used by the standard
Python interpreter, but not exposed as builtins like :class:`int` or
Python interpreter, but not exposed as builtins like :class:`int` or
:class:`str` are. Also, it does not include some of the types that arise
:class:`str` are.
transparently during processing such as the ``listiterator`` type.
Dynamic Type Creation
---------------------
.. function:: new_class(name, bases=(), kwds=None, exec_body=None)
Creates a class object dynamically using the appropriate metaclass.
The arguments are the components that make up a class definition: the
class name, the base classes (in order), the keyword arguments (such as
``metaclass``) and the callback function to populate the class namespace.
The *exec_body* callback should accept the class namespace as its sole
argument and update the namespace directly with the class contents.
.. function:: prepare_class(name, bases=(), kwds=None)
Calculates the appropriate metaclass and creates the class namespace.
The arguments are the components that make up a class definition: the
class name, the base classes (in order) and the keyword arguments (such as
``metaclass``).
The return value is a 3-tuple: ``metaclass, namespace, kwds``
*metaclass* is the appropriate metaclass
*namespace* is the prepared class namespace
*kwds* is an updated copy of the passed in *kwds* argument with any
``'metaclass'`` entry removed. If no *kwds* argument is passed in, this
will be an empty dict.
.. seealso::
:pep:`3115` - Metaclasses in Python 3000
Introduced the ``__prepare__`` namespace hook
Standard Interpreter Types
--------------------------
This module provides names for many of the types that are required to
implement a Python interpreter. It deliberately avoids including some of
the types that arise only incidentally during processing such as the
``listiterator`` type.
Typical use is for :func:`isinstance` or :func:`issubclass` checks.
Typical use is of these names is for :func:`isinstance` or
:func:`issubclass` checks.
The module defines the following nam
es:
Standard names are defined for the following typ
es:
.. data:: FunctionType
.. data:: FunctionType
LambdaType
LambdaType
The type of user-defined functions and functions created by
:keyword:`lambda`
The type of user-defined functions and functions created by
expressions.
:keyword:`lambda`
expressions.
.. data:: GeneratorType
.. data:: GeneratorType
...
...
Doc/reference/datamodel.rst
View file @
7fc570a5
...
@@ -1550,53 +1550,115 @@ Notes on using *__slots__*
...
@@ -1550,53 +1550,115 @@ Notes on using *__slots__*
Customizing class creation
Customizing class creation
--------------------------
--------------------------
By default, classes are constructed using :func:`type`.
A class definition
is
By default, classes are constructed using :func:`type`.
The class body
is
read into a separate namespace and the value of class name is bound
to the
executed in a new namespace and the class name is bound locally
to the
result of ``type(name, bases,
dict
)``.
result of ``type(name, bases,
namespace
)``.
When the class definition is read, if a callable ``metaclass`` keyword argument
The class creation process can be customised by passing the ``metaclass``
is passed after the bases in the class definition, the callable given will be
keyword argument in the class definition line, or by inheriting from an
called instead of :func:`type`. If other keyword arguments are passed, they
existing class that included such an argument. In the following example,
will also be passed to the metaclass. This allows classes or functions to be
both ``MyClass`` and ``MySubclass`` are instances of ``Meta``::
written which monitor or alter the class creation process:
* Modifying the class dictionary prior to the class being created.
class Meta(type):
pass
* Returning an instance of another class -- essentially performing the role of a
class MyClass(metaclass=Meta):
factory function.
pass
These steps will have to be performed in the metaclass's :meth:`__new__` method
class MySubclass(MyClass):
-- :meth:`type.__new__` can then be called from this method to create a class
pass
with different properties. This example adds a new element to the class
dictionary before creating the class::
class metacls(type):
Any other keyword arguments that are specified in the class definition are
def __new__(mcs, name, bases, dict):
passed through to all metaclass operations described below.
dict['foo'] = 'metacls was here'
return type.__new__(mcs, name, bases, dict)
You can of course also override other class methods (or add new methods); for
When a class definition is executed, the following steps occur:
example defining a custom :meth:`__call__` method in the metaclass allows custom
behavior when the class is called, e.g. not always creating a new instance.
If the metaclass has a :meth:`__prepare__` attribute (usually implemented as a
* the appropriate metaclass is determined
class or static method), it is called before the class body is evaluated with
* the class namespace is prepared
the name of the class and a tuple of its bases for arguments. It should return
* the class body is executed
an object that supports the mapping interface that will be used to store the
* the class object is created
namespace of the class. The default is a plain dictionary. This could be used,
for example, to keep track of the order that class attributes are declared in by
returning an ordered dictionary.
The appropriate metaclass is determined by the following precedence rules:
Determining the appropriate metaclass
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* If the ``metaclass`` keyword argument is passed with the bases, it is used.
The appropriate metaclass for a class definition is determined as follows:
* Otherwise, if there is at least one base class, its metaclass is used.
* if no bases and no explicit metaclass are given, then :func:`type` is used
* if an explicit metaclass is given and it is *not* an instance of
:func:`type`, then it is used directly as the metaclass
* if an instance of :func:`type` is given as the explicit metaclass, or
bases are defined, then the most derived metaclass is used
* Otherwise, the default metaclass (:class:`type`) is used.
The most derived metaclass is selected from the explicitly specified
metaclass (if any) and the metaclasses (i.e. ``type(cls)``) of all specified
base classes. The most derived metaclass is one which is a subtype of *all*
of these candidate metaclasses. If none of the candidate metaclasses meets
that criterion, then the class definition will fail with ``TypeError``.
Preparing the class namespace
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Once the appropriate metaclass has been identified, then the class namespace
is prepared. If the metaclass has a ``__prepare__`` attribute, it is called
as ``namespace = metaclass.__prepare__(name, bases, **kwds)`` (where the
additional keyword arguments, if any, come from the class definition).
If the metaclass has no ``__prepare__`` attribute, then the class namespace
is initialised as an empty :func:`dict` instance.
.. seealso::
:pep:`3115` - Metaclasses in Python 3000
Introduced the ``__prepare__`` namespace hook
Executing the class body
^^^^^^^^^^^^^^^^^^^^^^^^
The class body is executed (approximately) as
``exec(body, globals(), namespace)``. The key difference from a normal
call to :func:`exec` is that lexical scoping allows the class body (including
any methods) to reference names from the current and outer scopes when the
class definition occurs inside a function.
However, even when the class definition occurs inside the function, methods
defined inside the class still cannot see names defined at the class scope.
Class variables must be accessed through the first parameter of instance or
class methods, and cannot be accessed at all from static methods.
Creating the class object
^^^^^^^^^^^^^^^^^^^^^^^^^
Once the class namespace has been populated by executing the class body,
the class object is created by calling
``metaclass(name, bases, namespace, **kwds)`` (the additional keywords
passed here are the same as those passed to ``__prepate__``).
This class object is the one that will be referenced by the zero-argument
form of :func:`super`. ``__class__`` is an implicit closure reference
created by the compiler if any methods in a class body refer to either
``__class__`` or ``super``. This allows the zero argument form of
:func:`super` to correctly identify the class being defined based on
lexical scoping, while the class or instance that was used to make the
current call is identified based on the first argument passed to the method.
After the class object is created, any class decorators included in the
function definition are invoked and the resulting object is bound in the
local namespace to the name of the class.
.. seealso::
:pep:`3135` - New super
Describes the implicit ``__class__`` closure reference
Metaclass example
^^^^^^^^^^^^^^^^^
The potential uses for metaclasses are boundless. Some ideas that have been
The potential uses for metaclasses are boundless. Some ideas that have been
explored includ
ing
logging, interface checking, automatic delegation, automatic
explored includ
e
logging, interface checking, automatic delegation, automatic
property creation, proxies, frameworks, and automatic resource
property creation, proxies, frameworks, and automatic resource
locking/synchronization.
locking/synchronization.
...
@@ -1609,9 +1671,9 @@ to remember the order that class members were defined::
...
@@ -1609,9 +1671,9 @@ to remember the order that class members were defined::
def __prepare__(metacls, name, bases, **kwds):
def __prepare__(metacls, name, bases, **kwds):
return collections.OrderedDict()
return collections.OrderedDict()
def __new__(cls, name, bases,
classdict
):
def __new__(cls, name, bases,
namespace, **kwds
):
result = type.__new__(cls, name, bases, dict(
classdict
))
result = type.__new__(cls, name, bases, dict(
namespace
))
result.members = tuple(
classdict
)
result.members = tuple(
namespace
)
return result
return result
class A(metaclass=OrderedClass):
class A(metaclass=OrderedClass):
...
...
Doc/whatsnew/3.3.rst
View file @
7fc570a5
...
@@ -1239,6 +1239,10 @@ Add a new :class:`types.MappingProxyType` class: Read-only proxy of a mapping.
...
@@ -1239,6 +1239,10 @@ Add a new :class:`types.MappingProxyType` class: Read-only proxy of a mapping.
(:issue:`14386`)
(:issue:`14386`)
The new functions `types.new_class` and `types.prepare_class` provide support
for PEP 3115 compliant dynamic type creation. (:issue:`14588`)
urllib
urllib
------
------
...
...
Lib/test/test_types.py
View file @
7fc570a5
...
@@ -747,8 +747,257 @@ class MappingProxyTests(unittest.TestCase):
...
@@ -747,8 +747,257 @@ class MappingProxyTests(unittest.TestCase):
self
.
assertEqual
(
copy
[
'key1'
],
27
)
self
.
assertEqual
(
copy
[
'key1'
],
27
)
class
ClassCreationTests
(
unittest
.
TestCase
):
class
Meta
(
type
):
def
__init__
(
cls
,
name
,
bases
,
ns
,
**
kw
):
super
().
__init__
(
name
,
bases
,
ns
)
@
staticmethod
def
__new__
(
mcls
,
name
,
bases
,
ns
,
**
kw
):
return
super
().
__new__
(
mcls
,
name
,
bases
,
ns
)
@
classmethod
def
__prepare__
(
mcls
,
name
,
bases
,
**
kw
):
ns
=
super
().
__prepare__
(
name
,
bases
)
ns
[
"y"
]
=
1
ns
.
update
(
kw
)
return
ns
def
test_new_class_basics
(
self
):
C
=
types
.
new_class
(
"C"
)
self
.
assertEqual
(
C
.
__name__
,
"C"
)
self
.
assertEqual
(
C
.
__bases__
,
(
object
,))
def
test_new_class_subclass
(
self
):
C
=
types
.
new_class
(
"C"
,
(
int
,))
self
.
assertTrue
(
issubclass
(
C
,
int
))
def
test_new_class_meta
(
self
):
Meta
=
self
.
Meta
settings
=
{
"metaclass"
:
Meta
,
"z"
:
2
}
# We do this twice to make sure the passed in dict isn't mutated
for
i
in
range
(
2
):
C
=
types
.
new_class
(
"C"
+
str
(
i
),
(),
settings
)
self
.
assertIsInstance
(
C
,
Meta
)
self
.
assertEqual
(
C
.
y
,
1
)
self
.
assertEqual
(
C
.
z
,
2
)
def
test_new_class_exec_body
(
self
):
Meta
=
self
.
Meta
def
func
(
ns
):
ns
[
"x"
]
=
0
C
=
types
.
new_class
(
"C"
,
(),
{
"metaclass"
:
Meta
,
"z"
:
2
},
func
)
self
.
assertIsInstance
(
C
,
Meta
)
self
.
assertEqual
(
C
.
x
,
0
)
self
.
assertEqual
(
C
.
y
,
1
)
self
.
assertEqual
(
C
.
z
,
2
)
def
test_new_class_exec_body
(
self
):
#Test that keywords are passed to the metaclass:
def
meta_func
(
name
,
bases
,
ns
,
**
kw
):
return
name
,
bases
,
ns
,
kw
res
=
types
.
new_class
(
"X"
,
(
int
,
object
),
dict
(
metaclass
=
meta_func
,
x
=
0
))
self
.
assertEqual
(
res
,
(
"X"
,
(
int
,
object
),
{},
{
"x"
:
0
}))
def
test_new_class_defaults
(
self
):
# Test defaults/keywords:
C
=
types
.
new_class
(
"C"
,
(),
{},
None
)
self
.
assertEqual
(
C
.
__name__
,
"C"
)
self
.
assertEqual
(
C
.
__bases__
,
(
object
,))
def
test_new_class_meta_with_base
(
self
):
Meta
=
self
.
Meta
def
func
(
ns
):
ns
[
"x"
]
=
0
C
=
types
.
new_class
(
name
=
"C"
,
bases
=
(
int
,),
kwds
=
dict
(
metaclass
=
Meta
,
z
=
2
),
exec_body
=
func
)
self
.
assertTrue
(
issubclass
(
C
,
int
))
self
.
assertIsInstance
(
C
,
Meta
)
self
.
assertEqual
(
C
.
x
,
0
)
self
.
assertEqual
(
C
.
y
,
1
)
self
.
assertEqual
(
C
.
z
,
2
)
# Many of the following tests are derived from test_descr.py
def
test_prepare_class
(
self
):
# Basic test of metaclass derivation
expected_ns
=
{}
class
A
(
type
):
def
__new__
(
*
args
,
**
kwargs
):
return
type
.
__new__
(
*
args
,
**
kwargs
)
def
__prepare__
(
*
args
):
return
expected_ns
B
=
types
.
new_class
(
"B"
,
(
object
,))
C
=
types
.
new_class
(
"C"
,
(
object
,),
{
"metaclass"
:
A
})
# The most derived metaclass of D is A rather than type.
meta
,
ns
,
kwds
=
types
.
prepare_class
(
"D"
,
(
B
,
C
),
{
"metaclass"
:
type
})
self
.
assertIs
(
meta
,
A
)
self
.
assertIs
(
ns
,
expected_ns
)
self
.
assertEqual
(
len
(
kwds
),
0
)
def
test_metaclass_derivation
(
self
):
# issue1294232: correct metaclass calculation
new_calls
=
[]
# to check the order of __new__ calls
class
AMeta
(
type
):
def
__new__
(
mcls
,
name
,
bases
,
ns
):
new_calls
.
append
(
'AMeta'
)
return
super
().
__new__
(
mcls
,
name
,
bases
,
ns
)
@
classmethod
def
__prepare__
(
mcls
,
name
,
bases
):
return
{}
class
BMeta
(
AMeta
):
def
__new__
(
mcls
,
name
,
bases
,
ns
):
new_calls
.
append
(
'BMeta'
)
return
super
().
__new__
(
mcls
,
name
,
bases
,
ns
)
@
classmethod
def
__prepare__
(
mcls
,
name
,
bases
):
ns
=
super
().
__prepare__
(
name
,
bases
)
ns
[
'BMeta_was_here'
]
=
True
return
ns
A
=
types
.
new_class
(
"A"
,
(),
{
"metaclass"
:
AMeta
})
self
.
assertEqual
(
new_calls
,
[
'AMeta'
])
new_calls
.
clear
()
B
=
types
.
new_class
(
"B"
,
(),
{
"metaclass"
:
BMeta
})
# BMeta.__new__ calls AMeta.__new__ with super:
self
.
assertEqual
(
new_calls
,
[
'BMeta'
,
'AMeta'
])
new_calls
.
clear
()
C
=
types
.
new_class
(
"C"
,
(
A
,
B
))
# The most derived metaclass is BMeta:
self
.
assertEqual
(
new_calls
,
[
'BMeta'
,
'AMeta'
])
new_calls
.
clear
()
# BMeta.__prepare__ should've been called:
self
.
assertIn
(
'BMeta_was_here'
,
C
.
__dict__
)
# The order of the bases shouldn't matter:
C2
=
types
.
new_class
(
"C2"
,
(
B
,
A
))
self
.
assertEqual
(
new_calls
,
[
'BMeta'
,
'AMeta'
])
new_calls
.
clear
()
self
.
assertIn
(
'BMeta_was_here'
,
C2
.
__dict__
)
# Check correct metaclass calculation when a metaclass is declared:
D
=
types
.
new_class
(
"D"
,
(
C
,),
{
"metaclass"
:
type
})
self
.
assertEqual
(
new_calls
,
[
'BMeta'
,
'AMeta'
])
new_calls
.
clear
()
self
.
assertIn
(
'BMeta_was_here'
,
D
.
__dict__
)
E
=
types
.
new_class
(
"E"
,
(
C
,),
{
"metaclass"
:
AMeta
})
self
.
assertEqual
(
new_calls
,
[
'BMeta'
,
'AMeta'
])
new_calls
.
clear
()
self
.
assertIn
(
'BMeta_was_here'
,
E
.
__dict__
)
def
test_metaclass_override_function
(
self
):
# Special case: the given metaclass isn't a class,
# so there is no metaclass calculation.
class
A
(
metaclass
=
self
.
Meta
):
pass
marker
=
object
()
def
func
(
*
args
,
**
kwargs
):
return
marker
X
=
types
.
new_class
(
"X"
,
(),
{
"metaclass"
:
func
})
Y
=
types
.
new_class
(
"Y"
,
(
object
,),
{
"metaclass"
:
func
})
Z
=
types
.
new_class
(
"Z"
,
(
A
,),
{
"metaclass"
:
func
})
self
.
assertIs
(
marker
,
X
)
self
.
assertIs
(
marker
,
Y
)
self
.
assertIs
(
marker
,
Z
)
def
test_metaclass_override_callable
(
self
):
# The given metaclass is a class,
# but not a descendant of type.
new_calls
=
[]
# to check the order of __new__ calls
prepare_calls
=
[]
# to track __prepare__ calls
class
ANotMeta
:
def
__new__
(
mcls
,
*
args
,
**
kwargs
):
new_calls
.
append
(
'ANotMeta'
)
return
super
().
__new__
(
mcls
)
@
classmethod
def
__prepare__
(
mcls
,
name
,
bases
):
prepare_calls
.
append
(
'ANotMeta'
)
return
{}
class
BNotMeta
(
ANotMeta
):
def
__new__
(
mcls
,
*
args
,
**
kwargs
):
new_calls
.
append
(
'BNotMeta'
)
return
super
().
__new__
(
mcls
)
@
classmethod
def
__prepare__
(
mcls
,
name
,
bases
):
prepare_calls
.
append
(
'BNotMeta'
)
return
super
().
__prepare__
(
name
,
bases
)
A
=
types
.
new_class
(
"A"
,
(),
{
"metaclass"
:
ANotMeta
})
self
.
assertIs
(
ANotMeta
,
type
(
A
))
self
.
assertEqual
(
prepare_calls
,
[
'ANotMeta'
])
prepare_calls
.
clear
()
self
.
assertEqual
(
new_calls
,
[
'ANotMeta'
])
new_calls
.
clear
()
B
=
types
.
new_class
(
"B"
,
(),
{
"metaclass"
:
BNotMeta
})
self
.
assertIs
(
BNotMeta
,
type
(
B
))
self
.
assertEqual
(
prepare_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
prepare_calls
.
clear
()
self
.
assertEqual
(
new_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
new_calls
.
clear
()
C
=
types
.
new_class
(
"C"
,
(
A
,
B
))
self
.
assertIs
(
BNotMeta
,
type
(
C
))
self
.
assertEqual
(
prepare_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
prepare_calls
.
clear
()
self
.
assertEqual
(
new_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
new_calls
.
clear
()
C2
=
types
.
new_class
(
"C2"
,
(
B
,
A
))
self
.
assertIs
(
BNotMeta
,
type
(
C2
))
self
.
assertEqual
(
prepare_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
prepare_calls
.
clear
()
self
.
assertEqual
(
new_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
new_calls
.
clear
()
# This is a TypeError, because of a metaclass conflict:
# BNotMeta is neither a subclass, nor a superclass of type
with
self
.
assertRaises
(
TypeError
):
D
=
types
.
new_class
(
"D"
,
(
C
,),
{
"metaclass"
:
type
})
E
=
types
.
new_class
(
"E"
,
(
C
,),
{
"metaclass"
:
ANotMeta
})
self
.
assertIs
(
BNotMeta
,
type
(
E
))
self
.
assertEqual
(
prepare_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
prepare_calls
.
clear
()
self
.
assertEqual
(
new_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
new_calls
.
clear
()
F
=
types
.
new_class
(
"F"
,
(
object
(),
C
))
self
.
assertIs
(
BNotMeta
,
type
(
F
))
self
.
assertEqual
(
prepare_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
prepare_calls
.
clear
()
self
.
assertEqual
(
new_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
new_calls
.
clear
()
F2
=
types
.
new_class
(
"F2"
,
(
C
,
object
()))
self
.
assertIs
(
BNotMeta
,
type
(
F2
))
self
.
assertEqual
(
prepare_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
prepare_calls
.
clear
()
self
.
assertEqual
(
new_calls
,
[
'BNotMeta'
,
'ANotMeta'
])
new_calls
.
clear
()
# TypeError: BNotMeta is neither a
# subclass, nor a superclass of int
with
self
.
assertRaises
(
TypeError
):
X
=
types
.
new_class
(
"X"
,
(
C
,
int
()))
with
self
.
assertRaises
(
TypeError
):
X
=
types
.
new_class
(
"X"
,
(
int
(),
C
))
def
test_main
():
def
test_main
():
run_unittest
(
TypesTests
,
MappingProxyTests
)
run_unittest
(
TypesTests
,
MappingProxyTests
,
ClassCreationTests
)
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
test_main
()
test_main
()
Lib/types.py
View file @
7fc570a5
...
@@ -40,3 +40,61 @@ GetSetDescriptorType = type(FunctionType.__code__)
...
@@ -40,3 +40,61 @@ GetSetDescriptorType = type(FunctionType.__code__)
MemberDescriptorType
=
type
(
FunctionType
.
__globals__
)
MemberDescriptorType
=
type
(
FunctionType
.
__globals__
)
del
sys
,
_f
,
_g
,
_C
,
# Not for export
del
sys
,
_f
,
_g
,
_C
,
# Not for export
# Provide a PEP 3115 compliant mechanism for class creation
def
new_class
(
name
,
bases
=
(),
kwds
=
None
,
exec_body
=
None
):
"""Create a class object dynamically using the appropriate metaclass."""
meta
,
ns
,
kwds
=
prepare_class
(
name
,
bases
,
kwds
)
if
exec_body
is
not
None
:
exec_body
(
ns
)
return
meta
(
name
,
bases
,
ns
,
**
kwds
)
def
prepare_class
(
name
,
bases
=
(),
kwds
=
None
):
"""Call the __prepare__ method of the appropriate metaclass.
Returns (metaclass, namespace, kwds) as a 3-tuple
*metaclass* is the appropriate metaclass
*namespace* is the prepared class namespace
*kwds* is an updated copy of the passed in kwds argument with any
'metaclass' entry removed. If no kwds argument is passed in, this will
be an empty dict.
"""
if
kwds
is
None
:
kwds
=
{}
else
:
kwds
=
dict
(
kwds
)
# Don't alter the provided mapping
if
'metaclass'
in
kwds
:
meta
=
kwds
.
pop
(
'metaclass'
)
else
:
if
bases
:
meta
=
type
(
bases
[
0
])
else
:
meta
=
type
if
isinstance
(
meta
,
type
):
# when meta is a type, we first determine the most-derived metaclass
# instead of invoking the initial candidate directly
meta
=
_calculate_meta
(
meta
,
bases
)
if
hasattr
(
meta
,
'__prepare__'
):
ns
=
meta
.
__prepare__
(
name
,
bases
,
**
kwds
)
else
:
ns
=
{}
return
meta
,
ns
,
kwds
def
_calculate_meta
(
meta
,
bases
):
"""Calculate the most derived metaclass."""
winner
=
meta
for
base
in
bases
:
base_meta
=
type
(
base
)
if
issubclass
(
winner
,
base_meta
):
continue
if
issubclass
(
base_meta
,
winner
):
winner
=
base_meta
continue
# else:
raise
TypeError
(
"metaclass conflict: "
"the metaclass of a derived class "
"must be a (non-strict) subclass "
"of the metaclasses of all its bases"
)
return
winner
Misc/NEWS
View file @
7fc570a5
...
@@ -42,6 +42,10 @@ Core and Builtins
...
@@ -42,6 +42,10 @@ Core and Builtins
Library
Library
-------
-------
- Issue #14588: The types module now provide new_class() and prepare_class()
functions to support PEP 3115 compliant dynamic class creation. Patch by
Daniel Urban and Nick Coghlan.
- Issue #13152: Allow to specify a custom tabsize for expanding tabs in
- Issue #13152: Allow to specify a custom tabsize for expanding tabs in
textwrap. Patch by John Feuerstein.
textwrap. Patch by John Feuerstein.
...
@@ -166,6 +170,13 @@ Build
...
@@ -166,6 +170,13 @@ Build
- Issue #13210: Windows build now uses VS2010, ported from VS2008.
- Issue #13210: Windows build now uses VS2010, ported from VS2008.
Documentation
-------------
- Issue #14588: The language reference now accurately documents the Python 3
class definition process. Patch by Nick Coghlan.
What'
s
New
in
Python
3.3.0
Alpha
3
?
What'
s
New
in
Python
3.3.0
Alpha
3
?
===================================
===================================
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment