Что касается вашего первого вопроса, должен быть метакласс new_class
(что это так):
prepare_class
Причина в том, что если метакласс не является экземпляром типа python, он вызывает метакласс, передавая ему эти аргументы prepare_class
(см. __prepare__
), И поскольку вы возвращаете свой реальный метакласс в этой функции, он получает правильный тип для метакласса.
И о втором вопросе:
Какова цель принятия произвольного вызываемого?
Специальной цели нет, на самом деле это характер метаклассов, потому что из-за того, что создание экземпляра из класса всегда вызывает метакласс, вызывая его _calculate_meta
метод:
__prepare__
Это означает, что вы можете передать любой вызываемый как ваш метакласс. Например, если вы проверите его с помощью вложенной функции, результат будет по-прежнему остальным:
__call__
Для получения дополнительной информации о том, как Python разбивает класс:
Он вызывает __new__
функцию, которую он вызывает __init__
внутри себя, а затем, как вы можете видеть внутри питона, вызывает метод соответствующего метакласса, помимо поиска правильной мета (с помощью функции) и создания соответствующего пространства имен для класса.# 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
type
MyMetaClass
Итак, все в одном - это иерархия выполнения методов метакали:
metaclass_callable
1metaclass
__call__
print
И вот исходный код:
MyMetaClass.__call__
1. Обратите внимание, что он получает неявное выражение внутри функции new_class и перед возвратом.