Лучший стиль для программ на Python: что вы предлагаете? - PullRequest
2 голосов
/ 12 июня 2010

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

#! /usr/bin/env python

################################################################################

"""\
CLASS INFORMATION
-----------------
    Program Name: Program 11
    Programmer:   Stephen Chappell
    Instructor:   Stephen Chappell for CS 999-0, Python
    Due Date:     17 May 2010

DOCUMENTATION
-------------
    This is a simple encryption program that can encode and decode messages."""

################################################################################

import sys

KEY_FILE = 'Key.txt'

BACKUP = '''\
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO\
 PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
_@/6-UC'GzaV0%5Mo9g+yNh8b">Bi=<Lx [sQn#^R.D2Xc(\
Jm!4e${lAEWud&t7]H\`}pvPw)FY,Z~?qK|3SOfk*:1;jTrI''' #`

################################################################################

def main():
    "Run the program: loads key, runs processing loop, and saves key."
    encode_map, decode_map = load_key(KEY_FILE)
    try:
        run_interface_loop(encode_map, decode_map)
    except SystemExit:
        pass
    save_key(KEY_FILE, encode_map)

def run_interface_loop(encode_map, decode_map):
    "Shows the menu and runs the appropriate command."
    print('This program handles encryption via a customizable key.')
    while True:
        print('''\
MENU
====
(1) Encode
(2) Decode
(3) Custom
(4) Finish''')
        switch = get_character('Select: ', tuple('1234'))
        FUNC[switch](encode_map, decode_map)

def get_character(prompt, choices):
    "Gets a valid menu option and returns it."
    while True:
        sys.stdout.write(prompt)
        sys.stdout.flush()
        line = sys.stdin.readline()[:-1]
        if not line:
            sys.exit()
        if line in choices:
            return line
        print(repr(line), 'is not a valid choice.')

################################################################################

def load_key(filename):
    "Gets the key file data and returns encoding/decoding dictionaries."
    plain, cypher = open_file(filename)
    return dict(zip(plain, cypher)), dict(zip(cypher, plain))

def open_file(filename):
    "Load the keys and tries to create it when not available."
    while True:
        try:
            with open(filename) as file:
                plain, cypher = file.read().split('\n')
                return plain, cypher
        except:
            with open(filename, 'w') as file:
                file.write(BACKUP)

def save_key(filename, encode_map):
    "Dumps the map into two buffers and saves them to the key file."
    plain = cypher = str()
    for p, c in encode_map.items():
        plain += p
        cypher += c
    with open(filename, 'w') as file:
        file.write(plain + '\n' + cypher)

################################################################################

def encode(encode_map, decode_map):
    "Encodes message for the user."
    print('Enter your message to encode (EOF when finished).')
    message = get_message()
    for char in message:
        sys.stdout.write(encode_map[char] if char in encode_map else char)

def decode(encode_map, decode_map):
    "Decodes message for the user."
    print('Enter your message to decode (EOF when finished).')
    message = get_message()
    for char in message:
        sys.stdout.write(decode_map[char] if char in decode_map else char)

def custom(encode_map, decode_map):
    "Allows user to edit the encoding/decoding dictionaries."
    plain, cypher = get_new_mapping()
    for p, c in zip(plain, cypher):
        encode_map[p] = c
        decode_map[c] = p

################################################################################

def get_message():
    "Gets and returns text entered by the user (until EOF)."
    buffer = []
    while True:
        line = sys.stdin.readline()
        if line:
            buffer.append(line)
        else:
            return ''.join(buffer)

def get_new_mapping():
    "Prompts for strings to edit encoding/decoding maps."
    while True:
        plain = get_unique_chars('What do you want to encode from?')
        cypher = get_unique_chars('What do you want to encode to?')
        if len(plain) == len(cypher):
            return plain, cypher
        print('Both lines should have the same length.')

def get_unique_chars(prompt):
    "Gets strings that only contain unique characters."
    print(prompt)
    while True:
        line = input()
        if len(line) == len(set(line)):
            return line
        print('There were duplicate characters: please try again.')

################################################################################

# This map is used for dispatching commands in the interface loop.
FUNC = {'1': encode, '2': decode, '3': custom, '4': lambda a, b: sys.exit()}

################################################################################

if __name__ == '__main__':
    main()

