Skip to content
Advertisement

How to nullify python asyncio global variables?

I am writing a personal Telegram Bot to collect statistics on my accounts market.csgo.com. The main task of the bot is to send async requests to the API and display information via Telegram. Everything works as it should, but the problem is with global variables, or rather, their incorrect counting. An example of one of my functions:

...
import asyncio
import aiohttp


sale_total_sum = 0
amount_total_items = 0

async def get_on_sale(session, dictt, message):
    global sale_total_sum
    global amount_total_items

    async with session.get(f'https://market.csgo.com/api/v2/items?key={dictt[1][1]}') as resp:
        html = await resp.json()
        
        if html['items'] is None:
            pass
        else:
            each_sale_sum = 0
            each_amount_items = 0
            
            for i in html['items']:
                sale_total_sum += i['price']
                each_sale_sum += i['price']
                each_amount_items += 1
                amount_total_items += 1
               
            try:
                await bot.send_message(message.from_user.id,
                    f'<a href="{dictt[1][0]}">{dictt[0]}</a> : <b>{each_sale_sum} $</b>nItems: <i>{each_amount_items}</i>',
                    disable_web_page_preview=True, parse_mode=types.ParseMode.HTML)
            except exceptions.RetryAfter as e:
                await asyncio.sleep(e.timeout)


@dp.message_handler(content_types=['text'])
async def Main(message):
    profiles = users()
    
    async with aiohttp.ClientSession(trust_env=True) as session:
        tasks = []
        
        if message.text == 'On Sale 💰':
            await bot.send_message(message.from_user.id, 'Information request. Wait..')
           
            for i in profiles.items():
                task = asyncio.ensure_future(get_on_sale(session, i, message))
                tasks.append(task)
            await asyncio.gather(*tasks)
            
            await bot.send_message(message.from_user.id,
                f'<b>Total on sale: {sale_total_sum} $nTotal items: {amount_total_items}nBot start at: {start}</b>',
                reply_markup=kb_client, parse_mode=types.ParseMode.HTML)


executor.start_polling(dp, skip_updates=True)

Function result:

Account_1: 100 $
Items: 1
Account_2: 200 $
Items: 2
Account_3: 300 $
Items: 3
Total on sale: 600 $
Total items: 6

Bot works in polling mode executor.start_polling(dp, skip_updates=True). If the function async def get_on_sale is called for the first time after enabling, then its final count Total on sale: 600 ₽ Total items: 6 will be correct, but subsequent calls will double this amount, which is actually not like this:

Account_1: 100 $
Items: 1
Account_2: 200 $
Items: 2
Account_3: 300 $
Items: 3
Total on sale: 1200 $
Total items: 12

I know that the problem is in the global variables global sale_total_sum and global amount_total_items. But if you use simple variables instead, they will simply be overwritten, and not summarized as I need. Therefore, I want to ask – is there a way to somehow reset or reassign these global variables to 0 after the function ends? So that the data would be correct on the next call. Thank you.

Advertisement

Answer

The solution was to create an object with two fields where get_on_sale is the argument

from dataclasses import dataclass

@dataclass
class AggregatedStats:
    sum: int = 0
    items: int = 0

async def get_on_sale(session, dictt, message, stats):

      ...            
            for i in html['items']:
                stats.sum += i['price']
                each_sale_sum += i['price']
                each_amount_items += 1
                stats.items += 1
               
      ...

@dp.message_handler(content_types=['text'])
async def Main(message):
    profiles = users()
    
    async with aiohttp.ClientSession(trust_env=True) as session:
        tasks = []
        
        if message.text == 'On Sale 💰':
            await bot.send_message(message.from_user.id, 'Information request. Wait..')
           
            stats = AggregatedStats()

            for i in profiles.items():
                task = asyncio.ensure_future(get_on_sale(session, i, message, stats))
                tasks.append(task)
            await asyncio.gather(*tasks)
            
            await bot.send_message(message.from_user.id,
                f'<b>Total on sale: {stats.sum} ₽nTotal items: {stats.items}nBot start at: {start}</b>',
                reply_markup=kb_client, parse_mode=types.ParseMode.HTML)

8 People found this is helpful
Advertisement