21

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

logging:

Прихований текст
# _*_ coding: utf-8 _*_

import json
import urllib2
import time
import logging

def load_currency(log=False):
    """функція, котра завантажує дані щодо курсу валют: \
       долар, євро та рубль, готівковкий та безготівковий \
       зі серверу ПриватБанку."""
    result = {}
    FORMAT = '%(asctime)-15s | %(message)s'
    LEVEL = logging.INFO if log==True else logging.CRITICAL
    logging.basicConfig(format=FORMAT, level=LEVEL)
    logging.info("Start loading...")
    logging.info("Connect to source...")
    resp1 = urllib2.urlopen("https://api.privatbank.ua/p24api/pubinfo?json&exchange&coursid=5")
    logging.info("Connected. Loading data...")
    data1 = resp1.read()
    logging.info("Done.")
    data1 = json.loads(data1)
    for i in data1:
        key = '_'.join([i['ccy'],'cash','buy'])
        result[key]=i['buy']
        key = '_'.join([i['ccy'],'cash','sale'])
        result[key]=i['sale']
    logging.info("Waiting 2 seconds...")
    time.sleep(2)        
    #
    logging.info("Connect to source...")
    resp2 = urllib2.urlopen("https://api.privatbank.ua/p24api/pubinfo?exchange&json&coursid=11")
    logging.info("Connected. Loading data...")
    data2 = resp2.read()
    logging.info("Done.")
    data2 = json.loads(data2)
    for i in data2:
        key = '_'.join([i['ccy'],'ncash','buy'])
        result[key]=i['buy']
        key = '_'.join([i['ccy'],'ncash','sale'])
        result[key]=i['sale']
    #
    result = float_currency(result)
    logging.info("ALL OK")
    return result

Дякую. Тепер зручніше. Потрібен вивід передаємо параметр True, не потрібен - нічого не передаємо.

22

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Ще оптимізував саму функцію завантаження:

Прихований текст
def load_currency(log=False):
    """функція, котра завантажує дані щодо курсу валют: \
       долар, євро та рубль, готівковкий та безготівковий \
       зі серверу ПриватБанку."""
    result = {}
    FORMAT = '%(asctime)-15s | %(message)s'
    LEVEL = logging.INFO if log==True else logging.CRITICAL
    logging.basicConfig(format=FORMAT, level=LEVEL)
    sources = [("cash","https://api.privatbank.ua/p24api/pubinfo?json&exchange&coursid=5"),
               ("ncash","https://api.privatbank.ua/p24api/pubinfo?exchange&json&coursid=11")]
    log = ["Start loading...",
           "Connect to source...",
           "Connected. Loading data...",
           "Done. Waiting...",
           "ALL OK"]
    logging.info(log[0])
    for (type,link) in sources:
        logging.info(log[1])
        resp = urllib2.urlopen(link)
        logging.info(log[2])
        data = resp.read()
        logging.info(log[3])
        data = json.loads(data)
        for info in data:
            for direction in ["buy", "sale"]:
                key = '_'.join([info['ccy'],type,direction])
                result[key]=info[direction]        
    result = float_currency(result)
    logging.info(log[4])
    return result

Що скажете?

23

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Ось тут якраз не варто збирати повідомлення в список. iterable потрібні для циклів; тут же циклів немає, а рядок

logging.info("Connected. Loading data...")

одразу працює як коментар до коду, на відміну від вашого.

Подякували: A.N.Onim1

24

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

@A.N.Onim,

пару порад для зручності:

- викладіть свій проект на гітхаб. Шматки коду можна постити і сюди, але так, імго, буде зручніше робити рев'ю Вашого коду. Якщо, звісно, у ньому відсутні якісь "ліцензовані шматки для про-версії". :)
- раджу замінити коментарі на англомовні - так універсальніше.

25 Востаннє редагувалося A.N.Onim (28.12.2015 15:15:37)

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Шановне товариство, знову є питання.  :) Пишу сюди, так як тема питання схожа з попередніми. Пишу вже іншу прогу, повязану з курсом валют. Засобі ті ж - Python&wxPython. Программа завантажує архіви курсів з привату та будує графіки зміни курсів. Вона працює(ну то що зроблено уже те працює  :D ). Але є питання. Натискаю на кнопку котра показує графік за 7 днів.Спочатку завантажує потім малює графік. Все працює, але підвисає. Показую - натискаю на кнопку і бачу через секунд 3 таке:
http://f1.s.сайт-злодій/gt7AZKEO.png программа не вилітає - все добре - все працює секунд через 10 все малюється - час таким і повинен бути - я поставив затримку між 7-ма запитами до привату. Але то не є файно коли воно неначе підвисає. Чому так і як з цим боротись? Код обробника події натиску на кнопку та допоміжних функцій нище. Дякую.