Для всех этих программистов Pythonтам, ваша помощь запрашивается.Как следует форматировать (необязательно, чтобы кодирование было изменено в соответствии с руководством по стилю Python? Моему другу не нужно изучать неправильные вещи. Если у вас есть предложения по коду, не стесняйтесь публиковать их и в этой вики.


РЕДАКТИРОВАТЬ: Для тех, кто заинтересован, вот исходный код на C, который мой друг дал мне для перевода.

/******************************************************************************
 CLASS INFORMATION
 -----------------
   Program Name: Program 11 - Encodes/Decodes
   Programmer:   Evgnto nAl.Wi a 
   Instructor:   fsSP21 .C emgr2rCHoMal4 gyia ro-rm n ,
   Date Due:     MAY 4, 2010

 PLEDGE STATEMENT
 ---------------- 
   I pledge that all of the code in this program is my own _original_ work for 
   the spring 2010 semester. None of the code in this program has been copied 
   from anyone or anyplace unless I was specifically authorized to do so by my
   CS 214 instructor. This program has been created using properly licensed 
   software.
                                     Signed: ________________________________

 DOCUMENTATION
 -------------
   This program Encodes and decodes a program. It also gives you the option of
   making your own code.     
******************************************************************************/

#include <stdio.h>
#define ENCODE 1
#define DECODE 2 
#define OWNCODE 3
#define QUIT 4

void printPurpose();
void encode(char input[], char code1[]);
void decode(char input[], char code1[]);
void ownCode();

int main()
{
   char charIn;
   char code1[100] = "";
   char input[100] = ""; 

   int a;
   int b;
   int closeStatus;
   int number;
   a = 0;
   b = 0;

   FILE *code;

   printPurpose();

   if (!(code = fopen("code.txt", "r")))
   {
      printf("Error opening code.txt for reading");

      return 100; 
   }

   while ((charIn = fgetc(code)) != '\n')
   {   
      input[a] = charIn;
      a++;
   }
   while ((charIn = fgetc(code)) != EOF)
   { 
      code1[b] = charIn;
      b++;
   }  

   scanf("%d", &number);

   while (number != QUIT)
   {
      if (number == ENCODE)
         encode(input, code1);
      else if (number == DECODE)   
         decode(input, code1);
      else if (number == OWNCODE)
         ownCode();

      printf("\n\n");
      printPurpose();
      scanf("%d", &number);
   }
   printf("Thank you for using my program Mr. Halsey!!!!!!!!\n");

   closeStatus = fclose(code);

   if (closeStatus == EOF)
   {   
       printf("File close error.\n");
       return 201;
   }
   else
      printf("Exit successfully.\n");

   return 0;

}
/******************************************************************************
 Prints the purpose of the program
******************************************************************************/
void printPurpose()
{
   printf("This program Encodes, Decodes, and allows you to make your own"); 
   printf("code.\n");
   printf("Enter a 1 to Encode\n");
   printf("Enter a 2 to Decode\n");
   printf("Enter a 3 to make your own code\n");
   printf("Enter a 4 to Quit\n");
}

/******************************************************************************
 Encodes the sentence entered
******************************************************************************/
void encode(char input[], char code1[])
{
   char sentence[100] = "";
   char x;
   char y;

   int index;
   int index2;
   index = 0;

   printf("Enter your sentence\n");

   gets(sentence);
   gets(sentence);
   printf("Your encoded message is >");
   for (index2 = 0; (y = sentence[index2]) != '\0'; index2++)
   {
      while ((x = input[index]) != y)
         index++;
         if (x == y)
            printf("%c", code1[index]);        
         else 
            printf("error");
         index = 0;
   }

   return;
}

/******************************************************************************
 Decodes the sentence entered
******************************************************************************/
void decode(char input[], char code1[])
{
   char encodedMessage[100] = "";
   char x;
   char y;

   int index1;
   int index2;
   index2 = 0;

   printf("Enter encoded message\n");
   gets(encodedMessage);
   gets(encodedMessage);
   printf("Your decoded message is >");
   for (index1 = 0; (y = encodedMessage[index1]) != '\0'; index1++)
   {
      while (( x = code1[index2]) != y)
         index2++;
         if (x == y)
            printf("%c", input[index2]);         
         else
            printf("error");
         index2 = 0;
   }

   return;
}

/******************************************************************************
 Reads in your code and encodes / decodes 
******************************************************************************/
void ownCode()
{
   char charactersUsed[50] = "";
   char codeUsed[50]       = "";
   char sentence[50]       = "";

   int index1; 
   int index2;
   int number;
   int x;
   int y;
   index2 = 0;
   y      = 0;

   printf("Enter the characters you want to use.\n");
   printf("Use less than 50 characters and DO NOT REPEAT the characters.\n");

   gets(charactersUsed);
   gets(charactersUsed);

   printf("Enter the code for the characters.\n");
   gets(codeUsed);

   printf("\nEnter 1 to encode and 2 to decode or 3 to return to main menu.\n");
   scanf("%d", &number);

   while (number != OWNCODE)
   {
      if (number == ENCODE)
      {
         printf("Enter your sentence.\n");

         gets(sentence);
         gets(sentence);

         printf("Your encoded message is > ");

         for (index1 = 0; (y = sentence[index1]) != '\0'; index1++)
         {
            while (( x = charactersUsed[index2]) != y)
               index2++;
               if (x == y)
                  printf("%c", codeUsed[index2]);
               else
                  printf("error");
               index2 = 0;
         }
      }
      else if (number == DECODE)
      {
         printf("Enter your encoded sentence.\n");

         gets(sentence);
         gets(sentence);

         printf("Your decoded message is > ");

         for (index1 = 0; (y = sentence[index1]) != '\0'; index1++)
         {
            while (( x = codeUsed[index2]) != y)
               index2++;
            if (x == y)
               printf("%c", charactersUsed[index2]);
            else
               printf("error");
               index2 = 0;
         }
      }
      printf("\nEnter 1 to encode and 2 to decode or 3 to return to main menu.\n");
      scanf("%d", &number);
   }

   return;
}

Ответы [ 5 ]

8 голосов
/ 12 июня 2010

Поскольку вы спрашивали о форматировании и стиле, я удивлен, что никто еще не упомянул PEP 8 . Это номинально руководство для модулей, которые хотят быть включенными в стандартную библиотеку, но я считаю, что большая часть ее руководства применима почти везде.

6 голосов
/ 12 июня 2010

не используйте голые исключения;

try:
    with open(filename) as file:
        plain, cypher = file.read().split('\n')
        return plain, cypher
**except:**
    with open(filename, 'w') as file:
        file.write(BACKUP)

почти всегда неправильно использовать голые исключения, и в этом случае это неправильно. Поймать исключения, которые вы хотите перехватить, в этом случае наиболее вероятным является IOException и ошибка, которая может появиться, если файл не содержит '\ n' и ваша распаковка кортежа не удалась (подсказка: поймайте их в отдельности, кроме предложения). Также вам может быть интересно проверить, что произойдет, если у пользователя нет разрешения на запись в имя файла.

Есть ли причина, по которой вы здесь не используете print и raw_input ()?

def get_character(prompt, choices):
    "Gets a valid menu option and returns it."
    while True:
        sys.stdout.write(prompt)
        sys.stdout.flush()
        line = sys.stdin.readline()[:-1]
        if not line:
            sys.exit()
        if line in choices:
            return line
        print(repr(line), 'is not a valid choice.')

вы можете использовать str.translate () для этого:

    sys.stdout.write(encode_map[char] if char in encode_map else char)
3 голосов
/ 12 июня 2010

На мой взгляд, вся программа сомнительна. Выбор того, как вещи делятся на функции, довольно дурацкий, и он задокументирован как проект класса, а не как реальная система. Документация отчасти скрывает всю посредственную организацию. Вся программа демонстрирует уклон в сторону многословия, а не ясности.

Конструкция '''\ часто встречается. Смысл конструкции с тройными кавычками заключается в том, что возврат каретки и переносы строки работают нормально. Нет необходимости \ выходить из новой строки.

Я расскажу о функциях, в которых я вижу конкретные проблемы:

Вопрос о том, должен ли get_message существовать в этой форме, спорен. Вся функция может быть заменена одной строкой.

def get_message():
    "Gets and returns text entered by the user (until EOF)."
    return sys.stdin.read()

Способ взаимодействия main, run_interface_loop, get_character и FUNC сбивает с толку и не является лучшим способом решения проблемы. В частности, перехват SystemExit не очень хороший способ сообщить о завершении вашей программы в этом случае.

def main():
    encode_map, decode_map = load_key(KEY_FILE)
    run_interface_loop(encode_map, decode_map)
    save_key(KEY_FILE, encode_map)

def run_interface_loop():
    exit_picked = False
    while not exit_picked:
        print '''
MENU
====
(1) Encode
(2) Decode
(3) Custom
(4) Finish'''
        choice = sys.stdin.readline()
        if choice == '':
            break  # EOF was reached, no more asking the user for stuff
        choice = choice.strip()
        if choice == '1':
            encode(encode_map, decode_map) # This reads until EOF
            exit_picked = True # and so we might as well exit
        elif choice == '2':
            decode(encode_map, decode_map)
            exit_picked = True # Same here
        elif choice == '3':
            encode_map, decode_map = custom()
        elif choice == '4':
             exit_picked = True
        else:
             print "%s isn't a valid choice, try again." % (choice,)
2 голосов

Никогда не вызывайте sys.exit() и не повышайте SystemExit внутри функции.Вместо этого выведите другие исключения.

1 голос
/ 13 июня 2010

Также ознакомьтесь с рекомендациями Google по написанию Python. Они в основном соответствуют PEP, упомянутому выше, но в некоторых областях они более строгие.

Руководство по стилю Google Python

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...