Bindable classes¶
- class sage.misc.bindable_class.BindableClass[source]¶
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()
>>> from sage.all import * >>> from sage.misc.nested_class import NestedClassMetaclass >>> 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) >>> 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
>>> from sage.all import * >>> 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)
>>> from sage.all import * >>> x = outer.Inner(Integer(1),Integer(2),Integer(3)) (1, 2, 3)
This is similar to what happens with a static method:
sage: outer.f../_static(1,2,3) (1, 2, 3)
>>> from sage.all import * >>> outer.f../_static(Integer(1),Integer(2),Integer(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)
>>> from sage.all import * >>> outer.f(Integer(1),Integer(2),Integer(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 ...>>
>>> from sage.all import * >>> 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)
>>> from sage.all import * >>> Outer.f(outer, Integer(1),Integer(2),Integer(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))
>>> from sage.all import * >>> from sage.misc.bindable_class import BindableClass >>> 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'>
>>> from sage.all import * >>> 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)
>>> from sage.all import * >>> outer = Outer() >>> x = outer.Inner(Integer(1),Integer(2),Integer(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 ...>>
>>> from sage.all import * >>> 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'>]
>>> from sage.all import * >>> type(outer.Inner).mro() [<class 'sage.misc.bindable_class.BoundClass'>, <... 'functools.partial'>, <... 'object'>]
Still, documentation works as usual:
sage: outer.Inner.__doc__ ' some documentation '
>>> from sage.all import * >>> outer.Inner.__doc__ ' some documentation '
- class sage.misc.bindable_class.Inner2[source]¶
Bases:
BindableClass
Some documentation for Inner2