<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Stepan Skriabin</title><generator>teletype.in</generator><description><![CDATA[Stepan Skriabin]]></description><link>https://teletype.in/@stepan_skryabin?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=stepan_skryabin</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/stepan_skryabin?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/stepan_skryabin?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Tue, 14 Apr 2026 21:41:54 GMT</pubDate><lastBuildDate>Tue, 14 Apr 2026 21:41:54 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@stepan_skryabin/Etzsd7uknR5</guid><link>https://teletype.in/@stepan_skryabin/Etzsd7uknR5?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=stepan_skryabin</link><comments>https://teletype.in/@stepan_skryabin/Etzsd7uknR5?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=stepan_skryabin#comments</comments><dc:creator>stepan_skryabin</dc:creator><title>Измеряем продуктивность своей работы</title><pubDate>Fri, 20 May 2022 14:46:57 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/2b/e9/2be9fb4c-52dc-49a4-b3b0-37b7f6afd301.png"></media:content><category>Плагины</category><description><![CDATA[<img src="https://img4.teletype.in/files/35/ff/35ffd134-6589-4bff-94f6-1e8261b8ae7a.png"></img>Когда я начал работать на удалёнке над первым своим коммерческим проектом мне было не понятно насколько эффективно я работаю и и сколько конкретно времени трачу на написание кода. Также в условиях удалёнки необходимо чётче следить за своим графиком, чтобы не сгореть к чертям и не провалить проект.]]></description><content:encoded><![CDATA[
  <p id="syQB">Когда я начал работать на удалёнке над первым своим коммерческим проектом мне было не понятно насколько эффективно я работаю и и сколько конкретно времени трачу на написание кода. Также в условиях удалёнки необходимо чётче следить за своим графиком, чтобы не сгореть к чертям и не провалить проект.</p>
  <p id="E3JP">В своей работе я использую два простых инcтрумента: Pomodoro и WakaTime. Если про помидор все уже достаточно хорошо наслышали или даже пользуются, то второй инструмент не так популярен.</p>
  <h2 id="GP28">WakaTime</h2>
  <p id="7vaM">Проект озволяет отслеживать свою активность отправля статистику на сервера WakaTime. Отслеживается время работы, язык, название проекта, операционная система.  Полный список того какая информация передается можно посмотреть <a href="https://wakatime.com/legal/privacy-policy" target="_blank">тут.</a></p>
  <p id="5ktz">Киллерфичей для меня стало то, что отслеживается только активаня работа. Иными словами, запустить и свернуть окно IDE попивая чай не получится, время простоя не будет учитываться.</p>
  <p id="AKEe">Для работы требуется создать аккаунт на wakatime.com (есть авторизация через гитхаб, а гугла нет) и установить плагин в любимую IDE из <a href="https://wakatime.com/plugins" target="_blank">списка</a> поддерживаемых. После чего в плагин надо всавить api-key который гененируется в персональных настройках wakatime.com. Через небольшой промежуток времени вся отслеживаемая информация появится в разделе <strong>Dashboard</strong>.</p>
  <figure id="wzQz" class="m_retina">
    <img src="https://img4.teletype.in/files/35/ff/35ffd134-6589-4bff-94f6-1e8261b8ae7a.png" width="960" />
    <figcaption>красивые цветные картинки, на радость детям</figcaption>
  </figure>
  <p id="R5Wb">Есть как платная так и бесплатная подписка. Для индивидуального использования хватит и бесплатной подписки.</p>
  <p id="QD0K">Кроме общей статистики, в разделе <strong>Projects</strong> доступна возможность смотреть статистику по каждому проекту (или репозиторию) отдельно.</p>
  <p id="gh6V">В разделе <strong>Share</strong> есть возможность сгенерировать бирку (на которой указано общее время работы), тамже можно генерировать неплохие графики, сохраняя их в формате SVG, PNG. На удивление есть даже JSON, так что можно отрисовать график самостоятельно. Вся это красота может успешно использоваться в описании репы или в резюме.</p>
  <figure id="8Bs3" class="m_retina">
    <img src="https://img2.teletype.in/files/d8/3e/d83e6078-695d-42d9-a9b0-5887c2fd8662.png" width="960" />
    <figcaption>Настройки генерации графиков.</figcaption>
  </figure>
  <p id="sPxm">Можно настроить отправку раз в месяц/неделю/день статистики себе на почту или заспамить тимлида.</p>
  <p id="oUeF">Для особо требовательных и рукастых есть описание АПИ (REST API) через который можно получить всю ту же информация что и через сайт. </p>
  <p id="vJkz">Ну и как же не обойтись без <s>пиписькомерялки</s> доски лидеров, где можно посоревноваться в длинне... рейтинга.</p>
  <figure id="gb4S" class="m_retina">
    <img src="https://img2.teletype.in/files/91/61/916131c9-803a-4cdb-9c00-ff0ae71c4d6e.png" width="960" />
    <figcaption>да, опять китайцы впереди</figcaption>
  </figure>
  <p id="xvYj">Кроме интеграцим с популярными системами хранения кода (GitHub, GitLab, Bitbucked) есть интеграция с Slack, Google Calendar. Полный список можно найти <a href="https://wakatime.com/integrations/" target="_blank">тут</a>.</p>
  <p id="H2hi">Вообще проект не настолько и молодой. Создан в 2013 году и к настоящему времени насчитывает около 60 поддерживаемых приложений, в основном разные IDE и редакторы кода, но есть не только они. Есть даже поддержка интерпретаторов bash, zsh, iTerm2, fish и даже Excel/Word.</p>
  <p id="8e6Y">Итогом использования WakaTime для меня стало чёткое понимание своего физического уровня и количества времени которое я могу потратить на код и не умереть.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@stepan_skryabin/wg2R5jrbxnU</guid><link>https://teletype.in/@stepan_skryabin/wg2R5jrbxnU?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=stepan_skryabin</link><comments>https://teletype.in/@stepan_skryabin/wg2R5jrbxnU?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=stepan_skryabin#comments</comments><dc:creator>stepan_skryabin</dc:creator><title>Python - очередь с приоритетом</title><pubDate>Mon, 16 May 2022 18:16:19 GMT</pubDate><description><![CDATA[В статье разбираем практический случай создания очереди с сортировкой по приоритету.]]></description><content:encoded><![CDATA[
  <p id="fBU3">В статье разбираем практический случай создания очереди с сортировкой по приоритету.</p>
  <h2 id="Простая-очередь.">Простая очередь.</h2>
  <p id="CFxZ">Самый просто пример использования очереди - это поэтапная обработка ссылок на скачиваение файлов. Для этого достаточно воспользоваться простейшим списком <code>list</code> куда можно закидывать любой объект c помощью метода <code>.append()</code>. В действительности <code>list</code> не является настоящей очередью (<em>но сейчас это не важно</em>). Получить объект содержащийся в такой “очереди” так же просто, для этого есть метод <code>.pop()</code>. При этом стоит помнить, что метод <code>.pop()</code> этот элемент удаляет навсегда.</p>
  <p id="yAbA">Пример кода:</p>
  <pre id="Hcxm" data-lang="python">queue = []

