Как мне лучше разобрать эти аргументы?

Входными данными для 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 ответ
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)

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *