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): ....: 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): ....: 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