2010-06-12 47 views
2

我的一個朋友想要幫助學習編程,所以他給了我他爲他以前的課程寫的所有程序。他編寫的最後一個程序是一個加密程序,用Python重寫所有程序後,這就是他的加密程序(添加了我自己的要求後)的結果。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 = '''\ 
!"#$%&'()*+,-./:;<=>[email protected]\ 
PQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ 
[email protected]/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的風格指南而編寫的代碼)我的朋友不需要學習那些不正確的東西,如果你對代碼有什麼建議,也可以將它們發佈到這個wiki中。


編輯:對於那些有興趣,這裏是在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; 
} 
+0

C程序將無法工作。在同一個緩衝區調用'gets()'兩次會覆蓋它。無論如何,不​​應該使用'gets()'(使用'fgets()')。 'charIn'應該是'int'而不是'char',否則你可能會錯過'EOF'。指定空字符串'char buf [n] =「」'只是隱藏錯誤。 'while(x!= y)'附近的縮進是誤導性的。 ' – jfs 2010-06-12 20:39:36

回答

8

既然你問到的格式和風格,我很驚訝,沒有人提到PEP 8呢。它名義上是想要包含在標準庫中的模塊的指南,但我發現其大部分指導幾乎適用於任何地方。

+0

+1。這個例子也是兩件事。一個編碼和解碼功能模塊以及一個字符模式用戶界面(CLI)。請了解Python模塊並將其分解爲兩部分。 – 2010-06-12 20:56:52

3

在我看來,整個程序是有問題的選擇。如何將事物劃分爲函數是一種dopey,它被記錄爲一個類項目,不像r系統。文件類型掩蓋了整體平庸的組織。整個計劃顯示了對清晰度的偏好。

經常看到構造'''\。三重引用構造的要點是回車和換行符工作得很好。沒有必要\逃脫換行。

我會處理的功能我看到的具體問題作爲例子:

無論get_message應該存在於這種形式是值得商榷的。整個功能可以由一條線代替。

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

的方式mainrun_interface_loopget_characterFUNC互動是混亂的,而不是處理問題的最佳途徑。特別是,在這種情況下,捕獲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,) 
+1

'''\是完全有效的。它抑制了字符串中的最初換行符,但讓所有行都排列在左邊緣。 – 2010-06-12 15:27:27

6

不使用光禿的除外;

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) 

使用bare excepts幾乎總是錯誤的,在這種情況下,它是錯誤的。捕獲只想捕獲的異常,在這種情況下最有可能是IOException,如果文件不包含'\ n'並且您的元組解包失敗(提示:在單獨的except子句中捕獲它們),則可能會出現錯誤。另外,如果用戶沒有對文件名的寫入權限,您可能有興趣檢查會發生什麼情況。

你有什麼理由不在這裏使用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) 
+0

如果有的話,print()和input()將從Python 3中使用。但是,如果內存正常運行,print()不能正確刷新;和input()可能引發異常。程序中大部分都避免了異常處理,因爲我的朋友對編程還不熟悉,而且還不太瞭解。異常循環背後的想法是,如果由於某種原因失敗,文件將被有效的替換成功。如果出於某種其他原因而出現錯誤,則try/except子句的第二部分可能會因相同原因而失敗並使程序崩潰。 – 2010-06-12 19:05:30

+0

@Noctis Skytower:重新處理SystemExit,然後用finally子句處理它。說出你的意思。除了SystemExit還有其他例外。對於除SystemExit以外的任何異常,當前都會跳過文件保存。 – Omnifarious 2010-06-13 15:41:41

2

絕不要在函數內部調用sys.exit()或提高SystemExit。相反,反而會引發其他異常。

相關問題