Правильный инструмент треугольник УМК


Меня больше всего интересуют отзывы о общий подход к проблеме, соглашения об именовании, эффективность и т. д.

  • Я хотел бы избежать с помощью argparse/docopt или что-то подобное, если это будет крупный влияния на сложность программы.
  • Любые советы о том, как я должен идти о добавлении помочь-диалоги для простоты использования?

from collections import OrderedDict as oDct
from trianglesolver import solve, degree
from termcolor import colored, cprint
import numpy as np
import cmd



def prntDct(dct):
    for k, v in dct.items(): print(k + ' =', v)


def noNones(*args):
    return False if any(arg is None for arg in args) else True


def argify(string_in, ref_dict):
    fin = ref_dict.copy()
    string = string_in.replace(' ', ', ')
    temp = eval('dict({})'.format(string))
    matched = {k: temp[k] for k in temp if k in fin}
    fin.update(matched)
    return fin


def solvify(items):
    a,b,c,A,B,C = items

    if A is not None: A = A * degree
    if B is not None: B = B * degree
    C = C * degree

    try:
        if a is None: outs = solve(c=c, b=b, C=C)
        elif b is None: outs = solve(a=a, c=c, C=C)
        elif c is None: outs = solve(a=a, b=b, C=C)

    except:
        if noNones(a, A): outs = solve(a=a, A=A,C=C)
        elif noNones(a, B): outs = solve(a=a, B=B, C=C)
        elif noNones(b, A): outs = solve(b=b, A=A, C=C)
        elif noNones(b, B): outs = solve(b=b, B=B, C=C)
        elif noNones(c, A): outs = solve(c=c, A=A, C=C)
        elif noNones(c, B): outs = solve(c=c, B=B, C=C)

    finally:
        a,b,c,A,B,C = outs
        return ([a, b, c, A / degree, B / degree, C / degree])


def triangify(items, output_format, prec, scale=None, side='c'):
    a,b,c,A,B,C = solvify(items)

    if side is 'c': ordr = [a, b, c] + ['a', 'b', 'c']; set = [0,1]
    if side is 'b': ordr = [c, a, b] + ['c', 'a', 'b']; set = [1,2]
    if side is 'a': ordr = [c, b, a] + ['c', 'b', 'a']; set = [2,1]

    if scale is not None:
        sides_arrange = np.array(ordr[:3])
        sides_scaling = sides_arrange / ordr[2]
        sVals  = (sides_scaling * scale).tolist()
    else: sVals = ordr[:3]

    sKeys = ordr[3:]

    P = np.sum(sVals)
    S = (sVals[set[0]] * sVals[set[1]]) / 2

    fKeys = sKeys + ['A','B','C','P','S']
    toVals = sVals + [A,  B,  C,  P,  S]

    if type(prec) is int: fVals = np.around(np.array(toVals),prec)
    else: fVals = (np.around(np.array(toVals), 0)).astype(int)

    triangle = oDct(zip(fKeys, fVals))

    if output_format is 'all': output_format = 'abcABCPS'

    fin = {k: triangle[k] for k in list(output_format) if k in triangle}

    return fin



def main():
    scalar = ScalarCmd()
    print('\n' * 4)
    cprint('Triangle Scalar Tool', 'cyan')
    cprint('====================', 'cyan')
    print()
    cprint('type "help" for commands', 'cyan')
    print()
    scalar.ruler = colored('-', 'cyan')
    scalar.cmdloop()



defaults = oDct([
    ('P', None),
    ('S', None),
    ('a', None),
    ('b', None),
    ('c', None),
    ('A', None),
    ('B', None),
    ('C', 90),
    ('prec', 2),
    ('scale', 1),
    ('side', 'c'),
    ('output', 'all')])


class ScalarCmd(cmd.Cmd):
    prompt = (colored('\n>', 'green') + colored(' ', 'white'))

    def default(self, arg):
        print('invalid command, try typing "help"')

    def do_quit(self, arg):
        '''exits the program'''
        cprint('\nexiting...\n', 'red')
        exit()


    def do_solve(self, arg):
        '''type at least 2 sides or angles\n'''

        error = ['',
            'invalid command:',  # most of these docstrings are temps
            'type at least 2 sides named a/b/c or angles named A/B/C',
            'usage: TBD','']

        try:
            if len(arg) < 2:
                error[0] = '\nempty command:'
                raise

            else:
                args = argify(arg, defaults)

                sides_angles = list(args.values())[2:8]

                outs = triangify(
                    sides_angles,
                    args['output'],
                    args['prec'])

                print()
                prntDct(outs)
                print()  # <- easy blank lines

        except Exception:
            print(*error, sep='\n')
            return

    def do_scale(self, arg):
        '''type at least 2 sides or angles\n'''

        error = ['',
            'invalid command:',
            'type at least 2 sides named a/b/c or angles named A/B/C',
            'usage: TBD','']

        try:
            if len(arg) < 2:
                error[0] = '\nempty command:'
                raise

            else:
                args = argify(arg, defaults)

                sides_angles = list(args.values())[2:8]

                outs = triangify(
                    sides_angles,
                    args['output'],
                    args['prec'],
                    args['scale'],
                    args['side'])

                print()
                prntDct(outs)
                print()  # <- easy blank lines

        except Exception:
            print(*error, sep='\n')
            return



if __name__ == '__main__': main()

Я еще совсем дилетант в программировании на Python, так что я благодарю вас заранее за ваши отзывы!



622
4
задан 6 апреля 2018 в 04:04 Источник Поделиться
Комментарии
2 ответа

Общие


  • Лично я бы предпочел поставить пунктах, если if и else заявления на отдельных строках, даже если они являются только одной строки.

  • Вы должны избегать использования универсальный except без уточнения, исключения или использования универсального Exception. Вместо этого, вы должны поймать определенное исключение, вы ожидаете, что код, чтобы бросить. В противном случае, вы можете в конечном итоге поймать TypeError или другое исключение, которое указывает на ошибку и, которые должны распространяться, а не поймали. От PEP 8:


    Хорошее эмпирическое правило состоит в ограничении использования чуть-чуть 'за исключением' положения в двух случаях:


    1. Если обработчик исключений будет распечатать или протоколирование отладочных; по крайней мере, пользователь будет знать, что произошла ошибка.

    2. Если код должен делать генеральную уборку, а затем позволяет распространять исключения вверх поднять. попробовать...в конце концов может быть лучший способ справиться с этим делом.



  • В main метод должен быть в конце, как раз перед if __name__=="__main__" заявление.

Треугольник Решатель


  • solvify должен вернуть кортеж вместо списка, поскольку каждый показатель имеет определенный смысл.

  • argify не следует использовать evalвместо разбора входной строки напрямую.

  • Использовать оператор равенства (side=='c') вместо is ключевое слово для сравнения строк.

  • Использовать isinstance для типа проверки, как в if isinstance(prec,int) вместо if type(prec) is int

ScalarCmd


  • Это должна быть преобразована в отдельный файл, чтобы отделить UI и бэкенд.

  • try...raise внутри do_solve нет никаких исключений, чтобы поднять.

  • Я не уверен, если это возможно, используя termcolor но cmd.Cmd.cmdloop() есть intro параметр, который может использоваться для печати интро баннер.

Для получения более подробной информации о Python стиль конвенций ПЭП 8 является хорошим местом для начала.

4
ответ дан 6 апреля 2018 в 05:04 Источник Поделиться

Выбор имен переменных-это странно. Нет никаких причин, чтобы оставить i в print и dictно сохранить ее в argify и solvify. Будьте последовательны и держите их всех, или, ltrntvly, рмВ Лл м vwls.

3
ответ дан 6 апреля 2018 в 06:04 Источник Поделиться