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 from BindableClass, and if outer is an instance of Outer, then outer.Inner(...) is equivalent to Outer.Inner(outer, ...).

EXAMPLES:

Let us consider the following class Outer with a nested class Inner:

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 self, args
...
...       @staticmethod
...       def f_static(*args):
...           print args
...
sage: outer = Outer()

By default, when Inner is a class nested in Outer, accessing outer.Inner returns the Inner 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 receive outer 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 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 to Outer.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'>,
 <type 'functools.partial'>,
 <type 'object'>]

Still, documentation works as usual:

sage: outer.Inner.__doc__
' some documentation '

TESTS:

sage: from sage.misc.bindable_class import Outer
sage: TestSuite(Outer.Inner).run()
sage: outer = Outer()
sage: TestSuite(outer.Inner).run(skip=["_test_pickling"])
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

Outer.Inner2

alias of Inner2

Previous topic

ASCII Art

Next topic

Cached Functions and Methods

This Page