Как передать массив в функцию в Python?
Массив — это объект, его можно передать в функцию как и любой другой объект (число, строку и т.д.) в качестве аргумента.
# можно передать напрямую print([1, 2, 3, 4]) # [1, 2, 3, 4] # можно после присваивания переменной fruits = ['apple', 'banana', 'orange'] print(fruits) # ['apple', 'banana', 'orange']
Python-сообщество
- Начало
- » Python для новичков
- » ctypes — как изменить в функции содержимое двумерного массива?
#1 Март 15, 2020 20:12:18
maksimio Зарегистрирован: 2020-03-15 Сообщения: 3 Репутация: 0 Профиль Отправить e-mail
ctypes — как изменить в функции содержимое двумерного массива?
Здравствуйте, возникла следующая проблема: я не могу понять, как правильно с помощью ctypes передать в C-функцию двумерный массив из python, размер которого задается во время выполнения python-скрипта. В функции требуется изменить элементы двумерного массива. Гугление помогло найти лишь передачу одномерного массива в функцию — это сработало. Но как реализовать мой случай я не понимаю.
Вот пример функции на C, которую требуется вызвать из кода на python. Она перед этим компилируется в динамическую библиотеку.
void changeArray(int arrayLen_1, int arrayLen_2, int **array) for (int i = 0; i < arrayLen_1; i++) for (int j = 0; j < arrayLen_2; j++) array[i][j] = j+i; >
#2 Март 15, 2020 22:32:04
doza_and От: Зарегистрирован: 2010-08-15 Сообщения: 4138 Репутация: 252 Профиль Отправить e-mail
ctypes — как изменить в функции содержимое двумерного массива?
maksimio
void changeArray(int arrayLen_1, int arrayLen_2, int **array)
С такой сигнатурой это вовсе не двумерный массив. Передать то не проблема. Но изготовить такую штуку в питоне будет ой как непросто.
Приведите код на питоне которым вы собрались создавать этот “двумерный массив”.
#3 Март 16, 2020 00:15:08
maksimio Зарегистрирован: 2020-03-15 Сообщения: 3 Репутация: 0 Профиль Отправить e-mail
ctypes — как изменить в функции содержимое двумерного массива?
Двумерные массивы планировал создавать следующим образом:
a = 56 b = 4 array = [[0 for i in range(a)] for k in range(b)]
Сейчас я решил свою проблему, сколхозив передачу нескольких одномерных массивов в C-функцию. Пока это сгодится, но мне желательно бы иметь возможность изменять произвольное количество массивов, а не 8, как в коде ниже.
Код на Python функции, которая собирает C-функцию с помощью ctypes:
def read_csi(csi_buf, nr, nc, num_tones): '''Расшифровывает csi из csi_buf, вызывая с помощью ctypes C-функцию''' if nr != 2 or nc != 2 or num_tones != 56: raise TypeError("Error: nr != 2 or nc != 2 or num_tones != 56") csi_re = [[0 for i in range(num_tones)] for k in range(nr * nc)] csi_im = [[0 for i in range(num_tones)] for k in range(nr * nc)] lib = ctypes.CDLL('./libextract_csi.so') lib.read_csi.restype = None lib.read_csi.argtypes = (ctypes.POINTER(ctypes.c_ubyte), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER( ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) csi_buf = (ctypes.c_ubyte * len(csi_buf))(*csi_buf) for i in range(nr*nc): csi_re[i] = (ctypes.c_int * len(csi_re[i]))(*csi_re[i]) csi_im[i] = (ctypes.c_int * len(csi_im[i]))(*csi_im[i]) lib.read_csi(csi_buf, csi_re[0], csi_re[1], csi_re[2], csi_re[3], csi_im[0], csi_im[1], csi_im[2], csi_im[3]) csi_re[0], csi_re[1], csi_re[2], csi_re[3] = csi_re[0][:], csi_re[1][:], csi_re[2][:], csi_re[3][:] csi_im[0], csi_im[1], csi_im[2], csi_im[3] = csi_im[0][:], csi_im[1][:], csi_im[2][:], csi_im[3][:] return 're': csi_re, 'im': csi_im>
void read_csi(unsigned char *local_h, int *re0, int *re1, int *re2, int *re3, int *im0, int *im1, int *im2, int *im3)
//здесь происходит изменение содержимого всех массивов re и im на основании данных из local_h
>
#4 Март 16, 2020 06:48:52
doza_and От: Зарегистрирован: 2010-08-15 Сообщения: 4138 Репутация: 252 Профиль Отправить e-mail
ctypes — как изменить в функции содержимое двумерного массива?
maksimio
Сейчас я решил свою проблему
Очевидно вы ее не решили поскольку решение не соответствует требованиям первого поста.
В С не бывает двумерных массивов с переменными размерностями. Поэтому чисто формально передать туда такое нельзя.
Точнее непонятно в чем ваша проблема.
Это учебная задача? Нет -тогда нельзя менять интерфейс.
Вы хотите повысить быстродействие? Нет. Очевидно что все ваши манипуляции с массивами сожрут производительность. Тогда вы бы работали с данными лежащими в памяти подряд. Те нельзя работать со списками питона. Вместо них надо либо struct использовать либо что-то типа (ctypes.c_int*3)*5 либо numpy.array.
Вы делаете интерфейс к готовой системе? Нет. Сложность зашкаливает. В этом случае вы бы использовали boost python, pybind11, swig, cython или другие средства для этого предназначенные.
#5 Март 17, 2020 16:59:05
maksimio Зарегистрирован: 2020-03-15 Сообщения: 3 Репутация: 0 Профиль Отправить e-mail
ctypes — как изменить в функции содержимое двумерного массива?
Моя цель — повысить производительность. Время которое сожрут списки несущественно относительно времени, которое экономится, если C-функцию запускать с помощью ctypes (проверено профилировщиком). Я пробовал переписать эту функцию на python и не вызывать ее как dll — тогда код работает в 5 раз дольше.
Сейчас я просто хотел бы понять, каким образом я могу подать в C-функцию с помощью ctypes двумерный (а еще лучше многомерный) массив (т.е. массив указателей на указатели в C-функции). Я не знаю, с помощью какого типа данных в python это лучше сделать. У меня мало опыта, поэтому я был бы рад, если бы вы посоветовали что-то на этот счет. Либо я просто по прошествии некоторого времени смогу найти в интернете, как это можно сделать.
#6 Март 17, 2020 20:46:48
doza_and От: Зарегистрирован: 2010-08-15 Сообщения: 4138 Репутация: 252 Профиль Отправить e-mail
ctypes — как изменить в функции содержимое двумерного массива?
maksimio
каким образом я могу подать в C-функцию с помощью ctypes двумерный (а еще лучше многомерный) массив (т.е. массив указателей на указатели в C-функции)
Вы наверное не очень хорошо знаете C. Поэтому я еще раз вам повторю. Двумерный массив и массив указателей на указатели это совершенно разные типы.
Для второго нормальных аналогов в питоне нет.
#7 Март 17, 2020 23:31:40
py.user.next От: Зарегистрирован: 2010-04-29 Сообщения: 9639 Репутация: 839 Профиль Отправить e-mail
ctypes — как изменить в функции содержимое двумерного массива?
maksimio
Моя цель — повысить производительность.
Напиши, какую программу делаешь. Неглубокое знание языка C и неглубокое знания языка Python вряд ли приведут к успеху. Так что, если у тебя и программа не сделана ещё, то заниматься повышением её производительности считается ошибкой, которая называется “преждевременная оптимизация”.
Массивы и функции
Массивы, также как остальные переменные, можно передавать в функции в качестве аргументов. Рассмотрим такую программу:
#include #include #define N 10 void arr_make(int arr[], int min, int max); int main () { int arrI[N], i; arr_make(arrI, 30, 90); for (i=0; iN; i++) printf("%d ", arrI[i]); printf("\n"); } void arr_make(int arr[], int min, int max) { int i; srand(time(NULL)); for (i=0; iN; i++) arr[i] = rand() % (max - min + 1) + min; }
В теле функции main() объявляется массив, состоящий из 10 элементов. Далее вызывается функция arr_make() , которой передаются в качестве аргументов имя массива и два целых числа.
Если посмотреть на функцию arr_make() , то можно заметить, что ее первый параметр выглядит немного странно. Функция принимает массив неизвестно какого размера. Если предположить, что массивы передаются по значению, т.е. передаются их копии, то как при компиляции будет вычислен необходимый объем памяти для функции arr_make() , если неизвестно какого размера будет один из ее параметров?
На прошлом уроке мы выяснили, что имя массива — это константный указатель на первый элемент массива; т.е. имя массива содержит адрес. Выходит, что мы передаем в функцию копию адреса, а не копию значения. Как мы уже знаем, передача адреса приводит к возможности изменения локальных переменных в вызывающей функции из вызываемой. Ведь на одну и ту же ячейку памяти могут ссылаться множество переменных, и изменение значения в этой ячейке с помощью одной переменной неминуемо отражается на значениях других переменных.
Описание вида arr[] в параметрах функций говорит о том, что в качестве значения мы получаем указатель на массив, а не обычную (скалярную) переменную типа int, char, float и т.п.
Продолжим рассуждения. Если в функцию передается только адрес массива, то в теле функции никакого массива не существует, и когда там выполняется выражение типа arr[i] , то на самом деле arr — это не имя массива, а переменная-указатель, к которой прибавляется смещение. Поэтому цикл в функции arr_make() можно переписать на такой:
for(i=0; iN; i++) *arr++ = rand() % (max - min + 1) + min;
В теле цикла результат выражения справа от знака присваивания записывается по адресу, на который указывает arr. За это отвечает выражение *arr . Затем указатель arr начинает указывать на следующую ячейку памяти, т.к. к нему прибавляется единица ( arr++ ). Еще раз: сначала выполняется выражение записи значения по адресу, который содержится в arr; после чего изменяется адрес, содержащийся в указателе (сдвигается на одну ячейку памяти определенного размера).
Поскольку мы можем изменять arr, это доказывает, что arr — обычный указатель, а не имя массива. Тогда зачем в заголовке функции такой гламур, как arr[] ? Действительно, чаще используют просто переменную-указатель:
void arr_make(int *arr, int min, int max);
Хотя в таком случае становится не очевидно, что принимает функция — указатель на обычную переменную или все-таки на массив. В любом случае она будет работать.
Часто при передаче в функцию массивов туда же передают и количество его элементов в виде отдельного параметра. В примере выше N является глобальной константой, поэтому ее значение доступно как из функции main() , так и arr_make() . Иначе, более грамотно было бы написать функцию arr_make() так:
void arr_make(int *arr, int n, int min, int max) { int i; srand(time(NULL)); for (i=0; in; i++) arr[i] = rand() % (max - min + 1) + min; }
В данном случае параметр n — это количество обрабатываемых элементов массива.
Следует еще раз обратить внимание на то, что при передачи имени массива в функцию, последняя может его изменять. Однако такой эффект не всегда является желательным. Конечно, можно просто не менять значения элементов массива внутри функции, как в данном примере, где вычисляется сумма элементов массива; при этом сами элементы никак не изменяются:
int arr_sum(int *arr) { int i, s=0; for(i=0; iN; i++) { s = s + arr[i]; } return s; }
Но если вы хотите написать более надежную программу, в которой большинство функций не должны менять значения элементов массивов, то лучше в заголовках этих функций объявлять параметр-указатель как константу, например:
int arr_sum(const int *arr);
В этом случае, любая попытка изменить значение по адресу, содержащемуся в таком константном указателе, будет приводить к ошибке и программист будет знать, что функция пытается изменить массив.
Усовершенствуем программу, которая была приведена в начале этого урока:
#include #include #define N 10 void arr_make(int *arr, int min, int max); void arr_inc_dec(int arr[], char sign); void arr_print(int *arr); int main () { int arrI[N], i, minimum, maximum; char ch; printf("Enter minimum & maximum: "); scanf("%d %d", &minimum, &maximum); arr_make(arrI, minimum, maximum); arr_print(arrI); scanf("%*c"); // избавляемся от \n printf("Enter sign (+,-): "); scanf("%c", &ch); arr_inc_dec(arrI, ch); arr_print(arrI); } void arr_make(int *arr, int min, int max) { int i; srand(time(NULL)); for(i=0; iN; i++) *arr++ = rand() % (max - min + 1) + min; } void arr_inc_dec(int *arr, char sign) { int i; for (i=0; iN; i++) { if (sign == '+') arr[i]++; if (sign == '-') arr[i]--; } } void arr_print(int *arr) { int i; printf("The array is: "); for (i=0; iN; i++) printf("%d ", *arr++); printf("\n"); }
Теперь у пользователя запрашивается минимум и максимум, затем создается массив из элементов, значения которых лежат в указанном диапазоне. Массив выводится на экран с помощью функции arr_print() . Далее у пользователя запрашивается знак + или -. Вызывается функция arr_inc_dec() , которая в зависимости от введенного знака увеличивает или уменьшает на единицу значения элементов массива.
В функциях arr_make() и arr_print() используется нотация указателей. Причем в теле функций значения указателей меняются: они указывают сначала на первый элемент массива, затем на второй и т.д. В функции arr_inc_dec() используется вид обращения к элементам массива. При этом значение указателя не меняется: к arr прибавляется смещение, которое увеличивается на каждой итерации цикла. Ведь на самом деле запись arr[i] означает *(arr+i) .
При использовании нотации обращения к элементам массива программы получаются более ясные, а при использовании записи с помощью указателей они компилируются чуть быстрее. Это связано с тем, что когда компилятор встречает выражение типа arr[i] , то он тратит время на преобразование его к виду *(arr+i) . Однако лучше потратить лишнюю секунду при компиляции, но получить более читаемый код.
- Переделайте программу, которая приведена выше таким образом, чтобы она работала с вещественными числами. Вместо функции arr_inc_dec() напишите другую, которая изменяет значения элементов массива на любое значение, которое указывает пользователь.
- Напишите программу, в которой из одной функции в другую передается указатель не на начало массива, а на его середину.
- Напишите программу, в которой из функции main() в другую функцию передаются два массива: «заполненный» и «пустой». В теле этой функции элементам «пустого» массива должны присваиваться значения, так или иначе преобразованные из значений элементов «заполненного» массива, который не должен изменяться.
Курс с решением части задач:
pdf-версия
передача массива в функцию на питоне [закрыт]
Закрыт. Этот вопрос необходимо уточнить или дополнить подробностями. Ответы на него в данный момент не принимаются.
Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение.
Закрыт 4 года назад .
Как на питоне передать массив на выход в функцию? Делаю минимализацию по методу квайна, там очень полезно будет это использование.
Отслеживать
задан 5 окт 2019 в 5:35
Артём Подковыров Артём Подковыров
35 1 1 золотой знак 1 1 серебряный знак 5 5 бронзовых знаков
Так же, как аргумент любого другого типа.
5 окт 2019 в 5:59
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Под массивом вы скорее всего имеете в виду list? Не совсем понятно в чем проблема его передачи в функцию:
def my_function(some_list): #code pass my_function([1, 2, 3, 4, 5])
Или предварительно записав его в переменную
my_list = [1, 2, 3, 4, 5] my_function(my_list)
Отслеживать
ответ дан 5 окт 2019 в 8:04
Константин Комиссаров Константин Комиссаров
2,536 15 15 серебряных знаков 35 35 бронзовых знаков
invalid syntax же!
5 окт 2019 в 16:35
@andreymal где? почему?
5 окт 2019 в 16:37
Вы сами-то пробовали первый пример запустить?
5 окт 2019 в 16:38
@andreymal, а, все, тупанул, сейчас поправлю)
5 окт 2019 в 16:39
Да и второй пример тоже просто не работает, потому что локальная переменная my_list перекроет глобальную, и глобальный список будет недоступен внутри функции
5 окт 2019 в 16:40
- python
- массивы
- функции
- return
- Важное на Мете
Похожие
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.29.1725
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.