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

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

06.08.2019, 17:39. Показов 4622. Ответов 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
4651 / 2071 / 366
Регистрация: 17.03.2012
Сообщений: 10,180
Записей в блоге: 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
Ответ Создать тему
Новые блоги и статьи
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru