@@ -392,6 +392,7 @@ class C:
392392 verify (C .__spam__ == 1 )
393393 c = C ()
394394 verify (c .__spam__ == 1 )
395+
395396 class _instance (object ):
396397 pass
397398 class M2 (object ):
@@ -420,6 +421,96 @@ def spam(self):
420421 c = C ()
421422 verify (c .spam () == 42 )
422423
424+ # More metaclass examples
425+
426+ class autosuper (type ):
427+ # Automatically add __super to the class
428+ # This trick only works for dynamic classes
429+ # so we force __dynamic__ = 1
430+ def __new__ (metaclass , name , bases , dict ):
431+ # XXX Should check that name isn't already a base class name
432+ dict ["__dynamic__" ] = 1
433+ cls = super (autosuper , metaclass ).__new__ (metaclass ,
434+ name , bases , dict )
435+ while name [:1 ] == "_" :
436+ name = name [1 :]
437+ while name [- 1 :] == "_" :
438+ name = name [:- 1 ]
439+ if name :
440+ name = "_%s__super" % name
441+ else :
442+ name = "__super"
443+ setattr (cls , name , super (cls ))
444+ return cls
445+ class A :
446+ __metaclass__ = autosuper
447+ def meth (self ):
448+ return "A"
449+ class B (A ):
450+ def meth (self ):
451+ return "B" + self .__super .meth ()
452+ class C (A ):
453+ def meth (self ):
454+ return "C" + self .__super .meth ()
455+ class D (C , B ):
456+ def meth (self ):
457+ return "D" + self .__super .meth ()
458+ verify (D ().meth () == "DCBA" )
459+ class E (B , C ):
460+ def meth (self ):
461+ return "E" + self .__super .meth ()
462+ verify (E ().meth () == "EBCA" )
463+
464+ class autogetset (type ):
465+ # Automatically create getset attributes when methods
466+ # named _get_x and/or _set_x are found
467+ def __new__ (metaclass , name , bases , dict ):
468+ hits = {}
469+ for key , val in dict .iteritems ():
470+ if key .startswith ("_get_" ):
471+ key = key [5 :]
472+ get , set = hits .get (key , (None , None ))
473+ get = val
474+ hits [key ] = get , set
475+ elif key .startswith ("_set_" ):
476+ key = key [5 :]
477+ get , set = hits .get (key , (None , None ))
478+ set = val
479+ hits [key ] = get , set
480+ for key , (get , set ) in hits .iteritems ():
481+ dict [key ] = getset (get , set )
482+ return super (autogetset , metaclass ).__new__ (metaclass ,
483+ name , bases , dict )
484+ class A :
485+ __metaclass__ = autogetset
486+ def _get_x (self ):
487+ return - self .__x
488+ def _set_x (self , x ):
489+ self .__x = - x
490+ a = A ()
491+ verify (not hasattr (a , "x" ))
492+ a .x = 12
493+ verify (a .x == 12 )
494+ verify (a ._A__x == - 12 )
495+
496+ class multimetaclass (autogetset , autosuper ):
497+ # Merge of multiple cooperating metaclasses
498+ pass
499+ class A :
500+ __metaclass__ = multimetaclass
501+ def _get_x (self ):
502+ return "A"
503+ class B (A ):
504+ def _get_x (self ):
505+ return "B" + self .__super ._get_x ()
506+ class C (A ):
507+ def _get_x (self ):
508+ return "C" + self .__super ._get_x ()
509+ class D (C , B ):
510+ def _get_x (self ):
511+ return "D" + self .__super ._get_x ()
512+ verify (D ().x == "DCBA" )
513+
423514def pymods ():
424515 if verbose : print "Testing Python subclass of module..."
425516 log = []
@@ -1193,6 +1284,19 @@ def rev(self):
11931284 u = t .rev ()
11941285 verify (u == s )
11951286
1287+ class madunicode (unicode ):
1288+ _rev = None
1289+ def rev (self ):
1290+ if self ._rev is not None :
1291+ return self ._rev
1292+ L = list (self )
1293+ L .reverse ()
1294+ self ._rev = self .__class__ (u"" .join (L ))
1295+ return self ._rev
1296+ u = madunicode ("ABCDEF" )
1297+ verify (u .rev () == madunicode (u"FEDCBA" ))
1298+ verify (u .rev ().rev () == madunicode (u"ABCDEF" ))
1299+
11961300def all ():
11971301 lists ()
11981302 dicts ()
0 commit comments