简体   繁体   中英

Python. Code repeats several times because the command to execute it is different

I have patched up a Discord bot using Python and it is working fine already but there is one problem.

This code repeats itself several times, once for each category of posting and right now I have random, funny, sports, games and news, so you can see the redundancy it is and what it'll further become, if there's need to make more categories.

if '!random' in messageContent:
                channel = int(chanRandom.strip('"'))
                channel = client.get_channel(channel)
                while c < 50:
                    if messageContent == '!random':
                        submission = next(x for x in randomList[sortListHot] if not x.stickied)
                        sortType   = 'Hot sorting'
                    elif messageContent == '!random top':
                        submission = next(x for x in randomList[sortListTop] if not x.stickied)
                        sortType   = 'Top sorting'
                    elif messageContent == '!random new':
                        submission = next(x for x in randomList[sortListNew] if not x.stickied)
                        sortType   = 'New sorting'
                    with open(urlFile, 'r') as urlRead:
                        if str(submission.url) not in urlRead.read():
                            await channel.send(f"{submission.url}\n{submission.title}\n<https://reddit.com{submission.permalink}>")
                            await channel.send("-------------------------")
                            with open(urlFile, 'a+') as urlWrite:
                                urlWrite.write(str(f'{submission.url}\n'))
                            c += 2
                        else:
                            print(f'{messageContent} repost: {submission.url}')
                await channel.send(sortType)

My idea right now is to create a list with every possible command but the problem is posting in the correct channel with the variable channel = int(chanRandom.strip('"')) , which changes in accord to the command used channel = int(chanNews.strip('"')) and so on.

There is also an issue with memory usage, because I think the bot is saving everything but there is no need to but this is something for another time.

Any help is appreaciated.

I can't see the contents of all the variables here, but if you want to cut down on code repition, I'd recommend making a dictionary and mapping different variables to the user input.

Here is the idea of it:

my_mapping = {
    "!random": (sortListHot, "Hot sorting"),
    "!random top": (sortListTop, "Top sorting"),
    "!random new": (sortListNew, "New sorting")
}

sorting_type = my_mapping[messageContent.lower()][0]  # sortListHot/Top/New
sorting_text = my_mapping[messageContent.lower()][1]  # "Hot/Top/New sorting"

submission = next(x for x in randomList[sortingType] if not x.stickied)

Having these mapped to a dictionary will also allow for more entries to be added easily and flexibly (just add a new key with the value being a tuple following the current pattern).

The .lower() was added for case insensitivity.

I can also recommend looking into command decorators instead of using the on_message event.


References:

Thanks to @Diggy., I was able to complete the code. This is the new version:

messageContentTop = str.replace(messageContent, ' top','')
            messageContentNew = str.replace(messageContent, ' new', '')

            if messageContent or messageContentTop or messageContentNew in multiCom:
                if 'top' in messageContent:
                    channel = int(multiCom[messageContentTop][3])
                elif 'new' in messageContent:
                    channel = int(multiCom[messageContentNew][3])
                else:
                    channel = int(multiCom[messageContent][3])

                channel = client.get_channel(channel)
                while c < 50:
                    if 'new' and 'top' not in messageContent:
                        submission = next(x for x in multiCom[messageContent][4] if not x.stickied)
                        sortType   = 'Hot sorting'
                    elif 'top' in messageContent:
                        submission = next(x for x in multiCom[messageContentTop][5] if not x.stickied)
                        sortType   = 'Top sorting'
                    elif 'new' in messageContent:
                        submission = next(x for x in multiCom[messageContentNew][6] if not x.stickied)
                        sortType   = 'New sorting'
                    with open(urlFile, 'r') as urlRead:
                        if str(submission.url) not in urlRead.read():
                            await channel.send(f"{submission.url}\n{submission.title}\n<https://reddit.com{submission.permalink}>")
                            await channel.send("-------------------------")
                            with open(urlFile, 'a+') as urlWrite:
                                urlWrite.write(str(f'{submission.url}\n'))
                            c += 2
                        else:
                            print(f'{messageContent} repost: {submission.url}')
                await channel.send(sortType)

The multiCom (multiple commands, I'll think of a better name) dictionary is setup like this:

multiCom = {
    '!random':  ('!random',  '!random top',  'random new',   randomChan,  reddit.subreddit(randomSubs).hot(),  reddit.subreddit(randomSubs).top(),  reddit.subreddit(randomSubs).new()),
    '!funny':   ('!funny',   '!funny top',   '!funny new',   funnyChan,   reddit.subreddit(funnySubs).hot(),   reddit.subreddit(funnySubs).top(),   reddit.subreddit(funnySubs).new()),
    '!news':    ('!news',    '!news top',    '!news new',    newsChan,    reddit.subreddit(newsSubs).hot(),    reddit.subreddit(newsSubs).top(),    reddit.subreddit(newsSubs).new())
}

randomChan , funnyChan , newsChan are variables storing the server's channels IDs.

Cleaned up about 20kb from the old version and it is noticeably faster!

If you have code that does not fit a simple pattern and want to use a structure similar to a switch/case statement, you can write a helper function that will simulate it:

 def switch(value): yield lambda *match: value in match

Usage example:

 for case in switch(messageContent):

     if   case('!random'):
          submission = next(x for x in randomList[sortListHot] if not x.stickied)
          sortType   = 'Hot sorting'

     elif case('!random top'):
          submission = next(x for x in randomList[sortListTop] if not x.stickied)
          sortType   = 'Top sorting'

     elif case('!random new'):
          submission = next(x for x in randomList[sortListNew] if not x.stickied)
          sortType   = 'New sorting'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM