Metaprogramming¶
Autoname¶
Access an object’s name as a property
Autoname is a data-descriptor, which automatically looks up the name under which the object on which the descriptor is accessed is known by.
Import the descriptor using from mtoolbox.autoname import Autoname
.
Example
>>> class Object(object):
... name = Autoname()
>>> o = Object()
>>> o.name
'o'
By default Autoname will return the outer-most name that was defined for the object:
>>> class Object(object):
... name = Autoname()
>>> def func(anobject):
... return anobject.name
>>> o = Object()
>>> func(o)
'o'
You can change this behaviour by using the ‘inner’ keyword:
>>> class Object(object):
... name = Autoname(inner=True)
>>> o = Object()
>>> def func(anobject):
... return anobject.name
>>> func(o)
'anobject'
Note
Please be aware, that getting the inner-most name, is not what you want in most cases:
>>> class Object(object):
... name = Autoname(inner=True)
... def printname(self):
... print(self.name)
>>> o = Object()
>>> o.printname()
self
Warning
Defining multiple names for an object in the same call frame (which is easily said the same level of indention in your program) will cause undefinied behaviour, depending on the Python interpreter:
>>> class Object(object):
... name = Autoname()
>>> o = Object()
>>> g = o
>>> o.name in ['o', 'g']
True
-
class
mtoolbox.autoname.
Autoname
(initval=True, inner=False)[source]¶ Bases:
object
Create a new Autoname descriptor
Parameters: - initval (str, bool, None) – The initial name
- inner (bool) – Return the inner-most name of the object (or not)
Returns: An Autoname instance
Return type: -
__get__
(theobject, objtype)[source]¶ Return the name of theobject or None
Returns: the name of the object Return type: str or None Usage:
>>> class Object(object): ... name = Autoname() >>> obj = Object() >>> obj.name 'obj' >>> obj.name = 'another name' >>> obj.name 'another name'
-
__set__
(theobject, val)[source]¶ Set the name of the theobject
Parameters: - theobject (object) – The object to which’s class the descriptor is attached to
- val (str, bool or None) – Sets the name to depending on the type: str sets the name to this str. False or None sets the name to None. True sets the name to automatically lookup.
Returns: None
Raises: TypeError if type(val) is invalid
- Usage:
>>> class Object(object): ... name = Autoname() >>> o = Object() >>> o.name = 'k' >>> o.name 'k' >>> o.name = True >>> o.name 'o' >>> o.name = False >>> str(o.name) 'None' >>> o.name = 4 Traceback (most recent call last): ... TypeError: Autoname must be set to str, bool, NoneType
ILists¶
Module to provide an ‘intelligent’ list class
The IList class translates attribute access to the items it holds:
l.<name> == IList([obj.<name> for obj in l])
Import the IList class using from mtoolbox.ilist import IList
.
Example
>>> l = IList([complex(3, 4), complex(6)])
>>> l.real
[3.0, 6.0]
You can also use callable attributes of your objects:
>>> l = IList([complex(3, 4), complex(6)])
>>> l
[(3+4j), (6+0j)]
>>> l.conjugate()
[(3-4j), (6-0j)]
You can add callbacks, for appending and removing objects. These callbacks must accept two positional arguments - the list and the object. The callbacks are called _after_ executing append or remove:
>>> def on_append(l, x):
... print("Adding %s to %s." % (x, l))
>>> def on_remove(l, x):
... print("Removing %s from %s." % (x, l))
>>> l = IList(on_append=on_append, on_remove=on_remove)
>>> l.append(3)
Adding 3 to [3].
>>> l.remove(3)
Removing 3 from [].
>>> def invalid_callback(l):
... print(l)
>>> l = IList(on_append=invalid_callback)
Traceback (most recent call last):
...
TypeError: on_append and on_remove must accept 2 positional arguments
>>> l = IList(on_append=3)
Traceback (most recent call last):
...
TypeError: on_append and on_remove must accept 2 positional arguments
>>> def valid_callback(l=[], x=5):
... pass
>>> def valid_callback2(l, x=5, y=3):
... pass
>>> l = IList(on_append=valid_callback, on_remove=valid_callback2)
Be aware, that only attribute names, that are not used by the list class are overwritten, so if list implemented a attribute name, you can’t use it in this way. The following code doesn’t work, because list implements ‘__add__’ (so the result is NOT [4, 5] as one could expect):
>>> l = IList([1, 2])
>>> l + 3
Traceback (most recent call last):
...
TypeError: can only concatenate list (not "int") to list
If you wish to access attributes with these names, you can use
IList.getattr()
(see method documentation).
You can also apply any function to the items of an IList by
calling IList.apply()
(see method documentation).
-
class
mtoolbox.ilist.
IList
(iterable=None, on_append=None, on_remove=None)[source]¶ Bases:
list
‘intelligent’ list object
Parameters: Returns: An
IList
instanceReturn type: Note
Both callbacks must accept two positional arguments
-
append
(obj)[source]¶ Add obj to IList
Parameters: obj (object) – object to append to list Returns: None - Usage:
>>> l = IList() >>> l [] >>> l.append(3) >>> l [3]
-
apply
(func, *args, **kwargs)[source]¶ Apply func to the items of this IList
Parameters: Returns: An
IList
instanceReturn type: - Usage:
>>> def f(x, pow=2): ... return x**pow >>> l = IList([0, 1, 2, 3, 4, 5]) >>> l.apply(f, pow=3) [0, 1, 8, 27, 64, 125]
-