diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py
index abb0ddfe52..17f37a6432 100644
--- a/yt_dlp/YoutubeDL.py
+++ b/yt_dlp/YoutubeDL.py
@@ -1068,7 +1068,7 @@ class YoutubeDL:
         # correspondingly that is not what we want since we need to keep
         # '%%' intact for template dict substitution step. Working around
         # with boundary-alike separator hack.
-        sep = ''.join([random.choice(ascii_letters) for _ in range(32)])
+        sep = ''.join(random.choices(ascii_letters, k=32))
         outtmpl = outtmpl.replace('%%', f'%{sep}%').replace('$$', f'${sep}$')
 
         # outtmpl should be expand_path'ed before template dict substitution
diff --git a/yt_dlp/extractor/adn.py b/yt_dlp/extractor/adn.py
index e0c18c8773..f1f55e87fc 100644
--- a/yt_dlp/extractor/adn.py
+++ b/yt_dlp/extractor/adn.py
@@ -168,7 +168,7 @@ Format: Marked,Start,End,Style,Name,MarginL,MarginR,MarginV,Effect,Text'''
             }, data=b'')['token']
 
         links_url = try_get(options, lambda x: x['video']['url']) or (video_base_url + 'link')
-        self._K = ''.join([random.choice('0123456789abcdef') for _ in range(16)])
+        self._K = ''.join(random.choices('0123456789abcdef', k=16))
         message = bytes_to_intlist(json.dumps({
             'k': self._K,
             't': token,
diff --git a/yt_dlp/extractor/discovery.py b/yt_dlp/extractor/discovery.py
index fd3fc8fb0f..e6e109d5c5 100644
--- a/yt_dlp/extractor/discovery.py
+++ b/yt_dlp/extractor/discovery.py
@@ -78,7 +78,7 @@ class DiscoveryIE(DiscoveryGoBaseIE):
                 'Downloading token JSON metadata', query={
                     'authRel': 'authorization',
                     'client_id': '3020a40c2356a645b4b4',
-                    'nonce': ''.join([random.choice(string.ascii_letters) for _ in range(32)]),
+                    'nonce': ''.join(random.choices(string.ascii_letters, k=32)),
                     'redirectUri': 'https://www.discovery.com/',
                 })['access_token']
 
diff --git a/yt_dlp/extractor/funimation.py b/yt_dlp/extractor/funimation.py
index 18363c1b91..47c316664a 100644
--- a/yt_dlp/extractor/funimation.py
+++ b/yt_dlp/extractor/funimation.py
@@ -210,7 +210,7 @@ class FunimationIE(FunimationBaseIE):
             page = self._download_json(
                 'https://www.funimation.com/api/showexperience/%s/' % experience_id,
                 display_id, headers=headers, expected_status=403, query={
-                    'pinst_id': ''.join([random.choice(string.digits + string.ascii_letters) for _ in range(8)]),
+                    'pinst_id': ''.join(random.choices(string.digits + string.ascii_letters, k=8)),
                 }, note=f'Downloading {format_name} JSON')
             sources = page.get('items') or []
             if not sources:
diff --git a/yt_dlp/extractor/linuxacademy.py b/yt_dlp/extractor/linuxacademy.py
index a570248b7a..7bb64e17c4 100644
--- a/yt_dlp/extractor/linuxacademy.py
+++ b/yt_dlp/extractor/linuxacademy.py
@@ -75,9 +75,8 @@ class LinuxAcademyIE(InfoExtractor):
 
     def _perform_login(self, username, password):
         def random_string():
-            return ''.join([
-                random.choice('0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._~')
-                for _ in range(32)])
+            return ''.join(random.choices(
+                '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._~', k=32))
 
         webpage, urlh = self._download_webpage_handle(
             self._AUTHORIZE_URL, None, 'Downloading authorize page', query={
diff --git a/yt_dlp/extractor/tencent.py b/yt_dlp/extractor/tencent.py
index ff8bf991ef..44cae04720 100644
--- a/yt_dlp/extractor/tencent.py
+++ b/yt_dlp/extractor/tencent.py
@@ -32,7 +32,7 @@ class TencentBaseIE(InfoExtractor):
             padding_mode='whitespace').hex().upper()
 
     def _get_video_api_response(self, video_url, video_id, series_id, subtitle_format, video_format, video_quality):
-        guid = ''.join([random.choice(string.digits + string.ascii_lowercase) for _ in range(16)])
+        guid = ''.join(random.choices(string.digits + string.ascii_lowercase, k=16))
         ckey = self._get_ckey(video_id, video_url, guid)
         query = {
             'vid': video_id,
@@ -55,7 +55,7 @@ class TencentBaseIE(InfoExtractor):
             'platform': self._PLATFORM,
             # For VQQ
             'guid': guid,
-            'flowid': ''.join(random.choice(string.digits + string.ascii_lowercase) for _ in range(32)),
+            'flowid': ''.join(random.choices(string.digits + string.ascii_lowercase, k=32)),
         }
 
         return self._search_json(r'QZOutputJson=', self._download_webpage(
diff --git a/yt_dlp/extractor/tiktok.py b/yt_dlp/extractor/tiktok.py
index 2dd4510cc3..709d944dc6 100644
--- a/yt_dlp/extractor/tiktok.py
+++ b/yt_dlp/extractor/tiktok.py
@@ -49,7 +49,7 @@ class TikTokBaseIE(InfoExtractor):
 
     def _call_api_impl(self, ep, query, manifest_app_version, video_id, fatal=True,
                        note='Downloading API JSON', errnote='Unable to download API page'):
-        self._set_cookie(self._API_HOSTNAME, 'odin_tt', ''.join(random.choice('0123456789abcdef') for _ in range(160)))
+        self._set_cookie(self._API_HOSTNAME, 'odin_tt', ''.join(random.choices('0123456789abcdef', k=160)))
         webpage_cookies = self._get_cookies(self._WEBPAGE_HOST)
         if webpage_cookies.get('sid_tt'):
             self._set_cookie(self._API_HOSTNAME, 'sid_tt', webpage_cookies['sid_tt'].value)
@@ -68,8 +68,8 @@ class TikTokBaseIE(InfoExtractor):
             'build_number': app_version,
             'manifest_version_code': manifest_app_version,
             'update_version_code': manifest_app_version,
-            'openudid': ''.join(random.choice('0123456789abcdef') for _ in range(16)),
-            'uuid': ''.join([random.choice(string.digits) for _ in range(16)]),
+            'openudid': ''.join(random.choices('0123456789abcdef', k=16)),
+            'uuid': ''.join(random.choices(string.digits, k=16)),
             '_rticket': int(time.time() * 1000),
             'ts': int(time.time()),
             'device_brand': 'Google',
@@ -638,7 +638,7 @@ class TikTokUserIE(TikTokBaseIE):
             'max_cursor': 0,
             'min_cursor': 0,
             'retry_type': 'no_retry',
-            'device_id': ''.join(random.choice(string.digits) for _ in range(19)),  # Some endpoints don't like randomized device_id, so it isn't directly set in _call_api.
+            'device_id': ''.join(random.choices(string.digits, k=19)),  # Some endpoints don't like randomized device_id, so it isn't directly set in _call_api.
         }
 
         for page in itertools.count(1):
@@ -686,7 +686,7 @@ class TikTokBaseListIE(TikTokBaseIE):  # XXX: Conventionally, base classes shoul
             'cursor': 0,
             'count': 20,
             'type': 5,
-            'device_id': ''.join(random.choice(string.digits) for i in range(19))
+            'device_id': ''.join(random.choices(string.digits, k=19))
         }
 
         for page in itertools.count(1):
diff --git a/yt_dlp/extractor/videa.py b/yt_dlp/extractor/videa.py
index 52fa8fcec2..59ae933b08 100644
--- a/yt_dlp/extractor/videa.py
+++ b/yt_dlp/extractor/videa.py
@@ -119,7 +119,7 @@ class VideaIE(InfoExtractor):
             result += s[i - (self._STATIC_SECRET.index(l[i]) - 31)]
 
         query = parse_qs(player_url)
-        random_seed = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8))
+        random_seed = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
         query['_s'] = random_seed
         query['_t'] = result[:16]
 
diff --git a/yt_dlp/extractor/viu.py b/yt_dlp/extractor/viu.py
index 19d48234e4..dd4cad7ba8 100644
--- a/yt_dlp/extractor/viu.py
+++ b/yt_dlp/extractor/viu.py
@@ -251,7 +251,7 @@ class ViuOTTIE(InfoExtractor):
         return self._user_token
 
     def _get_token(self, country_code, video_id):
-        rand = ''.join(random.choice('0123456789') for _ in range(10))
+        rand = ''.join(random.choices('0123456789', k=10))
         return self._download_json(
             f'https://api-gateway-global.viu.com/api/auth/token?v={rand}000', video_id,
             headers={'Content-Type': 'application/json'}, note='Getting bearer token',
diff --git a/yt_dlp/extractor/vrv.py b/yt_dlp/extractor/vrv.py
index 89fa7affc2..ad9dc568a6 100644
--- a/yt_dlp/extractor/vrv.py
+++ b/yt_dlp/extractor/vrv.py
@@ -30,7 +30,7 @@ class VRVBaseIE(InfoExtractor):
         base_url = self._API_DOMAIN + '/core/' + path
         query = [
             ('oauth_consumer_key', self._API_PARAMS['oAuthKey']),
-            ('oauth_nonce', ''.join([random.choice(string.ascii_letters) for _ in range(32)])),
+            ('oauth_nonce', ''.join(random.choices(string.ascii_letters, k=32))),
             ('oauth_signature_method', 'HMAC-SHA1'),
             ('oauth_timestamp', int(time.time())),
         ]
diff --git a/yt_dlp/extractor/youku.py b/yt_dlp/extractor/youku.py
index ab59200d79..404f196f46 100644
--- a/yt_dlp/extractor/youku.py
+++ b/yt_dlp/extractor/youku.py
@@ -129,8 +129,8 @@ class YoukuIE(InfoExtractor):
 
     @staticmethod
     def get_ysuid():
-        return '%d%s' % (int(time.time()), ''.join([
-            random.choice(string.ascii_letters) for i in range(3)]))
+        return '%d%s' % (int(time.time()), ''.join(
+            random.choices(string.ascii_letters, k=3)))
 
     def get_format_name(self, fm):
         _dict = {