Форум программистов, компьютерный форум, киберфорум
Python для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.71/21: Рейтинг темы: голосов - 21, средняя оценка - 4.71
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739

Замедление скрипта

06.08.2019, 17:39. Показов 4684. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день. Решил немного освоить питон. Накидал небольшой скрипт который вытаскивает табличку из Excel файла. В файле строчек примерно до 3000.
чем дальше по файлу ползет скрипт, тем медленнее он выполняется. Такое ощущение, что он с каждым проходом от начала забора бегает. Читал, что такое можно поймать при использовании неизменяемых типов, пока не могу сообразить.
Можете ткнуть мордой?
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
from tkinter import filedialog
from tkinter import *
 
from typing import NamedTuple
 
import openpyxl
import sys
 
class Unit(NamedTuple):
    address: int
    description: str
    type: int
    size: int
    readonly: bool
    eeprom: bool
 
 
def openXLSMFile():
    Tk().withdraw()
    filename = filedialog.askopenfilename(title = "Select .xlsm file", filetypes = (("Excel files","*.xlsm *.xlsx"),("all files","*.*")))
    return filename
 
def findTableOffset(worksheet):
    for x in range(1, 100):
        for y in range (1, 100):
            if worksheet.cell(row = x, column = y).value == "Индекс":
                return x + 1, y
    return -1, -1
 
def makeUnit(worksheet, currentRow, columnOffset):
    address = int(worksheet.cell(row = currentRow, column = columnOffset).value)
    description = str(worksheet.cell(row = currentRow, column = columnOffset + 2).value)
    type = str(worksheet.cell(row = currentRow, column = columnOffset + 4).value)
    readonly = str(worksheet.cell(row = currentRow, column = columnOffset + 5).value)
    eeprom = str(worksheet.cell(row = currentRow, column = columnOffset + 6).value)
    if description == "Резерв" or description == "None":
        return -1
    size = 1
    if type == "WORD":
        size = 1
        type = 0
    elif type == "FLOAT":
        size = 2
        type = 1
    elif type[:4] == "CHAR":
        temp = type.rstrip("]").strip("CHAR[")
        if not str(temp).isdigit():
            return -1
        size = int(temp) / 2
        type = 2
    else:
        return -1
    if readonly == "R":
        readonly = True
    elif readonly == "W" or readonly == "RW" or readonly == "R/W" or readonly == "None":
        readonly == False
    else:
        return -1
    if eeprom == "EEPROM":
        eeprom = True
    elif eeprom == "NO" or eeprom == "None":
        eeprom = False
    else:
        return -1
    
    unit = Unit(address, description, type, size, readonly, eeprom)
    return unit
 
print("Use this script to convert Excel files to ModbusUtility file .mem")
 
filename = openXLSMFile()
if filename != "":
    print("File " + filename + " was opened Successfully")
    workbook = openpyxl.load_workbook(filename, read_only = True)
    worksheet = workbook.active
    rowOffset, columnOffset = findTableOffset(worksheet)
    if rowOffset == -1:
        sys.exit("File " + filename + " hasn't got modbus memory table!")
    currentRow = rowOffset
    unitsList = []
    while str(worksheet.cell(row = currentRow, column = columnOffset).value).isdigit():
        unit = makeUnit(worksheet, currentRow, columnOffset)
        if(unit != -1):
            unitsList.append(unit)
            print(str(unit.address), end = '\t\t')
            print(str(unit.description), end = '\t\t')
            print(str(unit.type), end = '\t')
            print(str(unit.size), end = '\t')
            print(str(unit.readonly), end = '\t')
            print(str(unit.eeprom))
        currentRow += 1
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
06.08.2019, 17:39
Ответы с готовыми решениями:

Вызов скрипта из скрипта
Мой скрипт должен отркрывать текстовый файл, в котором на языке python просто пересичлены функции и команд, например get_value() x =...

Запуск скрипта из скрипта
Возник вопрос, можно ли запустить python скрипт из другого python скрипта? Если да, то как?

Запуск скрипта из скрипта
нужно чтобы пользователь вводил строку в TexEdit и программа распознавала бы ввод и создавала переменные "на лету". ...

12
Эксперт Python
 Аватар для dondublon
4653 / 2073 / 366
Регистрация: 17.03.2012
Сообщений: 10,183
Записей в блоге: 6
06.08.2019, 18:00
Лучший ответ Сообщение было отмечено _SayHello как решение

Решение

