`.
+
+Types that do not have a logical equivalent in Python are exposed as
+instances of managed classes or structs (System.Decimal is an example).
+
+The .NET architecture makes a distinction between ``value types`` and
+``reference types``. Reference types are allocated on the heap, and
+value types are allocated either on the stack or in-line within an
+object.
+
+A process called ``boxing`` is used in .NET to allow code to treat a
+value type as if it were a reference type. Boxing causes a separate copy
+of the value type object to be created on the heap, which then has
+reference type semantics.
+
+Understanding boxing and the distinction between value types and
+reference types can be important when using Python.NET because the
+Python language has no value type semantics or syntax - in Python
+“everything is a reference”.
+
+Here is a simple example that demonstrates an issue. If you are an
+experienced C# programmer, you might write the following code:
+
+.. code:: python
+
+ items = System.Array.CreateInstance(Point, 3)
+ for i in range(3):
+ items[i] = Point(0, 0)
+
+ items[0].X = 1 # won't work!!
+
+While the spelling of ``items[0].X = 1`` is the same in C# and Python,
+there is an important and subtle semantic difference. In C# (and other
+compiled-to-IL languages), the compiler knows that Point is a value type
+and can do the Right Thing here, changing the value in place.
+
+In Python however, “everything’s a reference”, and there is really no
+spelling or semantic to allow it to do the right thing dynamically. The
+specific reason that ``items[0]`` itself doesn’t change is that when you
+say ``items[0]``, that getitem operation creates a Python object that
+holds a reference to the object at ``items[0]`` via a GCHandle. That
+causes a ValueType (like Point) to be boxed, so the following setattr
+(``.X = 1``) *changes the state of the boxed value, not the original
+unboxed value*.
+
+The rule in Python is essentially:
+
+ the result of any attribute or item access is a boxed value
+
+and that can be important in how you approach your code.
+
+Because there are no value type semantics or syntax in Python, you may
+need to modify your approach. To revisit the previous example, we can
+ensure that the changes we want to make to an array item aren’t “lost”
+by resetting an array member after making changes to it:
+
+.. code:: python
+
+ items = System.Array.CreateInstance(Point, 3)
+ for i in range(3):
+ items[i] = Point(0, 0)
+
+ # This _will_ work. We get 'item' as a boxed copy of the Point
+ # object actually stored in the array. After making our changes
+ # we re-set the array item to update the bits in the array.
+
+ item = items[0]
+ item.X = 1
+ items[0] = item
+
+This is not unlike some of the cases you can find in C# where you have
+to know about boxing behavior to avoid similar kinds of ``lost update``
+problems (generally because an implicit boxing happened that was not
+taken into account in the code).
+
+This is the same thing, just the manifestation is a little different in
+Python. See the .NET documentation for more details on boxing and the
+differences between value types and reference types.
diff --git a/doc/source/reference.rst b/doc/source/reference.rst
new file mode 100644
index 000000000..56bb2ad33
--- /dev/null
+++ b/doc/source/reference.rst
@@ -0,0 +1,42 @@
+C# Reference
+------------
+
+..
+ .. doxygennamespace:: Python::Runtime
+ :members:
+ :outline:
+
+.. doxygenclass:: Py
+ :members:
+
+.. doxygenclass:: Python::Runtime::PythonEngine
+ :members:
+.. doxygenclass:: Python::Runtime::PyObject
+ :members:
+
+.. doxygenclass:: Python::Runtime::PyDict
+ :members:
+.. doxygenclass:: Python::Runtime::PyTuple
+ :members:
+.. doxygenclass:: Python::Runtime::PyList
+ :members:
+.. doxygenclass:: Python::Runtime::PyInt
+ :members:
+.. doxygenclass:: Python::Runtime::PyString
+ :members:
+.. doxygenclass:: Python::Runtime::PyType
+ :members:
+.. doxygenclass:: Python::Runtime::PyModule
+ :members:
+.. doxygenclass:: Python::Runtime::PyIter
+ :members:
+
+.. doxygenclass:: Python::Runtime::PyBuffer
+ :members:
+.. doxygenenum:: Python::Runtime::BufferOrderStyle
+.. doxygenclass:: Python::Runtime::PyIterable
+ :members:
+.. doxygenclass:: Python::Runtime::PySequence
+ :members:
+.. doxygenclass:: Python::Runtime::PyNumber
+ :members:
diff --git a/pythonnet/__init__.py b/pythonnet/__init__.py
index 2cde01233..9d7b6c20a 100644
--- a/pythonnet/__init__.py
+++ b/pythonnet/__init__.py
@@ -1,9 +1,11 @@
+"""Python.NET runtime loading and configuration"""
+
import sys
from pathlib import Path
from typing import Dict, Optional, Union, Any
import clr_loader
-__all__ = ["set_runtime", "set_runtime_from_env", "load"]
+__all__ = ["set_runtime", "set_runtime_from_env", "load", "unload", "get_runtime_info"]
_RUNTIME: Optional[clr_loader.Runtime] = None
_LOADER_ASSEMBLY: Optional[clr_loader.Assembly] = None
@@ -13,9 +15,11 @@
def set_runtime(runtime: Union[clr_loader.Runtime, str], **params: str) -> None:
"""Set up a clr_loader runtime without loading it
- :param runtime: Either an already initialised `clr_loader` runtime, or one
- of netfx, coreclr, mono, or default. If a string parameter is given, the
- runtime will be created."""
+ :param runtime:
+ Either an already initialised `clr_loader` runtime, or one of netfx,
+ coreclr, mono, or default. If a string parameter is given, the runtime
+ will be created.
+ """
global _RUNTIME
if _LOADED:
@@ -145,7 +149,7 @@ def load(runtime: Union[clr_loader.Runtime, str, None] = None, **params: str) ->
def unload() -> None:
- """Explicitly unload a laoded runtime and shut down Python.NET"""
+ """Explicitly unload a loaded runtime and shut down Python.NET"""
global _RUNTIME, _LOADER_ASSEMBLY
if _LOADER_ASSEMBLY is not None:
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy