Вот довольно простое сообщение, которое использует метод split
из accessand pandas str
, а затем использует NumPy для выравнивания каждой строки в один массив.
Соответствующие значения извлекаются путем повторения нерасширенный столбец правильное количество раз с np.repeat
.
var1 = df.var1.str.split(',', expand=True).values.ravel()
var2 = np.repeat(df.var2.values, len(var1) / len(df))
pd.DataFrame({'var1': var1,
'var2': var2})
var1 var2
0 a 1
1 b 1
2 c 1
3 d 2
4 e 2
5 f 2
В отличие от предложений по некоторым другим ответам, использование атрибута DllImport
по-прежнему является правильным.
Я честно не понимаю, почему вы не можете делать так, как все остальные в мир и укажите путь relative к вашей DLL. Да, путь, в котором ваше приложение будет установлено, отличается на компьютерах разных людей, но это в основном универсальное правило, когда дело доходит до развертывания. Механизм DllImport
разработан с учетом этого.
На самом деле это даже не работает DllImport
. Это правила загрузки загружаемых файлов Win32 DLL, которые управляют вещами, независимо от того, используете ли вы удобные управляемые обертки (маршаллер P / Invoke просто вызывает LoadLibrary
). Эти правила перечислены здесь подробно здесь , но важные из них здесь взяты:
Прежде чем система будет искать DLL, она проверит следующее:
- Если DLL с тем же именем модуля уже загружена в память, система использует загруженную DLL, независимо от того, в какой директории она находится. Система не ищет DLL.
- Если DLL находится в списке известных DLL для версии Windows, на которой выполняется приложение, система использует свою копию известной DLL (и известных DLL-зависимых библиотек DLL, если таковая имеется). Система не ищет DLL.
Если функция
SafeDllSearchMode
включена (по умолчанию), порядок поиска выглядит следующим образом:blockquote>
- Каталог, из которого загружено приложение.
- Системный каталог. Используйте функцию
GetSystemDirectory
, чтобы получить путь к этому каталогу.- 16-разрядный системный каталог. Нет функции, которая получает путь к этому каталогу, но его обыскивают.
- Каталог Windows. Используйте функцию
GetWindowsDirectory
, чтобы получить путь к этому каталогу.- Текущий каталог.
- Каталоги, указанные в переменной среды
PATH
. Обратите внимание, что это не включает путь для каждого приложения, указанный в разделе реестра приложений. Ключ App Paths не используется при вычислении пути поиска DLL.Итак, если вы не назовете свою DLL той же самой вещи, что и системная DLL (что вы должны явно не выполняйте ни при каких обстоятельствах), порядок поиска по умолчанию начнет искать в каталоге, из которого было загружено ваше приложение. Если вы разместите DLL там во время установки, он будет найден. Все сложные проблемы исчезают, если вы просто используете относительные пути.
Просто напишите:
[DllImport("MyAppDll.dll")] // relative path; just give the DLL's name static extern bool MyGreatFunction(int myFirstParam, int mySecondParam);
Но если этот не работает , причине, и вам нужно заставить приложение искать в другом каталоге DLL, вы можете изменить путь поиска по умолчанию, используя функцию
SetDllDirectory
. Обратите внимание, что в соответствии с документацией:После вызова
SetDllDirectory
стандартный путь поиска DLL:blockquote>
- Каталог, из которого загружено приложение.
- Каталог, заданный параметром
lpPathName
.- Системный каталог. Используйте функцию
GetSystemDirectory
, чтобы получить путь к этому каталогу.- 16-разрядный системный каталог. Нет функции, которая получает путь к этому каталогу, но выполняется поиск.
- Каталог Windows. Используйте функцию
GetWindowsDirectory
, чтобы получить путь к этому каталогу.- Каталоги, перечисленные в переменной среды
PATH
.So пока вы вызываете эту функцию перед вызовом функции, импортированной из DLL в первый раз, вы можете изменить путь поиска по умолчанию, используемый для поиска DLL. Разумеется, преимущество состоит в том, что вы можете передать значение dynamic для этой функции, которое вычисляется во время выполнения. Это невозможно с атрибутом
DllImport
, поэтому вы по-прежнему будете использовать относительный путь (только имя DLL) и полагаться на новый порядок поиска, чтобы найти его для вас.Вам придется выполнить P / Invoke. Объявление выглядит следующим образом:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern bool SetDllDirectory(string lpPathName);
DllImport будет работать нормально, если не указан полный путь до тех пор, пока dll находится где-то на системном пути. Возможно, вы сможете временно добавить папку пользователя в путь.
Даже лучше, чем предложение Ran использовать GetProcAddress, просто вызовите LoadLibrary перед любыми вызовами функций DllImport (только с именем файла без пути), и они автоматически загружают загруженный модуль.
Я использовал этот метод для выбора во время выполнения, загружать ли 32-разрядную или 64-разрядную родную DLL без необходимости изменять кучу функций P / Invoke-d. Прикрепите код загрузки в статическом конструкторе для типа, который имеет импортированные функции, и все будет работать нормально.
Если вам нужен DLL-файл, который не находится на пути или в расположении приложения, то я не думаю, что вы можете сделать именно это, потому что DllImport
- это атрибут, а атрибуты - это только метаданные, которые установлены по типам, элементам и другим языковым элементам.
Альтернатива, которая может помочь вам выполнить то, что, как я думаю, вы пытаетесь, - использовать native LoadLibrary
через P / Invoke, чтобы загрузить a. dll из нужного вам пути, а затем используйте GetProcAddress
, чтобы получить ссылку на нужную вам функцию из DLL. Затем используйте их для создания делегата, который вы можете вызвать.
Чтобы упростить его использование, вы можете установить этот делегат в поле своего класса, чтобы его использовать, как вызов метода-члена.
EDIT
Вот фрагмент кода, который работает, и показывает, что я имел в виду.
class Program
{
static void Main(string[] args)
{
var a = new MyClass();
var result = a.ShowMessage();
}
}
class FunctionLoader
{
[DllImport("Kernel32.dll")]
private static extern IntPtr LoadLibrary(string path);
[DllImport("Kernel32.dll")]
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
public static Delegate LoadFunction<T>(string dllPath, string functionName)
{
var hModule = LoadLibrary(dllPath);
var functionAddress = GetProcAddress(hModule, functionName);
return Marshal.GetDelegateForFunctionPointer(functionAddress, typeof (T));
}
}
public class MyClass
{
static MyClass()
{
// Load functions and set them up as delegates
// This is just an example - you could load the .dll from any path,
// and you could even determine the file location at runtime.
MessageBox = (MessageBoxDelegate)
FunctionLoader.LoadFunction<MessageBoxDelegate>(
@"c:\windows\system32\user32.dll", "MessageBoxA");
}
private delegate int MessageBoxDelegate(
IntPtr hwnd, string title, string message, int buttons);
/// <summary>
/// This is the dynamic P/Invoke alternative
/// </summary>
static private MessageBoxDelegate MessageBox;
/// <summary>
/// Example for a method that uses the "dynamic P/Invoke"
/// </summary>
public int ShowMessage()
{
// 3 means "yes/no/cancel" buttons, just to show that it works...
return MessageBox(IntPtr.Zero, "Hello world", "Loaded dynamically", 3);
}
}
Примечание: я не удосужился использовать FreeLibrary
, поэтому этот код не является полным. В реальном приложении вы должны позаботиться о выпуске загруженных модулей, чтобы избежать утечки памяти.
Пока вы знаете каталог, где ваши библиотеки C ++ можно найти во время выполнения, это должно быть простым. Я ясно вижу, что это имеет место в вашем коде. Ваш myDll.dll
будет присутствовать внутри каталога myLibFolder
во временной папке текущего пользователя.
string str = Path.GetTempPath() + "..\\myLibFolder\\myDLL.dll";
Теперь вы можете продолжать использовать оператор DllImport, используя строку const, как показано ниже:
[DllImport("myDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int DLLFunction(int Number1, int Number2);
Как раз во время выполнения, прежде чем вы вызовете функцию DLLFunction
в библиотеке C ++) добавьте эту строку кода в код C #:
string assemblyProbeDirectory = Path.GetTempPath() + "..\\myLibFolder\\myDLL.dll";
Directory.SetCurrentDirectory(assemblyProbeDirectory);
Это просто указывает CLR на поиск неуправляемых библиотек C ++ по пути каталога, который вы получили во время выполнения вашей программы. Вызов Directory.SetCurrentDirectory
устанавливает текущий рабочий каталог приложения в указанный каталог. Если ваш myDLL.dll
присутствует на пути, представленном дорожкой assemblyProbeDirectory
, он будет загружен, и желаемая функция будет вызвана через p / invoke.
Если все не удается, просто поместите DLL в папку windows\system32
. Компилятор найдет его. Укажите DLL для загрузки с помощью: DllImport("user32.dll"...
, установите EntryPoint = "my_unmanaged_function"
, чтобы импортировать вашу неуправляемую функцию в ваше приложение C #:
using System;
using System.Runtime.InteropServices;
class Example
{
// Use DllImport to import the Win32 MessageBox function.
[DllImport ("user32.dll", CharSet = CharSet.Auto)]
public static extern int MessageBox
(IntPtr hWnd, String text, String caption, uint type);
static void Main()
{
// Call the MessageBox function using platform invoke.
MessageBox (new IntPtr(0), "Hello, World!", "Hello Dialog", 0);
}
}
Источник и даже больше DllImport
примеров: http : //msdn.microsoft.com/en-us/library/aa288468 (v = vs.71) .aspx [/ д2]