Подозреваю, обращение worksheet.cell медленное. Вызывается многократно. Поищите метод для поточного чтения всего листа сразу.
А зачем вообще так мучиться, почему бы не сохранить файл в .csv?
И, кстати, модуль typing не для этого. Для этого - collections.namedtuple.
1
Эксперт Python
5438 / 3859 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
06.08.2019, 18:25
Цитата Сообщение от _SayHello Посмотреть сообщение
Можете ткнуть мордой?
Было бы проще, если бы вы приложили файл и написали чего хотите.
А так как код весьма странный... непитоничный от слова совсем.... добавить особо нечего.
1
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
06.08.2019, 23:45  [ТС]
dondublon,
Цитата Сообщение от dondublon Посмотреть сообщение
Подозреваю, обращение worksheet.cell медленное.
Да, я нашел инфу, что в этом дело. Буду пробовать другие методы.
Цитата Сообщение от dondublon Посмотреть сообщение
А зачем вообще так мучиться, почему бы не сохранить файл в .csv?
Я, честно говоря, для себя задание придумал.
Цитата Сообщение от Garry Galler Посмотреть сообщение
Было бы проще, если бы вы приложили файл и написали чего хотите.
да я ж не студент, которому готовое надо. Я сам поковыряться хочу, возможно с подсказками)
По сути задача тривиальная.
Есть xlsm или xlsx файл, в котором лежит таблица состоящая из N столбцов и M строк. N - известно, M - нет.
В каждой строке лежит структура из N параметров.
1) Адрес
2) Описание
3) Тип
4) Параметр 1
5) Параметр 2
Эти параметры описывают один объект.
Строки отсортированы по адресу.
Некоторые строки могут иметь адрес, но иметь пустое описание - объект не существует, эти строки игнорируются.
Тип и параметры могут быть записаны некорректно - эти строки тоже пропускаем.
Задача по сути вытащить все валидные структуры параметров и переконвертировать в другой файл параметров поддерживаемый QSettings.
Табличка имеет заголовки столбцов, но не обязательно находится в A1. Первый столбец и первая строка имеет значение в ячейке "Индекс".
В общем небольшая прикладная задачка. Готовое решение не нужно.
После Си и С++, нетипичная для меня проблема возникла, вот и решил спросить.
Цитата Сообщение от Garry Galler Посмотреть сообщение
А так как код весьма странный... непитоничный от слова совсем....
я сегодня первый день пишу на скриптовом языке, стилем пока, увы, не овладел(
0
Эксперт Python
5438 / 3859 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
07.08.2019, 02:16
Лучший ответ Сообщение было отмечено _SayHello как решение

Решение

Цитата Сообщение от _SayHello Посмотреть сообщение
В общем небольшая прикладная задачка.
В Python такие задачи (in production) голым Python, как правило, не делают :-)
Есть pandas, в pandas есть read_excel. На выходе dataframe. Структура у который 100500 методов. То есть можно сделать что хочешь с данными.
Но если
Цитата Сообщение от _SayHello Посмотреть сообщение
для себя задание придумал.
- дело барское - мучайся :-)

длинно:
Python
1
elif readonly == "W" or readonly == "RW" or readonly == "R/W" or readonly == "None"
питонично:
Python
1
elif readonly in ('W',"RW","R/W",None):
while в Python медленный.
В print не нужно делать преобразование в строку.
Само чтение по ячейкам, очевидно, неоптимальное (хотя, да, сами excel либы тоже делают это медленно).
К тому ж некоторые Python либы, бывает еще страдают неуборкой мусора в циклических вызовах.
Был бы файл с данными приложен - попробовал бы оптимизировать код.
А так могу на кофейной гуще еще погадать...

Добавлено через 56 минут

P.S. Ваш подход с индексами и смещениями - типично сишный подход. В python он, как правило, не нужен.
В python обходы структур делаются через итераторы.

Можно итерировать не по объектам ячеек, а сразу получать их значения.
Python
1
2
3
4
5
from openpyxl import load_workbook
wb = load_workbook('1.xlsx')
ws = wb.active
for row in ws.values:  # получаем все значения всех ячеек в текущей строке
    print(row)
Выхлоп - неизменяемый кортеж на каждую строку. Дешево и сердито.
Python
1
2
3
4
5
('id', 'text', 'class')
(1, 'cat meow cat', 'первый')
(2, 'purr cat cat', 'первый')
(3, 'cat whisker meow', 'первый
(4, 'dog bark cat', 'второй')
Кортеж очень легко распаковать на отдельные значения:
Python
1
x,y,z = (1,2,3)
1
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
07.08.2019, 13:03  [ТС]
Garry Galler,
Цитата Сообщение от Garry Galler Посмотреть сообщение
Есть pandas, в pandas есть read_excel. На выходе dataframe.
спасибо, посмотрю
Цитата Сообщение от Garry Galler Посмотреть сообщение
питонично:
да, у меня тоже было ощущение, то я Си на Питон натягиваю.

Добавлено через 5 часов 33 минуты
Garry Galler, dondublon, переписал маленько, теперь все отлично. Работает быстро)
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
from tkinter import filedialog
from tkinter import *
 
import openpyxl
import sys
 
 
def openXLSMFile():
    Tk().withdraw()
    filename = filedialog.askopenfilename(title = "Select .xlsm file", filetypes = (("Excel files","*.xlsm *.xlsx"),("all files","*.*")))
    return filename
 
def findTableOffset(worksheet):
   for row in worksheet.iter_rows(min_row = 1, max_row = 100, max_col = 100):
       for cell in row:
           if cell.value == "Индекс":
                return cell.row + 1, cell.column
   return -1, -1
 
 
def getData(worksheet, currentRow):
    address = int(currentRow[0].value)
    description = str(currentRow[2].value)
    type = str(currentRow[4].value)
    readonly = str(currentRow[5].value)
    eeprom = str(currentRow[6].value)
    if description in  ("Резерв", "None"):
        return -1
    size = 1
    if type == "WORD":
        size = 1
        type = 0
    elif type == "FLOAT":
        size = 2
        type = 1
    elif type[:4] == "CHAR":
        temp = type.rstrip("]").strip("CHAR[")
        if not str(temp).isdigit():
            return -1
        size = int(temp) / 2
        type = 2
    else:
        return -1
    if readonly == "R":
        readonly = True
    elif readonly in ("W", "RW", "R/W", "None"):
        readonly == False
    else:
        return -1
    if eeprom == "EEPROM":
        eeprom = True
    elif eeprom in ("NO", "None"):
        eeprom = False
    else:
        return -1
    data = (address, description, type, size, readonly, eeprom)
    return data
 
print("Use this script to convert Excel files to ModbusUtility file .mem")
 
filename = openXLSMFile()
if filename != "":
    print("File " + filename + " was opened Successfully")
    workbook = openpyxl.load_workbook(filename, read_only=True)
    worksheet = workbook.active
    rowOffset, columnOffset = findTableOffset(worksheet)
    print(str(rowOffset)  + " " + str(columnOffset))
    if rowOffset == -1:
        sys.exit("File " + filename + " hasn't got modbus memory table!")
    currentrow = rowOffset
    datalist = []
    for row in worksheet.iter_rows(min_row = rowOffset, min_col = columnOffset, max_col = columnOffset + 6):
        if not row or str(row[0].value).isdigit():
            data = getData(worksheet, row)
            if data != -1:
                print(data, sep = "\t\t")
        else:
            break
Спасибо за подсказки, кусок практики получил, пойду теорию почитаю)))
0
Эксперт Python
5438 / 3859 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
07.08.2019, 13:35
Цитата Сообщение от _SayHello Посмотреть сообщение
переписал маленько
А почему вариант с самым простым итератором отбросили?
Вот эти варианты абсолютно идентичны по результату. Но, очевидно, что первый самый простой.
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for row in ws.values:
    print(row)
    
print("*" * 20)    
for row in ws.rows:
    print([cell.value for cell in row])
        
print("*" * 20)    
for row in ws.iter_rows():
    print([cell.value for cell in row])
 
    
print("*" * 20) 
max_row = ws.max_row 
max_column = ws.max_column
for row in range(1,max_row+1):
    print([ws.cell(column=col, row=row).value
        for col in range(1,max_column+1)
    ])
Для итерации вам не нужно знать кол-ва строк и столбцов.
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
07.08.2019, 15:19  [ТС]
Garry Galler, Вообще я подумал, что если в файле табличка смещена от начала на rowOffset и colOffset, и при этом в столбцах с адресами < colOffset будет лежать какая либо бесполезная инфа, то используя такой цикл
Python
1
2
for row in ws.values:
    print(row)
мы получим список значений не привязанный к colOffset. При данном способе
Python
1
for row in worksheet.iter_rows(min_row = rowOffset, min_col = columnOffset, max_col = columnOffset + 6):
мы сразу отбрасываем ячейки с адресами < columnOffset
Я такой логикой пользовался

Вот например такая таблица:
C
1
2
3
4
5
Колонка_1  Колонка_2    Колонка_3
None           None            Индекс
None           None            1
None           None            2
None           2               3
Предположим мы нашли что colOffset = 2 и используем цикл
Python
1
for row in ws.values:
получим результаты:
("Индекс")
(1)
(2)
(2, 3)
Как в последнем определить какое из чисел невалидное?

Добавлено через 31 минуту
Garry Galler,
Цитата Сообщение от _SayHello Посмотреть сообщение
получим результаты:
("Индекс")
(1)
(2)
(2, 3)
Как в последнем определить какое из чисел невалидное
Пардон, проверил, не так работает.

