- data-model.py
- data-model.py
#!# ============
#!# Data Model
#!# ============
#!#
#!# This page contains a memo of the Python 3.6 data model.
#!#
#!# For a complete reference documentation, look at
#!# https://docs.python.org/3/reference/datamodel.html
#!#
####################################################################################################
import collections
import os
from Tools import *
####################################################################################################
#!#
#!# At __main__ level
#!# -----------------
a_global = 1
print('file:', os.path.basename(__file__))
#o#
####################################################################################################
#!#
#!# Basic Customisation
#!# -------------------
#h# print_rule()
class Foo:
"""Foo is a class"""
attr1 = 1
# Arbitrary code
attr2 = []
for i in range(10):
attr2.append(i)
def __init__(self, *args, **kwargs):
print_method('Foo', '__init__', self, args, kwargs)
def method(self, arg1, arg2, attr1='abc'):
"""a method"""
method.attr1 = 'abc' # set method attributes
# def __del__(self):
# def __repr__(self):
# def __str__(self):
# def __bytes__(self):
# def __format__(self, format_spec):
# def __lt__(self, other):
# def __le__(self, other):
# def __eq__(self, other):
# def __ne__(self, other):
# def __gt__(self, other):
# def __ge__(self, other):
# def __hash__(self):
# def __bool__(self):
#!#
foo = Foo(1, 2, attr1='abc')
#o#
print(Foo.__class__)
print('doc:', Foo.__doc__)
#o#
pretty_print('dict:', Foo.__dict__)
#o#
print('doc:', Foo.method.__doc__)
print('name:', Foo.method.__name__) # method
print('qualname:', Foo.method.__qualname__) # Foo.method
print('module:', Foo.method.__module__) # __main__
#o#
print('code:', Foo.method.__code__)
print('globals:', Foo.method.__globals__)
#o#
# A tuple containing default argument values for those arguments that have defaults, or None if no
# arguments have a default value
print('defaults:', Foo.method.__defaults__) # ('abc',)
# A dict containing defaults for keyword-only parameters.
print('kwdefaults:', Foo.method.__kwdefaults__) # None
#o#
# None or a tuple of cells that contain bindings for the function’s free variables.
# print('closure:', Foo.method.__closure__)
# A dict containing annotations of parameters. The keys of the dict are the parameter names, and
# 'return' for the return annotation, if provided.
# print('annotations:', Foo.method.__annotations__)
#!#
print(foo.method.attr1) # 'abc'
#o#
foo.method(1, 2)
#o#
#?# __func__
#?# __self__
####################################################################################################
#h# print_rule()
class FooWithNew:
def __new__(cls, *args, **kwargs):
print_method('FooWithNew', '__new__', cls, args, kwargs)
def __init__(self, *args, **kwargs):
# never called
print_method(self, '__init__', self, args, kwargs)
#!#
foo = FooWithNew(1, 2, attr1='abc')
#o#
####################################################################################################
#!#
#!# Subclasses
#!# ----------
#h# print_rule()
class Bar(Foo):
def __init__(self, *args, **kwargs):
print_method(self, '__init__', self, args, kwargs)
super().__init__(*args, **kwargs)
#!#
obj = Bar(1, 2, attr1='abc')
#o#
####################################################################################################
#!#
#!# Customizing Attribute Access
#!# ----------------------------
#h# print_rule()
class Attributes:
attr1 = 1
def __getattr__(self, name):
print_method(self, '__getattr__', self, name)
return None
def __setattr__(self, name, value):
print_method(self, '__setattr__', self, name)
def __delattr__(self, name):
print_method(self, '__deltattr__', self, name)
# def __dir__(self):
#!#
obj = Attributes()
print(obj.attr1)
print(obj.foo)
#o#
####################################################################################################
class Attributes2:
attr1 = 1
# Fixme:
def __getattribute__(self, name):
print_method(self, '__getattribute__', self, name)
raise AttributeError
# return type.__getattribute__(self, name)
# return object.__getattribute__(self, name)
#!#
obj = Attributes2()
#print(obj.attr1)
#obj.foo
##o#
####################################################################################################
#!#
#!# Implementing Descriptors
#!# ------------------------
#h# print_rule()
#!# :frompy:`3.6` :feature:`__set_name__` `PEP 487 - Descriptor Protocol Enhancements <https://www.python.org/dev/peps/pep-0487>`_
class Descriptor:
def __init__(self, name, value):
self._name = name
self._value = value
def __get__(self, instance, owner):
print_method(self, '__get__', self, instance, owner)
return self._value
def __set__(self, instance, value):
print_method(self, '_set__', self, instance, value)
self._value = value
def __delete__(self, instance):
print_method(self, '__delete__', self, instance)
# since 3.6
def __set_name__(self, owner, name):
print_method(self, '__set_name__', self, owner, name)
class UsingDescriptor:
attr1 = Descriptor('attr1', 1) # class __set_name__(__main__.UsingDescriptor, 'attr1')
#!# Invoking Descriptors
obj = UsingDescriptor()
print(obj.attr1) # call __get__
obj.attr1 = 2 # call __set__
del obj.attr1 # call __delete__
#o#
####################################################################################################
#!#
#!# Slots
#!# -----
#h# print_rule()
class Slotted:
__slots__ = ('x', 'y')
#!#
obj = Slotted()
print(obj.__slots__)
obj.x = 1 # implemented as descriptor
obj.y = 2
#o#
####################################################################################################
#!#
#!# Properties
#!# ----------
#h# print_rule()
class Property:
def get_x(self):
return self.__x
def set_x(self, value):
self.__x = value
def del_x(self):
del self.__x
x = property(get_x, set_x, del_x, "I'm the 'x' property.")
####################################################################################################
#!#
#!# Customising Class Creation
#!# --------------------------
#!#
#!# :frompy:`3.6`
#!#
#!# `PEP 487 - Simpler customization of class creation <https://www.python.org/dev/peps/pep-0487>`_
#h# print_rule()
class Philosopher:
def __init_subclass__(cls, default_name, **kwargs):
print_method(cls, '__init_subclass__', default_name, kwargs)
super().__init_subclass__(**kwargs)
cls.default_name = default_name
class AustralianPhilosopher(Philosopher, default_name="Bruce"):
pass
obj = Philosopher()
obj = AustralianPhilosopher()
#o#
class PluginBase:
subclasses = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.subclasses.append(cls)
class Plugin1(PluginBase):
pass
class Plugin2(PluginBase):
pass
print(PluginBase.subclasses)
#o#
####################################################################################################
#!#
#!# Metaclass
#!# ---------
#h# print_rule()
class Metaclass(type):
@classmethod
def __prepare__(meta_cls, name, bases, **kwargs):
print_method(meta_cls, '__prepare__', name, bases, kwargs)
return collections.OrderedDict()
def __new__(meta_cls, name, bases, namespace, **kwargs):
print_method('Metaclass', '__new__', meta_cls, name, bases, namespace, kwargs)
result = type.__new__(meta_cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
def __init__(cls, name, bases, namespace):
# Attention: first parameter is cls, not meta_cls !
print_method('Metaclass', '__init__', cls, name, bases, namespace)
print_method('Metaclass', '__init__', cls.__dict__)
type.__init__(cls, name, bases, namespace)
# super(Metaclass, cls).__init__(name, bases, namespace)
def __call__(cls, *args, **kwargs):
print_method(cls, '__call__', cls, args, kwargs)
return type.__call__(cls, *args, **kwargs)
class Metaclassed(metaclass=Metaclass):
def __init__(self, *args, **kwargs):
print_method(self, '__init__', self, args, kwargs)
def one(self): pass
def two(self): pass
def three(self): pass
def four(self): pass
#o#
pretty_print(Metaclassed.__dict__)
#o#
class SubMetaclassed(Metaclassed):
pass
#o#
print(Metaclassed.members)
#o#
obj = Metaclassed(1, 2, attr1='abc')
#o#
obj = SubMetaclassed(1, 2, attr1='abc')
#o#
####################################################################################################
#!#
#!# Customising Instance and Subclass Checks
#!# ----------------------------------------
#!#
#!# `PEP 3119 - Introducing Abstract Base Classes <https://www.python.org/dev/peps/pep-3119>`_
class CheckableMetaclass(type):
def __instancecheck__(self, instance):
print_method(self, '__init_subclass__', self, instance)
return super().__instancecheck__(instance)
def __subclasscheck__(self, subclass):
print_method(self, '__subclasscheck__', self, subclass)
return super().__subclasscheck__(subclass)
class CheckableClass(metaclass=CheckableMetaclass):
pass
class SubCheckableClass(CheckableClass):
pass
subobj = SubCheckableClass()
print(isinstance(subobj, CheckableClass))
print(isinstance(subobj, SubCheckableClass))
print(issubclass(subobj.__class__, CheckableClass))
#o#
####################################################################################################
#!#
#!# Emulating Callable Objects
#!# --------------------------
#h# print_rule()
class Callable:
def __call__(self, *args, **kwargs):
print_method(self, '__call__', args, kwargs)
#!#
obj = Callable()
obj(1, 2, attr1='abc') # call Callable.__call__
#o#
####################################################################################################
#!#
#!# Emulating Container Types
#!# -------------------------
#h# print_rule()
class Container:
def __init__(self, *values):
print_method(self, '__init__', values)
self._values = list(values) # mutable
def __len__(self):
print_method(self, '__len__')
return len(self._values)
def __length_hint__(self):
print_method(self, '__length_hint__')
# Called to implement operator.length_hint()
return 10
def __getitem__(self, key):
print_method(self, '__getitem__', key)
return self._values[key] # key can be a slice
def __missing__(self, key):
# Called by dict.__getitem__() to implement self[key] for dict subclasses when key is not in the dictionary.
print_method(self, '__missing__')
def __setitem__(self, key, value):
print_method(self, '__setitem__', key, value)
self._values[key] = value
def __delitem__(self, key):
print_method(self, '__delitem__', key)
del self._values[key]
def __iter__(self):
print_method(self, '__iter__')
return iter(self._values)
def __reversed__(self):
print_method(self, '__reversed__')
return reversed(self._values)
def __contains__(self, item):
print_method(self, '__contains__', item)
return item in self._values
#!#
obj = Container(*range(5))
print(obj[1])
obj[4] = 6
print(len(obj))
print(list(obj))
print(list(reversed(obj)))
print(1 in obj)
#o#
####################################################################################################
#!#
#!# Emulating Numeric Types
#!# -----------------------
class Numeric:
# These methods are called to implement the binary arithmetic operations:
# + - * @ / // % divmod() pow() ** << >> & ^ |
def __add__(self, other):
pass
def __sub__(self, other):
pass
def __mul__(self, other):
pass
def __matmul__(self, other):
pass
def __truediv__(self, other):
pass
def __floordiv__(self, other):
pass
def __mod__(self, other):
pass
def __divmod__(self, other):
pass
def __pow__(self, other, modulo):
pass
def __lshift__(self, other):
pass
def __rshift__(self, other):
pass
def __and__(self, other):
pass
def __xor__(self, other):
pass
def __or__(self, other):
pass
# These methods are called to implement the binary arithmetic operations with reflected (swapped) operands:
# + - * @ / // % divmod() pow() ** << >> & ^ |
def __radd__(self, other):
pass
def __rsub__(self, other):
pass
def __rmul__(self, other):
pass
def __rmatmul__(self, other):
pass
def __rtruediv__(self, other):
pass
def __rfloordiv__(self, other):
pass
def __rmod__(self, other):
pass
def __rdivmod__(self, other):
pass
def __rpow__(self, other):
pass
def __rlshift__(self, other):
pass
def __rrshift__(self, other):
pass
def __rand__(self, other):
pass
def __rxor__(self, other):
pass
def __ror__(self, other):
pass
# These methods are called to implement the augmented arithmetic assignments:
# += -= *= @= /= //= %= **= <<= >>= &= ^= |=
def __iadd__(self, other):
pass
def __isub__(self, other):
pass
def __imul__(self, other):
pass
def __imatmul__(self, other):
pass
def __itruediv__(self, other):
pass
def __ifloordiv__(self, other):
pass
def __imod__(self, other):
pass
def __ipow__(self, other, modulo):
pass
def __ilshift__(self, other):
pass
def __irshift__(self, other):
pass
def __iand__(self, other):
pass
def __ixor__(self, other):
pass
def __ior__(self, other):
pass
# Called to implement the unary arithmetic operations:
# - + abs() ~
def __neg__(self):
pass
def __pos__(self):
pass
def __abs__(self):
pass
def __invert__(self):
pass
# Called to implement the built-in functions complex(), int(), float() and round():
def __complex__(self):
pass
def __int__(self):
pass
def __float__(self):
pass
def __round__(self, n):
pass
def __index__(self):
# Called to implement operator.index()
pass
####################################################################################################
#!#
#!# With Statement Context Managers
#!# -------------------------------
class ContextManager:
def __init__(self, *args, **kwargs):
print_method(self, '__init__', self, args, kwargs)
def __enter__(self):
print_method(self, '__enter__', self)
return 'something' # value for as
def __exit__(self, exc_type, exc_value, traceback):
print_method(self, '__exit__', self, exc_type, exc_value, traceback)
#!#
with ContextManager(1, 2, attr1='abc') as obj:
print('here', obj)
#o#
try:
with ContextManager(1, 2, attr1='abc') as obj:
print('here', obj)
raise NameError('an error')
except NameError as exception:
print(exception)
#o#
####################################################################################################
#!#
#!# Coroutines
#!# ----------
#!# Awaitable Objects
#!# ~~~~~~~~~~~~~~~~~
# object.__await__(self)
#!# Coroutine Objects
#!# ~~~~~~~~~~~~~~~~~
# coroutine.send(value)
# coroutine.throw(type[, value[, traceback]])
# coroutine.close()
#!# Asynchronous Iterators
#!# ~~~~~~~~~~~~~~~~~~~~~~
#!#
#!# An asynchronous iterable is able to call asynchronous code in its __aiter__ implementation, and
#!# an asynchronous iterator can call asynchronous code in its __anext__ method.
class Reader:
async def readline(self):
pass
def __aiter__(self):
# Must return an asynchronous iterator object.
return self
async def __anext__(self):
# Must return an awaitable resulting in a next value of the iterator.
# Should raise a StopAsyncIteration error when the iteration is over.
val = await self.readline()
if val == b'':
raise StopAsyncIteration
return val
#!# Asynchronous Context Managers
#!# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#!#
#!# An asynchronous context manager is a context manager that is able to suspend execution in its
#!# __aenter__ and __aexit__ methods.
class AsyncContextManager:
async def __aenter__(self):
# This method is semantically similar to the __enter__(),
# with only difference that it must return an awaitable.
await log('entering context')
async def __aexit__(self, exc_type, exc, tb):
# This method is semantically similar to the __exit__(),
# with only difference that it must return an awaitable.
await log('exiting context')
3.3.5. Data Model¶
This page contains a memo of the Python 3.6 data model.
For a complete reference documentation, look at https://docs.python.org/3/reference/datamodel.html
import collections
import os
from Tools import *
3.3.5.2. Basic Customisation¶
class Foo:
"""Foo is a class"""
attr1 = 1
# Arbitrary code
attr2 = []
for i in range(10):
attr2.append(i)
def __init__(self, *args, **kwargs):
print_method('Foo', '__init__', self, args, kwargs)
def method(self, arg1, arg2, attr1='abc'):
"""a method"""
method.attr1 = 'abc' # set method attributes
# def __del__(self):
# def __repr__(self):
# def __str__(self):
# def __bytes__(self):
# def __format__(self, format_spec):
# def __lt__(self, other):
# def __le__(self, other):
# def __eq__(self, other):
# def __ne__(self, other):
# def __gt__(self, other):
# def __ge__(self, other):
# def __hash__(self):
# def __bool__(self):
foo = Foo(1, 2, attr1='abc')
@Foo.__init__
<__main__.Foo object at 0x7faff8f92c88>
(1, 2)
{'attr1': 'abc'}
print(Foo.__class__)
print('doc:', Foo.__doc__)
<class 'type'>
doc: Foo is a class
pretty_print('dict:', Foo.__dict__)
'dict:'
mappingproxy({ '__dict__': <attribute '__dict__' of 'Foo' objects>,
'__doc__': 'Foo is a '
'class',
'__init__': <function Foo.__init__ at 0x7faff8f786a8>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'Foo' objects>,
'attr1': 1,
'attr2': [ 0,
1,
2,
3,
4,
5,
6,
7,
8,
9],
'i': 9,
'method': <function Foo.method at 0x7faff8f78378>})
print('doc:', Foo.method.__doc__)
print('name:', Foo.method.__name__) # method
print('qualname:', Foo.method.__qualname__) # Foo.method
print('module:', Foo.method.__module__) # __main__
doc: a method
name: method
qualname: Foo.method
module: __main__
print('code:', Foo.method.__code__)
print('globals:', Foo.method.__globals__)
code: <code object method at 0x7faff8f6c9c0, file "<ipython-input-1-f634fa719b33>", line 15>
globals: {'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': <module 'builtins' (built-in)>, '__builtins__': <module 'builtins' (built-in)>, '_ih': [''], '_oh': {}, '_dh': ['/tmp/tmp9kfthd8s'], 'In': [''], 'Out': {}, 'get_ipython': <bound method InteractiveShell.get_ipython of <ipykernel.zmqshell.ZMQInteractiveShell object at 0x7fb001358e48>>, 'exit': <IPython.core.autocall.ZMQExitAutocall object at 0x7fb00008dfd0>, 'quit': <IPython.core.autocall.ZMQExitAutocall object at 0x7fb00008dfd0>, '_': '', '__': '', '___': '', 'save_figure': <function save_figure at 0x7faff97e4488>, 'collections': <module 'collections' from '/home/opt/python-virtual-env/py36/lib64/python3.6/collections/__init__.py'>, 'os': <module 'os' from '/home/opt/python-virtual-env/py36/lib64/python3.6/os.py'>, 'pretty_print': <function pretty_print at 0x7faff8f7d158>, 'print_function': <function print_function at 0x7faff8f7d1e0>, 'print_method': <function print_method at 0x7faff8f7d268>, 'print_rule': <function print_rule at 0x7faff8f7d2f0>, 'a_global': 1, 'Foo': <class '__main__.Foo'>, 'foo': <__main__.Foo object at 0x7faff8f92c88>}
# A tuple containing default argument values for those arguments that have defaults, or None if no
# arguments have a default value
print('defaults:', Foo.method.__defaults__) # ('abc',)
# A dict containing defaults for keyword-only parameters.
print('kwdefaults:', Foo.method.__kwdefaults__) # None
defaults: ('abc',)
kwdefaults: None
# None or a tuple of cells that contain bindings for the function’s free variables.
# print('closure:', Foo.method.__closure__)
# A dict containing annotations of parameters. The keys of the dict are the parameter names, and
# 'return' for the return annotation, if provided.
# print('annotations:', Foo.method.__annotations__)
print(foo.method.attr1) # 'abc'
abc
foo.method(1, 2)
class FooWithNew:
def __new__(cls, *args, **kwargs):
print_method('FooWithNew', '__new__', cls, args, kwargs)
def __init__(self, *args, **kwargs):
# never called
print_method(self, '__init__', self, args, kwargs)
foo = FooWithNew(1, 2, attr1='abc')
@FooWithNew.__new__
<class '__main__.FooWithNew'>
(1, 2)
{'attr1': 'abc'}
3.3.5.3. Subclasses¶
class Bar(Foo):
def __init__(self, *args, **kwargs):
print_method(self, '__init__', self, args, kwargs)
super().__init__(*args, **kwargs)
obj = Bar(1, 2, attr1='abc')
@Bar.__init__
<__main__.Bar object at 0x7faff8f92978>
(1, 2)
{'attr1': 'abc'}
@Foo.__init__
<__main__.Bar object at 0x7faff8f92978>
(1, 2)
{'attr1': 'abc'}
3.3.5.4. Customizing Attribute Access¶
class Attributes:
attr1 = 1
def __getattr__(self, name):
print_method(self, '__getattr__', self, name)
return None
def __setattr__(self, name, value):
print_method(self, '__setattr__', self, name)
def __delattr__(self, name):
print_method(self, '__deltattr__', self, name)
# def __dir__(self):
obj = Attributes()
print(obj.attr1)
print(obj.foo)
1
@Attributes.__getattr__
<__main__.Attributes object at 0x7faff8f92e10>
'foo'
None
class Attributes2:
attr1 = 1
# Fixme:
def __getattribute__(self, name):
print_method(self, '__getattribute__', self, name)
raise AttributeError
# return type.__getattribute__(self, name)
# return object.__getattribute__(self, name)
obj = Attributes2()
#print(obj.attr1)
#obj.foo
##o#
3.3.5.5. Implementing Descriptors¶
:frompy:`3.6` :feature:`__set_name__` PEP 487 - Descriptor Protocol Enhancements
class Descriptor:
def __init__(self, name, value):
self._name = name
self._value = value
def __get__(self, instance, owner):
print_method(self, '__get__', self, instance, owner)
return self._value
def __set__(self, instance, value):
print_method(self, '_set__', self, instance, value)
self._value = value
def __delete__(self, instance):
print_method(self, '__delete__', self, instance)
# since 3.6
def __set_name__(self, owner, name):
print_method(self, '__set_name__', self, owner, name)
class UsingDescriptor:
attr1 = Descriptor('attr1', 1) # class __set_name__(__main__.UsingDescriptor, 'attr1')
Invoking Descriptors
obj = UsingDescriptor()
print(obj.attr1) # call __get__
obj.attr1 = 2 # call __set__
del obj.attr1 # call __delete__
@Descriptor.__get__
<__main__.Descriptor object at 0x7faff8f0a2e8>
<__main__.UsingDescriptor object at 0x7faff8f019b0>
<class '__main__.UsingDescriptor'>
1
@Descriptor._set__
<__main__.Descriptor object at 0x7faff8f0a2e8>
<__main__.UsingDescriptor object at 0x7faff8f019b0>
2
@Descriptor.__delete__
<__main__.Descriptor object at 0x7faff8f0a2e8>
<__main__.UsingDescriptor object at 0x7faff8f019b0>
3.3.5.6. Slots¶
class Slotted:
__slots__ = ('x', 'y')
obj = Slotted()
print(obj.__slots__)
obj.x = 1 # implemented as descriptor
obj.y = 2
('x', 'y')
3.3.5.7. Properties¶
class Property:
def get_x(self):
return self.__x
def set_x(self, value):
self.__x = value
def del_x(self):
del self.__x
x = property(get_x, set_x, del_x, "I'm the 'x' property.")
3.3.5.8. Customising Class Creation¶
PEP 487 - Simpler customization of class creation
class Philosopher:
def __init_subclass__(cls, default_name, **kwargs):
print_method(cls, '__init_subclass__', default_name, kwargs)
super().__init_subclass__(**kwargs)
cls.default_name = default_name
class AustralianPhilosopher(Philosopher, default_name="Bruce"):
pass
obj = Philosopher()
obj = AustralianPhilosopher()
@type.__init_subclass__
'Bruce'
{}
class PluginBase:
subclasses = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.subclasses.append(cls)
class Plugin1(PluginBase):
pass
class Plugin2(PluginBase):
pass
print(PluginBase.subclasses)
[<class '__main__.Plugin1'>, <class '__main__.Plugin2'>]
3.3.5.9. Metaclass¶
class Metaclass(type):
@classmethod
def __prepare__(meta_cls, name, bases, **kwargs):
print_method(meta_cls, '__prepare__', name, bases, kwargs)
return collections.OrderedDict()
def __new__(meta_cls, name, bases, namespace, **kwargs):
print_method('Metaclass', '__new__', meta_cls, name, bases, namespace, kwargs)
result = type.__new__(meta_cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
def __init__(cls, name, bases, namespace):
# Attention: first parameter is cls, not meta_cls !
print_method('Metaclass', '__init__', cls, name, bases, namespace)
print_method('Metaclass', '__init__', cls.__dict__)
type.__init__(cls, name, bases, namespace)
# super(Metaclass, cls).__init__(name, bases, namespace)
def __call__(cls, *args, **kwargs):
print_method(cls, '__call__', cls, args, kwargs)
return type.__call__(cls, *args, **kwargs)
class Metaclassed(metaclass=Metaclass):
def __init__(self, *args, **kwargs):
print_method(self, '__init__', self, args, kwargs)
def one(self): pass
def two(self): pass
def three(self): pass
def four(self): pass
@type.__prepare__
'Metaclassed'
()
{}
@Metaclass.__new__
<class '__main__.Metaclass'>
'Metaclassed'
()
OrderedDict([ ( '__module__',
'__main__'),
( '__qualname__',
'Metaclassed'),
( '__init__',
<function Metaclassed.__init__ at 0x7faff8f730d0>),
( 'one',
<function Metaclassed.one at 0x7faff8f73e18>),
( 'two',
<function Metaclassed.two at 0x7faff8f731e0>),
( 'three',
<function Metaclassed.three at 0x7faff8f7dc80>),
( 'four',
<function Metaclassed.four at 0x7faff8f78268>)])
{}
@Metaclass.__init__
<class '__main__.Metaclassed'>
'Metaclassed'
()
OrderedDict([ ( '__module__',
'__main__'),
( '__qualname__',
'Metaclassed'),
( '__init__',
<function Metaclassed.__init__ at 0x7faff8f730d0>),
( 'one',
<function Metaclassed.one at 0x7faff8f73e18>),
( 'two',
<function Metaclassed.two at 0x7faff8f731e0>),
( 'three',
<function Metaclassed.three at 0x7faff8f7dc80>),
( 'four',
<function Metaclassed.four at 0x7faff8f78268>)])
@Metaclass.__init__
mappingproxy({ '__dict__': <attribute '__dict__' of 'Metaclassed' objects>,
'__doc__': None,
'__init__': <function Metaclassed.__init__ at 0x7faff8f730d0>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'Metaclassed' objects>,
'four': <function Metaclassed.four at 0x7faff8f78268>,
'members': ( '__module__',
'__qualname__',
'__init__',
'one',
'two',
'three',
'four'),
'one': <function Metaclassed.one at 0x7faff8f73e18>,
'three': <function Metaclassed.three at 0x7faff8f7dc80>,
'two': <function Metaclassed.two at 0x7faff8f731e0>})
pretty_print(Metaclassed.__dict__)
mappingproxy({ '__dict__': <attribute '__dict__' of 'Metaclassed' objects>,
'__doc__': None,
'__init__': <function Metaclassed.__init__ at 0x7faff8f730d0>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'Metaclassed' objects>,
'four': <function Metaclassed.four at 0x7faff8f78268>,
'members': ( '__module__',
'__qualname__',
'__init__',
'one',
'two',
'three',
'four'),
'one': <function Metaclassed.one at 0x7faff8f73e18>,
'three': <function Metaclassed.three at 0x7faff8f7dc80>,
'two': <function Metaclassed.two at 0x7faff8f731e0>})
class SubMetaclassed(Metaclassed):
pass
@type.__prepare__
'SubMetaclassed'
(<class '__main__.Metaclassed'>,)
{}
@Metaclass.__new__
<class '__main__.Metaclass'>
'SubMetaclassed'
(<class '__main__.Metaclassed'>,)
OrderedDict([ ( '__module__',
'__main__'),
( '__qualname__',
'SubMetaclassed')])
{}
@Metaclass.__init__
<class '__main__.SubMetaclassed'>
'SubMetaclassed'
(<class '__main__.Metaclassed'>,)
OrderedDict([ ( '__module__',
'__main__'),
( '__qualname__',
'SubMetaclassed')])
@Metaclass.__init__
mappingproxy({ '__doc__': None,
'__module__': '__main__',
'members': ( '__module__',
'__qualname__')})
print(Metaclassed.members)
('__module__', '__qualname__', '__init__', 'one', 'two', 'three', 'four')
obj = Metaclassed(1, 2, attr1='abc')
@Metaclass.__call__
<class '__main__.Metaclassed'>
(1, 2)
{'attr1': 'abc'}
@Metaclassed.__init__
<__main__.Metaclassed object at 0x7faff8f0a1d0>
(1, 2)
{'attr1': 'abc'}
obj = SubMetaclassed(1, 2, attr1='abc')
@Metaclass.__call__
<class '__main__.SubMetaclassed'>
(1, 2)
{'attr1': 'abc'}
@SubMetaclassed.__init__
<__main__.SubMetaclassed object at 0x7faff8f0a860>
(1, 2)
{'attr1': 'abc'}
3.3.5.10. Customising Instance and Subclass Checks¶
PEP 3119 - Introducing Abstract Base Classes
class CheckableMetaclass(type):
def __instancecheck__(self, instance):
print_method(self, '__init_subclass__', self, instance)
return super().__instancecheck__(instance)
def __subclasscheck__(self, subclass):
print_method(self, '__subclasscheck__', self, subclass)
return super().__subclasscheck__(subclass)
class CheckableClass(metaclass=CheckableMetaclass):
pass
class SubCheckableClass(CheckableClass):
pass
subobj = SubCheckableClass()
print(isinstance(subobj, CheckableClass))
print(isinstance(subobj, SubCheckableClass))
print(issubclass(subobj.__class__, CheckableClass))
@CheckableMetaclass.__init_subclass__
<class '__main__.CheckableClass'>
<__main__.SubCheckableClass object at 0x7faff8f01cc0>
True
True
@CheckableMetaclass.__subclasscheck__
<class '__main__.CheckableClass'>
<class '__main__.SubCheckableClass'>
True
3.3.5.11. Emulating Callable Objects¶
class Callable:
def __call__(self, *args, **kwargs):
print_method(self, '__call__', args, kwargs)
obj = Callable()
obj(1, 2, attr1='abc') # call Callable.__call__
@Callable.__call__
(1, 2)
{'attr1': 'abc'}
3.3.5.12. Emulating Container Types¶
class Container:
def __init__(self, *values):
print_method(self, '__init__', values)
self._values = list(values) # mutable
def __len__(self):
print_method(self, '__len__')
return len(self._values)
def __length_hint__(self):
print_method(self, '__length_hint__')
# Called to implement operator.length_hint()
return 10
def __getitem__(self, key):
print_method(self, '__getitem__', key)
return self._values[key] # key can be a slice
def __missing__(self, key):
# Called by dict.__getitem__() to implement self[key] for dict subclasses when key is not in the dictionary.
print_method(self, '__missing__')
def __setitem__(self, key, value):
print_method(self, '__setitem__', key, value)
self._values[key] = value
def __delitem__(self, key):
print_method(self, '__delitem__', key)
del self._values[key]
def __iter__(self):
print_method(self, '__iter__')
return iter(self._values)
def __reversed__(self):
print_method(self, '__reversed__')
return reversed(self._values)
def __contains__(self, item):
print_method(self, '__contains__', item)
return item in self._values
obj = Container(*range(5))
print(obj[1])
obj[4] = 6
print(len(obj))
print(list(obj))
print(list(reversed(obj)))
print(1 in obj)
@Container.__init__
(0, 1, 2, 3, 4)
@Container.__getitem__
1
1
@Container.__setitem__
4
6
@Container.__len__
5
@Container.__iter__
@Container.__len__
[0, 1, 2, 3, 6]
@Container.__reversed__
[6, 3, 2, 1, 0]
@Container.__contains__
1
True
3.3.5.13. Emulating Numeric Types¶
class Numeric:
# These methods are called to implement the binary arithmetic operations:
# + - * @ / // % divmod() pow() ** << >> & ^ |
def __add__(self, other):
pass
def __sub__(self, other):
pass
def __mul__(self, other):
pass
def __matmul__(self, other):
pass
def __truediv__(self, other):
pass
def __floordiv__(self, other):
pass
def __mod__(self, other):
pass
def __divmod__(self, other):
pass
def __pow__(self, other, modulo):
pass
def __lshift__(self, other):
pass
def __rshift__(self, other):
pass
def __and__(self, other):
pass
def __xor__(self, other):
pass
def __or__(self, other):
pass
# These methods are called to implement the binary arithmetic operations with reflected (swapped) operands:
# + - * @ / // % divmod() pow() ** << >> & ^ |
def __radd__(self, other):
pass
def __rsub__(self, other):
pass
def __rmul__(self, other):
pass
def __rmatmul__(self, other):
pass
def __rtruediv__(self, other):
pass
def __rfloordiv__(self, other):
pass
def __rmod__(self, other):
pass
def __rdivmod__(self, other):
pass
def __rpow__(self, other):
pass
def __rlshift__(self, other):
pass
def __rrshift__(self, other):
pass
def __rand__(self, other):
pass
def __rxor__(self, other):
pass
def __ror__(self, other):
pass
# These methods are called to implement the augmented arithmetic assignments:
# += -= *= @= /= //= %= **= <<= >>= &= ^= |=
def __iadd__(self, other):
pass
def __isub__(self, other):
pass
def __imul__(self, other):
pass
def __imatmul__(self, other):
pass
def __itruediv__(self, other):
pass
def __ifloordiv__(self, other):
pass
def __imod__(self, other):
pass
def __ipow__(self, other, modulo):
pass
def __ilshift__(self, other):
pass
def __irshift__(self, other):
pass
def __iand__(self, other):
pass
def __ixor__(self, other):
pass
def __ior__(self, other):
pass
# Called to implement the unary arithmetic operations:
# - + abs() ~
def __neg__(self):
pass
def __pos__(self):
pass
def __abs__(self):
pass
def __invert__(self):
pass
# Called to implement the built-in functions complex(), int(), float() and round():
def __complex__(self):
pass
def __int__(self):
pass
def __float__(self):
pass
def __round__(self, n):
pass
def __index__(self):
# Called to implement operator.index()
pass
3.3.5.14. With Statement Context Managers¶
class ContextManager:
def __init__(self, *args, **kwargs):
print_method(self, '__init__', self, args, kwargs)
def __enter__(self):
print_method(self, '__enter__', self)
return 'something' # value for as
def __exit__(self, exc_type, exc_value, traceback):
print_method(self, '__exit__', self, exc_type, exc_value, traceback)
with ContextManager(1, 2, attr1='abc') as obj:
print('here', obj)
@ContextManager.__init__
<__main__.ContextManager object at 0x7faff8f1bf98>
(1, 2)
{'attr1': 'abc'}
@ContextManager.__enter__
<__main__.ContextManager object at 0x7faff8f1bf98>
here something
@ContextManager.__exit__
<__main__.ContextManager object at 0x7faff8f1bf98>
None
None
None
try:
with ContextManager(1, 2, attr1='abc') as obj:
print('here', obj)
raise NameError('an error')
except NameError as exception:
print(exception)
@ContextManager.__init__
<__main__.ContextManager object at 0x7faff8f0a0f0>
(1, 2)
{'attr1': 'abc'}
@ContextManager.__enter__
<__main__.ContextManager object at 0x7faff8f0a0f0>
here something
@ContextManager.__exit__
<__main__.ContextManager object at 0x7faff8f0a0f0>
<class 'NameError'>
NameError('an error',)
<traceback object at 0x7fb0010f1988>
an error
3.3.5.15. Coroutines¶
3.3.5.15.1. Awaitable Objects¶
# object.__await__(self)
3.3.5.15.2. Coroutine Objects¶
# coroutine.send(value)
# coroutine.throw(type[, value[, traceback]])
# coroutine.close()
3.3.5.15.3. Asynchronous Iterators¶
An asynchronous iterable is able to call asynchronous code in its __aiter__ implementation, and an asynchronous iterator can call asynchronous code in its __anext__ method.
class Reader:
async def readline(self):
pass
def __aiter__(self):
# Must return an asynchronous iterator object.
return self
async def __anext__(self):
# Must return an awaitable resulting in a next value of the iterator.
# Should raise a StopAsyncIteration error when the iteration is over.
val = await self.readline()
if val == b'':
raise StopAsyncIteration
return val
3.3.5.15.4. Asynchronous Context Managers¶
An asynchronous context manager is a context manager that is able to suspend execution in its __aenter__ and __aexit__ methods.
class AsyncContextManager:
async def __aenter__(self):
# This method is semantically similar to the __enter__(),
# with only difference that it must return an awaitable.
await log('entering context')
async def __aexit__(self, exc_type, exc, tb):
# This method is semantically similar to the __exit__(),
# with only difference that it must return an awaitable.
await log('exiting context')