>>> class Man (object): >>> pass >>> me = Man (height = 180, weight = 80) Traceback (most recent call last): File "<stdin>", line 20, in <module> TypeError: object .__ new __ () takes no parameters
>>> class AttributeInitType (type): >>> def __call __ (self, * args, ** kwargs): >>> "" "Calling a class creates a new object." "" >>> # First of all we create the object itself ... >>> obj = type .__ call __ (self, * args) >>> # ... and add the arguments passed to it as attributes. >>> for name in kwargs: >>> setattr (obj, name, kwargs [name]) >>> # return the finished object >>> return obj
>>> class Man (object): >>> __metaclass__ = AttributeInitType
>>> me = Man (height = 180, weigth = 80) >>> print me.height 180
>>> from abc import ABCMeta, abstractmethod >>> class A (object): >>> __metaclass __ = ABCMeta >>> @abstractmethod >>> def foo (self): pass >>> >>> A () Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Can't instantiate
>>> class C (A): >>> def foo (self): print (42) >>> C <class '__main __. C'> >>> a = C () >>> a.foo () 42
>>> class ABCMeta (type): >>> def __new __ (mcls, name, bases, namespace): >>> bases = _fix_bases (bases) >>> cls = super (ABCMeta, mcls) .__ new __ (mcls, name, bases, namespace) >>> # Find the set (set) of abstract method names among our own >>> # methods and methods of ancestors >>> abstracts = set (name >>> for name, value in namespace.items () >>> if getattr (value, "__isabstractmethod__", False)) >>> for base in bases: >>> for name in getattr (base, "__abstractmethods__", set ()): >>> value = getattr (cls, name, None) >>> if getattr (value, "__isabstractmethod__", False): >>> abstracts.add (name) >>> cls .__ abstractmethods__ = frozenset (abstracts) >>> return cls
>>> class _Abstract (object): >>> def __new __ (cls, * args, ** kwds): >>> am = cls .__ dict __. get ("__ abstractmethods__") >>> if am: >>> raise TypeError ("can't instantiate abstract class% s" >>> "with abstract methods% s"% >>> (cls .__ name__, "," .join (sorted (am)))) >>> return super (_Abstract, cls) .__ new __ (cls, * args, ** kwds) >>> >>> def _fix_bases (bases): >>> for base in bases: >>> if issubclass (base, _Abstract): >>> # _Abstract is already among ancestors >>> return bases >>> if object in bases: >>> # Replace object with _Abstract if the class is directly inherited from object >>> # and not listed among other ancestors >>> return tuple ([_ Abstract if base is object else base >>> for base in bases]) >>> # Add _Abstract to the end otherwise >>> return bases + (_Abstract,)
>>> def abstractmethod (funcobj): >>> funcobj .__ isabstractmethod__ = True >>> return funcobj
>>> class ModelBase (type): >>> "" " >>> Metaclass for all models. >>> "" " >>> def __new __ (cls, name, bases, attrs): >>> super_new = super (ModelBase, cls) .__ new__ >>> parents = [b for b in bases if isinstance (b, ModelBase)] >>> if not parents: >>> # If this isn't a subclass of Model, don't do anything special. >>> return super_new (cls, name, bases, attrs)
>>> #Class creation >>> module = attrs.pop ('__ module__') >>> new_class = super_new (cls, name, bases, {'__module__': module}) >>> attr_meta = attrs.pop ('Meta', None) >>> abstract = getattr (attr_meta, 'abstract', False) >>> if not attr_meta: >>> meta = getattr (new_class, 'Meta', None) >>> else: >>> meta = attr_meta >>> base_meta = getattr (new_class, '_meta', None)
>>> new_class.add_to_class ('_ meta', Options (meta, ** kwargs))
>>> if not abstract: >>> new_class.add_to_class ('DoesNotExist', >>> subclass_exception ('DoesNotExist', ObjectDoesNotExist, module)) >>> new_class.add_to_class ('MultipleObjectsReturned', >>> subclass_exception ('MultipleObjectsReturned', >>> MultipleObjectsReturned, module))
>>> if base_meta and not base_meta.abstract: >>> if not hasattr (meta, 'ordering'): >>> new_class._meta.ordering = base_meta.ordering >>> if not hasattr (meta, 'get_latest_by') : >>> new_class._meta.get_latest_by = base_meta.get_latest_by
>>> if getattr (new_class, '_default_manager', None): >>> new_class._default_manager = None >>> >>> m = get_model (new_class._meta.app_label, name, False) >>> if m is not None: >>> return m
>>> for obj_name, obj in attrs.items (): >>> new_class.add_to_class (obj_name, obj)
>>> # Do the appropriate setup for any model parents. >>> o2o_map = dict ([(f.rel.to, f) for f in new_class._meta.local_fields >>> if isinstance (f, OneToOneField)])
>>> for base in parents: >>> if not hasattr (base, '_meta'): >>> # Models without _meta are not active and do not represent interest >>> continue >>> >>> # All fields of any type for this model >>> new_fields = new_class._meta.local_fields + \ >>> new_class._meta.local_many_to_many + \ >>> new_class._meta.virtual_fields >>> field_names = set ([f.name for f in new_fields]) >>> >>> if not base._meta.abstract: >>> # Processing "concrete" classes ... >>> if base in o2o_map: >>> field = o2o_map [base] >>> field.primary_key = True >>> new_class._meta.setup_pk (field) >>> else: >>> attr_name = '% s_ptr'% base._meta.module_name >>> field = OneToOneField (base, name = attr_name, >>> auto_created = True, parent_link = True) >>> new_class.add_to_class (attr_name, field) >>> new_class._meta.parents [base] = field >>> >>> else: >>> # .. and abstract. >>> >>> # Check for name collisions between classes >>> # declared in this class and in the abstract ancestor >>> parent_fields = base._meta.local_fields + base._meta.local_many_to_many >>> for field in parent_fields: >>> if field.name in field_names: >>> raise FieldError ('Local field% r in class% r clashes' \ >>> 'with field of similar name from' \ >>> 'abstract base class% r'% \ >>> (field.name, name, base .__ name__)) >>> new_class.add_to_class (field.name, copy.deepcopy (field)) >>> >>> # All non-abstract parents are transferred to the heir. >>> new_class._meta.parents.update (base._meta.parents) >>> >>> # Basic Managers inherit from abstract classes >>> base_managers = base._meta.abstract_managers >>> base_managers.sort () >>> for _, mgr_name, manager in base_managers: >>> val = getattr (new_class, mgr_name, None) >>> if not val or val is manager: >>> new_manager = manager._copy_to_model (new_class) >>> new_class.add_to_class (mgr_name, new_manager) >>> >>> # Virtual fields (like GenericForeignKey) are taken from the parent >>> for field in base._meta.virtual_fields: >>> if base._meta.abstract and field.name in field_names: >>> raise FieldError ('Local field% r in class% r clashes' \ >>> 'with field of similar name from' \ >>> 'abstract base class% r'% \ >>> (field.name, name, base .__ name__)) >>> new_class.add_to_class (field.name, copy.deepcopy (field)) >>>
>>> if abstract: >>> # Abstract models cannot be instantiated and do not appear >>> # in the list of models for the application, therefore, they look a little different than >>> # normal models >>> attr_meta.abstract = False >>> new_class.Meta = attr_meta >>> return new_class
>>> new_class._prepare () >>> register_models (new_class._meta.app_label, new_class) >>> return get_model (new_class._meta.app_label, name, False)
class AttributeInitType (type): def __call __ (self, * args, ** kwargs): obj = type .__ call __ (self, * args) for name in kwargs: setattr (obj, name, kwargs [name]) return obj __metaclass__ = AttributeInitType class Man: pass me = Man (height = 180, weigth = 80) print me.height The standard stream will display: 180
Metaclasses are more than 99% of users should ever worry about. If you people who need it they do not need an explanation of why).
Metaclasses are too much for most users. If at all you are wondering the question is whether they are needed, they are definitely not needed. They are used only by people who know exactly what they are doing and do not need explanations.
Source: https://habr.com/ru/post/65625/
All Articles