Добавлено через 12 минут
Garry Galler, а можно как то в данном цикле
Python
1
for row in ws.values:
начальный интератор подвинуть, чтобы он не с начла файла бежал, а например с 5 строки?
0
Эксперт Python
5438 / 3859 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
07.08.2019, 16:12
Цитата Сообщение от _SayHello Посмотреть сообщение
Вот например такая таблица:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from openpyxl import Workbook
wb = Workbook()
ws = wb.create_sheet(title="Data")
data = [
    ('Колонка_1',  'Колонка_2',    'Колонка_3'),
    (None,           None,            'Индекс'),
    (None,           None,            1),
    (None,           None,            2),
    (None,           2,               3)
]
# создаем таблицу
for idx_row,row in enumerate(data,1):
    for idx_col,cell in enumerate(row,1):
         _ = ws.cell(column=idx_col, row=idx_row, value=cell)
# сохраняем
wb.save(filename = 'testxxx.xlsx')
   
wb = load_workbook('testxxx.xlsx')
ws = wb['Data']  
for row in ws.values:
    print(row)
Цитата Сообщение от _SayHello Посмотреть сообщение
Пардон, проверил, не так работает.
Вот, вот :-). А то я тоже удивился - как так.
Code
1
2
3
4
5
6
# прочитанные значения    
('Колонка_1', 'Колонка_2', 'Колонка_3')
(None, None, 'Индекс')
(None, None, 1)
(None, None, 2)
(None, 2, 3)
Python
1
2
3
4
5
6
7
8
9
10
# если хотим получить срез таблицы - например, без первого столбца    
ws_range = ws['B1:C%d' % ws.max_row ]
for row in ws_range:
    print([cell.value for cell in row])       
 
['Колонка_2', 'Колонка_3']
[None, 'Индекс']
[None, 1]
[None, 2]
[2, 3]
Добавлено через 2 минуты
Цитата Сообщение от _SayHello Посмотреть сообщение
чтобы он не с начала файла бежал, а например с 5 строки?
Берем срез таблицы. С ws.values не получится, так как он возвращают генератор и параметров у него нет.
1
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
07.08.2019, 16:17  [ТС]
Garry Galler,
Цитата Сообщение от Garry Galler Посмотреть сообщение
Берем срез таблицы.
Спасибо, на всякий случай учебник почитаю, а то не все вещи очевидны)))
А так и правда, особо не зная языка, кустарным способом удалось решить задачу за достаточно малое время. Порог вхождения и правда низкий)
0
Эксперт Python
5438 / 3859 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
07.08.2019, 16:49
Цитата Сообщение от _SayHello Посмотреть сообщение
на всякий случай учебник почитаю
В данном случае имеется ввиду не срез в понимании Python синтаксиса table[1:10], а срез в понимании excel, где используются буквенно-числовые обозначения для обозначения диапазонов строк-колонок.
# хотим получить срез таблицы c 4-ой строки
Python
1
2
3
4
# хотим получить срез таблицы c 4-ой строки и без первой колонки - до конца 
ws_range = ws['B4:C%d' % ws.max_row ]
for row in ws_range:
    print([cell.value for cell in row])
Code
1
2
[None, 2]
[2, 3]
0
 Аватар для _SayHello
874 / 535 / 175
Регистрация: 30.07.2015
Сообщений: 1,739
07.08.2019, 16:50  [ТС]
Garry Galler, ага, это я понял
0
Эксперт Python
5438 / 3859 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
08.08.2019, 02:23
Цитата Сообщение от Garry Galler Посмотреть сообщение
С ws.values не получится
Сказать такое о Python - значит почти всегда немного ошибиться :-)
Python
1
2
3
4
from itertools import islice 
# пропустить три строки  и  пройти до конца
for row in islice(ws.values,3,ws.max_row):
    print(row)
Впрочем, тоже самое дает и вариант с iter_rows
Python
1
2
3
# начать с 4 строки
for row in ws.iter_rows(values_only=True,min_row=4):
    print(row)
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
08.08.2019, 02:23
Помогаю со студенческими работами здесь

Замедление действия
Как мне добиться эффекта плавного появления текста? Может можно как нибудь замедлить операцию cout???

Замедление процессора
После отвоза в магазин, процессор стал медленнее работать. По словам работников настройки не меняли.. Но суть в том, что до отвоза сервера...

Замедление программы на VB
Привет всем! Проконсультируйте пожалуйста. При выполнении программы, наблюдается замедление выполнений процелур. То есть сразу после...

Замедление интернета
Здравствуйте, мне нужно замедлить скорость своего интернета. можнл ли как то это сделать через bat? P.s не для вирусов xD

Замедление загрузки Windows 7
Всем доброго времени суток. До этого я создал тему в разделе windows 7(https://www.cyberforum.ru/windows7/thread648451.html) и там...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . . а удачный момент так и не приходит.
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица. Задача: зафиксировать три левых колонки в отчете. Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка) / / . . .
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: при выборе сотрудника (справочник Сотрудники) в ТЧ документа. . .
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru