Ответы пользователя по тегу Python
  • Как нарисовать пиксельное изображение в Python?

    @deliro
    Pillow
    Ответ написан
    Комментировать
  • Почему возникает ошибка при обновлении pip?

    @deliro
    Это значит, что у тебя установлен пакет sanetime такой версии, который требует такую версию python-dateutil, которая не входит в промежуток требуемых версий pip.

    Сначала выполни

    pip install -U sanetime

    А потом обновляй pip
    Ответ написан
    Комментировать
  • Можно ли так описать хэш-таблицу?

    @deliro
    1. ХТ пуста от 2/3 своего размера до 1/3. 1/3 - это уже она вот-вот реаллоцируется.
    2. Про циклы - фигня. В питоне нет ни одного способа добавить элементы кучей так, чтобы на самом деле они добавились не в цикле на уровне Си. Даже dict comprehensions добавляют элементы последовательно.
    3. Хэш от ключа - это встроенная функция hash(). Для конкретной ХТ берется остаток от деления хэша на размер ХТ. На самом деле, берётся хэш по битовой маске (размер_ХТ - 1) [Например hash(obj) & 2**16 - 1]. Но для степеней двойки эти операции равноценны.
    4. Ты совсем забыл момент с разрешением коллизий (это когда хэши двух разных ключей совпадают). В питоновых словарях это самый интересный момент. И именно из-за него удаленные данные из словаря не удаляются физически до следующей реаллокации.
    5. "Очень быстро" - это как?

    UPD.

    На текущий момент реализация словаря в питоне поменялась. В 3.6 версии сделали все словари по умолчанию ordered и заодно уменьшили размер словаря в байтах на 20-25%. Вот реализация актуальных словарей на питоне (в оригинале, она, конечно на Си):

    Раскрыть
    import array
    import collections
    import itertools
    
    # Placeholder constants
    FREE = -1
    DUMMY = -2
    
    
    class Dict(collections.MutableMapping):
        "Space efficient dictionary with fast iteration and cheap resizes."
    
        @staticmethod
        def _gen_probes(hashvalue, mask):
            "Same sequence of probes used in the current dictionary design"
            PERTURB_SHIFT = 5
            if hashvalue < 0:
                hashvalue = -hashvalue
            i = hashvalue & mask
            yield i
            perturb = hashvalue
            while True:
                i = (5 * i + perturb + 1) & 0xFFFFFFFFFFFFFFFF
                yield i & mask
                perturb >>= PERTURB_SHIFT
    
        def _lookup(self, key, hashvalue):
            "Same lookup logic as currently used in real dicts"
            assert self.filled < len(self.indices)  # At least one open slot
            freeslot = None
            for i in self._gen_probes(hashvalue, len(self.indices) - 1):
                index = self.indices[i]
                if index == FREE:
                    return (FREE, i) if freeslot is None else (DUMMY, freeslot)
                elif index == DUMMY:
                    if freeslot is None:
                        freeslot = i
                elif (
                    self.keylist[index] is key
                    or self.hashlist[index] == hashvalue
                    and self.keylist[index] == key
                ):
                    return (index, i)
    
        @staticmethod
        def _make_index(n):
            "New sequence of indices using the smallest possible datatype"
            if n <= 2 ** 7:
                return array.array("b", [FREE]) * n  # signed char
            if n <= 2 ** 15:
                return array.array("h", [FREE]) * n  # signed short
            if n <= 2 ** 31:
                return array.array("l", [FREE]) * n  # signed long
            return [FREE] * n  # python integers
    
        def _resize(self, n):
            """Reindex the existing hash/key/value entries.
               Entries do not get moved, they only get new indices.
               No calls are made to hash() or __eq__().
    
            """
            n = 2 ** n.bit_length()  # round-up to power-of-two
            self.indices = self._make_index(n)
            for index, hashvalue in enumerate(self.hashlist):
                for i in Dict._gen_probes(hashvalue, n - 1):
                    if self.indices[i] == FREE:
                        break
                self.indices[i] = index
            self.filled = self.used
    
        def clear(self):
            self.indices = self._make_index(8)
            self.hashlist = []
            self.keylist = []
            self.valuelist = []
            self.used = 0
            self.filled = 0  # used + dummies
    
        def __getitem__(self, key):
            hashvalue = hash(key)
            index, i = self._lookup(key, hashvalue)
            if index < 0:
                raise KeyError(key)
            return self.valuelist[index]
    
        def __setitem__(self, key, value):
            hashvalue = hash(key)
            index, i = self._lookup(key, hashvalue)
            if index < 0:
                self.indices[i] = self.used
                self.hashlist.append(hashvalue)
                self.keylist.append(key)
                self.valuelist.append(value)
                self.used += 1
                if index == FREE:
                    self.filled += 1
                    if self.filled * 3 > len(self.indices) * 2:
                        self._resize(4 * len(self))
            else:
                self.valuelist[index] = value
    
        def __delitem__(self, key):
            hashvalue = hash(key)
            index, i = self._lookup(key, hashvalue)
            if index < 0:
                raise KeyError(key)
            self.indices[i] = DUMMY
            self.used -= 1
            # If needed, swap with the lastmost entry to avoid leaving a "hole"
            if index != self.used:
                lasthash = self.hashlist[-1]
                lastkey = self.keylist[-1]
                lastvalue = self.valuelist[-1]
                lastindex, j = self._lookup(lastkey, lasthash)
                assert lastindex >= 0 and i != j
                self.indices[j] = index
                self.hashlist[index] = lasthash
                self.keylist[index] = lastkey
                self.valuelist[index] = lastvalue
            # Remove the lastmost entry
            self.hashlist.pop()
            self.keylist.pop()
            self.valuelist.pop()
    
        def __init__(self, *args, **kwds):
            if not hasattr(self, "keylist"):
                self.clear()
            self.update(*args, **kwds)
    
        def __len__(self):
            return self.used
    
        def __iter__(self):
            return iter(self.keylist)
    
        def iterkeys(self):
            return iter(self.keylist)
    
        def keys(self):
            return list(self.keylist)
    
        def itervalues(self):
            return iter(self.valuelist)
    
        def values(self):
            return list(self.valuelist)
    
        def iteritems(self):
            return itertools.izip(self.keylist, self.valuelist)
    
        def items(self):
            return zip(self.keylist, self.valuelist)
    
        def __contains__(self, key):
            index, i = self._lookup(key, hash(key))
            return index >= 0
    
        def get(self, key, default=None):
            index, i = self._lookup(key, hash(key))
            return self.valuelist[index] if index >= 0 else default
    
        def popitem(self):
            if not self.keylist:
                raise KeyError("popitem(): dictionary is empty")
            key = self.keylist[-1]
            value = self.valuelist[-1]
            del self[key]
            return key, value
    
        def __repr__(self):
            return "Dict(%r)" % self.items()
    
        def show_structure(self):
            "Diagnostic method.  Not part of the API."
            print("=" * 50)
            print(self)
            print("Indices:", self.indices)
            for i, row in enumerate(zip(self.hashlist, self.keylist, self.valuelist)):
                print(i, row)
            print("-" * 50)
    
    
    if __name__ == "__main__":
        d = Dict([("timmy", "red"), ("barry", "green"), ("guido", "blue")])
        d.show_structure()

    Описание (возможно, понадобится VPN из-за выходок РКН)
    Ответ написан
    2 комментария
  • Как происходит удаление из множества?

    @deliro
    Множество — это почти тот же словарь. Там та же самая хэш-таблица. Только значений нет, есть только ключи. Соответственно, алгоритм поиска тот же — вычисляем хэш элемента, по нему определяем индекс в хэш-таблице за константное время и помечаем элемент как удалённый.
    Ответ написан
    Комментировать
  • Как правильно распрасить json?

    @deliro
    Это не JSON. В JSON кавычки двойные

    In [6]: x = '[{"tzid": "000000000", "phone": "000000", "service": "test", "statu
       ...: s": "TZ_NUM_PREPARE"}]'
    
    In [7]: x
    Out[7]: '[{"tzid": "000000000", "phone": "000000", "service": "test", "status": "TZ_NUM_PREPARE"}]'
    
    In [8]: json.loads(x)
    Out[8]: 
    [{'tzid': '000000000',
      'phone': '000000',
      'service': 'test',
      'status': 'TZ_NUM_PREPARE'}]
    Ответ написан
    1 комментарий
  • Как в Python3 использовать вложенный список в multiprocessing?

    @deliro
    Не надо так низкоуровнево писать (обычно).

    from concurrent.futures import ProcessPoolExecutor
    
    
    D = {'x': [1, 2, 3], 'y': [4, 5, 6], 'z': [7, 8, 9]}
    
    
    def process(arg):
        key, values = arg
        return key, [v * 10 for v in values]
    
    
    if __name__ == "__main__":
        with ProcessPoolExecutor() as executor:
            result = executor.map(process, D.items())
    
        print(dict(result))


    Чтобы убедиться, что оно действительно работает и не блокирует друг друга:
    from concurrent.futures import ProcessPoolExecutor
    from time import sleep
    
    
    D = {'x': [1, 2, 3], 'y': [4, 5, 6], 'z': [7, 8, 9]}
    
    
    def process(arg):
        key, values = arg
        print("executing", key, values)
        sleep(1)
        return key, [v * 10 for v in values]
    
    
    if __name__ == "__main__":
        with ProcessPoolExecutor(2) as executor:
            result = executor.map(process, D.items())
    
        print(dict(result))
    Ответ написан
    7 комментариев
  • Как происходит создание словаря?

    @deliro
    Нет.

    1. Создаётся в Си структура словаря
    2. Создаётся хэш-таблица на 8 элементов (это до 6 ключ-значений словаря)
    3. Поочерёдно добавляются (на уровне Си) элементы

    Когда ты вставляешь 7-ой элемент в словарь, хэш-таблица увеличивается в 2 раза — до 16 ячеек (это до 11 ключ-значений), все существующие в старой хэш-таблице элементы (кроме удалённых [да, удаление значения из словаря не удаляет его на самом деле до следующей реаллокации]) переезжают по одному в новую, при этом заново вычисляются хэши всех этих элементов (потому что старые хэши работали только со старым размером хэш-таблицы).

    И так до бесконечности. Как только количество элементов в словаре превышает load factor хэш-таблицы (который равен 2/3) — происходит создание новой хэш-таблицы. Но не раньше.

    Вот этот код, возможно, поможет тебе понять, как это работает:
    import sys
    
    def fs(s):
        if s >= 2 ** 20:
            return f"{s/(2**20):.2f}МБ"
        if s >= 2 ** 10:
            return f"{s/(2**10):.2f}КБ"
        return f"{s}Б"
    
    def g():
        n = int((2**16) * (2/3))
        d = dict.fromkeys(range(n))
        print("Размер словаря:", fs(sys.getsizeof(d)), "Элементов:", len(d))
        for i in range(n):
            del d[i]
        print("Размер словаря всё ещё", fs(sys.getsizeof(d)), "хотя он пуст. Элементов:", len(d))
        
        # В уже пустой словарь весом 1.25мб вставляем всего лишь один элемент
        d["hello"] = "world"
        newsize = sys.getsizeof(d)
        print("Хэш-таблица превысила load factor (2/3), реаллокация. Новый размер:", fs(newsize), "Элементов:", len(d))
    
    g()
    Ответ написан
    Комментировать
  • Как создать новый проект в pycharm?

    @deliro
    Это правильно, что он не видит компилятор. Ведь у питона интерпретатор.
    Ответ написан
    Комментировать
  • Почему Python установился в \Appdata\Locals\Programs\ и как его безболезненно переместить?

    @deliro
    1. Потому что в папку юзера можно устанавливать без админских прав
    2. Нет
    3. Не стоит
    Ответ написан
    2 комментария
  • Как подсчитать повторяющиеся символы в Python?

    @deliro
    import collections
    
    with open('symbols.txt', 'r') as f:
        data = f.read()
    
    counter = collections.Counter(data)
    print(counter.most_common(None))


    Если файл настолько большой, что не влезает в ОЗУ, у Counter есть метод update, в который можно кусками вкидывать символы
    Ответ написан
    1 комментарий
  • Как получить и вывести данные из JSON в Python?

    @deliro
    Разберись с итераторами в питоне
    Ответ написан
    Комментировать
  • Как работают разделяемые ссылки в классах?

    @deliro
    Ты не читал документацию, верно? append добавил в список тройку, которую шарят все инстансы класса, но append возвращает ничего. И это ничего ты и присваиваешь
    Ответ написан
    Комментировать
  • Как можно связать классы чтоб подобная конструкция работать?

    @deliro
    class Book:
        def __init__(self, name):
            self.name = name
    
        def __repr__(self):
            return f"<Book: {self.name}>"
    
        def __eq__(self, other):
            if not isinstance(other, type(self)):
                return False
            return self.name == other.name
    
    
    class Lib:
        def __init__(self, books=None):
            if books is None:
                self.books = []
            else:
                self.books = books[:]
    
        def __iadd__(self, other):
            if not isinstance(other, Book):
                raise TypeError("Not a book")
            self.books.append(other)
            return self
    
        def __iter__(self):
            return iter(self.books)
    
    
    lib = Lib()
    book1 = Book("Fluent Python")
    book2 = Book("Mein Kampf")
    
    lib += book1
    lib += book2
    
    for book in lib:
        print(book)


    Однако, лучше не злоупотреблять оверрайдингом операторов неявной логикой и сделать явный метод .add_book() и явный метод .iterate_books()
    Ответ написан
    Комментировать
  • Как устроена сортировка в Python?

    @deliro
    Сортировка строк основана на поэлементном сравнении позиций символов в таблице кодировки. Надеюсь, этот пример тебе поможет понять:

    In [1]: x = ['a', 'aaa', 'A', 'AA', 'AAA', 'AaA']
    
    In [2]: sorted(x)
    Out[2]: ['A', 'AA', 'AAA', 'AaA', 'a', 'aaa']
    
    In [3]: [[ord(i) for i in el] for el in sorted(x)]
    Out[3]: [[65], [65, 65], [65, 65, 65], [65, 97, 65], [97], [97, 97, 97]]
    Ответ написан
    2 комментария
  • Какова вероятность получить идентичные последовательности?

    @deliro
    get_seq2 не делает ничего полезного, если тебе не нужны какие-то промежуточные результаты. Распределения get_seq1 и get_seq2 совпадают. Только get_seq2 работает в 7 раз медленней.

    Очевидно, раз распределения совпадают, то вероятность получить одинаковую последовательность такая же, как вероятность получить её внутри одной функции — P(get_seq1() == get_seq1()) == P(get_seq1() == get_seq2()) == 1 / N * 1 / N-1 * ... * 1/1, где N - длина последовательности

    Распределение очень просто измерить:

    def measure(fn):
        n = 10
        p = []
        for _ in range(10):
            p.append([0] * n)
            
        for _ in range(10**6):
            seq = fn(n)
            for i, el in enumerate(seq):
                p[el][i] += 1
                
        return p


    И получаем матрицы, которые показывают, как часто элемент (строка) встречается на определённом индексе (столбец). При устремлении n к бесконечности, они уравняются и в том, и в другом случае. Значит, распределение у них равное и выбрасывай функцию №2

    >>> measure(get_seq1)
    [[99919, 100094, 99918, 100106, 100275, 100068, 100154, 99995, 100254, 99217],
     [99766, 100119, 100263, 99692, 99904, 99946, 100378, 99573, 100052, 100307],
     [100470, 100170, 99583, 100699, 99723, 99924, 99743, 100296, 99856, 99536],
     [100373, 100060, 99779, 99566, 99761, 99850, 100135, 100109, 100081, 100286],
     [100187, 99933, 99528, 100120, 99986, 99897, 99798, 100082, 100220, 100249],
     [100357, 99866, 99828, 99928, 100218, 100322, 100546, 99774, 99675, 99486],
     [99533, 99710, 100332, 99507, 100526, 100117, 99435, 100356, 100378, 100106],
     [99571, 100246, 99968, 100280, 100162, 99406, 99907, 100185, 99752, 100523],
     [99913, 99821, 100573, 99876, 99931, 100207, 99895, 99962, 100054, 99768],
     [99911, 99981, 100228, 100226, 99514, 100263, 100009, 99668, 99678, 100522]]


    >>> measure(get_seq2)
    [[99740, 100055, 99943, 99346, 99970, 100129, 100306, 99887, 100170, 100454],
     [100324, 100029, 99635, 100189, 99822, 100019, 99970, 100613, 99778, 99621],
     [99487, 100227, 100431, 99973, 99767, 99982, 100256, 100325, 99777, 99775],
     [99974, 99739, 100295, 100221, 99926, 100097, 99134, 100275, 99841, 100498],
     [100091, 99770, 99578, 99967, 100364, 100097, 99820, 99565, 100747, 100001],
     [99874, 99914, 100011, 99799, 99947, 99854, 100629, 99938, 100135, 99899],
     [100143, 100200, 99946, 100157, 99754, 99598, 100223, 99860, 99747, 100372],
     [100095, 100058, 100037, 100209, 100549, 100335, 99759, 99231, 100087, 99640],
     [100117, 99971, 99967, 100017, 99682, 99696, 100147, 100634, 99514, 100255],
     [100155, 100037, 100157, 100122, 100219, 100193, 99756, 99672, 100204, 99485]]
    Ответ написан
    Комментировать
  • Как найти частичное совпадение строк?

    @deliro
    pip3 install fuzzywuzzy[speedup]

    from fuzzywuzzy import fuzz
    
    x = "0 .. трубок использовали для прожигания стальковша.Замена воронки 18м 8сл. Разлита полностью."
    y = "трубок использооали для прожигания"
    
    fuzz.partial_ratio(x, y)


    https://github.com/seatgeek/fuzzywuzzy
    Ответ написан
    8 комментариев
  • Как в Python избежать ошибки TabError?

    @deliro
    1. Читать ошибку, в первую очередь.
    2. Поставить редактор, который умеет показывать разными символами табы и пробелы
    3. Убедиться, что у тебя либо только табы, либо только пробелы. Лучше, конечно, только пробелы, потому что PEP8
    4. Не задавать идиотских вопросов, ответы на которые в гугле на целых 10 релевантных страниц
    Ответ написан
    Комментировать
  • Легкий в установке python фреймворк?

    @deliro
    docker + docker-compose, состоящий из двух сервисов:
    1. nginx/Caddy, куда (чаще всего) нужно подложить один файлик: nginx.conf/Caddyfile соответсвенно
    2. Gunicorn/uWSGI + django

    Для ознакомления: https://github.com/wemake-services/wemake-django-t...

    С докером никаких systemd и установок пакетов не требуется. Всё, что нужно – поставить сам докер.

    P.S. Caddy бонусом сам устанавливает и поддерживает свежим сертификат от Let's Encrypt, твой сервис защищён и доступен по HTTPS из коробки ВООБЩЕ без действий с твоей стороны.
    Ответ написан
    Комментировать