Мой асинхронный декоратор продолжает возвращать ошибку NoneType

Я пытаюсь закодировать сервер сокетов на своем Raspberry Pi. Я пытаюсь использовать декоратор для подключения клиента к серверу (который будет моим Raspberry Pi). Но мой код продолжает выдавать ошибку NoneType. Я немного новичок в асинхронных декораторах, и мне нужна помощь. Не могли бы вы посмотреть, откуда берется моя ошибка, и, пожалуйста, немного поправьте мой код? Я перечислю свой код и сообщения об ошибках ниже.

Мое сообщение об ошибке:

C:\Users\####\AppData\Local\Programs\Python\Python36-32\python.exe C:/Users/#####/Desktop/autorank/server/client.py
Traceback (most recent call last):
  File "C:/Users/#####/Desktop/autorank/server/client.py", line 5, in <module>
    @client.connection(("192.168.0.11", 56500))
TypeError: 'NoneType' object is not callable

Мой клиентский код для пакета:

import socket, asyncio

class Client:
    def __init__(self):
        self.s = None
        self.data = None

    def connection(self, addr):
        """An asynchronous decorator for any server mainloop. Just decorate it with this and add a Client parameter."""

        def wrapper1(func):
            async def wrapper2(*args):
                self.connect(addr)
                await func(self)
                self.close_conn()
                return await func(self)
            return wrapper2

    async def connect(self, addr):
        """Connects to the desired server. You can make a server mainloop with the connection decorator."""

        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.connect(addr)

        self.addr = addr

        print(f"Connected to {addr}")

    async def close_conn(self):
        """Closes connection with the address connected to."""

        self.s.close()

        print(f"Disconnected from {self.addr}")
        del self.addr

    async def send_bytes(self, bytes_data):
        """Sends bytedata through a pipe to connected address"""

        self.s.sendall(bytes_data)

        print(f"Sent {bytes_data.decode()} in bytedata format to {self.addr}")

    async def recv(self, buf_size):
        """Recieves data from a server in bytedata format"""

        self.data = self.s.recv(buf_size)

И, наконец, мой main.py:

import asyncserver

client = asyncserver.Client()

@client.connection(("192.168.0.11", 56500))
def mainloop(cli):
    cli.send_bytes(b'Hello!!')
    cli.recv(1024)
    print(cli.data.decode())

Пожалуйста, скажите, должен ли я улучшить свой вопрос, и любые ответы приветствуются!

Взглянув еще раз на этот код, вы поймете, что он совершенно неверен, поскольку использует блокирующие сокеты внутри цикла событий asyncio. Например, ваша сопрограмма send_bytes() заблокирует весь цикл событий, ожидая, пока одноранговый узел примет байты. Это серьезный недостаток, который приведет к сбою в работе другого асинхронного кода из-за невозможности распараллеливания. Вместо этого вы должны использовать asyncio.open_connection, хранить объекты потока, которые он возвращает, и работать с ними.

user4815162342 19.12.2020 01:24

Ничего, если вы можете объяснить больше? Я пытался найти хороший учебник по асинхронному серверу, но не смог его найти! Я был бы признателен, если бы вы прислали ссылку на учебник по асинхронному серверу, но все остальное приветствуется!

codernaut1 19.12.2020 01:27

Я не знаю учебника по серверу, но пример эхо-сервера в документации — хорошее начало.

user4815162342 19.12.2020 01:29
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
83
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Декоратор connection правильно определяет wrapper1, но не возвращает его. Он неявно возвращает None, и это то, что используется как mainloop на верхнем уровне, что приводит к ошибке.

Обратите внимание, что wrapper2 ожидает func(self), что может привести к другой ошибке, о том, что None не является ожидаемым. Если вы планируете ждать функцию, которую вы декорируете, вы должны либо сделать ее асинхронной (async def mainloop(cli): ...), либо заставить ее возвращать ожидаемый объект.

Наконец, wrapper2 не должен принимать произвольные *args, если не будет их использовать. Это приведет к тому, что что-то вроде mainloop(1, 2, 3) будет работать, игнорируя аргументы. Обычно точка принятия обертки *args состоит в том, чтобы перенаправить их в обернутую функцию. Если вы не хотите или не нуждаетесь в этом, просто сделайте так, чтобы wrapper2 не принимал аргументов.

Другие вопросы по теме