Skip to content

Некоторые ответы на часто задаваемые вопросы

Asyncio

В этом разделе будет очень сжатое и простое описание работы с модулем asyncio и простые рекомендации как решать проблемы с блокировками.

Что такое coroutine?

Coroutine это функция (сопрограмма), которая должна вызываться через await.

Когда в Python выполнение кода доходит до await, он останавливает выполнение в этой функции, и вернётся к ней, пока не выполнит другие сопрограммы и не завершит работу этой функции.

Благодаря такому подходу, программа может выполнять конкурентно несколько задач одновременно без использования потоков, а следовательно, будет экономия ресурсов железа и высокая производительность.

Не забывайте перед async функцией писать вначале await, иначе она не запустится

import asyncio


async def get_banana() -> str: return "banana"


async def main():
    print(get_banana())  # <coroutine object get_banana at 0x...>
    print(await get_banana())  # banana


asyncio.run(main())

Где надо писать await ?

Надо await писать только внутри async функций и больше нигде.

1
2
3
4
5
6
7
8
9
# bad
async def foo() -> str: return "foo"


def main():
    print(await foo()) # SyntaxError: 'await' outside async function


main()
1
2
3
4
5
6
# bad
async def main():
    print("main")


await main()  # SyntaxError: 'await' outside function
# good
import asyncio

async def foo() -> str: return "foo"


async def main():
    print(await foo())


asyncio.run(main())

Как происходит "блокировка" функции?

В асинхронном программировании блокирующие функции это все функции без конструкции await, работающие на принципе IO (Input/Output).

Но не все блокирующие функции плохи, так как их использование неизбежно. Главное этим не злоупотреблять. Если заблокируете выполнение функции надолго, то ваш бот зависнет, потому что он не остановил функцию в нужный момент, чтобы выполнять другие сопрограммы.

Конечно, интерпретатор Python не запрещает использовать синхронные решения в программировании асинхронных, но в этом нет смысла, так как пропадают все преимущества асинхронности.

Самые частые проблемы блокировок происходят из-за функций то типу time.sleep(). В async функциях используйте asyncio.sleep().

# bad
time.sleep(10)
# good
await asyncio.sleep(10)

Так же распространённой проблемой долгой блокировки является модуль requests, urllib3 и ему производные API-обёртки (vk_api, и тп).

Они хороши для неасинхронного программирования, но могут произойти ситуации, когда запрос и ответ с сервера может идти долго и бот из-за этого зависнет. Используйте для этого модуль aiohttp, он идёт зависимостью в vkbottle или используйте встроенный AiohttpClient.

1
2
3
4
5
6
# bad
async def send_httpbin_get() -> dict:
    r = requests.get('http://httpbin.org/get')
    if r.status_code == 200:
        js = r.json()
        return js
1
2
3
4
5
6
7
8
# good, recommended
# see https://vkbottle.rtfd.io/ru/latest/low-level/http-client/
from vkbottle.http import AiohttpClient


async def send_httpbin_get() -> dict:
    http_client = AiohttpClient()
    return await http_client.request_json('http://httpbin.org/get')
# good
import aiohttp


async def send_httpbin_get() -> dict:
    async with aiohttp.ClientSession() as session:
        async with session.get('http://httpbin.org/get') as r:
            if r.status == 200:
                js = await r.json()
                return js

Почему так мало базы? Ничего не понятно

В Python написание async кода требует такого же освоения и понимания, как и других синтаксических конструкций.

Подробнее о работе с asyncio читайте в официальной документации.

Дополнительные материалы помимо официальной документации:

Какие методы присутствуют во фреймворке

Всё что есть в официальной документации от vk.com.

Синтаксис методов, параметры и ошибки аналогичны документации выше, только методы пишутся в snake_case, а не camelCase.

from vkbottle.api import API

api = API("token")

# https://api.vk.com/method/account.ban
await api.account.ban(owner_id=1)


# https://api.vk.com/method/account.getBanned
await api.account.get_banned(offset=0, count=1)

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

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

Как получить токен для пользователя

Самый простой способ воспользоваться сервисом vkhost.github.io

Как получить токен для бота

bot_methods У бота (токена от сообщества) не все методы доступны в отличие от получения токена через пользователя, учитывайте это. На картинке красным выделен один из методов, который будет работать в ботах.

Чат бот Быстрый старт

Как отправить метод, которого нет во фреймворке

Если очень нужно использовать то, чего во фреймворке и официальной документации нет, используйте API.request, Bot.api.request или Message.ctx_api.request методы.

После их выполнения вернёт словарь с json ответом, а не типизированный объект, учитывайте это.

Код ниже показывает простой пример использования VK API. Он выполнит заданный код и завершает работу.

import asyncio

from vkbottle.api import API

api = API("token")


async def main():
    await api.request("users.get", {})  # Single request

    # Multiple request for one session
    async for response in api.request_many(
        [api.APIRequest("users.get", {}), api.APIRequest("groups.get", {})]
    ):
        print(response)


asyncio.run(main())

Для бота необходимо инициализировать класс Bot. В нём присутствует класс API, его дополнительно инициализировать не надо.

import asyncio
from vkbottle.bot import Bot

bot = Bot("token")

async def main():
    print(await bot.api.request("users.get", {}))  # Single request
    # Multiple request for one session
    async for response in bot.api.request_many(
        [bot.api.APIRequest("users.get", {}), bot.api.APIRequest("groups.get", {})]
    ):
        print(response)


asyncio.run(main())

Также доступ к классу API можно получить через объект Message с помощью параметра Message.ctx_api

from vkbottle.bot import Bot, Message

bot = Bot(token="token")
admin_ids = [1, 100]


@bot.on.message(text="админы")
async def who_admins(message: Message):
    admins = [f"{adm.first_name} {adm.last_name}" for adm in (await message.ctx_api.users.get(admin_ids))]
    print((await message.ctx_api.request("users.get", {"user_ids": admin_ids})))
    await message.answer(f"Администраторы этого бота: {' '.join(admins)}")


bot.run_forever()

Pydantic.error_wrappers.ValidationError

Объекты в этом фреймворке типизированы и генерируются на основе официальной VK-API схемы.

Они её обновляют без предупреждений и из-за этого могут произойти поломки с валидацией объектов.

Если эта ошибка произошла, попробуйте обновить типы:

pip install git+https://github.com/vkbottle/types -U

Если и это не помогло, пишите issue (в vkbottle, не types) или в чат ВК/Телеграмм.