Created
November 21, 2017 17:08
-
-
Save den-run-ai/b54321af32b839c2e4812b442e1423e6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Python for .NET or .NET for Python" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Denis Akhiyarov\n", | |
"\n", | |
"- Senior Consultant, Wood - Intelligent Operations\n", | |
"- Faculty, NAU\n", | |
"\n", | |
"Python.NET core developer\n", | |
"@denfromufa (stackoverflow, github, twitter, linkedin)\n", | |
"\n", | |
"Python and C#" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Python for .NET (Python.NET, pythonnet)\n", | |
"\n", | |
"https://github.com/pythonnet/pythonnet\n", | |
"\n", | |
"Python for .NET is a package that gives Python programmers nearly seamless integration with the .NET Common Language Runtime (CLR) and provides a powerful application scripting tool for .NET developers.\n", | |
"\n", | |
"Runs on Windows (.NET Framework 4.0+), Linux and OSX (Mono 4.8+), Windows Subsystem for Linux (WSL), Python 2.7 to 3.6.\n", | |
".NET Core (CoreCLR) support is partial." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"### original author - Brian Lloyd at Zope Corporation in 2003\n", | |
"\n", | |
"#### 5 core developers:\n", | |
" \n", | |
"##### Victor Uriarte @vmuriart, \n", | |
"##### Benedikt Reinartz @filmor\n", | |
"##### Denis Akhiyarov @denfromufa, \n", | |
"##### Dmitriy Ivanov @dmitriyse\n", | |
"##### Tony Roberts @pyxll\n", | |
" " | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"What is really Python.NET?!" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"scrolled": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"source": [ | |
"<img src=\"Library/interop_bridge.PNG\">" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"What is Python.NET good for?\n", | |
"\n", | |
"* Re-use existing .NET assemblies and APIs from Python\n", | |
"* Write extensions for Python in .NET\n", | |
"* Embed Python engine in .NET app (dark-matter enterprise software)\n", | |
"* Re-use any Python libraries from .NET, e.g. from SciPy and PyData stacks" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"<img src=\"./Library/github_overview.PNG\">" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"<img src='./Library/github_tags.PNG'>" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"### 6 open-source projects using it: \n", | |
"\n", | |
"https://github.com/pythonnet/pythonnet/wiki/Projects-using-pythonnet\n", | |
"\n", | |
"#### QuantConnect (Open-source C#, F# and Python algorithmic trading platform)\n", | |
"![QuantConnect](https://avatars2.githubusercontent.com/u/3912814?v=3&s=200)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"#### DWSIM - Chemical Process Simulator on Windows, Linix, iOS, Android\n", | |
"![DWSIM](https://lh3.googleusercontent.com/pZwWK99tRhq3z4_vX6h5fY_FzIx4CWFdEXXdvg1PPi2qIo-_jeOwzi9U0M2-OvfyT7Y=w300-rw)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"#### pywebview (abstraction over webview components on all major platforms)\n", | |
"![](https://raw.githubusercontent.com/r0x0r/pywebview/master/logo/logo.png)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"#### toga (cross-platform UI widget toolkit)\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"source": [ | |
"<tr>\n", | |
"<td> <img src=\"https://pybee.org/project/projects/libraries/toga/toga.png\"/> </td>\n", | |
"<td> <img src=\"https://pybee.org/static/images/brutus-270.png?h=279716d8\"/> </td>\n", | |
"</tr>" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"#### msl-loadlib (Load a shared library and access a 32-bit library from 64-bit Python) + MSL-Equipment for lab equipment\n", | |
"![New Zealand](https://avatars3.githubusercontent.com/u/25604265?v=3&s=200)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"https://github.com/useaible/RyskampLearningMachine\n", | |
"\n", | |
"Platform for AI faster than TF\n", | |
"![](https://avatars2.githubusercontent.com/u/23392944?v=3&s=400)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"### Python.NET embedded in several commercial applications (e.g. DSPACE)\n", | |
"### Used by banking, investment, energy and automation industries" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Questions:\n", | |
"\n", | |
"### How many used IronPython, pywin32, comtypes, pythonnet?\n", | |
"### How many used .NET languages such as C#, F#, VB.NET?\n", | |
"### How many built extensions for Python or embedded Python in other applications?" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"### Installation and deployment options:\n", | |
"https://github.com/pythonnet/pythonnet/wiki/Installation\n", | |
"#### pip, conda, nuget, docker, WinPython:\n", | |
"- pip install pythonnet\n", | |
"- conda install -c pythonnet pythonnet\n", | |
"- Install-Package pythonnet_py35_dotnet\n", | |
"- docker pull pythonnet/pythonnet:python3.5-mono4.8.0-pythonnet2.3.0" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"#### deploy with PyInstaller, cx_Freeze, or Briefcase (from PyBee) using WIX/MSI:\n", | |
"\n", | |
"- pyinstaller PythonAppWithDotNet.py\n", | |
"\n", | |
"- SadConsole MonoGame app packaged into stand-alone executable:\n", | |
"https://github.com/pythonnet/pythonnet/issues/325" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## nPython.exe\n", | |
"\n", | |
"### Console App - CPython embedded in .NET and also Python interactive prompt" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"source": [ | |
"![](./Library/nPython_console.PNG)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## demo apps\n", | |
"\n", | |
"### WinForms (.NET and Mono):\n", | |
"\n", | |
"#### \"wordpad.py\" and \"splitter.py\"\n", | |
"\n", | |
"### WPF:\n", | |
"\n", | |
"#### \"DynamicGrid.py\"" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Mono embedded in CPython, running in Linux Subsystem on Windows 10 with X11 server" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"source": [ | |
"![](./Library/wsl_mono_pythonnet.PNG)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": { | |
"collapsed": true, | |
"scrolled": true, | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"!python pythonnet\\demo\\wordpad.py" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"collapsed": true, | |
"scrolled": false, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"%cd pythonnet\\demo\n", | |
"!python DynamicGrid.py" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"collapsed": true, | |
"scrolled": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"%cd ..\\..\\" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Visual Studio IDE experience\n", | |
"\n", | |
"#### Builds (msbuild driven by setuptools)\n", | |
"#### Intellisense (requires switching between environments)\n", | |
"#### Testing (unit tests - C# and Python)\n", | |
"#### Debugging (mixed-mode cross-language, remote, attach, cross-platform)\n", | |
"#### Interactive C# (csi) - limited to 32-bit, scriptcs & icsharp for 64-bit" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"![](./Library/pythonnet_solution.PNG)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"!pythonnet\\pythonnet.sln" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": { | |
"scrolled": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"scriptcs (ctrl-c to exit or :help for help)\n", | |
"\n", | |
"> \n" | |
] | |
} | |
], | |
"source": [ | |
"!scriptcs" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"# Python for .NET Disclaimer\n", | |
"\n", | |
"\n", | |
"Note that this package does _not_ implement Python as a first-class CLR\n", | |
"language - it does not produce managed code (IL) from Python code. Rather,\n", | |
"it is an integration of the CPython engine with the .NET or Mono runtime.\n", | |
"This approach allows you to use CLR services and continue to use existing\n", | |
"Python code and C-API extensions while maintaining native execution\n", | |
"speeds for Python code. If you are interested in a pure managed-code\n", | |
"implementation of the Python language, you should check out the\n", | |
"[IronPython][1] project, which is in active development.\n", | |
"\n", | |
"Another project [Pyjion][2] allows to JIT compile Python bytecode to IL bytecode\n", | |
"\n", | |
"\n", | |
"\n", | |
"[1]: http://www.ironpython.com\n", | |
"[2]: https://github.com/Microsoft/Pyjion" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Getting Started\n", | |
"\n", | |
"A key goal for this project has been that Python for .NET should\n", | |
"\"work just the way you'd expect in Python\", except for cases that are\n", | |
".NET specific (in which case the goal is to work \"just the way\n", | |
"you'd expect in C#\"). In addition, with the IronPython project havin\n", | |
"established a community, the goal is that code written for IronPython\n", | |
"run without modification under Python for .NET.\n", | |
"\n", | |
"\n", | |
"A good way to start is to interactively explore .NET usage in python\n", | |
"interpreter by following along with the examples in this tutorial. If you\n", | |
"get stuck, there are also a number of demos and unit tests located in the\n", | |
"source directory of the distribution that can be helpful as examples." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Importing Modules\n", | |
"\n", | |
"Python.NET treats CLR namespaces as Python packages." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"#!git clone https://github.com/pythonnet/pythonnet\n", | |
"#!cd pythonnet\n", | |
"#!python setup.py install" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": { | |
"scrolled": true, | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"\u001b[31mDEPRECATION: --egg has been deprecated and will be removed in the future. This flag is mutually exclusive with large parts of pip, and actually using it invalidates pip's ability to manage the installation process.\u001b[0m\n", | |
"Collecting git+https://github.com/pythonnet/pythonnet\n", | |
" Cloning https://github.com/pythonnet/pythonnet to /tmp/pip-jrt1l9o_-build\n", | |
"Installing collected packages: pythonnet\n", | |
" Running setup.py install for pythonnet ... \u001b[?25ldone\n", | |
"\u001b[?25hSuccessfully installed pythonnet-2.4.0.dev0\n" | |
] | |
} | |
], | |
"source": [ | |
"!pip install git+https://github.com/pythonnet/pythonnet --egg" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Collecting clrmagic\n", | |
" Downloading clrmagic-0.0.1a2-py2.py3-none-any.whl\n", | |
"Requirement already satisfied: pythonnet in /home/nbcommon/anaconda3_420/lib/python3.5/site-packages (from clrmagic)\n", | |
"Installing collected packages: clrmagic\n", | |
"Successfully installed clrmagic-0.0.1a2\n" | |
] | |
} | |
], | |
"source": [ | |
"!pip install clrmagic" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"%reload_ext clrmagic" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"import clr\n", | |
"from System import String\n", | |
"clr.AddReference('System.Collections')\n", | |
"from System.Collections import *" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"source": [ | |
"Types from any loaded assembly may be imported.\n", | |
"To load an assembly, use the `AddReference` method:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": { | |
"collapsed": true, | |
"scrolled": false, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"clr.AddReference(\"System.Windows.Forms\")\n", | |
"from System.Windows.Forms import Form" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Using Classes\n", | |
"\n", | |
"Python for .NET allows you to use any non-private from Python:\n", | |
"* classes, \n", | |
"* structs,\n", | |
"* interfaces,\n", | |
"* delegates, etc. " | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"To create an instance of a managed class, you use the standard instantiation syntax, passing a set of arguments that match one of its public constructors:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": { | |
"collapsed": true, | |
"scrolled": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"from System.Drawing import Point\n", | |
"\n", | |
"p = Point(5, 5)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Method Overloading in .NET\n", | |
"\n", | |
"![](http://thinkergy.com/wp-content/uploads/2015/04/shutterstock_15378148.jpg)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"In most cases, Python for .NET can determine the correct constructor to\n", | |
"call automatically based on the arguments. In some cases, it may be necessary\n", | |
"to call a particular overloaded constructor, which is supported by a special \"Overloads\" attribute, on a class:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"(<System.String at 0x7fcbcec94278>, 'AAAAAAAAAA')" | |
] | |
}, | |
"execution_count": 13, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"from System import String, Char, Int32\n", | |
"\n", | |
"s = String.Overloads[Char, Int32]('A', 10)\n", | |
"s = String.__overloads__[Char, Int32]('A', 10)\n", | |
"\n", | |
"s, str(s)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Using Generics\n", | |
"\n", | |
"`Python.NET` also supports generic types. A generic type must be bound to\n", | |
"create a concrete type before it can be instantiated. Generic types support\n", | |
"the subscript syntax to create bound types:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 14, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"from System.Collections.Generic import Dictionary\n", | |
"from System import *\n", | |
"\n", | |
"dict1 = Dictionary[String, String]()\n", | |
"dict2 = Dictionary[String, Int32]()\n", | |
"dict3 = Dictionary[String, Type]()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"When you pass a list of types using the subscript syntax, you can also\n", | |
"pass a subset of Python types that directly correspond to .NET types:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"dict1 = Dictionary[str, str]()\n", | |
"dict2 = Dictionary[str, int]()\n", | |
"dict3 = Dictionary[str, Decimal]()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"source": [ | |
"This shorthand also works when explicitly selecting generic methods or\n", | |
"specific versions of overloaded methods and constructors (explained later).\n", | |
"\n", | |
"You can also subclass managed classes in Python. See the `helloform.py` file\n", | |
"in the `/demo` directory of the distribution for a simple Windows Forms\n", | |
"example that demonstrates subclassing a managed class." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Fields And Properties\n", | |
"\n", | |
"You can get and set fields and properties of CLR objects just as if they\n", | |
"were regular attributes:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 16, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"from System import Environment\n", | |
"\n", | |
"name = Environment.MachineName\n", | |
"Environment.ExitCode = 1" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Using Indexers\n", | |
"\n", | |
"If a managed object implements one or more indexers, you can call the\n", | |
"indexer using standard Python indexing syntax:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"(<System.Collections.Hashtable at 0x7fcbcecb3ef0>,\n", | |
" ['value 1', 'value 2'],\n", | |
" ['key 1', 'key 2'])" | |
] | |
}, | |
"execution_count": 17, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"from System.Collections import Hashtable\n", | |
"\n", | |
"table = Hashtable()\n", | |
"table[\"key 1\"] = \"value 1\"\n", | |
"table[\"key 2\"] = \"value 2\"\n", | |
"\n", | |
"table, list(table.Values), list(table.Keys)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"source": [ | |
"Overloaded indexers are supported, using the same notation one would\n", | |
"use in C#:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"# Loading clrmagic extension (pip install clrmagic) \n", | |
"# to generate runtime C# code, usable from IPython\n", | |
"%reload_ext clrmagic" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Below is runtime generated method `idxnames` that shows example of overloading indexer in CLR type `IndexedNames`" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 19, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"<function clrmagic.create_cs_function.<locals>.<lambda>>" | |
] | |
}, | |
"execution_count": 19, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"%%CS idxnames System.dll\n", | |
"public static object idxnames() { return new IndexedNames(); }\n", | |
"class IndexedNames {\n", | |
" private string[] namelist = new string[size];\n", | |
" static public int size = 10;\n", | |
" public IndexedNames() { for (int i = 0; i < size; i++) namelist[i] = \"N. A.\"; }\n", | |
" public string this[int index] {\n", | |
" get {\n", | |
" string tmp;\n", | |
" if ( index >= 0 && index <= size-1 ) tmp = namelist[index];\n", | |
" else tmp = \"\";\n", | |
" return ( tmp );\n", | |
" }\n", | |
" set { if( index >= 0 && index <= size-1 ) namelist[index] = value; }\n", | |
" }\n", | |
" public int this[string name] {\n", | |
" get {\n", | |
" int index = 0;\n", | |
" while(index < size) {\n", | |
" if (namelist[index] == name) return index;\n", | |
" index++;\n", | |
" }\n", | |
" return index;\n", | |
" }\n", | |
" }\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 20, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"(5, 'abc', 'N. A.')" | |
] | |
}, | |
"execution_count": 20, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"idx1=idxnames()\n", | |
"\n", | |
"idx1[5]=\"abc\"\n", | |
"\n", | |
"idx1[\"abc\"], idx1[5], idx1[0]" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Using Methods\n", | |
"\n", | |
"Methods of CLR objects behave generally like normal Python methods.\n", | |
"Static methods may be called either through the class or through an\n", | |
"instance of the class. All public and protected methods of CLR objects\n", | |
"are accessible to Python:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 21, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"['/',\n", | |
" '/etc/resolv.conf',\n", | |
" '/etc/hostname',\n", | |
" '/etc/hosts',\n", | |
" '/usr/bin/AzureFilesFuseDriver']" | |
] | |
}, | |
"execution_count": 21, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"from System import Environment\n", | |
"\n", | |
"drives = Environment.GetLogicalDrives()\n", | |
"list(drives)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 22, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Int32 CompareTo(Boolean)\n", | |
"Int32 CompareTo(System.Object)\n" | |
] | |
} | |
], | |
"source": [ | |
"from System import Boolean\n", | |
"\n", | |
"print(Boolean.CompareTo.__doc__)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 23, | |
"metadata": { | |
"scrolled": false, | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Help on class Boolean in module System:\n", | |
"\n", | |
"class Boolean(ValueType)\n", | |
" | Void .ctor()\n", | |
" | \n", | |
" | Method resolution order:\n", | |
" | Boolean\n", | |
" | ValueType\n", | |
" | Object\n", | |
" | builtins.object\n", | |
" | \n", | |
" | Methods defined here:\n", | |
" | \n", | |
" | __call__(self, /, *args, **kwargs)\n", | |
" | Call self as a function.\n", | |
" | \n", | |
" | __delitem__(self, key, /)\n", | |
" | Delete self[key].\n", | |
" | \n", | |
" | __eq__(self, value, /)\n", | |
" | Return self==value.\n", | |
" | \n", | |
" | __ge__(self, value, /)\n", | |
" | Return self>=value.\n", | |
" | \n", | |
" | __getitem__(self, key, /)\n", | |
" | Return self[key].\n", | |
" | \n", | |
" | __gt__(self, value, /)\n", | |
" | Return self>value.\n", | |
" | \n", | |
" | __hash__(self, /)\n", | |
" | Return hash(self).\n", | |
" | \n", | |
" | __init__(self, /, *args, **kwargs)\n", | |
" | Initialize self. See help(type(self)) for accurate signature.\n", | |
" | \n", | |
" | __iter__(self, /)\n", | |
" | Implement iter(self).\n", | |
" | \n", | |
" | __le__(self, value, /)\n", | |
" | Return self<=value.\n", | |
" | \n", | |
" | __lt__(self, value, /)\n", | |
" | Return self<value.\n", | |
" | \n", | |
" | __ne__(self, value, /)\n", | |
" | Return self!=value.\n", | |
" | \n", | |
" | __new__(*args, **kwargs) from CLR.CLR Metatype\n", | |
" | Create and return a new object. See help(type) for accurate signature.\n", | |
" | \n", | |
" | __setitem__(self, key, value, /)\n", | |
" | Set self[key] to value.\n", | |
" | \n", | |
" | __str__(self, /)\n", | |
" | Return str(self).\n", | |
" | \n", | |
" | ----------------------------------------------------------------------\n", | |
" | Data and other attributes defined here:\n", | |
" | \n", | |
" | CompareTo = <unbound method 'CompareTo'>\n", | |
" | Int32 CompareTo(Boolean)\n", | |
" | Int32 CompareTo(System.Object)\n", | |
" | \n", | |
" | Equals = <unbound method 'Equals'>\n", | |
" | Boolean Equals(Boolean)\n", | |
" | Boolean Equals(System.Object)\n", | |
" | \n", | |
" | FalseString = 'False'\n", | |
" | \n", | |
" | GetHashCode = <unbound method 'GetHashCode'>\n", | |
" | Int32 GetHashCode()\n", | |
" | \n", | |
" | GetTypeCode = <unbound method 'GetTypeCode'>\n", | |
" | System.TypeCode GetTypeCode()\n", | |
" | \n", | |
" | Parse = <unbound method 'Parse'>\n", | |
" | Boolean Parse(System.String)\n", | |
" | \n", | |
" | ToString = <unbound method 'ToString'>\n", | |
" | System.String ToString()\n", | |
" | System.String ToString(System.IFormatProvider)\n", | |
" | \n", | |
" | TrueString = 'True'\n", | |
" | \n", | |
" | TryParse = <unbound method 'TryParse'>\n", | |
" | Boolean TryParse(System.String, Boolean ByRef)\n", | |
" | \n", | |
" | ----------------------------------------------------------------------\n", | |
" | Data descriptors inherited from Object:\n", | |
" | \n", | |
" | Overloads\n", | |
" | \n", | |
" | __overloads__\n", | |
" | \n", | |
" | ----------------------------------------------------------------------\n", | |
" | Data and other attributes inherited from Object:\n", | |
" | \n", | |
" | Finalize = <unbound method 'Finalize'>\n", | |
" | Void Finalize()\n", | |
" | \n", | |
" | GetType = <unbound method 'GetType'>\n", | |
" | System.Type GetType()\n", | |
" | \n", | |
" | MemberwiseClone = <unbound method 'MemberwiseClone'>\n", | |
" | System.Object MemberwiseClone()\n", | |
" | \n", | |
" | ReferenceEquals = <unbound method 'ReferenceEquals'>\n", | |
" | Boolean ReferenceEquals(System.Object, System.Object)\n", | |
"\n" | |
] | |
} | |
], | |
"source": [ | |
"help(Boolean)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Overloaded and Generic Methods\n", | |
"\n", | |
"While Python for .NET will generally be able to figure out the right\n", | |
"version of an overloaded method to call automatically, there are cases\n", | |
"where it is desirable to select a particular method overload explicitly.\n", | |
"\n", | |
"Methods of CLR objects have an `__overloads__`, which will soon be\n", | |
"deprecated in favor of iPy compatible Overloads, attribute that can be\n", | |
"used for this purpose:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 24, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "subslide" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"from System import Console\n", | |
"\n", | |
"# in jupyter writes to nbserver console\n", | |
"Console.WriteLine.Overloads[bool](True) \n", | |
"Console.WriteLine.Overloads[str](\"true\")\n", | |
"Console.WriteLine.Overloads[int](42)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Similarly, generic methods may be bound at runtime using the subscript\n", | |
"syntax directly on the method:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 25, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"<function clrmagic.create_cs_function.<locals>.<lambda>>" | |
] | |
}, | |
"execution_count": 25, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"%%CS GenericMethods System.dll\n", | |
"public static object GenericMethods() {\n", | |
" return new TypeWithGenerics();\n", | |
"}\n", | |
"class TypeWithGenerics {\n", | |
" public TypeWithGenerics() { \n", | |
" }\n", | |
" public System.Type genericmethod<T>(T g) {\n", | |
" return g.GetType();\n", | |
" }\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 26, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"('Int32', 'String')" | |
] | |
}, | |
"execution_count": 26, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"twg = GenericMethods()\n", | |
"twg.genericmethod[int](10).Name, twg.genericmethod[str](\"10\").Name" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Exception Handling\n", | |
"\n", | |
"You can raise and catch managed exceptions just the same as you would\n", | |
"pure-Python exceptions:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 27, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"aiieee!\n", | |
"None\n" | |
] | |
} | |
], | |
"source": [ | |
"from System import NullReferenceException\n", | |
"\n", | |
"try:\n", | |
" raise NullReferenceException(\"aiieee!\")\n", | |
"except NullReferenceException as e:\n", | |
" print(e.Message)\n", | |
" print(e.Source)\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Delegates and Events\n", | |
"\n", | |
"![](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRa6P3mA1aftKij7n80VftxgEuIXCU749hG2TSDomBDgaJQ6iOR2A)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Using Arrays\n", | |
"\n", | |
"The type `System.Array` supports the subscript syntax in order to\n", | |
"make it easy to create managed arrays from Python:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 28, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"[1, 2]" | |
] | |
}, | |
"execution_count": 28, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"from System import Array\n", | |
"\n", | |
"myarray = Array[int]([1,2])\n", | |
"list(myarray)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Managed arrays support the standard Python sequence protocols:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 29, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"1\n", | |
"2\n", | |
"2\n", | |
"1\n", | |
"2\n" | |
] | |
} | |
], | |
"source": [ | |
"items = Array[int]([1,2])\n", | |
"\n", | |
"# Get first item\n", | |
"v = items[0]\n", | |
"items[0] = v\n", | |
"print(v)\n", | |
"\n", | |
"# Get last item\n", | |
"v = items[-1]\n", | |
"items[-1] = v\n", | |
"print(v)\n", | |
"\n", | |
"# Get length\n", | |
"l = len(items)\n", | |
"print(l)\n", | |
"\n", | |
"# Containment test\n", | |
"for test in items:\n", | |
" print(test)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Multidimensional arrays support indexing using the same notation one\n", | |
"would use in C#:" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"source": [ | |
"```python\n", | |
"items[0, 2]\n", | |
"\n", | |
"items[0, 2, 3]\n", | |
"```" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Using Collections\n", | |
"\n", | |
"Managed arrays and managed objects that implement the IEnumerable\n", | |
"interface can be iterated over using the standard iteration\n", | |
"Python idioms:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 30, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\n", | |
"Python.Runtime, Version=2.4.0.0, Culture=neutral, PublicKeyToken=null\n", | |
"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\n", | |
"__CodeGenerator_Assembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null\n", | |
"e__NativeCall_Assembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null\n", | |
"System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\n", | |
"Mono.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756\n", | |
"System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\n", | |
"System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\n", | |
"System.Collections, Version=4.0.10.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\n", | |
"System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\n", | |
"Accessibility, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\n", | |
"System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\n", | |
"System.Windows, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\n", | |
"Mono.WebBrowser, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756\n", | |
"clrmagic, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null\n", | |
"5d6ye0qz, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null\n", | |
"jmq26ncd, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null\n" | |
] | |
} | |
], | |
"source": [ | |
"import System\n", | |
"domain = System.AppDomain.CurrentDomain\n", | |
"\n", | |
"for item in domain.GetAssemblies():\n", | |
" name = item.GetName()\n", | |
" print(name)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Using COM Components\n", | |
"\n", | |
"### Early-binding:\n", | |
"\n", | |
"Using Microsoft-provided tools such as `aximp.exe` and `tlbimp.exe`,\n", | |
"it is possible to generate managed wrappers for COM libraries. \n", | |
"\n", | |
"After generating such a wrapper, you can use the libraries from Python just like any other managed code.\n", | |
"\n", | |
"### Dynamic late-binding\n", | |
"\n", | |
"Dynamic late-binding to COM objects requires some boiler-plate code due to special-handling in .NET" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Type Conversion\n", | |
"\n", | |
"Type conversion under Python for .NET is fairly straightforward - most\n", | |
"elemental Python types (string, int, long, etc.) convert automatically to\n", | |
"compatible managed equivalents (String, Int32, etc.) and vice-versa.\n", | |
"Note that all strings returned from the CLR are returned as unicode.\n", | |
"\n", | |
"Types that do not have a logical equivalent in Python are exposed as\n", | |
"instances of managed classes or structs (System.Decimal is an example)." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"The .NET architecture makes a distinction between `value types` and\n", | |
"`reference types`. Reference types are allocated on the heap, and value\n", | |
"types are allocated either on the stack or in-line within an object.\n", | |
"\n", | |
"A process called `boxing` is used in .NET to allow code to treat a value\n", | |
"type as if it were a reference type. Boxing causes a separate copy of the\n", | |
"value type object to be created on the heap, which then has reference\n", | |
"type semantics.\n", | |
"\n", | |
"Understanding boxing and the distinction between value types and reference\n", | |
"types can be important when using Python for .NET because the Python\n", | |
"language has no value type semantics or syntax - in Python\n", | |
"\"everything is a reference\".\n", | |
"\n", | |
"Here is a simple example that demonstrates an issue. If you are an\n", | |
"experienced C# programmer, you might write the following code:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 31, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"0" | |
] | |
}, | |
"execution_count": 31, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"items = System.Array.CreateInstance(Point, 3)\n", | |
"for i in range(3):\n", | |
" items[i] = Point(0, 0)\n", | |
"\n", | |
"items[0].X = 1 # won't work!!\n", | |
"\n", | |
"items[0].X" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"source": [ | |
"While the spelling of `items[0].X = 1` is the same in C# and Python,\n", | |
"there is an important and subtle semantic difference.\n", | |
"In C# (and other compiled-to-IL languages), the compiler knows that\n", | |
"Point is a value type and can do the Right Thing here, changing the\n", | |
"value in place." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"In Python however, \"everything's a reference\", and there is really no\n", | |
"spelling or semantic to allow it to do the right thing dynamically.\n", | |
"The specific reason that `items[0]` itself doesn't change is that when\n", | |
"you say `items[0]`, that getitem operation creates a Python object that\n", | |
"holds a reference to the object at `items[0]` via a GCHandle.\n", | |
"That causes a ValueType (like Point) to be boxed, so the following\n", | |
"setattr (`.X = 1`) _changes the state of the boxed value,\n", | |
"not the original unboxed value_." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"The rule in Python is essentially:\n", | |
"\n", | |
"> the result of any attribute or item access is a boxed value\n", | |
"\n", | |
"and that can be important in how you approach your code.\n", | |
"\n", | |
"Because there are no value type semantics or syntax in Python,\n", | |
"you may need to modify your approach. To revisit the previous example,\n", | |
"we can ensure that the changes we want to make to an array item\n", | |
"aren't \"lost\" by resetting an array member after making changes to it:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 32, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"{X=1,Y=0} {X=1,Y=0} 1 1\n" | |
] | |
} | |
], | |
"source": [ | |
"items = System.Array.CreateInstance(Point, 3)\n", | |
"for i in range(3):\n", | |
" items[i] = Point(0, 0)\n", | |
"# This _will_ work. We get 'item' as a boxed copy of the Point\n", | |
"# object actually stored in the array. After making our changes\n", | |
"# we re-set the array item to update the bits in the array.\n", | |
"\n", | |
"item = items[0]\n", | |
"item.X = 1\n", | |
"items[0] = item\n", | |
"print(item, items[0], item.X, items[0].X)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"This is not unlike some of the cases you can find in C# where you have to\n", | |
"know about boxing behavior to avoid similar kinds of `lost update` problems\n", | |
"(generally because an implicit boxing happened that was not taken\n", | |
"into account in the code).\n", | |
"\n", | |
"This is the same thing, just the manifestation is a little different\n", | |
"in Python. See the .NET documentation for more details on boxing and the\n", | |
"differences between value types and reference types." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Embedding Python\n", | |
"\n", | |
"**Note on SECURITY:** because Python code running under Python for .NET is inherently\n", | |
"unverifiable, it runs totally under the radar of the security infrastructure\n", | |
"of the CLR so you should restrict use of the Python assembly to trusted code.\n", | |
"\n", | |
"These classes include **PyObject**, **PyList**, **PyDict**, **PyTuple**, etc.\n", | |
"You can review the **nPython.exe** source code in **Console.csproj** project\n", | |
"for example of embedding CPython in console .NET app. " | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"At a very high level, to embed Python in your application you will need to:\n", | |
"\n", | |
"- Reference `Python.Runtime.dll` in your build environment\n", | |
"- Call `PythonEngine.Initialize()` to initialize Python\n", | |
"- Call `PythonEngine.ImportModule(name)` or `Py.Import(name)` to import a module\n", | |
"- Wrap all calls to Python with `Py.GIL()` blocks" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"**Important Note for embedders:** Python is not free-threaded and\n", | |
"uses a global interpreter lock to allow multi-threaded applications\n", | |
"to interact safely with the Python interpreter.\n", | |
"Much more information about this is available in the Python C-API\n", | |
"documentation on the www.python.org Website.\n", | |
"\n", | |
"When embedding Python in a managed application, you have to manage the\n", | |
"GIL in just the same way you would when embedding Python in\n", | |
"a C or C++ application." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Before interacting with any of the objects or APIs provided by the\n", | |
"Python.Runtime namespace, calling code must have acquired the Python\n", | |
"global interpreter lock by calling the `PythonEngine.AcquireLock` method.\n", | |
"The only exception to this rule is the `PythonEngine.Initialize` method,\n", | |
"which may be called at startup without having acquired the GIL.\n", | |
"\n", | |
"When finished using Python APIs, managed code must call a corresponding\n", | |
"`PythonEngine.ReleaseLock` to release the GIL and allow other threads\n", | |
"to use Python.\n", | |
"\n", | |
"The AcquireLock and ReleaseLock methods are thin wrappers over the\n", | |
"unmanaged `PyGILState_Ensure` and `PyGILState_Release` functions from\n", | |
"the Python API, and the documentation for those APIs applies to\n", | |
"the managed versions." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Calling numpy from .NET using pythonnet" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 33, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"'/home/nbuser/anaconda3_420/lib/python3.5/site-packages/Python.Runtime.dll'" | |
] | |
}, | |
"execution_count": 33, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"clrpath = clr.FindAssembly(\"Python.Runtime\")\n", | |
"clrpath" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 34, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"'/home/nbuser/library'" | |
] | |
}, | |
"execution_count": 34, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"curpath = %pwd\n", | |
"curpath" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 35, | |
"metadata": { | |
"scrolled": false, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"'/home/nbuser/library/Python.Runtime.dll'" | |
] | |
}, | |
"execution_count": 35, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"from shutil import copy\n", | |
"\n", | |
"copy(clrpath, curpath)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 37, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"<function clrmagic.create_cs_function.<locals>.<lambda>>" | |
] | |
}, | |
"execution_count": 37, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"%%CS numpynetcall Python.Runtime.dll;Microsoft.CSharp.dll;System.Core.dll;System.dll\n", | |
"public static object numpynetcall(string dummy) {\n", | |
" using (Python.Runtime.Py.GIL()) {\n", | |
" dynamic np = Python.Runtime.Py.Import(\"numpy\");\n", | |
" dynamic sys = Python.Runtime.Py.Import(\"sys\");\n", | |
" dynamic pp = Python.Runtime.Py.Import(\"pprint\");\n", | |
" pp.pprint(np.cos(np.pi * 2));\n", | |
" dynamic sin = np.sin;\n", | |
" pp.pprint(sin(5));\n", | |
" double c = np.cos(5) + sin(5);\n", | |
" pp.pprint(c);\n", | |
" dynamic a = np.array(new System.Collections.Generic.List<float> { 1, 2, 3 });\n", | |
" pp.pprint(a.dtype);\n", | |
" dynamic b = np.array(new System.Collections.Generic.List<float> { 6, 5, 4 }, \n", | |
" Python.Runtime.Py.kw(\"dtype\", np.int32));\n", | |
" pp.pprint(b.dtype);\n", | |
" System.Console.WriteLine(a * b); \n", | |
" return (object)np;\n", | |
" }\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 38, | |
"metadata": { | |
"scrolled": true, | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"1.0\n", | |
"-0.95892427466313845\n", | |
"-0.6752620891999122\n", | |
"dtype('float64')\n", | |
"dtype('int32')\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/plain": [ | |
"<module 'numpy' from '/home/nbuser/anaconda3_420/lib/python3.5/site-packages/numpy/__init__.py'>" | |
] | |
}, | |
"execution_count": 38, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"numpynetcall(\"dummy\")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Calling sympy from .NET using pythonnet" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 40, | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"<function clrmagic.create_cs_function.<locals>.<lambda>>" | |
] | |
}, | |
"execution_count": 40, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"%%CS sympynetcall Python.Runtime.dll;Microsoft.CSharp.dll;System.Core.dll;System.dll\n", | |
"public static object sympynetcall(string dummy) {\n", | |
" using (Python.Runtime.Py.GIL()) {\n", | |
" dynamic sym = Python.Runtime.Py.Import(\"sympy\");\n", | |
" dynamic pp = Python.Runtime.Py.Import(\"pprint\");\n", | |
" dynamic x = sym.symbols('x');\n", | |
" dynamic a = sym.symbols('a');\n", | |
" dynamic roots = sym.solvers.solve(sym.Pow(x, 2) - a, x);\n", | |
" pp.pprint(roots); \n", | |
" return (object)sym;\n", | |
" }\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 41, | |
"metadata": { | |
"scrolled": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"[-sqrt(a), sqrt(a)]\n" | |
] | |
}, | |
{ | |
"data": { | |
"text/plain": [ | |
"<module 'sympy' from '/home/nbuser/anaconda3_420/lib/python3.5/site-packages/sympy/__init__.py'>" | |
] | |
}, | |
"execution_count": 41, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"sympynetcall(\"\")" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Python embedded in Python using Python.NET?!\n", | |
"![](http://i0.kym-cdn.com/photos/images/facebook/000/531/557/a88.jpg)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 42, | |
"metadata": { | |
"scrolled": false, | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"<function clrmagic.create_cs_function.<locals>.<lambda>>" | |
] | |
}, | |
"execution_count": 42, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"%%CS pynetcall Python.Runtime.dll;Microsoft.CSharp.dll;System.Core.dll\n", | |
"public static object pynetcall(string modstr)\n", | |
"{\n", | |
"\n", | |
" dynamic modobj;\n", | |
" using (Python.Runtime.Py.GIL())\n", | |
" {\n", | |
" modobj = Python.Runtime.Py.Import(modstr);\n", | |
" }\n", | |
" return (object)modobj;\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 43, | |
"metadata": { | |
"scrolled": true, | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"'3.5.2 |Anaconda custom (64-bit)| (default, Jul 2 2016, 17:53:06) \\n[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]'" | |
] | |
}, | |
"execution_count": 43, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"pynetcall(\"sys\").version" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Using Tensorflow Effectively with Python.NET" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 44, | |
"metadata": { | |
"collapsed": true, | |
"slideshow": { | |
"slide_type": "fragment" | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"# RUN THIS IN SCRIPTCS\n", | |
"##r C:\\Python\\Python35_64b\\lib\\site-packages\\Python.Runtime.dll\n", | |
"# using Python.Runtime;\n", | |
"# dynamic sys; using (Py.GIL()) {sys=Py.Import(\"sys\");}\n", | |
"# dynamic np; using (Py.GIL()) {np=Py.Import(\"numpy\");}\n", | |
"# dynamic tf; using (Py.GIL()) {tf=Py.Import(\"tensorflow\");}\n", | |
"# dynamic data = np.ones(5);\n", | |
"# dynamic x=tf.constant(data, Py.kw(\"name\",\"x\"));\n", | |
"# dynamic z = tf.Variable(tf.multiply(tf.pow(x,2),5), Py.kw(\"name\",\"z\"));\n", | |
"# dynamic y = tf.Variable(tf.multiply(tf.constant(3.0,Py.kw(\"dtype\",\"float64\")),x), Py.kw(\"name\", 'y'));\n", | |
"# dynamic model = tf.global_variables_initializer();\n", | |
"# dynamic ssn=tf.Session(); ssn.run(model); ssn.run(y).ToString();" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"https://github.com/pythonnet/pythonnet/wiki/Various-debugging-scenarios-of-embedded-CPython\n", | |
"Mixed-mode cross-language debugging\n", | |
"![](https://camo.githubusercontent.com/800df4d0632f0c4707bd8febb18e419409f4631e/687474703a2f2f692e696d6775722e636f6d2f356d7a306357772e676966)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"Attach remote debugger (ptvsd) to Python code embedded with pythonnet:\n", | |
"\n", | |
"![](https://camo.githubusercontent.com/b091ed0e0960237ba97cc3fc49744cca0abdba32/687474703a2f2f692e696d6775722e636f6d2f4a336b3475566e2e676966)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"slideshow": { | |
"slide_type": "slide" | |
} | |
}, | |
"source": [ | |
"## Low-level implementation details:\n", | |
"\n", | |
"### DLLExport (C-API for Mono) for reverse pinvoke - expose .NET types to unmanaged code\n", | |
"### pycparser and clang for parsing CPython header files\n", | |
"### .NET Reflection everywhere - getattr() and compile() in Python\n", | |
"### Macros (Decref, Incref) re-implemented as unsafe blocks of C# code" | |
] | |
} | |
], | |
"metadata": { | |
"anaconda-cloud": {}, | |
"celltoolbar": "Slideshow", | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.5.2" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment