# HG changeset patch
# User Simon King <simon.king@uni-jena.de>
# Date 1318941258 -7200
# Node ID d55939d59984b8053eea8c591c44b1f8de0188ef
# Parent 5a230a7dc86c584e7faf3a5c9665ee6a7547342a
#11935: Use a weak form of "pickling by construction" for parent and element classes of a category.
diff --git a/sage/categories/category.py b/sage/categories/category.py
a
|
b
|
|
704 | 704 | <class 'sage.categories.algebras.Algebras.parent_class'> |
705 | 705 | sage: type(C) |
706 | 706 | <class 'sage.structure.dynamic_class.DynamicMetaclass'> |
| 707 | |
| 708 | By trac ticket #11935, a parent class only depends on the base ring |
| 709 | of a category if the choice of the base ring alters the type of the |
| 710 | super categories. A typical example is the category of algebras over |
| 711 | a field versus algebras over a non-field. |
| 712 | :: |
| 713 | |
| 714 | sage: Algebras(QQ).parent_class is Algebras(GF(3)).parent_class |
| 715 | True |
| 716 | sage: Algebras(QQ).parent_class is Algebras(ZZ).parent_class |
| 717 | False |
| 718 | sage: Algebras(ZZ['t']).parent_class is Algebras(ZZ['t','x']).parent_class |
| 719 | True |
| 720 | |
707 | 721 | """ |
708 | | # Remark: |
709 | | # For now, we directly call the underlying function, avoiding the overhead |
710 | | # of using a cached function. The rationale: When this lazy method is called |
711 | | # then we can be sure that the parent class had not been constructed before. |
712 | | # The parent and element classes belong to a category, and they are pickled |
713 | | # as such. Hence, they are rightfully cached as an attribute of a category. |
714 | | # |
715 | | # However, we should try to "unify" parent classes. They should depend on the |
716 | | # super categories, but not on the base (except when the super categories depend |
717 | | # on the base). When that is done, calling the cached function will be needed again. |
718 | | #return dynamic_class("%s.parent_class"%self.__class__.__name__, |
719 | | # tuple(cat.parent_class for cat in self.super_categories()), |
720 | | # self.ParentMethods, |
721 | | # reduction = (getattr, (self, "parent_class"))) |
722 | | return dynamic_class_internal.f("%s.parent_class"%self.__class__.__name__, |
| 722 | try: |
| 723 | return dynamic_class_internal.cache[("%s.parent_class"%self.__class__.__name__, |
723 | 724 | tuple(cat.parent_class for cat in self.super_categories()), |
724 | | self.ParentMethods, |
725 | | reduction = (getattr, (self, "parent_class"))) |
| 725 | self.ParentMethods, None, None), ()] |
| 726 | except KeyError: |
| 727 | # Use the cache in a way that does not depend on the reduction data. |
| 728 | # The reduction is inserted afterwards. It is by construction. Since |
| 729 | # the parent class is not only cached as a dynamic class but also as |
| 730 | # an attribute of a category, the cache will not break. |
| 731 | C = dynamic_class_internal("%s.parent_class"%self.__class__.__name__, |
| 732 | tuple(cat.parent_class for cat in self.super_categories()), |
| 733 | self.ParentMethods) |
| 734 | C._reduction = (getattr, (self, "parent_class")) |
| 735 | return C |
726 | 736 | |
727 | 737 | @lazy_attribute |
728 | 738 | def element_class(self): |
… |
… |
|
735 | 745 | <class 'sage.categories.algebras.Algebras.element_class'> |
736 | 746 | sage: type(C) |
737 | 747 | <class 'sage.structure.dynamic_class.DynamicMetaclass'> |
| 748 | |
| 749 | By trac ticket #11935, an element class only depends on the base ring |
| 750 | of a category if the choice of the base ring alters the type of the |
| 751 | super categories. A typical example is the category of algebras over |
| 752 | a field versus algebras over a non-field. |
| 753 | :: |
| 754 | |
| 755 | sage: Algebras(QQ).element_class is Algebras(GF(3)).element_class |
| 756 | True |
| 757 | sage: Algebras(QQ).element_class is Algebras(ZZ).element_class |
| 758 | False |
| 759 | sage: Algebras(ZZ['t']).element_class is Algebras(ZZ['t','x']).element_class |
| 760 | True |
| 761 | |
738 | 762 | """ |
739 | | # Remark: |
740 | | # For now, we directly call the underlying function, avoiding the overhead |
741 | | # of using a cached function. The rationale: When this lazy method is called |
742 | | # then we can be sure that the element class had not been constructed before. |
743 | | # The parent and element classes belong to a category, and they are pickled |
744 | | # as such. Hence, they are rightfully cached as an attribute of a category. |
745 | | # |
746 | | # However, we should try to "unify" element classes. They should depend on the |
747 | | # super categories, but not on the base (except when the super categories depend |
748 | | # on the base). When that is done, calling the cached function will be needed again. |
749 | | #return dynamic_class("%s.element_class"%self.__class__.__name__, |
750 | | # (cat.element_class for cat in self.super_categories()), |
751 | | # self.ElementMethods, |
752 | | # reduction = (getattr, (self, "element_class")) |
753 | | # ) |
754 | | return dynamic_class_internal.f("%s.element_class"%self.__class__.__name__, |
| 763 | try: |
| 764 | return dynamic_class_internal.cache[("%s.element_class"%self.__class__.__name__, |
755 | 765 | tuple(cat.element_class for cat in self.super_categories()), |
756 | | self.ElementMethods, |
757 | | reduction = (getattr, (self, "element_class"))) |
| 766 | self.ElementMethods, None, None), ()] |
| 767 | except KeyError: |
| 768 | # Use the cache in a way that does not depend on the reduction data. |
| 769 | # The reduction is inserted afterwards. It is by construction. Since |
| 770 | # the element class is not only cached as a dynamic class but also as |
| 771 | # an attribute of a category, the cache will not break. |
| 772 | C = dynamic_class_internal("%s.element_class"%self.__class__.__name__, |
| 773 | tuple(cat.element_class for cat in self.super_categories()), |
| 774 | self.ElementMethods) |
| 775 | C._reduction = (getattr, (self, "element_class")) |
| 776 | return C |
758 | 777 | |
759 | 778 | def required_methods(self): |
760 | 779 | """ |