Обробник
def OnClickWeek(self, event):
        if not self.is_week:
            self.values_week = load.load(7)
        self.draw_panel.draw_axis()
        self.draw_panel.draw_grid(6)
        self.currency = 'RUB'
        data = [(item[0], item[1]) for item in self.values_week]
        self.draw_panel.draw_graph_week(self.currency, data)
        self.is_week = True
        self.left_button.Disable()
        self.right_button.Enable()
модуль завантаження - з ним повязане "гальмування"
import urllib2
import datetime
import json
import time

def load(value):
    date = datetime.datetime.now().date()
    date -= datetime.timedelta(days=2)
    result = [] # [(date, RUB_cash_buy, USD_cash_buy, EUR_cash_buy)]
    for i in range(value):
        print "load", date
        link = "https://api.privatbank.ua/p24api/exchange_rates?json&date="+".".join([str(date.day), str(date.month), str(date.year)])
        temp = urllib2.urlopen(link).read()
        temp = json.loads(temp)
        result.append((".".join([str(date.day), str(date.month), str(date.year)]),
                       temp['exchangeRate'][5]['purchaseRateNB'],
                       temp['exchangeRate'][8]['purchaseRateNB'],
                       temp['exchangeRate'][2]['purchaseRateNB']))
        date -=datetime.timedelta(days=1)
        time.sleep(1)
    return result

І коли воно за 7 днів то нічого, але ж там і побільше потрібно завантажувати.

А ось зробив скрін, коли вантажить за місяць - все працює але вінда показує що прога зависла:
http://f2.s.сайт-злодій/gt7AZKES.png

26

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Запит іде в тому ж потоці, що й інтерфейс, тому і гальмує. Вам треба створити новий потік, в ньому надіслати запит, а потім передати результат назад інтерфейсу асинхронно.

Подякували: A.N.Onim, leofun012

27 Востаннє редагувалося A.N.Onim (28.12.2015 16:58:07)

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

koala написав:

Запит іде в тому ж потоці, що й інтерфейс, тому і гальмує. Вам треба створити новий потік, в ньому надіслати запит, а потім передати результат назад інтерфейсу асинхронно.

Зрозумів. Щось повязане з багатопоточністю. Які ключьові слова? З якого боку почати шукати інфу?

28 Востаннє редагувалося koala (28.12.2015 17:49:56)

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Бібліотека threading.
Базово вам потрібен нащадок Thread-а, у якого метод run буде робити оту всю довгу операцію. Можна ще додати блокування (Lock) - хоча б перед оновленням інтерфейсу.
https://docs.python.org/2/library/threading.html

Подякували: A.N.Onim1

29

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Дякую. Буду читати.

30 Востаннє редагувалося A.N.Onim (29.12.2015 15:44:26)

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Слухайте, пан koala, я тут почитав всяхих статей, і... а як щодо не threading, а multiprocessing? Тобто зроблю скрипт окремий для завантаження, котрий запускається як тільки запускається головний. А GUI  в головному. Що скажете?

31

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Процес - трохи важча конструкція, ніж тред. Втім, чому б ні?

32 Востаннє редагувалося A.N.Onim (29.12.2015 20:18:51)

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

koala написав:

Процес - трохи важча конструкція, ніж тред. Втім, чому б ні?

Вибачте, за баломутство, але я таки як додумавсь як зробити задопомогою потоків.  :D Ну тобто як не складно зробити.

Подякували: koala1

33 Востаннє редагувалося A.N.Onim (29.12.2015 20:24:39)

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Прихований текст

Доречі, знайшов код проги на Tk, яка допомогає візуально подивитись на багатопоточність. Кожна лінія - один поток, котрий перший дойде тим кольором і замальовується кнопка "Go".

# -*- coding: cp1251 -*-
import threading, time, sys
from Tkinter import Tk, Canvas, Button, LEFT, RIGHT, NORMAL, DISABLED
global champion
# Задается дистанция, цвет полосок и другие параметры
distance = 300
colors = ["Red","Orange","Yellow","Green","Blue","DarkBlue","Violet"]
nrunners = len(colors) # количество дополнительных потоков
positions = [0] * nrunners # список текущих позиций
h, h2 = 20, 10 # параметры высоты полосок
def run(n):
    """Программа бега n-го участника (потока)"""
    global champion
    while 1:
        for i in range(10000): # интенсивные вычисления
            pass
        graph_lock.acquire()
        positions[n] += 1 # передвижение на шаг
        if positions[n] == distance: # если уже финиш
            if champion is None: # и чемпион еще не определен,
                champion = colors[n] # назначается чемпион
            graph_lock.release()
            break
        graph_lock.release()
