cdxcore.pretty#
A simple cdxcore.pretty.PrettyObject
class which mimics directory access to its members.
Overview#
The purpose is a functional-programming style pattern for generating complex objects:
from cdxbasics.prettydict import PrettyObject
pdct = PrettyObject(z=1)
pdct.num_samples = 1000
pdct.num_batches = 100
pdct.method = "signature"
The object allows accessing members via []
:
print( pdct[‘num_samples’] ) # -> 1000 print( pdct[‘num_batches’] ) # -> 100
Features#
cdxcore.pretty.PrettyObject
implements all relevant dictionary protocols, so objects of type cdxcore.pretty.PrettyObject
can
(nearly always) be passed where dictionaries are expected:
A
cdxcore.pretty.PrettyObject
object supports standard dictionary semantics in addition to member attribute access. That means you can usepdct['num_samples']
as well aspdc.num_samples
. You can mix standard dictionary notation with member attribute notation:print(pdct["num_samples"]) # -> prints "1000" pdct["test"] = 1 # sets pdct.test to 1
Iterations work just like for dictionaries; for example:
for k,v in pdct.items(): print( k, v)
Applying
str
andrepr
to objects of typecdxcore.pretty.PrettyObject
will return dictionary-type results, so for exampleprint(pdct)
of the above will return{'z': 1, 'num_samples': 1000, 'num_batches': 100, 'method': 'signature'}
.
The cdxcore.pretty.PrettyObject.at_pos
attribute allows accessing elements of the ordered dictionary
by positon:
cdxcore.pretty.PrettyObject.at_pos[i]
returns the i th element.cdxcore.pretty.PrettyObject.at_pos.keys[i]
returns the i th key.cdxcore.pretty.PrettyObject.at_pos.items[i]
returns the i th item.
For example:
print(pdct.at_pos[3]) # -> prints "signature"
print(pdct.at_pos.keys[3]) # -> prints "method"
You can also assign member functions to a cdxcore.pretty.PrettyObject
.
The following works as expected:
pdct.f = lambda self, y: return self.y*x
(to assign a static function which does not refer to self
, use pdct['g'] = lambda z : return z
).
Dataclasses#
dataclasses
rely on default values of any member being “frozen” objects, which most user-defined objects and
cdxcore.pretty.PrettyObject
objects are not.
This limitation applies as well to flax modules.
To use non-frozen default values, use the
cdxcore.pretty.PrettyObject.as_field()
function:
from cdxbasics.prettydict import PrettyObject
from dataclasses import dataclass
@dataclass
class Data:
data : PrettyObject = PrettyObject(x=2).as_field()
def f(self):
return self.data.x
d = Data() # default constructor used.
d.f() # -> returns 2
Import#
from cdxcore.pretty import PrettyObject as pdct
Documentation#
Classes
|
Class mimicing an ordered dictionary. |
- class cdxcore.pretty.PrettyObject(copy=None, **kwargs)[source]#
Bases:
MutableMapping
Class mimicing an ordered dictionary.
Example:
from cdxcore.pretty import PrettyObject pdct = PrettyObject() pdct.x = 1 pdct['y'] = 2 print( pdct['x'], pdct.y ) # -> prints 1 2
The object mimics a dictionary:
print(pdct) # -> '{'x': 1, 'y': 2}' u = dict( pdct ) print(u) # -> {'x': 1, 'y': 2} u = { k: 2*v for k,v in pdct.items() } print(u) # -> {'x': 2, 'y': 4} l = list( pdct ) print(l) # -> ['x', 'y']
Important: attributes starting with ‘__’ cannot be accessed with item
[]
notation. In other words:pdct = PrettyObject() pdct.__x = 1 # fine _ = pdct['__x'] # <- throws an exception
Access by Index Position
cdxcore.pretty.PrettyObject
retains order of construction. To access its members by index position, use thecdxcore.pretty.PrettyObject.at_pos
attribute:print(pdct.at_pos[1]) # -> prints "2" print(pdct.at_pos.keys[1]) # -> prints "y" print(list(pdct.at_pos.items[2])) # -> prints "[('x', 1), ('y', 2)]"
Assigning Member Functions
PrettyObject
objects also allow assigning bona fide member functions by a simple semantic of the form:pdct = PrettyObject(b=2) pdct.mult_b = lambda self, x: self.b*x pdct.mult_b(3) # -> 6
Calling
pdct.mult_b(3)
with abovepdct
will return 6 as expected. To assign static member functions, use the[]
operator. The reason for this is as follows: consider:def mult( a, b ): return a*b pdct = PrettyObject() pdct.mult = mult pdct.mult(3,4) --> produces am error as three arguments must be passed: self, 3, and 4
In this case, use:
pdct = PrettyObject() pdct['mult'] = mult pdct.mult(3,4) --> 12
You can also pass member functions to the constructor:
p = PrettyObject( f=lambda self, x: self.y*x, y=2) p.f(3) # -> 6
Operators
Objects of type
cdxcore.pretty.PrettyObject
support the following operators:Comparison operator
==
and!=
test for equality of keys and values. Unlike for dictionaries comparisons are performed in in order. That meansPrettyObject(x=1,y=2)
andPrettyObject(y=2,x=1)
are not equal.Super/subset operators
>=
and<=
test for a super/sup set relationship, respectively.The
a | b
returns the union of twocdxcore.pretty.PrettyObject
. Elements of theb
overwrite any elements ofa
, if they are present in both. The order of the new dictionary is determined by the order of appearance of keys in firsta
and thenb
, that means in all but trivial casesa|b != b|a
.The
|=
operator is a short-cut forcdxcore.pretty.PrettyObject.update()
.
- Parameters:
- copyMapping, optional
If present, assign elements of
copy
toself
.- ** kwargs:
Key/value pairs to be added to
self
.
- Attributes:
at_pos
Elementary access to the data contained in
self
by ordinal position.
Methods
as_field
()This function provides support for
dataclasses.dataclass
fields withPrettyObject
default values.clear
()Delete all elements.
copy
(**kwargs)Return a shallow copy; optionally add further key/value pairs.
get
(key[, default])Equivalent to
dict.get()
.items
()Equivalent to
dict.items()
keys
()Equivalent to
dict.keys()
pop
(key[, default])Equivalent to
dict.pop()
.popitem
()as a 2-tuple; but raise KeyError if D is empty.
setdefault
(key[, default])Equivalent to
dict.setdefault()
.update
([other])Equivalent to
dict.update()
.values
()Equivalent to
dict.values()
- as_field()[source]#
This function provides support for
dataclasses.dataclass
fields withPrettyObject
default values.When adding a field with a non-frozen default value to a
@dataclass
class, adefault_factory
has to be provided. The functionas_field
returns the correspondingdataclasses.Field
element by returning simply:def factory(): return self return dataclasses.field( default_factory=factory )
Usage is as follows:
from dataclasses import dataclass @dataclass class A: data : PrettyDict = PrettyDict(x=2).as_field() a = A() print(a.data.x) # -> "2" a = A(data=PrettyDict(x=3)) print(a.data.x) # -> "3"
- property at_pos#
Elementary access to the data contained in
self
by ordinal position. The ordinal position of an element is determined by the order of addition to the dictionary.at_pos[position]
returns an element or elements at an ordinal position:It returns a single element if
position
refers to only one field.If
position
is a slice then the respecitve list of fields is returned.
at_pos.keys[position]
returns the key or keys atposition
.at_pos.items[position]
returns the tuple(key, element)
or a list thereof forposition
.
You can also write data using the attribute notation:
at_pos[position] = item
assigns an item to an ordinal position:If
position
refers to a single element,item
must be the value to be assigned to this element.If
position
is a slice then ‘item
must resolve to a list (or generator) of the required size.
- get(key, default=<cdxcore.pretty.__No_Default_dummy object>)[source]#
Equivalent to
dict.get()
.
- items()[source]#
Equivalent to
dict.items()
- keys()[source]#
Equivalent to
dict.keys()
- pop(key, default=<cdxcore.pretty.__No_Default_dummy object>)[source]#
Equivalent to
dict.pop()
.
- setdefault(key, default=None)[source]#
Equivalent to
dict.setdefault()
.
- update(other=None, **kwargs)[source]#
Equivalent to
dict.update()
.Note that functon assignments are handled in normal dictionary fashion - in particular, bound functions will not become magically unbound.
- values()[source]#
Equivalent to
dict.values()