Это моя первая программа на Python, и я хотел узнать о ней мнения всех. Цель программы — разделить адрес электронной почты на имя пользователя и доменное имя.
import sys
import getopt
argv = sys.argv[1:]
# -------Error Handling-Start----------
try:
opts, args = getopt.getopt(argv, "l:s:h", ["list ", "single ", "help "])
except getopt.GetoptError as err:
print(f"{err}n""n"
"Usage: <Options> <Input> n"
"-l, --list Specify a list of emails to be sliced n"
"-s, --single Specify a single email to be sliced n"
"-h, --help Show options")
opts = []
# -------Error Handling-End------------
for opt, file_arg in opts:
if opt in ['-h', '--help']:
sys.exit("Usage: <Options> <Input> n"
"-l, --list Specify a list of emails to be sliced n"
"-s, --single Specify a single email to be sliced n"
"-h, --help Show options")
# If option -h is present, display MAN page
for opt, email_arg in opts:
if opt in ['-s', '--single']:
email = email_arg
username = email[:email.index('@')]
domain = email[email.index('@') + 1:]
print(f"Your username: {username}")
print(f"Your domain name: {domain}n")
# If option -s is present, split input email into username and domain then print the output
for opt, file_arg in opts:
if opt in ['-l', '--list']:
file = file_arg
email_file = open(file, "r")
for string in email_file:
username = string[:string.index('@')]
domain = string[string.index('@') + 1:]
print(f"Your username: {username}")
print(f"Your domain name: {domain}")
# If option -l is present read file specified then loop through each line while splitting each into username and domain
if len(sys.argv) == 1:
sys.exit("Usage: <Options> <Input> n"
"-l, --list Specify a list of emails to be sliced n"
"-s, --single Specify a single email to be sliced n"
"-h, --help Show options")
# If only one argument is supplied, print MAN page.
1 ответ
Общий стиль выглядит хорошо. Самая большая возможность для улучшения — это использование вами getopt
. Вам следует использовать более новую и простую argparse
вместо. Большая часть вашего кода используется для анализа и использования аргументов командной строки. Все это можно сделать в трех строках с argparse
.
import argparse
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("-f", "--file", dest="file", default=False, action="store_true")
arg_parser.add_argument("input", type=str)
args = arg_parser.parse_args()
Вместо того, чтобы использовать --single
или же --list
, Я добавил один флаг --file
(или же -f
), поскольку первый вариант не только неоднозначен (что произойдет, если вы не укажете ни один из них или оба?), но и потенциально вводит в заблуждение их имя. Параметр справки с «-h» вводится автоматически.
"-f", "--file"
— это флаги, которые вы можете использовать для указания этого аргумента. dest=file
означает, что созданный объект args
будет иметь атрибут args.file
в котором хранится полученное значение. action="store_true"
означает, что флаг должен быть указан без значения (т. е. -f
вместо -f True
), чтобы установить его.
После этого вы можете получить доступ к своим входам как к строкам (потому что type=str
) к args.input
(потому что первый аргумент add_argument
был "input"
).
open
файла всегда следует сочетать с close
когда вы закончите его использовать, то же самое верно и для других объектов ввода-вывода, таких как сетевые соединения. Вместо того, чтобы звонить вручную close
, лучше использовать контекстные менеджеры Python с with
ключевое слово, которое автоматически выполняет любую очистку.
if args.file:
with open(args.input, "r") as file:
emails = file.readlines()
else:
emails = [args.input]
Ваш код для разделения электронной почты на имя пользователя и домен может быть выполнен с помощью str.split
, предполагая, что существует ровно один «@». Если нет «@» или больше одного, вам, вероятно, все равно следует уведомить пользователя об ошибке. Если вы хотите иметь реальный «серьезный» код, который запускается в производство в действующей системе, см. Комментарий Тоби Спейта о том, как это правильно сделать.
if email.count("@") != 1:
... # Notify the user
username, domain = email.split("@")
print(f"Your username: {username}")
print(f"Your domain name: {domain}")
Наконец, ваше использование sys.exit
это неверно. Вы должны использовать только sys.exit(n)
с целым числом n
. sys.exit(0)
означает «успешно», все остальное — «не удалось». Если у вас нет особых потребностей, sys.exit(1)
это вариант отказа по умолчанию.
Чтобы отображать удобные сообщения об ошибках, проще всего использовать print
. Вы можете отображать сообщения как сообщение об ошибке, указав file=sys.stderr
(в отличие от значения по умолчанию file=sys.stdout
).
print(f"{email} is not a valid email.", file=sys.stderr)
sys.exit(1)
В целом, вот как могла бы выглядеть ваша программа:
import sys
import argparse
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("-f", "--file", dest="file", default=False, action="store_true")
arg_parser.add_argument("input", type=str)
args = arg_parser.parse_args()
if args.file:
with open(args.input, "r") as file:
emails = file.readlines()
else:
emails = [args.input]
for email in emails:
if email.count("@") != 1:
print(f"{email} is not a valid email.", file=sys.stderr)
sys.exit(1)
username, domain = email.split("@")
print(f"Your username: {username}")
print(f"Your domain name: {domain}")
Мне пришлось бы поискать соответствующий RFC (5322, в наши дни?), Чтобы узнать,
@
разрешено в локальной части. Если да, то мы захотим найти последний@
для идентификации домена. Вокруг очень много сломанного кода для обработки электронной почты (я часто сталкиваюсь с системами, которые думают, что им разрешено изменять регистр локальной части!), И я бы не хотел поощрять более широкое внедрение теми, кто не может или не хочет прочтите RFC.— Тоби Спейт
Я думаю, вы неправильно прочитали код —
--single
кажется, принимает аргументы, и--list
средства читать из файла. Я думаю, что их можно было бы переименовать, как показывает ваша интерпретация!— Тоби Спейт
@TobySpeight Вы совершенно правы относительно аргументов. Я обновлю свой ответ, чтобы показать правильное поведение. Что касается RFC5322, то вы тоже правы. Хотя я думаю, что это должно быть скорее примечанием: «Если вам действительно нужна серьезная и безопасная система, не пытайтесь реализовать парсер электронной почты самостоятельно». Если углубляться в детали, я считаю, что на этом уровне обзор выходит за рамки.
— Андреас Т.