item1 = &quot;https://www.example.com/001.zip&quot;
item2 = &quot;https://www.example.com/002.zip&quot;
item3 = &quot;https://www.example.com/003.zip&quot;

# Закинем в очередь объекты
queue.append(item1)
queue.append(item2)
queue.append(item3)

# Получаем из очереди объекты
queue.pop()
# Выведет:
queue.pop() # &quot;https://www.example.com/003.zip&quot;
queue.pop() # &quot;https://www.example.com/002.zip&quot;
queue.pop() # &quot;https://www.example.com/001.zip&quot;</pre>
  <p id="9xBp">Вроде всё просто, но в данном случае простота не значит гибкость. Вот основные проблемы:</p>
  <ol id="UCF4">
    <li id="0OJV">нет автоматической сортировки, элементы из списка можно получить с конца в начало (<em>если вызывать</em> <code>.pop(0)</code> - <em>с начала в конец</em>);</li>
    <li id="cOGq">при применении метода <code>.pop()</code> к списку не содержащему элементов возникает исключение <code>IndexError</code> которое нужно обработать.</li>
    <li id="cYwV">нет гарантии что вы работаете однозначно с одним и тем же объектом <code>queue</code></li>
  </ol>
  <h2 id="Реализация-очереди-с-приоритетом.">Реализация очереди с приоритетом.</h2>
  <p id="oMdl">Для избежания недостатков простого <code>list</code> предлагаю вооружится встроенным модулем <code>heapq</code> (куча) и паттерном Синглтон.</p>
  <p id="ZYin">Почему и зачем использовать модуль <code>heapq</code>? Всё просто, этот модуль может просто и быстро отсортировать объекты по приоритету.</p>
  <p id="cHr2">Паттерн <strong>Синглтон</strong> здесь будет использоваться для гарантированной работы только с одним экземпляром объекта <code>Queue</code>.</p>
  <p id="sAmv">Весь код класса <code>Queue</code> приведён ниже:</p>
  <pre id="yJtl" data-lang="python">import heapq


