#python
#python
Вопрос:
Я создаю бота Facebook Messenger, который возвращает время прибытия автобусов на указанную остановку. Пока бот работает нормально, но Facebook не разрешает, чтобы сообщения, отправляемые ботами, содержали более 320 символов. Часто бот может отображать только первые 5 или около того, не превышая этот предел, что недостаточно хорошо при очень загруженных остановках.
У меня есть if
инструкция, которая показывает только первые пять результатов, если у остановки больше, чем это, а затем передает результаты функции бота send_message
.
Я ищу способ получить результаты из больших списков остановок отдельными порциями по 5 и заставить бота продолжить с того места, где он остановился, после отправки первого сообщения. Мой текущий код выглядит следующим образом:
if len(info["results"]) > 5:
while i < 5:
n.append("Route:" " " str(info['results'][i]['route']) " " "to" " " str(info['results'][i]['destination']) "n" "Due:" " " str(info["results"][i]["duetime"]) " " "minutes." "n")
i = i 1
else:
while i < len(info["results"]):
n.append("Route:" " " str(info['results'][i]['route']) " " "to" " " str(info['results'][i]['destination']) "n" "Due:" " " str(info["results"][i]["duetime"]) " " "minutes." "n")
i = i 1
return 'n'.join(str(x) for x in n)
return
Оператор внизу — это то, что передается send_message
функции. Есть ли какой-либо способ, которым я могу использовать метод множественных сообщений?
Комментарии:
1. Является
send_message
простой функцией или членом класса?info
Создается в этой функции или передается ей в качестве аргумента?2. Кажется, это яркий пример для генератора.
3. Для написания исчерпывающего ответа недостаточно кода, но как насчет вызова
my_iter = iter(my_list)
?. После этого вы можете просто вызватьnext(my_iter)
, чтобы использовать следующее сообщение, и внутреннее состояние итератора гарантирует, что вы не обрабатываете одно и то же сообщение дважды.4. @trincot
send_message
— это простая функция. Он принимает содержимое сообщения от отправителя и передает его в качестве аргумента на сервер реального времени автобусной компании. Затем он отправляет результаты.5. Вы вызываете
send_message
через регулярные промежутки времени?
Ответ №1:
Вы можете сделать это легко, написав функцию генератора, как chunks()
в приведенном ниже коде:
info = {'results': [
{'route': 1, 'destination': 'DestA', 'duetime': '10'},
{'route': 2, 'destination': 'DestB', 'duetime': '20'},
{'route': 3, 'destination': 'DestC', 'duetime': '30'},
{'route': 4, 'destination': 'DestD', 'duetime': '40'},
{'route': 5, 'destination': 'DestE', 'duetime': '50'},
{'route': 6, 'destination': 'DestF', 'duetime': '60'},
{'route': 7, 'destination': 'DestG', 'duetime': '70'},
{'route': 8, 'destination': 'DestH', 'duetime': '80'},
],
}
def chunks(info, n):
results = info['results']
for i in range(0, len(results), n):
chunk = [
'Route: {} to {}nDue: {} minutes.n'.format(
result['route'], result['destination'], result["duetime"])
for result in results[i:i n]]
yield 'n'.join(chunk)
for i, chunk in enumerate(chunks(info, 5), 1):
print('== CHUNK {} ==n{}'.format(i, chunk))
Вывод:
== CHUNK 1 ==
Route: 1 to DestA
Due: 10 minutes.
Route: 2 to DestB
Due: 20 minutes.
Route: 3 to DestC
Due: 30 minutes.
Route: 4 to DestD
Due: 40 minutes.
Route: 5 to DestE
Due: 50 minutes.
== CHUNK 2 ==
Route: 6 to DestF
Due: 60 minutes.
Route: 7 to DestG
Due: 70 minutes.
Route: 8 to DestH
Due: 80 minutes.
Комментарии:
1. Спасибо, это отлично работает! Сначала это повторялось бесконечно, но это была моя собственная ошибка, я оставил там ненужный цикл.
2. Всегда пожалуйста. Мне было интересно, почему от вас не было никакого ответа. Кстати, я настоятельно рекомендую вам научиться использовать строковый
.format()
метод, потому что его использование значительно упрощает создание и печать выходных данных, чем добавление нескольких строк вместе, как это делается в вашем коде.
Ответ №2:
Вот пример кода для того, как добиться этого с помощью ключевого слова generators и yield —
def splitter(long_mess) :
split_mess = ""
for index in xrange(len(long_mess)) :
if index>0 and index%5==0 :
yield split_mess
split_mess = ""
split_mess = str(long_mess[index]) #replace with the n.append line
yield split_mess
input = "This is a really long message"
ans = splitter(input)
for i in ans :
print i #replace with send_message(i)
Выходной сигнал :
This
is a
reall
y lon
g mes
sage
Ответ №3:
Вот пример кода, который создает список списков, содержащий информацию о 5 остановках. Затем вы можете вызвать send_message
цикл
def split_into_pairs_of_5(info)
outer = []
inner = []
for x in range(len(info["results"])):
if x % 5 == 0 and inner:
outer.append(inner)
inner = []
inner.append("Route:" " " str(info['results'][i]['route']) " " "to" " " str(info['results'][i]['destination']) "n" "Due:" " " str(info["results"][i]["duetime"]) " " "minutes." "n")
if inner:
outer.append(inner)
inner = []
return outer
result = split_into_pairs_of_5(info)
for i in info:
send_message('n'.join(str(x) for x in i))
Ответ №4:
Мой подход использует itertools.groupby()
группировку записей в виде фрагмента из 5 (или любого положительного числа). В вашем сообщении вы не показываете имя, в котором send_message
вызывается, поэтому я просто называю его сам: get_info
:
import itertools
def show_rec(rec):
output = 'Route: {route} to {destination}, due in {duetime} minutes'.format(**rec)
return output
def get_info(group_size=5):
# Do something to get info
counter = itertools.count()
for _, group in itertools.groupby(info['results'], key=lambda v: next(counter) // group_size):
yield 'n'.join(show_rec(r) for r in group)
# Here is inside function send_message
for output in get_info(group_size=5):
print output
print
Обсуждение
- Для меня первоочередной задачей является не решение этой проблемы, а то, как представить запись в приятном, понятном и понятном виде, для этого я создал функцию
show_rec
для выполнения этой работы get_info
это действительно генератор, а не обычная функция (см. Ключевое слово yield)- Внутри
get_info
я группирую записи в group ofgroup_size
с помощьюitertools.groupby
функции, которая сама по себе является генератором. - Обратите внимание, что
counter
это объект генератора, где asnext(counter)
даст 0, 1, 2, 3, 4, 5, 6, 7, 8, … Выражениеnext(counter) // group_size
даст 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, … дляgroup_size=5
и это то, что мы используем для группировки записей.
Ответ №5:
Вы можете использовать функцию генератора с range
(или xrange
в Python 2.7), например:
info = {'results': [
{'route': 1, 'destination': 'DestA', 'duetime': '1'},
{'route': 2, 'destination': 'DestB', 'duetime': '2'},
{'route': 3, 'destination': 'DestC', 'duetime': '3'},
{'route': 4, 'destination': 'DestD', 'duetime': '4'},
{'route': 5, 'destination': 'DestE', 'duetime': '5'},
{'route': 6, 'destination': 'DestF', 'duetime': '6'},
{'route': 7, 'destination': 'DestG', 'duetime': '7'},
{'route': 8, 'destination': 'DestH', 'duetime': '8'},
]}
def iter_with_chunks(seq, chunk_size):
for index in range(0, len(seq), chunk_size):
yield seq[index: index chunk_size]
for count, chunk in enumerate(iter_with_chunks(info["results"], 5), 1):
print("== CHUNK {count} ==".format(count=count))
for item in chunk:
output = 'Route: {route} to {destination},n'
'due in {duetime} minutesn'.format(**item)
print(output)
Вывод:
== CHUNK 1 ==
Route: 1 to DestA,
due in 1 minutes
Route: 2 to DestB,
due in 2 minutes
Route: 3 to DestC,
due in 3 minutes
Route: 4 to DestD,
due in 4 minutes
Route: 5 to DestE,
due in 5 minutes
== CHUNK 2 ==
Route: 6 to DestF,
due in 6 minutes
Route: 7 to DestG,
due in 7 minutes
Route: 8 to DestH,
due in 8 minutes