Как мне известно, встроенного решения не существует.
Вы можете сделать что-то вроде этого:
По сути, вы считаете tupel числом элементов, которое в нем содержится, и только добавляете их, если есть достаточно места.
import random
random.seed(1) # In case you want to control the output
items = ['item_1', 'item_2', 'item_3', 'item_4', ('item_5a', 'item_5b'), 'item_6', ('item_7a', 'item_7b')]
def random_choice(original_choice_list,n,replace=True):
list_length = sum(map(lambda x: len(x) if isinstance(x,tuple) else 1,original_choice_list))
choice_list = original_choice_list.copy()
output = []
actual_n = 0
if not replace and n > list_length:
raise ValueError("List has only {} elements but you want {}. With replace = False not possible".format(list_length,n))
while actual_n < n:
if not choice_list:
return random_choice(original_choice_list, n, replace)
item = random.choice(choice_list)
if isinstance(item,tuple):
if len(item) + actual_n <= n:
output.append(item)
actual_n += len(item)
else:
output.append(item)
actual_n += 1
if not replace:
choice_list.remove(item)
return output
for i in range(5):
print(random_choice(items,4,replace=False))
print("######")
for i in range(5):
print(random_choice(items,4,replace=True))
Выход
['item_2', 'item_6', 'item_1', 'item_3']
['item_4', ('item_5a', 'item_5b'), 'item_6']
['item_6', 'item_4', 'item_2', 'item_1']
['item_4', 'item_1', 'item_6', 'item_2']
['item_6', 'item_4', 'item_3', 'item_2']
#####
[('item_5a', 'item_5b'), 'item_1', 'item_3']
['item_1', 'item_1', 'item_1', 'item_6']
[('item_5a', 'item_5b'), 'item_1', 'item_4']
['item_6', 'item_2', 'item_4', 'item_6']
['item_1', ('item_5a', 'item_5b'), 'item_2']