class Queue:
    def __new__(cls):
        if not hasattr(cls, &#x27;instance&#x27;):
            cls.instance = super(Queue, cls).__new__(cls)
        return cls.instance
        
    def __init__(self):
        self.queue = []
        heapq.heapify(self.queue)
        self.index = 0
    
    def __str__(self):
        return f&quot;Last index element in queue: {self.index}.&quot;
    
    def __repr__(self):
        return f&quot;Queue instance contains {self.queue.__len__()} elements.&quot;
        
    def push(self, item, priority=False):
        priority_level = 1
        if priority:
            priority_level = -1
        entry = (priority_level, self.index, item)
        heapq.heappush(self.queue, entry)
        self.index = self.index + 1
        
    def pull(self):
        entry = heapq.heappop(self.queue)
        return entry[2]
   
     
# Использование:

scheduler = Queue()

item1 = &quot;https://www.example.com/001.zip&quot;
item2 = &quot;https://www.example.com/002.zip&quot;
item3 = &quot;https://www.example.com/003.zip&quot;

scheduler.push(item1)
scheduler.push(item2, priority=True)
scheduler.push(item3) 

# Вывод:
str(scheduler)   # Last index element in queue: 2.
repr(scheduler)  # Queue instance contains 3 elements.
scheduler.pull() # &quot;https://www.example.com/002.zip&quot;
scheduler.pull() # &quot;https://www.example.com/001.zip&quot;
scheduler.pull() # &quot;https://www.example.com/003.zip&quot;</pre>
  <p id="9Dye">А теперь подробнее разберём код. Для начала импортируем необходимый модуль <code>heapq</code> :</p>
  <pre id="7vGr" data-lang="python">import heapq</pre>
  <p id="Ygmg">Дальше создадим класс <code>Queue</code> и добавим в него конструктор <code>__new__</code> и инициализатор <code>__init__</code>:</p>
  <pre id="wq0u" data-lang="python">class Queue:
    def __new__(cls):
        if not hasattr(cls, &#x27;instance&#x27;):
            cls.instance = super().__new__(cls)
        return cls.instance</pre>
  <p id="YUw7">Здесь я подробнее остановлюсь на конструкторе <code>__new__</code>  (<em>это и будет наша реализация паттерна <strong>Синглтон</strong></em>):</p>
  <p id="FdIR">Для дальнейшего создания любого количества экземпляров класса <code>Queue</code> которые будут гарантировано ссылаться только на один объект <code>Queue</code> в памяти - можно воспользоваться “волшебным” методом <code>__new__</code> который инициализируется в самом начале создания экземпляра класса.</p>
  <p id="r7Rg">Итак, следите за руками:</p>
  <ol id="dw3r">
    <li id="MNMu">С помощью метода <code>hasattr()</code> сделаем проверку на отсутствие аттрибута <code>instance</code> у вновь создаваемого экземпляра класса <code>Queue</code></li>
    <li id="mx38">Если <code>instance</code> нет - создадим аттрибут <code>instance</code> и присвоим ему результат выполнения <code>super().__new__(cls)</code> .</li>
    <li id="eBQu">Если <code>instance</code> в экземпляре есть - просто вернём содержимое <code>instance</code></li>
    <li id="vI7V">Магия тут кроется в том что результатом первого вызова <code>super().__new__(cls)</code> будет создан экземпляр класса <code>Queue</code> , а все последующие попытки создать экземпляры класса <code>Queue</code> вынужденно будут возвращать результат первого вызова <code>super()__new__(cls)</code> .</li>
  </ol>
  <p id="dmPH">Дальше идёт метод <code>__init__</code> :</p>
  <pre id="2MWw" data-lang="python">def __init__(self):
    self.queue = []
    heapq.heapify(self.queue)
    self.index = 0</pre>
  <p id="epDd">В котором мы создадим объект <code>self.queue</code> - очередь с пустым списком <code>list</code> . Для того чтобы превратить его в “кучу” <code>heap</code> просто передадим <code>self.queue</code> в качестве параметра в функцию <code>heapify()</code>. Далее создадим объект с информацией о начальном  индексе <code>self.index</code>. По умолчанию индекс = 0.</p>
  <p id="7dne">Следующие методы <code>__str__</code> и <code>__repr__</code> имеют практическую ценность в случае отладки нашего кода (<em>но они не обязательны</em>):</p>
  <pre id="RixL" data-lang="python">def __str__(self):
    return f&quot;Last index element in queue: {self.index - 1}.&quot;
    
def __repr__(self):
    return f&quot;Queue instance contains {self.queue.__len__()} elements.&quot;</pre>
  <p id="tk9V">Метод <code>__str__</code> будет выводить индекс присвоенный объекту в нашей очереди, который был добавлен последним. Метод <code>__repr__</code> будет информировать об общем количестве элементов в очереди.</p>
  <p id="OuXt">Метод <code>push()</code> отвечает за добавление объекта в очередь:</p>
  <pre id="27gg" data-lang="python">def push(self, item: Any, priority=False):
    priority_level = 1
    if priority:
        priority_level = -1
    entry = (priority_level, self.index, item)
    heapq.heappush(self.queue, entry)
    self.index = self.index + 1</pre>
  <p id="fZiP"><code>entry</code> это кортеж с тремя элементами: приоритет, индекс, и сам объект. У каждого объекта помещаемого в очередь задается приоритет. Перед каждым помещением объекта в очередь приоритет сбрасывается на 1. Если <code>priority=True</code> тогда объект в очередь помещается с приоритетом = -1. Теперь этот элемент будет в самом начале очереди, а значит наш метод <code>pull()</code> выдаст его первым. Происходит это потому, что <code>heapq</code> сортирует очередь исходя из “веса” элемента, с учётом его расположения. В случае наличия в очереди нескольких элементов с одинаковым приоритетом, сортировка будет осуществлятся по “весу” второго элемента - индекса. После добавления объекта в очередь, увеличиваем индекс на 1 пункт.</p>
  <p id="zbbV">Метод <code>pull()</code> отвечает за возврат объекта из очереди, с учётом приоритета:</p>
  <pre id="kQdh" data-lang="python">def pull(self):
    entry = heapq.heappop(self.queue)
    return entry[2]</pre>
  <p id="M22e">Метод <code>.heappop()</code> берёт из очереди объект у которого самое нижнее значение приоритета и номер индекса и выдаёт нам только последний (третий) элемент. Не забываем что нумерация идёт от 0.</p>
  <h2 id="Реализация-очереди-поддерживающую-работу-с-потоками.">Реализация очереди поддерживающей работу с потоками.</h2>
  <p id="NHmU">Код который мы написали выше не подходит для работы с множеством потоков (<em>используя модуль</em> <code>threading</code>). В случае использования потоков, где один пишет сообщение в очередь, а второй забирает это сообщение из очереди и обрабатывает его, может возникнуть блокировка очереди для одного из потоков, которая может привести к возникновению исключения. Для исправления проблемы понадобиться заменить модуль <code>heapq</code> на <code>queue</code> и изменить несколько строк в нашем классе <code>Queue</code> .</p>
  <p id="mLoS">Вот наши изменения:</p>
  <ol id="rXQZ">
    <li id="HCm9">удаляем импорт модуля <code>heapq</code> и добавляем импорт класса <code>PriorityQueue</code> из модуля <code>queue</code></li>
    <li id="pk7q"><code>self.queue = []</code> меняем на <code>self.queue = PriorityQueue()</code>, для создание экземпляра класса <code>PriorityQueue</code></li>
    <li id="F06Q">удаляем строчку <code>heapq.heapify(self.queue)</code></li>
    <li id="vMJE">в методе <code>__repr__()</code> меняем <code>self.queue.__len__()</code> на <code>self.queue._qsize()</code></li>
    <li id="LHZx"><code>heapq.heappush(self.queue, entry)</code> меняем на <code>self.queue.put(entry)</code></li>
    <li id="5CVX">в методе <code>.pull()</code> строчку <code>entry = heapq.heappop(self.queue)</code> меняем на</li>
  </ol>
  <pre id="3dDF" data-lang="python">if self.queue._qsize() == 0:
    return None
else:
    entry = self.queue.get()</pre>
  <p id="ERH1"><em>Пояснение: в случае если количество элементов в очереди будет равно 0 <code>self.queue.get()</code> будет выполнятся вечно, т.к. будет ожидать элемент из очереди. Для предотвращения такого поведения делаем проверку.</em></p>
  <p id="E5T6">Итак, весь код выглядит вот так:</p>
  <pre id="Zpye" data-lang="python">from queue import PriorityQueue


class Queue:
    def __new__(cls):
        if not hasattr(cls, &#x27;instance&#x27;):
            cls.instance = super().__new__(cls)
        return cls.instance
    
    def __init__(self):
        self.queue = PriorityQueue()
        self.index = 0
    
    def __str__(self):
        return f&quot;Last index element in queue: {self.index}&quot;
    
    def __repr__(self):
        return f&quot;Queue instance contains {self.queue._qsize()} elements.&quot;
        
    def push(self, item, priority=False):
        priority_level = 1
        if priority:
            priority.level = -1
        entry = (priority_level, self.index, item)
        self.queue.put(entry)
        self.index = self.index + 1
        
    def pull(self):
        if self.queue._qsize() == 0:
            return None
        else:
            entry = self.queue.get()
        return entry[2]</pre>
  <p id="IXRl">Таким образом наш класс <code>Queue</code> теперь стал поддерживать работу с потоками.</p>
  <p id="ldEU">Пример использования:</p>
  <pre id="vS4V" data-lang="python">from threading import Thread


scheduler = Queue()


def generate_links(item):
    for i in range(item):
        scheduler.push(i)
    # добавим одну приоритетную
    scheduler.push(item+1, priority=True)
    
    
def print_links():
    n=0
    while n is not None:
        n=scheduler.pull()
        print(f&quot;Item in scheduler = {n}&quot;)
        
        
first_thread = Thread(target=generate_links, name=&#x27;Generator&#x27;, args=(5,))
seconf_thread = Thread(target=print_links, name=&#x27;Printer&#x27;)

first_thread.start()
str(scheduler)   # Last index element in queue: 5.
repr(scheduler)  # Queue instance contains 6 elements.
seconf_thread.start() 

# Вывод:
# Item in schedule = 6
# Item in schedule = 0
# Item in schedule = 1
# Item in schedule = 2
# Item in schedule = 3
# Item in schedule = 4
# Item in schedule = None ## None - очередь пуста</pre>

]]></content:encoded></item></channel></rss>