Bindable classes¶
-
class
sage.misc.bindable_class.
BindableClass
¶ Bases:
object
Bindable classes
This class implements a binding behavior for nested classes that derive from it. Namely, if a nested class
Outer.Inner
derives fromBindableClass
, and ifouter
is an instance ofOuter
, thenouter.Inner(...)
is equivalent toOuter.Inner(outer, ...)
.EXAMPLES:
Let us consider the following class
Outer
with a nested classInner
:sage: from sage.misc.nested_class import NestedClassMetaclass sage: class Outer: ....: __metaclass__ = NestedClassMetaclass # just a workaround for Python misnaming nested classes ....: ....: class Inner: ....: def __init__(self, *args): ....: print(args) ....: ....: def f(self, *args): ....: print("{} {}".format(self, args)) ....: ....: @staticmethod ....: def f_static(*args): ....: print(args) sage: outer = Outer()
By default, when
Inner
is a class nested inOuter
, accessingouter.Inner
returns theInner
class as is:sage: outer.Inner is Outer.Inner True
In particular,
outer
is completely ignored in the following call:sage: x = outer.Inner(1,2,3) (1, 2, 3)
This is similar to what happens with a static method:
sage: outer.f_static(1,2,3) (1, 2, 3)
In some cases, we would want instead
Inner`
to receiveouter
as parameter, like in a usual method call:sage: outer.f(1,2,3) <__main__.Outer object at ...> (1, 2, 3)
To this end,
outer.f
returns a bound method:sage: outer.f <bound method Outer.f of <__main__.Outer object at ...>>
so that
outer.f(1,2,3)
is equivalent to:sage: Outer.f(outer, 1,2,3) <__main__.Outer object at ...> (1, 2, 3)
BindableClass
gives this binding behavior to all its subclasses:sage: from sage.misc.bindable_class import BindableClass sage: class Outer: ....: __metaclass__ = NestedClassMetaclass # just a workaround for Python misnaming nested classes ....: ....: class Inner(BindableClass): ....: " some documentation " ....: def __init__(self, outer, *args): ....: print("{} {}".format(outer, args))
Calling
Outer.Inner
returns the (unbound) class as usual:sage: Outer.Inner <class '__main__.Outer.Inner'>
However,
outer.Inner(1,2,3)
is equivalent toOuter.Inner(outer, 1,2,3)
:sage: outer = Outer() sage: x = outer.Inner(1,2,3) <__main__.Outer object at ...> (1, 2, 3)
To achieve this,
outer.Inner
returns (some sort of) bound class:sage: outer.Inner <bound class '__main__.Outer.Inner' of <__main__.Outer object at ...>>
Note
This is not actually a class, but an instance of
functools.partial
:sage: type(outer.Inner).mro() [<class 'sage.misc.bindable_class.BoundClass'>, <... 'functools.partial'>, <... 'object'>]
Still, documentation works as usual:
sage: outer.Inner.__doc__ ' some documentation '
-
class
sage.misc.bindable_class.
BoundClass
(*args)¶ Bases:
functools.partial
-
class
sage.misc.bindable_class.
Inner2
¶ Bases:
sage.misc.bindable_class.BindableClass
Some documentation for Inner2
-
class
sage.misc.bindable_class.
Outer
¶ Bases:
object
A class with a bindable nested class, for testing purposes
-
class
Inner
¶ Bases:
sage.misc.bindable_class.BindableClass
Some documentation for Outer.Inner
-
class