Opened 12 years ago

Last modified 6 years ago

## #10467 closed enhancement

# Improve lookup of private attributes — at Version 1

Reported by: | Simon King | Owned by: | tbd |
---|---|---|---|

Priority: | major | Milestone: | sage-4.6.2 |

Component: | categories | Keywords: | private attribute lookup |

Cc: | Merged in: | ||

Authors: | Simon King | Reviewers: | |

Report Upstream: | N/A | Work issues: | |

Branch: | Commit: | ||

Dependencies: | Stopgaps: |

### Description (last modified by )

By a private attribute, I mean an attribute whose name starts with two underscores and does not end with an underscore. Such an attribute is used, e.g., in the default `__repr__`

method of Sage objects.

It should be reasonable to assume that private attributes belong to a particular instance, not to its class or its category; after all, they are subject to Python's name mangling.

In particular, if `P`

is a parent/element, then `P.__foo`

is either defined for the instance `P`

or will not be available from `P.category().parent_class`

resp. from `P.category().element_class`

.

It turns out that this assumption holds thorought Sage: When one lets the `__getattr__`

methods of Parent/Element? immediately raise an `AttributeError`

when a private attribute is requested, then all doc tests still pass.

That is what my patch mainly does. In addition, it removes several occurences of an idiom like

if hasattr(self,'foo'): return self.foo

and replaces it with

try: return self.foo except AttributeError: pass

which saves half of the computation time when the attribute actually exists.

The advantage is a considerable speedup. Here are two examples (the last is actually a serious computation):

Without the patch:

sage: P.<x> = QQ[] sage: timeit('a=repr(x)') 625 loops, best of 3: 74.7 Âµs per loop sage: R.<x,y> = InfinitePolynomialRing(QQ) sage: I = R.ideal([x[1]^2+y[2]*y[3], x[2]*y[1]*x[3]-y[1]*y[2]]) sage: %time I.groebner_basis() CPU times: user 23.09 s, sys: 0.02 s, total: 23.11 s Wall time: 23.67 s [y_2*y_1^3 + y_2*y_1^2, y_2^2*y_1 - y_2*y_1^2, y_3*y_1 - y_2*y_1, x_1*y_2*y_1^2 + x_1*y_2*y_1, x_1^2 + y_2*y_1, x_2*y_2*y_1 - x_1*y_2*y_1, x_2*x_1*y_3 - y_2*y_1, x_3*y_2*y_1 - x_1*y_2*y_1, x_3*x_1*y_2 - y_2*y_1, x_3*x_2*y_1 - y_2*y_1]

With the patch:

sage: P.<x> = QQ[] sage: timeit('a=repr(x)') 625 loops, best of 3: 40.5 Âµs per loop sage: R.<x,y> = InfinitePolynomialRing(QQ) sage: I = R.ideal([x[1]^2+y[2]*y[3], x[2]*y[1]*x[3]-y[1]*y[2]]) sage: %time I.groebner_basis() CPU times: user 14.43 s, sys: 0.03 s, total: 14.46 s Wall time: 14.53 s [y_2*y_1^3 + y_2*y_1^2, y_2^2*y_1 - y_2*y_1^2, y_3*y_1 - y_2*y_1, x_1*y_2*y_1^2 + x_1*y_2*y_1, x_1^2 + y_2*y_1, x_2*y_2*y_1 - x_1*y_2*y_1, x_2*x_1*y_3 - y_2*y_1, x_3*y_2*y_1 - x_1*y_2*y_1, x_3*x_1*y_2 - y_2*y_1, x_3*x_2*y_1 - y_2*y_1]

The patch also adds doctests in `Parent.__getattr__`

, `Element.__getattr__`

and several methods of `SageObject`

.

### Change History (1)

### comment:1 Changed 12 years ago by

Description: | modified (diff) |
---|---|

Status: | new → needs_review |

**Note:**See TracTickets for help on using tickets.