Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] - نسخه متنی

David Ascher, Alex Martelli, Anna Ravenscroft

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید







Recipe 20.10. Using _ _new_ _ and _ _init_ _ Appropriately in Custom Metaclasses


Credit: Michele Simionato, Stephan Diehl, Alex
Martelli


Problem


You are writing a custom metaclass, and you are not sure which tasks
your metaclass should perform in its _ _new_ _
method, and which ones it should perform in its _ _init_
_
method instead.


Solution


Any preliminary processing that your custom metaclass performs on the
name, bases, or dict of the class being built, can affect the way in
which the class object gets built only if it occurs in the
metaclass' _ _new_ _ method,
before your code calls the
metaclass' superclass' _
_new_ _
. For example, that's the only time
when you can usefully affect the new class'
_ _slots_ _, if any:

class MetaEnsure_foo(type):
def _ _new_ _(mcl, cname, cbases, cdict):
# ensure instances of the new class can have a '_foo' attribute
if '_ _slots_ _' in cdict and '_foo' not in cdict['_ _slots_ _']:
cdict['_ _slots_ _'] = tuple(cdict['_ _slots_ _']) + ('_foo',)
return super(MetaEnsure_foo, mcl)._ _new_ _(mcl, cname, cbases, cdict)

Metaclass method _ _init_ _ is generally the most
appropriate one for any changes that your custom metaclass makes to
the class object after the class object is
builtfor example, continuing the example code for metaclass
MetaEnsure_foo:

    def _ _init_ _(cls, cname, cbases, cdict):
super(MetaEnsure_foo, cls)._ _init_ _(cls, cname, cbases, cdict)
cls._foo = 23


Discussion


The custom metaclass MetaEnsure_foo performs a
definitely "toy" task presented
strictly as an example: if the class object being built defines a
_ _slots_ _ attribute (to save memory),
MetaEnsure_foo ensures that the class object
includes a slot _foo, so that instances of that
class can have an attribute thus named. Further, the custom metaclass
sets an attribute with name _foo and value 23 on
each new class object. The point of the recipe isn't
really this toy task, but rather, a clarification on how _
_new_ _
and _ _init_ _ methods of a
custom metaclass are best coded, and which tasks are most appropriate
for each.

Whenever you instantiate any class x
(whether x is a custom metaclass or an
ordinary class) with or without arguments (we can employ the usual
Python notation *a, **k to mean
arbitrary positional and named arguments), Python internally performs
the equivalent of the following snippet of code:

    new_thing = X._ _new_ _(X, *a, **k)
if isinstance(new_thing, X):
X._ _init_ _(new_thing, *a, **k)

The new_thing thus built and initialized is the
result of instantiating x. If
x is a custom metaclass, in particular,
this snippet occurs at the end of the execution of a
class statement, and the arguments (all
positional) are the name, bases, and dictionary of the new class that
is being built.

So, your custom metaclass' _ _new_
_
method is the code that has dibsit executes first.
That's the moment in which you can adjust the name,
bases, and dictionary that you receive as arguments, to affect the
way the new class object is built. Most characteristics of the class
object, but not all, can also be changed later. An example of an
attribute that you have to set before building
the class object is _ _slots_ _. Once the class
object is built, the slots, if any, are defined, and any further
change to _ _slots_ _ has no effect.

The custom metaclass in this recipe carefully uses
super to delegate work to its superclass, rather
than carelessly calling type._ _new_ _ or
type._ _init_ _ directly: the latter usage would
be a subtle mistake, impeding the proper working of multiple
inheritance among metaclasses. Further, this recipe is careful in
naming the first parameters to both methods: cls to
mean an ordinary class (the object that is the first argument to a
custom metaclass' _ _init_ _),
mcl to mean a metaclass (the object that is the
first argument to a custom metaclass' _
_new_ _
). The common usage of self should
be reserved to mean normal instances, not classes nor metaclasses,
and therefore it doesn't normally occur in the body
of a custom metaclass. All of these names are a matter of mere
convention, but using appropriate conventions promotes clarity, and
this use of cls and mcl was blessed
by Guido van Rossum himself, albeit only verbally.

The usage distinction between _ _new_ _ and
_ _init_ _ that this recipe advocates for custom
metaclasses is basically the same criterion that
any class should always follow: use _
_new_ _
when you must, only for jobs that cannot be done
later; use _ _init_ _ for all jobs that can be
left until _ _init_ _ time. Following these
conventions makes life easiest for anybody who must tweak your custom
metaclass or make it work well in a multiple inheritance situation,
and thus enhances the reusability of your code. _ _new_
_
should contain only the essence of
your metaclass: stuff that anybody using your metaclass in any way at
all must surely want (or else he
wouldn't be using your metaclass!) because
it's stuff that's not easy to
tweak, modify, or override. _ _init_ _ is
"softer", so most of what your
metaclass is doing to the class objects you generate, should be
there, exactly because it will be easier for reusers to tweak or
avoid.


See Also


Library Reference and Python in a
Nutshell
docs on built-ins super and
_ _slots_ _, and special methods _ _init_
_
and _ _new_ _.


/ 394