Задать вопрос
  • Как быть c иммутабельными объектами в асинхронной (или многопоточной среде)?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Функциональное программирование
    Седой и строгий
    Судя по тексту вопроса, вы мыслите категориями императивного стиля и объектно-ориентированной парадигмы, где переменная - это коробка, в которой лежат данные, а код - это последовательность конкретных действий, типа "возьми данные из коробки, прибавь к ним единицу, положи обратно в коробку". В ФП нет состояния/коробки. В ФП данные трактуются как последовательность их преобразований.

    Например есть некоторая функция складывающая аргументы:
    function addition(a, b) {
        return a + b;
    }

    И есть некое значение-аккумулятор X. Значение X не равно 7, значение X равно

    addition(addition(addition(addition(addition(addition(1, 1), 1), 1), 1), 1), 1)

    или addition(addition(addition(1, 2), 3), 1) или сотням других вариантов. То есть функции от предыдущих состояний, в математическом смысле.

    Естественно, в реальном мире не всё так радужно, как в теории. Совсем без состояния обойтись нельзя, и на низком уровне оно всё равно хранится как некоторое значение области памяти. Но функциональщику не приходится заморачиваться мелочами вроде порядка выполнения, синхронизацией и т.п. Он просто описывает высокоуровневые правила преобразований, а обо всём остальном беспокоится среда выполнения.

    Например в Clojure один из способов решить задачу подобную описанной вами - использовать атом.
    ;; Создаём счётчик с нулевым начальным значением
    (def counter (atom 0))
    
    ;; Применяем к нему функцию инкремента
    (swap! counter inc)

    Любую функцию, в том чилсе более сложную, чем инкремент, можно применить к атому, транзакционной памяти или агенту в нагруженной многопоточной среде и даже не задумываться о возникновении гонки, взаимоблокировки и прочем.

    Если развить задачу до работы с персистентными данными в базе, то для clojure-программиста сложнее она не станет. Достаточно использовать СУБД Datomic, построенную на идее event sourcing'а, при которой в БД хранятся не сами значения, а последовательность операций над ними. Эффект тот же, что и с атомом - сто клиентов одновременно зафиксировали в БД намерение увеличить counter, а сто первый получил результат применения ста инкрементов к начальному значению.
    Ответ написан
    4 комментария
  • Справедливая ли цена для такого сайта?

    sergey-gornostaev
    @sergey-gornostaev
    Седой и строгий
    В Москве - это очень маленькая цена, в Верхней Пышме - большая. Для солидной студии - это копейки, для студентов-шабашников - деньги. Ваш вопрос в принципе дискуссионный, а с таким количеством неизвестных он приведёт к появлению ответов основанных только на мнениях.

    P.S. интернет-магазин без онлайн покупок называется каталогом.
    Ответ написан
    Комментировать
  • Как защитить продукт от воровства?

    sergey-gornostaev
    @sergey-gornostaev
    Седой и строгий
    В современном мире ценность программного обеспечения определяется прежде всего работавшими над ним специалистами. По настоящему хороший продукт можно украсть только переманив команду. Если продукт такой, что достаточно украсть только код, то он не стоит беспокойств.
    Ответ написан
  • Какие проблемы могут возникнуть с aiohttp?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Асинхронное программирование
    Седой и строгий
    Везде пишут, что aiohttp позволяет запускать асинхронные воркеры и при этом писать код так, будто бы он синхронный.

    Херню пишут.

    поэтому event loop перейдёт сразу к присваиванию.

    Нет, вся цепочка асинхронных вызовов от кода принявшего клиентское соединение до кода лезущего в базу остановится в ожидании данных, а цикл событий побежит дальше обслуживать другие цепочки и проверит готовность данных на следующей итерации.
    Ответ написан
    5 комментариев
  • Что является основной причиной говнокода?

    sergey-gornostaev
    @sergey-gornostaev
    Седой и строгий
    Роберт Мартин в своём хрестоматийном трёхтомнике - "Чистый код", "Чистая архитектура" и "Идеальный программист" - пишет, что причиной плохого кода всегда является непрофессионализм написавшего его программиста, без исключений.
    Ответ написан
    Комментировать
  • Реализация redis pub/sub в tornado?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Tornado
    Седой и строгий
    Библиотеки brukva и toredis уже не обновлялись по нескольку лет. Зато Tornado в последнем обновлении окончательно перешёл на использование очереди событий asyncio, что даёт возможность использовать свежие и хорошие библиотеки. Например aioredis:
    import asyncio
    import aioredis
    from tornado import web, websocket
    from tornado.ioloop import IOLoop
    
    connections = []
    
    class WSHandler(websocket.WebSocketHandler):
        def open(self):
            connections.append(self)
    
        def on_message(self, message):
            ...
    
        def on_close(self):
            connections.remove(self)
    
    
    class GetHandler(web.RequestHandler):
        def get(self):
            self.render("chat.html")
    
    
    async def consumer(channel):
        while await channel.wait_message():
            msg = await channel.get(encoding='utf-8')
            for connection in connections:
                await connection.write_message(msg)
    
    
    async def setup():
        connection = await aioredis.create_redis('redis://localhost')
        channel = await connection.subscribe('notifications')
        asyncio.ensure_future(consumer(channel))
    
    
    application = web.Application([
        (r'/', GetHandler),
        (r'/chat/', WSHandler),
    ])    
    
    
    if __name__ == '__main__':
        application.listen(8000)
        loop = IOLoop.current()
        loop.add_callback(setup)
        loop.start()

    Естественно, это максимально упрощённый пример, в реальном коде соединения не стоит держать в глобальной переменной, а при завершении работы сервера стоит отписаться от канала и закрыть соединение с redis.
    Ответ написан
    Комментировать
  • Как переопределить if в python?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Python
    Седой и строгий
    Прежде всего хочу заметить, что настолько больших возможностей по расширению языка, как в Lisp'ах, никакой другой язык не предоставляет. Но в некоторых языках, в том числе в Python, можно немного поколдовать с кодом на этапе его разбора.

    dumb_translator.py
    import ast
    import sys
    
    class DumbLisp(ast.NodeTransformer):
        def fix(self, source, result):
            ast.copy_location(result, source)
            ast.fix_missing_locations(result)
            return result
    
        def visit_Expr(self, node):
            if isinstance(node.value, ast.Tuple):
                t = node.value
                if isinstance(t.elts[0], ast.Name):
                    if t.elts[0].id == 'newif':
                        _else = [ast.Expr(value=t.elts[3])] if len(t.elts) == 4 else []
                        _if = ast.If(test=t.elts[1],
                                    body=[ast.Expr(value=t.elts[2])],
                                    orelse=_else)
                        self.generic_visit(_if)
                        return self.fix(node, _if)
                    elif t.elts[0].id == 'define':
                        assign = ast.Assign(targets=[ast.Name(id=t.elts[1].id, ctx=ast.Store())],
                                            value=t.elts[2])
                        return self.fix(node, assign)
                    else:
                        call = ast.Expr(value=ast.Call(func=t.elts[0], args=t.elts[1:], keywords=[]))
                        return self.fix(node, call)
            return node
    
    
    with open(sys.argv[1]) as fh:
        tree = ast.parse(fh.read())
        DumbLisp().visit(tree)
        code = compile(tree, filename=sys.argv[1], mode="exec")
        exec(code)

    test.dl
    (define, a, 1)
    
    (newif, a == 1, (print, 'Yes'), (print, 'No'))

    Запускаем
    python dumb_translator.py test.dl

    Естественно, пример предельно простой, а потому в качестве s-форм приходится использовать кортежи. Но есть полноценный фронтенд компилятора Python, транслирующий в python-байткод диалект Lisp близкий к Clojure - Hy.
    Ответ написан
    1 комментарий
  • Почему не запускается postgres 9.6?

    Melkij
    @Melkij
    DBA для вашего PostgreSQL?
    Всё ему нравится,
    согласованное состояние восстановления достигнуто

    начало передачи журнала с главного сервера, с позиции 4A4/E000000 на линии времени 2

    База запустилась, репликация запустилась, всё работает.

    А вот вам, наверное, не нравится то что база не принимает read only коннекты? Проверьте настройку hot_standby в postgresql.conf, дефолтно выключено.
    Ответ написан
    1 комментарий
  • Как добиться поддержки кириллицы в Python3 flask + mysql?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Python
    Седой и строгий
    Начать однозначно стоит с чтения Unicode HOWTO документации Python. И обязательно убедиться, что кодировка базы - UTF-8.
    Ответ написан
    1 комментарий
  • Отображать поле в зависимости от статуса пользователя, как?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Django
    Седой и строгий
    Вам надо переопределить метод get_fields:
    @admin.register(CompanyNews)
    class CompanyNewsAdmin(admin.ModelAdmin):
        ...
    
        def get_fields(self, request, obj=None):
            fields = super(StudentAdmin, self).get_fields(request, obj)
            if not request.user.is_superuser:
                fields.remove('IsVisible')
            return fields
    Ответ написан
    Комментировать
  • Что лучше локальные файлы или БД?

    sim3x
    @sim3x
    и недавно узнал, что html шаблоны можно кодировать в base64 и хранить в бд MySQL
    а теперь забудьте.

    В здравом уме никто
    - не кодирует хтмл в бейз64
    - почти никто не хранит шаблоны в БД

    Шаблоны следует хранить в файлах, так как так их можно поместить в гит и следить за их изменениями
    Ответ написан
    Комментировать
  • Почему threading выполнятеся снова и снова в приложении flask которое захостено на Heroku?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Python
    Седой и строгий
    Почитайте "12 факторов", чтобы понять как работает Heroku и почему для этой платформы нельзя писать программы так, как вы написали.
    Ответ написан
    Комментировать
  • Чем править базу данных?

    Melkij
    @Melkij
    DBA для вашего PostgreSQL?
    Судя по расширениям - это куски mysql.
    Только запросами к запущенному серверу mysql и взаимодействовать. Клиент выберите любой, их много
    Ответ написан
    9 комментариев
  • Стоит ли новичку в Python использовать сразу PyCharm?

    sergey-gornostaev
    @sergey-gornostaev
    Седой и строгий
    Я уже много раз писал об этом, но повторю: Не нужно использовать IDE на этапе обучения. Во-первых, IDE избавляет вас от рутинных операций, но именно рутинные операции позволяют набить руку . Во-вторых, IDE скрывает многие процессы, выполняя их за программиста, но именно они позволяют понять базовые принципы. Так что IDE надо начинать использовать только тогда, когда ты уже профи, всё знаешь и тебе надо увеличить производительность труда.
    Ответ написан
    13 комментариев
  • Как проверить не отключился ли клиент от Django websocket?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Django
    Седой и строгий
    Достаточно определить в обработчике соответствующий метод:
    class MyConsumer(AsyncWebsocketConsumer):
        async def disconnect(self, close_code):
            # соединение закрылось
    Ответ написан
    6 комментариев
  • Django, как проще всего отправить асинхронно письмо?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Django
    Седой и строгий
    Самый простой - это запустить функцию отправки письма в отдельном потоке:
    from threading import Thread
    from django.core.mail import send_mail
    
    Thread(target=send_mail, args=(subject, txt_msg_body, settings.DEFAULT_FROM_EMAIL, smtp_to),
           kwargs={'fail_silently': (not settings.DEBUG), 'html_message': html_msg_body}).start()

    Но нет гарантий отправки и есть опасность завалить систему при большом количестве отправлений.
    Ответ написан
    Комментировать
  • В чем проблема в этом триггере?

    Melkij
    @Melkij
    DBA для вашего PostgreSQL?
    Вы в after insert триггере на табличке со странным названием lechenie выполняете безусловный insert в эту же самую таблицу. Вопрос к вам: почему вы в результате ожидаете что-то кроме бесконечной рекурсии?
    Ответ написан
    6 комментариев
  • Как слить два списка в словарь?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Python
    Седой и строгий
    Вариант на случай, когда для не повторяющихся ключей значения не нужно заворачивать в список:
    d = {}
    for k, v in zip(list1, list2):
        if k in d:
            if not isinstance(d[k], list):
                d[k], t = [], d[k]
                d[k].append(t)
            d[k].append(v)
        else:
            d[k] = v
    Ответ написан
  • Как сделать валидацию возраста?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Django
    Седой и строгий
    По мотивам документации:
    from datetime import timedelta
    from django.db import models
    from django.core.exceptions import ValidationError
    from django.utils import timezone
    
    
    class Person(models.Model):
        dob = models.DateField('Дата рождения')
    
        def clean_fields(self, exclude=None):
            super().clean_fields(exclude=exclude)
    
            now = timezone.now()
            if self.dob > (now - timedelta(days=30)):
                raise ValidationError('Рано ещё заносить в базу')
            if (now.year - self.dob.year) > 120:
                raise ValidationError('Поздно уже заносить в базу')
    Ответ написан
    1 комментарий