Входными данными для price () будут СТРОКИ, как вы видите ниже. Если строка начинается с «-«, я хотел бы, чтобы все, что следует, было сохранено в fiat_name, а затем извлекало символ из _KNOWN_FIAT_SYMBOLS. «—rub» (ПРИМЕР) может быть в любой позиции в списке, переданном через price ()
Если необязательное fiat_name не существует в _KNOWN_FIAT_SYMBOLS, я бы хотел, чтобы по умолчанию он был USD / $
Я бы хотел, чтобы код был оптимизирован и очищен / минимизирован. Я пытаюсь практиковать чистый и читаемый код.
import re
_KNOWN_FIAT_SYMBOLS = {"USD":"$", "RUB":"₽"} # this will be populated with more symbols/pairs later
def price(*arguments):
# default to USD/$
fiat_name = "USD"
arguments = list(arguments)
cryptos = []
for arg in arguments:
arg = arg.strip()
if not arg:
continue
for part in arg.split(","):
if part.startswith("-"):
fiat_name = part.upper().lstrip("-")
continue
crypto = re.sub("[^a-z0-9]", "", part.lower())
if crypto not in cryptos:
cryptos.append(crypto)
if not cryptos:
cryptos.append("btc")
fiat_symbol = _KNOWN_FIAT_SYMBOLS.get(fiat_name)
if not fiat_symbol:
fiat_name = "USD"
fiat_symbol = "$"
print(f"{cryptos} to: {fiat_name}{fiat_symbol}")
price("usd", "usdc", "--rub") # ['usd', 'usdc'] to: RUB₽ (becuase of the optional --rub)
price("usd,usdc,eth", "btc", "-usd") # ['usd', 'usdc', 'eth', 'btc'] to: USD$ (becuase of the optional --usd)
price("usd", "usdc,btc", "-xxx") #['usd', 'usdc', 'btc'] to: USD$ (because xxx does not exist in _KNOWN_FIAT_SYMBOLS
price("usd,usdc,eth", "btc") # ['usd', 'usdc', 'eth', 'btc'] to: USD$ (becuase no optional fiat_name was given)
price("usd,--rub,eth", "btc") # ['usd', 'eth', 'btc'] to: RUB₽ (becuase of the optional --rub)
price("--rub") # ['btc'] to: RUB₽ (becuase of the optional --rub and the cryptos is empty)
price("") # ['btc'] to: USD$ (becuase of the default USD and the cryptos is empty)
1 ответ
Вернуть данные. Алгоритмический код должен возвращать данные, а не печатать — по крайней мере, когда это возможно. Это лучше для тестирования, отладки, рефакторинга и, возможно, по другим причинам. Как минимум, верните простой кортеж или dict. Еще лучше было бы иметь какой-нибудь значимый объект данных (например, namedtuple
,
dataclass
, или же attrs
класс). Печатайте в другом месте, обычно в функции, работающей на внешнем краю вашей программы.
Функция *args
уже независимые кортежи. Значит, тебе не нужно
arguments = list(arguments)
.
Алгоритмическая читаемость. Ваш текущий код в целом в порядке: мне не составило большого труда понять, как он должен работать. Однако сами правила синтаксического анализа имеют тенденцию требовать раздражающего количества условной логики: мне не понравились первые наброски, которые я набросал. Но я придумал альтернативу, которая мне больше понравилась: одна функция фокусируется на синтаксическом анализе только названий валют (довольно узкая, текстовая задача); а другая часть касается неприятностей, связанных с отсутствующими / неизвестными данными. Обратите внимание, что обе функции возвращают значимые объекты данных — важный инструмент для написания более читаемого кода — а вторая функция обрабатывает отсутствующие / неизвестные значения в «декларативном» стиле. В целом эта версия кажется мне несколько более удобочитаемой. Если вам нужно оптимизировать исходную скорость, она, вероятно, медленнее.
import re
from collections import namedtuple
_KNOWN_FIAT_SYMBOLS = {"USD":"$", "RUB":"₽"}
FiatCryptos = namedtuple('FiatCryptos', 'name symbol cryptos')
Currency = namedtuple('Currency', 'name is_fiat')
def price(*arguments):
currencies = list(parse_currencies(arguments))
cryptos = [c.name for c in currencies if not c.is_fiat] or ['btc']
fiats = [c.name.upper() for c in currencies if c.is_fiat] or ['USD']
f = fiats[0]
syms = _KNOWN_FIAT_SYMBOLS
name, sym = (f, syms[f]) if f in syms else ('USD', '$')
return FiatCryptos(name, sym, cryptos)
def parse_currencies(arguments):
for arg in arguments:
for part in arg.strip().split(','):
if part:
is_fiat = part.startswith('-')
name = re.sub('[^a-z0-9]', '', part.lower())
yield Currency(name, is_fiat)