Новые кодеры иногда пишут такой код:
my_calculator.button_0 = tkinter.Button(root, text=0)
my_calculator.button_1 = tkinter.Button(root, text=1)
my_calculator.button_2 = tkinter.Button(root, text=2)
...
Затем кодер остается с кучей именованных переменных с усилием кодирования O ( m * n ), где m - это число именованных переменных, а n - это количество раз, к которому необходимо получить доступ к группе переменных (включая создание) , Более проницательный новичок отмечает, что единственная разница в каждой из этих строк - это число, которое изменяется на основе правила и решает использовать цикл. Тем не менее, они зациклились на том, как динамически создавать эти имена переменных, и могут попробовать что-то вроде этого:
for i in range(10):
my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)
Вскоре они обнаруживают, что это не сработает.
Если программа требует произвольных переменных «имена», лучше всего подходит словарь, как объясняется в других ответах. Однако, если вы просто пытаетесь создать много переменных, и вы не возражаете ссылаться на них с последовательностью целых чисел, вы, вероятно, ищете list
. Это особенно верно, если ваши данные однородны, например, ежедневные показания температуры, еженедельные оценки викторины или сетка графических виджета.
Это можно собрать следующим образом:
my_calculator.buttons = []
for i in range(10):
my_calculator.buttons.append(tkinter.Button(root, text=i))
Этот list
также может быть создан в одной строке с пониманием:
my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]
Результат в любом случае - это заполненный list
, с первым элементом, к которому обращаются с помощью my_calculator.buttons[0]
, следующего с my_calculator.buttons[1]
и т. д. Имя переменной «base» становится именем list
, и для доступа к нему используется различный идентификатор.
Наконец, не забудьте другие структуры данных, такие как set
- это аналогично словарю, за исключением того, что каждое «имя» не имеет привязанного к нему значения. Если вам просто нужна «сумка» объектов, это может быть отличным выбором. Вместо этого:
keyword_1 = 'apple'
keyword_2 = 'banana'
if query == keyword_1 or query == keyword_2:
print('Match.')
У вас будет следующее:
keywords = {'apple', 'banana'}
if query in keywords:
print('Match.')
Используйте последовательность list
для последовательности похожих объектов, a set
для произвольного - помещенный пакет предметов или dict
для мешка с именами со связанными значениями.
5.6. Создание процесса Вызов fork в Cygwin особенно интересен, поскольку он плохо отображается поверх Win32 API. Это очень затрудняет правильную реализацию. В настоящее время ветвь Cygwin является реализацией без копирования при записи, аналогичной той, что была в ранних версиях UNIX. Первое, что происходит, когда родительский процесс разветвляется на дочерний процесс, - это то, что родительский процесс инициализирует пробел в таблице процессов Cygwin для дочернего элемента. Затем он создает приостановленный дочерний процесс с помощью вызова Win32 CreateProcess. Затем родительский процесс вызывает setjmp для сохранения своего собственного контекста и устанавливает указатель на него в области общей памяти Cygwin (общей для всех задач Cygwin). Затем он заполняет дочерние разделы .data и .bss, копируя из своего собственного адресного пространства в приостановленное дочернее адресное пространство. После инициализации адресного пространства дочернего объекта дочерний процесс запускается, пока родительский объект ожидает мьютекса. Ребенок обнаруживает, что он разветвлен и выполняет прыжки в длину с использованием сохраненного буфера перехода. Затем дочерний объект устанавливает мьютекс, на котором ожидает родительский элемент, и блокирует другой мьютекс. Это сигнал для родителя скопировать свой стек и кучу в дочерний элемент, после чего он освобождает мьютекс, которого ожидает дочерний элемент, и возвращается из вызова fork. Наконец, ребенок выходит из режима блокировки последнего мьютекса, воссоздает все отображенные в памяти области, переданные ему через общую область, и возвращается из самого форка. Хотя у нас есть некоторые идеи относительно того, как ускорить работу В нашей реализации fork за счет уменьшения количества переключений контекста между родительским и дочерним процессами fork почти наверняка будет неэффективным в Win32. К счастью, в большинстве случаев порожденное семейством вызовов, предоставляемое Cygwin, можно заменить пару fork / exec с небольшими усилиями. Эти вызовы отображаются чисто поверх Win32 API. В результате они намного эффективнее. Изменение программы драйвера компилятора для вызова spawn вместо fork было тривиальным изменением и увеличило скорость компиляции на двадцать-тридцать процентов в наших тестах. Однако spawn и exec представляют свои собственные трудности. Поскольку в Win32 нет никакого способа сделать настоящий exec, Cygwin должен изобрести свои собственные идентификаторы процессов (PID). В результате, когда процесс выполняет несколько вызовов exec, будет несколько PID Windows, связанных с одним PID Cygwin. В некоторых случаях заглушки каждого из этих процессов Win32 могут задерживаться, ожидая выхода из своего exec'd процесса Cygwin. blockquote> Звучит как большая работа, не так ли? И да, это slooooow. РЕДАКТИРОВАТЬ: документ устарел, пожалуйста, посмотрите этот отличный ответ для обновления
Я, конечно, не знаю подробностей об этом, потому что я никогда не делал этого, но родной NT API имеет возможность разветвлять процесс (подсистема POSIX в Windows нуждается в этой возможности - я не уверен, что подсистема POSIX поддерживается даже больше).
Поиск ZwCreateProcess () должен содержать дополнительную информацию - например, этот бит информации от Максима Шацких :
Самым важным параметром здесь является SectionHandle. Если этот параметр равен NULL, ядро перекроет текущий процесс. В противном случае этот параметр должен быть дескриптором объекта раздела SEC_IMAGE, созданного в EXE-файле, перед вызовом ZwCreateProcess ().
Хотя обратите внимание, что Коринна Виншен указывает, что Cygwin обнаружил использование ZwCreateProcess ( ) еще ненадежный :
Iker Arizmendi писал (а):
> Because the Cygwin project relied solely on Win32 APIs its fork > implementation is non-COW and inefficient in those cases where a fork > is not followed by exec. It's also rather complex. See here (section > 5.6) for details: > > http://www.redhat.com/support/wpapers/cygnus/cygnus_cygwin/architecture.html
Этот документ довольно старый, 10 лет или около того. Хотя мы все еще используем вызовы Win32 для эмуляции fork, метод изменился заметно. В частности, мы больше не создаем дочерний процесс в приостановленном состоянии, если только конкретные данные не нуждаются в специальной обработке в родительском элементе, прежде чем они будут скопированы в дочерний. В текущем выпуске 1.5.25 единственный случай для дочернего ребенка - открытые сокеты в родительском. Предстоящая версия 1.7.0 вообще не будет приостановлена.
Одна из причин не использовать ZwCreateProcess заключалась в том, что до версии 1.5.25 мы по-прежнему поддерживаем пользователей Windows 9x. Однако две попытки использовать ZwCreateProcess для систем на базе NT потерпели неудачу по той или иной причине.
Было бы очень хорошо, если бы этот материал был бы лучше или вообще документирован, особенно пара данных и как подключите процесс к подсистеме. Хотя fork не является концепцией Win32, я не вижу, что было бы плохо сделать fork проще.
fork
с немедленным exec
", то, возможно, CreateProcess является кандидатом. Но fork
без exec
часто бывает желательным, и это то, что водители люди просят реального fork
.
– Aaron McDaid
16 October 2014 в 18:56
fork
Unix, но он выполняет это с помощью негерметичного решения , и вы должны быть готовы к непредвиденным ситуациям.
– Pacerier
13 August 2015 в 11:11
Люди пытались реализовать fork в Windows. Это самая близкая вещь, которую я могу найти:
Снято с: http://doxygen.scilab.org/5.3/d0/d8f/forkWindows_8c_source.html#l00216
static BOOL haveLoadedFunctionsForFork(void);
int fork(void)
{
HANDLE hProcess = 0, hThread = 0;
OBJECT_ATTRIBUTES oa = { sizeof(oa) };
MEMORY_BASIC_INFORMATION mbi;
CLIENT_ID cid;
USER_STACK stack;
PNT_TIB tib;
THREAD_BASIC_INFORMATION tbi;
CONTEXT context = {
CONTEXT_FULL |
CONTEXT_DEBUG_REGISTERS |
CONTEXT_FLOATING_POINT
};
if (setjmp(jenv) != 0) return 0; /* return as a child */
/* check whether the entry points are
initilized and get them if necessary */
if (!ZwCreateProcess && !haveLoadedFunctionsForFork()) return -1;
/* create forked process */
ZwCreateProcess(&hProcess, PROCESS_ALL_ACCESS, &oa,
NtCurrentProcess(), TRUE, 0, 0, 0);
/* set the Eip for the child process to our child function */
ZwGetContextThread(NtCurrentThread(), &context);
/* In x64 the Eip and Esp are not present,
their x64 counterparts are Rip and Rsp respectively. */
#if _WIN64
context.Rip = (ULONG)child_entry;
#else
context.Eip = (ULONG)child_entry;
#endif
#if _WIN64
ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Rsp,
MemoryBasicInformation, &mbi, sizeof mbi, 0);
#else
ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Esp,
MemoryBasicInformation, &mbi, sizeof mbi, 0);
#endif
stack.FixedStackBase = 0;
stack.FixedStackLimit = 0;
stack.ExpandableStackBase = (PCHAR)mbi.BaseAddress + mbi.RegionSize;
stack.ExpandableStackLimit = mbi.BaseAddress;
stack.ExpandableStackBottom = mbi.AllocationBase;
/* create thread using the modified context and stack */
ZwCreateThread(&hThread, THREAD_ALL_ACCESS, &oa, hProcess,
&cid, &context, &stack, TRUE);
/* copy exception table */
ZwQueryInformationThread(NtCurrentThread(), ThreadBasicInformation,
&tbi, sizeof tbi, 0);
tib = (PNT_TIB)tbi.TebBaseAddress;
ZwQueryInformationThread(hThread, ThreadBasicInformation,
&tbi, sizeof tbi, 0);
ZwWriteVirtualMemory(hProcess, tbi.TebBaseAddress,
&tib->ExceptionList, sizeof tib->ExceptionList, 0);
/* start (resume really) the child */
ZwResumeThread(hThread, 0);
/* clean up */
ZwClose(hThread);
ZwClose(hProcess);
/* exit with child's pid */
return (int)cid.UniqueProcess;
}
static BOOL haveLoadedFunctionsForFork(void)
{
HANDLE ntdll = GetModuleHandle("ntdll");
if (ntdll == NULL) return FALSE;
if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory &&
ZwCreateThread && ZwGetContextThread && ZwResumeThread &&
ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose)
{
return TRUE;
}
ZwCreateProcess = (ZwCreateProcess_t) GetProcAddress(ntdll,
"ZwCreateProcess");
ZwQuerySystemInformation = (ZwQuerySystemInformation_t)
GetProcAddress(ntdll, "ZwQuerySystemInformation");
ZwQueryVirtualMemory = (ZwQueryVirtualMemory_t)
GetProcAddress(ntdll, "ZwQueryVirtualMemory");
ZwCreateThread = (ZwCreateThread_t)
GetProcAddress(ntdll, "ZwCreateThread");
ZwGetContextThread = (ZwGetContextThread_t)
GetProcAddress(ntdll, "ZwGetContextThread");
ZwResumeThread = (ZwResumeThread_t)
GetProcAddress(ntdll, "ZwResumeThread");
ZwQueryInformationThread = (ZwQueryInformationThread_t)
GetProcAddress(ntdll, "ZwQueryInformationThread");
ZwWriteVirtualMemory = (ZwWriteVirtualMemory_t)
GetProcAddress(ntdll, "ZwWriteVirtualMemory");
ZwClose = (ZwClose_t) GetProcAddress(ntdll, "ZwClose");
if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory &&
ZwCreateThread && ZwGetContextThread && ZwResumeThread &&
ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose)
{
return TRUE;
}
else
{
ZwCreateProcess = NULL;
ZwQuerySystemInformation = NULL;
ZwQueryVirtualMemory = NULL;
ZwCreateThread = NULL;
ZwGetContextThread = NULL;
ZwResumeThread = NULL;
ZwQueryInformationThread = NULL;
ZwWriteVirtualMemory = NULL;
ZwClose = NULL;
}
return FALSE;
}
fork
выйдет из строя, это приведет к сбою программы, или поток просто сработает? Если он сбой программы, то это не работает. Просто любопытно, потому что я ищу реальное решение и надеюсь, что это может быть достойной альтернативой.
– leetNightshade
28 April 2014 в 21:26
Ваши лучшие варианты: CreateProcess () или CreateThread () . Здесь есть дополнительная информация о портировании здесь .
В следующем документе представлена некоторая информация о переносе кода из UNIX в Win32: https://msdn.microsoft.com/en-us/library/y23kc048.aspx
Помимо всего прочего, это указывает на то, что модель процесса отличается от двух систем и рекомендует рассматривать CreateProcess и CreateThread, где требуется поведение типа fork ().
До того, как Microsoft представила свою новую «подсистему Linux для Windows», CreateProcess()
была самой близкой вещью Windows к fork()
, но Windows требует указать исполняемый файл для запуска в этом процессе.
Процесс создания UNIX сильно отличается от Windows. Его вызов fork()
в основном дублирует текущий процесс почти в целом, каждый в своем собственном адресном пространстве, и продолжает запускать их отдельно. Хотя сами процессы разные, они все еще работают с одной и той же программой . Здесь здесь для хорошего обзора модели fork/exec
.
Going наоборот, эквивалент Windows CreateProcess()
представляет собой fork()/exec()
пару функций в UNIX.
Если вы портировали программное обеспечение на Windows, а вы не Смысл слоя перевода, Cygwin предоставил возможность, которую вы хотите, но это было довольно kludgey.
Конечно, с новой подсистемой Linux , ближайшей вещь Windows fork()
на самом деле fork()
: -)
Если вы только заботитесь о создании подпроцесса и ожидаете его, возможно, _spawn * API в process.h достаточно. Вот еще информация об этом:
https://docs.microsoft.com/en-us/cpp/c-runtime-library/process-and-environment-control https://en.wikipedia.org/wiki/Process.h
Нет простого способа эмуляции fork () в Windows.
Я предлагаю вам вместо этого использовать потоки.
fork
была точно i>, что сделал CygWin. Но, если вы когда-либо читали , как i>, они это делали, yor & quot; нет простого способа & quot; это грубое недоразумение :-)
– paxdiablo
5 April 2018 в 01:11
Ну, на самом деле окна не имеют ничего подобного. Тем более что fork может использоваться для концептуального создания потока или процесса в * nix.
Итак, я должен сказать:
#foo.py
import os
print os.getcwd()
print __file__
#in the interactive interpreter
>>> import foo
/Users/jason
foo.py
#and finally, at the shell:
~ % python foo.py
/Users/jason
foo.py
и
>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'
(я слышал, что для приложений на C __file__
неплотного решения
, и вы должны быть готовы к неожиданным ситуациям. – Unix, но выполняет это с помощью Pacerier 13 August 2015 в 11:11