我有一个.py文件,我想调用它并获取它在我的应用程序中返回的值。
我的主要意图是在我的基于C#的通用应用程序中使用scikit-learn进行机器学习,我将如何实现这一点?
在UWP中,您的选择非常有限。通用应用程序在沙盒中运行,并且在如何与经典桌面应用程序(如Python)交互方面受到限制,这使您无法使用本地Python安装简单地"shell执行"脚本。
有一种方法可以在Windows 8.1 WinRT中使用代理组件来实现,但应用程序需要侧载;它不适用于从商店安装的应用程序。当然,它需要Windows的桌面版本,在Windows Phone上也不起作用。此外,我没有看到任何关于Windows 10 UWP的提及,我严重怀疑它是否仍然有效。
也许你最好的选择是尝试UWP版本的CPython。我从未使用过它,我不知道它处于什么状态,我也不知道需要付出多少努力才能让scikit学习在它中工作。但如果你想让你的应用程序在多个平台上工作(桌面、移动、物联网…),我不认为还有其他选择。
另一方面,如果你只针对桌面,我建议你放弃使用UWP,而是创建一个经典的桌面应用程序。这将允许您在没有任何限制的情况下使用标准CPython版本,无论是调用本地安装的版本还是将其嵌入到您的应用程序中。
您可以使用独立的应用程序代理。正如Damir Arh所说,这种方法不能用于通过商店分发应用程序。其主要思想是为代理注册一个自定义扩展,并通过执行一个帮助文件来启动它。
代理:
static class Program
{
const string ProxyExtension = ".python-proxy";
const string ResultExtension = ".python-proxy-result";
[STAThread]
static void Main(params string[] args)
{
if (args.Length != 1)
return;
if ("install".Equals(args[0], StringComparison.Ordinal))
{
var path = Application.ExecutablePath;
SetAssociation(ProxyExtension, "PythonProxy", path, "Python Proxy");
}
else
{
var path = args[0];
if (!File.Exists(path))
return;
var serviceExt = Path.GetExtension(path);
if (!ProxyExtension.Equals(serviceExt, StringComparison.OrdinalIgnoreCase))
return;
path = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path).TrimEnd());
var ext = Path.GetExtension(path);
if (!".py".Equals(ext, StringComparison.OrdinalIgnoreCase))
return;
var start = new ProcessStartInfo
{
FileName = "python.exe",
Arguments = '"' + path + '"',
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
};
using (var process = Process.Start(start))
{
using (var reader = process.StandardOutput)
{
var result = reader.ReadToEnd();
var output = path + ResultExtension;
using (var mutex = new Mutex(true, "PythonProxy Mutex"))
{
File.WriteAllText(output, result);
}
}
}
}
}
public static void SetAssociation(string ext, string name, string openWithPath, string description)
{
using (var key = Registry.ClassesRoot.CreateSubKey(ext))
{
if (key == null)
return;
key.SetValue("", name);
}
using (var key = Registry.ClassesRoot.CreateSubKey(name))
{
if (key == null)
return;
key.SetValue("", description);
using (var shellKey = key.CreateSubKey("shell"))
{
if (shellKey == null)
return;
using (var openKey = shellKey.CreateSubKey("open"))
{
if (openKey == null)
return;
using (var commandKey = openKey.CreateSubKey("command"))
{
if (commandKey == null)
return;
commandKey.SetValue("", $""{openWithPath}" "%1"");
}
}
}
}
using (var key = Registry.CurrentUser.OpenSubKey($@"SoftwareMicrosoftWindowsCurrentVersionExplorerFileExts{ext}"))
{
if (key != null)
key.DeleteSubKey("UserChoice", false);
}
Native.SHChangeNotify(Native.SHCNE_ASSOCCHANGED, Native.SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero);
}
class Native
{
public const uint SHCNE_ASSOCCHANGED = 0x08000000;
public const uint SHCNF_IDLIST = 0x0000;
[DllImport("shell32.dll")]
public static extern void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
}
}
通用应用:
public async void Fun()
{
var local = ApplicationData.Current.LocalFolder;
var scriptFile = await local.CreateFileAsync("script.py", CreationCollisionOption.ReplaceExisting);
using (var stream = await scriptFile.OpenStreamForWriteAsync())
using (var writer = new StreamWriter(stream))
{
await writer.WriteLineAsync(@"print ""Hello, World!""");
}
var proxyFile = await local.CreateFileAsync("script.py.python-proxy", CreationCollisionOption.ReplaceExisting);
await Launcher.LaunchFileAsync(proxyFile);
var resultPath = "script.py.python-proxy-result";
var counter = 0;
IStorageItem resultFile = null;
while (resultFile == null)
{
if (counter != 0)
{
if (counter++ > 5)
throw new Exception();
await Task.Delay(250);
}
resultFile = await local.TryGetItemAsync(resultPath);
}
try
{
using (var mutex = new Mutex(true, "PythonProxy Mutex")) { }
}
catch (AbandonedMutexException) { }
using (var stream = await local.OpenStreamForReadAsync(resultPath))
using (var reader = new StreamReader(stream))
{
var content = await reader.ReadToEndAsync();
var dialog = new MessageDialog(content);
await dialog.ShowAsync();
}
await scriptFile.DeleteAsync();
await proxyFile.DeleteAsync();
await resultFile.DeleteAsync();
}
我相信,如果你使用这样的东西(如何打印出子进程用C#打印的值?)来运行python脚本并捕获stdout,你应该能够实现所需的功能