• Как грепать в консоле вывод от python?

    Vindicar
    @Vindicar
    RTFM!
    Питон по умолчанию буферизует вывод - не выводит в stdout сразу.
    Если подождешь подольше, то grep потом выведет сразу пачку Hello, когда буфер наполнится и будет выведен в stdout целиком.

    Можно сделать это в нужный тебе момент, вызвав sys.stdout.flush().
    Ответ написан
    Комментировать
  • Выдача ролей по реакциям discord.py?

    Vindicar
    @Vindicar
    RTFM!
    Гугли! На гитхабе discord.py есть готовый пример как это реализуется.
    Ответ написан
    Комментировать
  • Как написать такой декоратор?

    Vindicar
    @Vindicar
    RTFM!
    Именно так, как написано в ОП посте - боюсь, что нельзя.
    Но есть варианты.
    1. Передавать в декоратор параметр - словарь, куда будут складываться методы. Так сделано в комменте П. Ерошевича.
    2. Использовать пару декораторов, один для методов, другой для класса. Первый ставит некоторую метку на методы (нестандартный атрибут), второй проверяет __dict__ класса и складывает в словарь методы с этим атрибутом.
    Например:
    def methoddecorator(method):
      setattr(method, 'super_secret_attribute', True) #ставим метку на метод
      return method
    
    def classdecorator(cls):
      methods = dict()
      for name, obj in cls.__dict__.items():
        #ищем вызываемые объекты с меткой. Можно уточнить, конечно.
        if callable(obj) and getattr(obj, 'super_secret_attribute', None) is True:
          delattr(obj, 'super_secret_attribute') #удаляем метку
          methods[name] = obj #запоминаем метод
      setattr(cls, 'methods', methods) #записываем словарь меченых методов в поле класса
      return cls
    
    @classdecorator
    class Cls:
      #этот метод попадёт в Cls.methods
      @methoddecorator
      def method1(self):
        pass
    
      #этот метод НЕ попадёт в Cls.methods
      def method2(self):
        pass
    Ответ написан
    1 комментарий
  • Как мне отключить масштабируемость окна?

    Vindicar
    @Vindicar
    RTFM!
    Не используй метод show(), он исключительно отладочный и не предназначен для показа изображений в ходе нормальной работы.
    Варинты есть такие:
    1. разобраться с Tkinter - он предоставляет куда больше контроля над окном. Насчет "нельзя менять размер" - точно может, но вот "нельзя передвигать" - это уже не факт. Tkinter идет в стандартной поставке, для простых GUI подойдёт.
    2. Пишешь игру? Можешь потыкаться в pygame, он вроде для такого предназначен.
    3. Если не нужна кроссплатформенность (только под Windows), то можно попробовать создавать окно без заголовка прямо через WinAPI, но это очень гемморойно. Я бы не стал связываться.
    Ответ написан
    Комментировать
  • Вернуть переопределенный метод?

    Vindicar
    @Vindicar
    RTFM!
    Переопределить нужный метод самому? Для одного-двух методов может и подойти, при условии что вы уверены, что методы Class1 будут корректно работать с инстансами вашего класса.
    def __methodname__(self, *args, **kwargs):
        return Class1.__methodname__(self, *args, **kwargs)

    Это, конечно, хак... но с другой стороны, вы явно задаёте желаемое поведение от общего предка, так что новых неявных зависимостей по идее не возникает.
    Ответ написан
    Комментировать
  • Как сделать выполнение функции как Event-событие?

    Vindicar
    @Vindicar
    RTFM!
    Погоди-погоди-погоди... если я правильно понимаю, ты хочешь создать класс со следующими свойствами:
    1. Экземпляры класса должны хранить в себе список пользовательских callback-функций с одинаковой сигнатурой.
    2. При вызове экземпляра этого класса (как callable object), все callback-функции должны быть вызваны поочерёдно.
    3. Добавить и удалить новый callback должно быть можно посредством операторов += и -=.
    Я верно понял? Тогда мне неясно причем тут декоратор, и что должна будет делать декорируемая функция.

    Я бы написал что-то в духе:
    class EventCaller:
        #конструктор
        def __init__(self):
            #поскольку мы не планируем позволять двойную подписку, то у нас будет множество, а не список.
            self.__callbacks = set();
        # магический метод перегрузки оператора +=
        def __iadd__(self, callback):
            #проверка, что нам вообще передали callable object
            if not callable(callback):
                raise Exception("Callback object is not callable")
            #эта проверка не позволяет подписаться дважды одним объектом
            if callback in self.__callbacks:
                raise Exception("Double event subscription")
            self.__callbacks.add(callback)
        #магический метод перегрузки оператора -=
        def __isub__(self, callback):
            if callback not in self.__callbacks:
                raise Exception("No such event handler")
            self.__callbacks.remove(callback)
        #магический метод, позволяющий вызывать экземпляр объекта как функцию
        #аргументы, переданные методу, сохраняются как есть
        #неименованные - в кортеже args, именованные - в словаре kwargs
        def __call__(self, *args, **kwargs):
            for callback in self.__callbacks:
                try:
                    callback(*args, **kwargs)
                except:
                    pass


    Вот черновик такого класса. Он, конечно, нуждается в доработке:
    а) стоит добавить потоко-безопасную работу со списком обработчиков. Возможно, заменить список на потоко-безопасное хранилище.
    б) стоит запоминать выкинутые обработчиками исключения, и сообщать о них тем или иным способом (перевыбрасывать? выбрасывать своё исключение со списком всех произошедших?)
    в) так что если один из обработчиков изменит переданные объекты, это повлияет на последующие. Если такое поведение надо избежать, возможно, стоит создавать отдельную глубокую копию (см. модуль copy) args и kwargs для каждого обработчика. Хотя там свои заморочки.

    Пример использования:
    #простой обработчик, печатающий переданные ему аргументы
    def evthandler(*args, **kwargs):
        print "Unnamed arguments are:", args
        print "Named arguments are:", kwargs
    #
    #создаем объект-событие
    evt = EventCaller()
    #подписываемся на него
    evt += evthandler
    #генерируем событие. Аргументы могут быть произвольными, они будут переданы обработчикам как есть
    evt("unnamed arg 1", "unnamed arg 2", kwarg1=True, kwarg2=42)
    #отписываемся
    evt -= evthandler
    #этот вызов не будет иметь эффекта, так как список обработчиков события пуст
    evt("unnamed arg 1", "unnamed arg 2", kwarg1=True, kwarg2=42)


    За синтаксическую правильность кода не ручаюсь, но идея должна быть ясна.
    Ответ написан
  • Как реализовать прием-передачу текста через сокет не закрывая и не открывая его каждый раз заново?

    Vindicar
    @Vindicar
    RTFM!
    Погоди, сначала разберемся в логике работы соединения. Есть как минимум два варианта работы:
    А) Односторонний запрос-ответ, или ведущий-ведомый (то, что реализовано в приведенном коде). Т.е. клиент(ведущий) шлет запрос, получает ответ от ведомого, и либо закрывает соединение, либо шлёт еще запрос. Так работает HTTP, к примеру.
    Б) произвольный порядок. И клиент, и сервер могут послать сообщение другой стороне в произвольный момент, но другая сторона не обязана отвечать немедленно. Так обычно работают IM-системы.

    Для второго варианта работы логика будет примерно такой:
    1. Установить соединение
    2. Ждать, пока не появятся принятые данные, не поступят сообщения для отправки или не будет получен сигнал об остановке.
    3. Если получен сигнал остановки, см. п. 11.
    4. Проверить, есть ли принятые данные, если нет, см. п. 7.
    5. Принять данные и разобрать их формат, преобразовав их в сообщения.
    6. Обработать принятые сообщения, например сгенерировать событие.
    7. Проверить, есть ли сообщения на отправку, если нет, см. п. 10.
    8. Сформировать данные для отправки.
    9. Отправить данные.
    10. См. п. 2
    11. Закрыть соединение.

    При этом данные - это та строка байт, которая отправляется через сокет, а сообщение - это те структуры данных, которыми оперирует твоя программа. В простейшем случае это будет одно и то же.

    Реализовать такую логику можно следующим образом: создаешь отдельный поток обработки соединения, который в цикле выполняет шаги 2-10. Этот поток должен предоставлять метод для постановки сообщения в очередь на отправку, и событие для реакции на принятые сообщения*.
    В этом случае твоя основаная программа стартует этот поток, подписывается на его события, и дергает его метод отправки по мере надобности. Таким образом можно разделить код работы с сетью и GUI.

    * Еще пригодится служебная мелочь, вроде команды на остановку потока и закрытие соединения, проверку наличия ошибок и тд. В простейшей программе без этого можно обойтись.
    Ответ написан
    3 комментария