Ticket #11999 (needs_work defect)
Renaming lazy attributes
| Reported by: | SimonKing | Owned by: | jason |
|---|---|---|---|
| Priority: | major | Milestone: | sage-5.10 |
| Component: | misc | Keywords: | |
| Cc: | nthiery | Work issues: | |
| Report Upstream: | N/A | Reviewers: | Travis Scrimshaw |
| Authors: | Simon King | Merged in: | |
| Dependencies: | Stopgaps: |
Description
Currently, it is not possible to take an existing lazy attribute and assign it to a different name. The reason is that a lazy attribute overwrites itself by a usual attribute of its __name__. But __name__ is created during initialisation of the lazy attribute. Thus, we have the following example:
sage: class Foo(object): ....: @lazy_attribute ....: def _bar(self): ....: return 5 ....: bar = _bar ....: sage: f = Foo() sage: f.bar # it seems to work,... 5 sage: f.__dict__['bar'] # ... but the lazy attribute has not become a usual attribute Traceback (most recent call last): ... KeyError: 'bar' sage: f.__dict__['_bar'] 5
By consequence, f.bar is much slower than f._bar:
sage: %timeit f.bar 625 loops, best of 3: 2.78 µs per loop sage: %timeit f._bar 625 loops, best of 3: 185 ns per loop
I suggest to provide lazy attributes with a method rename(), returning a copy of that lazy attribute under a new name.
Example, which is a doc test of my patch:
sage: class Foo(object):
....: @lazy_attribute
....: def _bar(self):
....: return 5
....: bar = _bar.rename("bar")
....:
sage: f = Foo()
sage: f.bar
5
sage: f.__dict__['bar']
5
sage: %timeit f.bar
625 loops, best of 3: 184 ns per loop
sage: %timeit f._bar
625 loops, best of 3: 184 ns per loop
Attachments
Change History
Changed 19 months ago by SimonKing
-
attachment
trac11999_lazy_attribute_rename.patch
added
comment:4 Changed 7 months ago by tscrim
- Status changed from needs_review to needs_work
- Reviewers set to Travis Scrimshaw
I believe you should mention that the renamed name needs to match.
sage: class Foo(object):
....: @lazy_attribute
....: def attr(self):
....: return 5
....: bar = attr
....: renamed = attr.rename("renamed")
....: diffname = attr.rename("renamed")
....:
sage: f = Foo()
sage: f.bar
5
sage: f.attr
5
sage: f.renamed
5
sage: f.diffname
5
sage: %timeit f.bar
625 loops, best of 3: 15.8 µs per loop
sage: %timeit f.attr
625 loops, best of 3: 344 ns per loop
sage: %timeit f.renamed
625 loops, best of 3: 355 ns per loop
sage: %timeit f.diffname
625 loops, best of 3: 23.2 µs per loop
sage: f.__dict__
{'renamed': 5, 'attr': 5}
Additionally please use auto trac linking :trac:`11999` in the doc. Functionally it looks good.

Add the possibility to rename a lazy attribute