def ready_steady_go():
    """Инициализация начальных позиций и запуск потоков"""
    graph_lock.acquire()
    for i in range(nrunners):
        positions[i] = 0
        threading.Thread(target=run, args=[i,]).start()
    graph_lock.release()
def update_positions():
    """Обновление позиций"""
    graph_lock.acquire()
    for n in range(nrunners):
        c.coords(rects[n], 0, n*h, positions[n], n*h+h2)
    tk.update_idletasks() # прорисовка изменений
    graph_lock.release()
def quit():
    """Выход из программы"""
    tk.quit()
    sys.exit(0)
# Прорисовка окна, основы для прямоугольников и самих прямоугольников,
# кнопок для пуска и выхода
tk = Tk()
tk.title("Соревнование потоков")
c = Canvas(tk, width=distance, height=nrunners*h, bg="White")
c.pack()
rects = [c.create_rectangle(0, i*h, 0, i*h+h2, fill=colors[i])
for i in range(nrunners)]
go_b = Button(text="Go", command=tk.quit)
go_b.pack(side=LEFT)
quit_b = Button(text="Quit", command=quit)
quit_b.pack(side=RIGHT)
# Замок, регулирующий доступ к функции пакета Tk
graph_lock = threading.Lock()
# Цикл проведения соревнований
while 1:
    go_b.config(state=NORMAL), quit_b.config(state=NORMAL)
    tk.mainloop() # Ожидание нажатия клавиш
    champion = None
    ready_steady_go()
    go_b.config(state=DISABLED), quit_b.config(state=DISABLED)
    # Главный поток ждет финиша всех участников
    while sum(positions) < distance*nrunners:
        update_positions()
    update_positions()
    go_b.config(bg=champion) # Кнопка окрашивается в цвет победителя
    tk.update_idletasks()

Скріни проги:
http://f5.s.сайт-злодій/gt7AZKFT.png
http://f4.s.сайт-злодій/gt7AZKFU.png
http://f6.s.сайт-злодій/gt7AZKFV.png

34 Востаннє редагувалося A.N.Onim (30.12.2015 22:15:05)

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Прихований текст

Кому цікаво, ось які графіки я отримав за ~3 роки (1150 днів(якщо точніше)). Курс НБУ, готівка, купівля. http://f6.s.сайт-злодій/gt7AZKGp.png
http://f1.s.сайт-злодій/gt7AZKGq.png
http://f6.s.сайт-злодій/gt7AZKGr.png
З доларом майже півроку щось не те - але то не баг проги - я провіряв приват дає такий курс на майже півроку  - 7,993.

35

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

A.N.Onim написав:

З доларом майже півроку щось не те - але то не баг проги - я провіряв приват дає такий курс на майже півроку  - 7,993.

Ну так і було - після майдану гривня почала падати

36

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Q-bart написав:
A.N.Onim написав:

З доларом майже півроку щось не те - але то не баг проги - я провіряв приват дає такий курс на майже півроку  - 7,993.

Ну так і було - після майдану гривня почала падати

По-перше, я помиливсь не півроку, а більше року, а по-друге, я все розумію але не 300 ж днів курс 7,993.  *JOKINGLY*

37

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

Bartash написав:

@A.N.Onim,

пару порад для зручності:

- викладіть свій проект на гітхаб. Шматки коду можна постити і сюди, але так, імго, буде зручніше робити рев'ю Вашого коду. Якщо, звісно, у ньому відсутні якісь "ліцензовані шматки для про-версії". :)
- раджу замінити коментарі на англомовні - так універсальніше.

Чи є сенс заливати прогу на git, якщо лише один файл?

38

Re: Оптимізація коду або Боротьба з говнокодом[Python&wxPython]

@A.N.Onim,

Перше відповім по коду.
У Пітоні робота з потоками має свої специфіки, у зв'язку з чим часто замість потоків юзаються subprocess. Але використання threading ніхто не заборонив - я лише наводжу альтернативний приклад.

Щодо гітхабу:

- якщо програма може бути корисною комусь,
- або треба надійно тримати сирці, мінімізувавши ризики втрати внаслідок типових форс-мажорів,
- абощо, -

то кількість файлів не матиме значення. Крім того, у процесі рефакторингу файлів може побільшати.