m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
6.8 KiB

6 months ago
  1. """Singleton mechanism"""
  2. from .core import Registry
  3. from .assumptions import ManagedProperties
  4. from .sympify import sympify
  5. class SingletonRegistry(Registry):
  6. """
  7. The registry for the singleton classes (accessible as ``S``).
  8. Explanation
  9. ===========
  10. This class serves as two separate things.
  11. The first thing it is is the ``SingletonRegistry``. Several classes in
  12. SymPy appear so often that they are singletonized, that is, using some
  13. metaprogramming they are made so that they can only be instantiated once
  14. (see the :class:`sympy.core.singleton.Singleton` class for details). For
  15. instance, every time you create ``Integer(0)``, this will return the same
  16. instance, :class:`sympy.core.numbers.Zero`. All singleton instances are
  17. attributes of the ``S`` object, so ``Integer(0)`` can also be accessed as
  18. ``S.Zero``.
  19. Singletonization offers two advantages: it saves memory, and it allows
  20. fast comparison. It saves memory because no matter how many times the
  21. singletonized objects appear in expressions in memory, they all point to
  22. the same single instance in memory. The fast comparison comes from the
  23. fact that you can use ``is`` to compare exact instances in Python
  24. (usually, you need to use ``==`` to compare things). ``is`` compares
  25. objects by memory address, and is very fast.
  26. Examples
  27. ========
  28. >>> from sympy import S, Integer
  29. >>> a = Integer(0)
  30. >>> a is S.Zero
  31. True
  32. For the most part, the fact that certain objects are singletonized is an
  33. implementation detail that users shouldn't need to worry about. In SymPy
  34. library code, ``is`` comparison is often used for performance purposes
  35. The primary advantage of ``S`` for end users is the convenient access to
  36. certain instances that are otherwise difficult to type, like ``S.Half``
  37. (instead of ``Rational(1, 2)``).
  38. When using ``is`` comparison, make sure the argument is sympified. For
  39. instance,
  40. >>> x = 0
  41. >>> x is S.Zero
  42. False
  43. This problem is not an issue when using ``==``, which is recommended for
  44. most use-cases:
  45. >>> 0 == S.Zero
  46. True
  47. The second thing ``S`` is is a shortcut for
  48. :func:`sympy.core.sympify.sympify`. :func:`sympy.core.sympify.sympify` is
  49. the function that converts Python objects such as ``int(1)`` into SymPy
  50. objects such as ``Integer(1)``. It also converts the string form of an
  51. expression into a SymPy expression, like ``sympify("x**2")`` ->
  52. ``Symbol("x")**2``. ``S(1)`` is the same thing as ``sympify(1)``
  53. (basically, ``S.__call__`` has been defined to call ``sympify``).
  54. This is for convenience, since ``S`` is a single letter. It's mostly
  55. useful for defining rational numbers. Consider an expression like ``x +
  56. 1/2``. If you enter this directly in Python, it will evaluate the ``1/2``
  57. and give ``0.5``, because both arguments are ints (see also
  58. :ref:`tutorial-gotchas-final-notes`). However, in SymPy, you usually want
  59. the quotient of two integers to give an exact rational number. The way
  60. Python's evaluation works, at least one side of an operator needs to be a
  61. SymPy object for the SymPy evaluation to take over. You could write this
  62. as ``x + Rational(1, 2)``, but this is a lot more typing. A shorter
  63. version is ``x + S(1)/2``. Since ``S(1)`` returns ``Integer(1)``, the
  64. division will return a ``Rational`` type, since it will call
  65. ``Integer.__truediv__``, which knows how to return a ``Rational``.
  66. """
  67. __slots__ = ()
  68. # Also allow things like S(5)
  69. __call__ = staticmethod(sympify)
  70. def __init__(self):
  71. self._classes_to_install = {}
  72. # Dict of classes that have been registered, but that have not have been
  73. # installed as an attribute of this SingletonRegistry.
  74. # Installation automatically happens at the first attempt to access the
  75. # attribute.
  76. # The purpose of this is to allow registration during class
  77. # initialization during import, but not trigger object creation until
  78. # actual use (which should not happen until after all imports are
  79. # finished).
  80. def register(self, cls):
  81. # Make sure a duplicate class overwrites the old one
  82. if hasattr(self, cls.__name__):
  83. delattr(self, cls.__name__)
  84. self._classes_to_install[cls.__name__] = cls
  85. def __getattr__(self, name):
  86. """Python calls __getattr__ if no attribute of that name was installed
  87. yet.
  88. Explanation
  89. ===========
  90. This __getattr__ checks whether a class with the requested name was
  91. already registered but not installed; if no, raises an AttributeError.
  92. Otherwise, retrieves the class, calculates its singleton value, installs
  93. it as an attribute of the given name, and unregisters the class."""
  94. if name not in self._classes_to_install:
  95. raise AttributeError(
  96. "Attribute '%s' was not installed on SymPy registry %s" % (
  97. name, self))
  98. class_to_install = self._classes_to_install[name]
  99. value_to_install = class_to_install()
  100. self.__setattr__(name, value_to_install)
  101. del self._classes_to_install[name]
  102. return value_to_install
  103. def __repr__(self):
  104. return "S"
  105. S = SingletonRegistry()
  106. class Singleton(ManagedProperties):
  107. """
  108. Metaclass for singleton classes.
  109. Explanation
  110. ===========
  111. A singleton class has only one instance which is returned every time the
  112. class is instantiated. Additionally, this instance can be accessed through
  113. the global registry object ``S`` as ``S.<class_name>``.
  114. Examples
  115. ========
  116. >>> from sympy import S, Basic
  117. >>> from sympy.core.singleton import Singleton
  118. >>> class MySingleton(Basic, metaclass=Singleton):
  119. ... pass
  120. >>> Basic() is Basic()
  121. False
  122. >>> MySingleton() is MySingleton()
  123. True
  124. >>> S.MySingleton is MySingleton()
  125. True
  126. Notes
  127. =====
  128. Instance creation is delayed until the first time the value is accessed.
  129. (SymPy versions before 1.0 would create the instance during class
  130. creation time, which would be prone to import cycles.)
  131. This metaclass is a subclass of ManagedProperties because that is the
  132. metaclass of many classes that need to be Singletons (Python does not allow
  133. subclasses to have a different metaclass than the superclass, except the
  134. subclass may use a subclassed metaclass).
  135. """
  136. def __init__(cls, *args, **kwargs):
  137. super().__init__(cls, *args, **kwargs)
  138. cls._instance = obj = Basic.__new__(cls)
  139. cls.__new__ = lambda cls: obj
  140. cls.__getnewargs__ = lambda obj: ()
  141. cls.__getstate__ = lambda obj: None
  142. S.register(cls)
  143. # Delayed to avoid cyclic import
  144. from .basic import Basic