



  

classtools 0.1 documentation

 [classtools](index.html#document-index)

  

 

[classtools](index.html#document-index)

* [Docs](index.html#document-index) »

* classtools 0.1 documentation

* [Edit on GitHub](https://github.com/eevee/classtools/blob/stable/docs/index.rst)

---

classtools[¶](#module-classtools "Permalink to this headline")

==============================================================

Collection of small class-related utilities that will hopefully save you a

tiny bit of grief, in the vein of itertools and functools.

*class* classtools.classproperty(*desc*, *fget*, *fset=None*, *fdel=None*)[¶](#classtools.classproperty "Permalink to this definition")

Method decorator similar to @property, but called like a

classmethod.

```

class Square(object):

    @classproperty

    def num\_sides(cls):

        return 4

```

Setting and deleting are not supported, due to the design of the descriptor

protocol. If you need a class property you can set or delete, you need to

create a metaclass and put a regular @property on it.

This decorator is of questionable use for normal classes, but may be

helpful for “declarative” classes such as enums.

*class* classtools.frozenproperty(*fget*)[¶](#classtools.frozenproperty "Permalink to this definition")

Similar to the built-in @property decorator, but without support for

setters or deleters. This makes it a “non-data” descriptor, which you can

overwrite directly. Compare:

```

class Cat(object):

    @property

    def num\_legs(self):

        return 2 + 2

```

```

>>> cat = Cat()

>>> cat.num\_legs

4

>>> cat.num\_legs = 5

...

AttributeError: can't set attribute

```

Versus:

```

class Cat(object):

    @frozenproperty

    def num\_legs(self):

        return 2 + 2

```

```

>>> cat = Cat()

>>> cat.num\_legs

4

>>> cat.num\_legs = 5

>>> cat.num\_legs

5

```

classtools.keyed\_ordering(*cls*)[¶](#classtools.keyed_ordering "Permalink to this definition")

Class decorator to generate all six rich comparison methods, based on a

\_\_key\_\_ method.

Many simple classes are wrappers for very simple data, and want to defer

comparisons to that data. Rich comparison is very flexible and powerful,

but makes this simple case tedious to set up. There’s the standard

library’s total\_ordering decorator, but it still requires you to write

essentially the same method twice, and doesn’t correctly handle

NotImplemented before 3.4.

With this decorator, comparisons will be done on the return value of

\_\_key\_\_, in much the same way as the key argument to sorted.

For example, if you have a class representing a span of time:

```

@keyed\_ordering

class TimeSpan(object):

    def \_\_init\_\_(self, start, end):

        self.start = start

        self.end = end

    def \_\_key\_\_(self):

        return (self.start, self.end)

```

This is equivalent to the following, assuming 3.4’s total\_ordering:

```

@total\_ordering

class TimeSpan(object):

    def \_\_init\_\_(self, start, end):

        self.start = start

        self.end = end

    def \_\_eq\_\_(self, other):

        if not isinstance(other, TimeSpan):

            return NotImplemented

        return (self.start, self.end) == (other.start, other.end)

    def \_\_lt\_\_(self, other):

        if not isinstance(other, TimeSpan):

            return NotImplemented

        return (self.start, self.end) < (other.start, other.end)

```

The NotImplemented check is based on the class being decorated, so

subclassses can still be correctly compared.

You may also implement some of the rich comparison methods in the decorated

class, in which case they’ll be left alone.

*class* classtools.reify(*wrapped*)[¶](#classtools.reify "Permalink to this definition")

Method decorator similar to @property, except that after the wrapped

method is called, its return value is stored in the instance dict,

effectively replacing this decorator. The name means “to make real”,

because some value becomes a “real” instance attribute as soon as it’s

computed.

The wrapped method is thus only called once at most, making this decorator

particularly useful for lazy/delayed creation of resources, or expensive

computations that will always have the same result but may not be needed at

all. For example:

```

class Resource(object):

    @reify

    def result(self):

        print('fetching result')

        return "foo"

```

```

>>> r = Resource()

>>> r.result

fetching result

'foo'

>>> r.result

'foo'

>>> # result not called the second time, because r.result is now populated

```

Because this is a “non-data descriptor”, it’s possible to set or delete the

attribute:

```

>>> r.result = "bar"

>>> r.result

'bar'

>>> del r.result

>>> r.result

fetching result

'foo'

```

Deleting the attribute causes the wrapped method to be called again on the

next read. While it’s possible to take advantage of this to create a cache

with manual eviction, the author strongly advises you not to think of this

decorator as merely a caching mechanism. Strictly speaking, cache eviction

should only ever affect performance, but consider the following:

```

class Database(object):

    @reify

    def connection(self):

        return dbapi.connect(...)

```

Here, reify is used as lazy initialization, and its return value is a

(mutable!) handle to some external resource. That handle is not cached in

any meaningful sense: its permanence is guaranteed by the class. Having it

transparently evicted and recreated would not only destroy the illusion

that it’s a regular attribute, but completely break the class’s semantics.

*class* classtools.weakattr(*name*)[¶](#classtools.weakattr "Permalink to this definition")

Descriptor that transparently wraps its stored value in a weak

reference. Reading this attribute will never raise AttributeError; if

the reference is broken or missing, you’ll just get None.

To use, create a weakattr in the class body and assign to it as normal.

You must provide an attribute name, which is used to store the actual

weakref in the instance dict.

```

class Foo(object):

    bar = weakattr('bar')

    def \_\_init\_\_(self, bar):

        self.bar = bar

```

```

>>> class Dummy(object): pass

>>> obj = Dummy()

>>> foo = Foo(obj)

>>> assert foo.bar is obj

>>> print(foo.bar)

<object object at ...>

>>> del obj

>>> print(foo.bar)

None

```

Of course, if you try to assign a value that can’t be weak referenced,

you’ll get a TypeError. So don’t do that. In particular, a lot of

built-in types can’t be weakref’d!

Note that due to the \_\_dict\_\_ twiddling, this descriptor will never

trigger \_\_getattr\_\_, \_\_setattr\_\_, or \_\_delattr\_\_.

