# HG changeset patch
# User Simon King <simon.king@unijena.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 nonfield. 
 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 nonfield. 
 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  """ 