首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >问答游戏的帐号注册系统

问答游戏的帐号注册系统
EN

Code Review用户
提问于 2015-12-01 21:01:21
回答 2查看 1.4K关注 0票数 6

作为学校信息和通信技术课程项目的一部分,我们班被要求按照既定的标准编写一个测试程序。第一部分是一个程序,通过向用户询问球员姓名、年龄、电子邮件和性别等细节来处理注册过程。

代码语言:javascript
复制
import getpass
import os
import pickle
import time

nope = "I didn't quite get that. Mind trying again?"
yn = {'y': True, 'n': False}

if os.path.exists('players'):
    with open('players', 'rb') as f:
        if os.stat('players').st_size == 0:
            accounts = {}
        else:
            accounts = pickle.loads(f.read())
else:
    f = open('players', 'wb')
    f.close()
    accounts = {}

class Player(object):

    def __init__(self):
        self.name = ""
        self.email = ""
        self.password = ""
        self.age = ""
        self.gender = ""

    def write(self):
        accounts[p.name] = [p.email, p.password, p.age, p.gender]
        with open('players', 'wb') as f:
            pickle.dump(accounts, f)

p = Player()

def askChoices(question, options, errorMessage):
    while True:
        answer = str(input(question)).lower()
        if answer in options:
            return options[answer]
        else:
            print(errorMessage)

def register():

    print("\nWelcome, new player!")

    while True:
        p.name = input("What is your name? ")
        if p.name in accounts:
            print("Name already taken. Please try again.")
        else:
            break

    isEmailValid = False
    while not isEmailValid:
        p.email = str(input("What is your email address? "))
        if '@' in p.email and '.' in p.email:
            isEmailValid == True
            break
        else:
            print(nope, "(Input must contain '@' and '.')")

    p.password = getpass.getpass('Please enter a password. ')

    while True:
        try:
            p.age = int(input("How old are you? "))
            break
        except ValueError:
            print(nope, "(Input must be an integer)")

    p.gender = askChoices("What gender are you? ('m' for male, 'f' for female, 'o' for other) ", # it was not my idea to add the 'other' option
                          {'m': "Male", 'f': "Female", 'o': "Other"},
                          nope)

    print("\nName:", p.name,
          "\nEmail:", p.email,
          "\nPassword:", ('*' * len(p.password)),
          "\nAge:", p.age,
          "\nGender:", p.gender)

    correct = askChoices("Is this information correct? (y/n) ",
                         yn, nope)

    if correct:
        print("\nRegistration successful!")
        p.write()
        login()
    elif not correct:
        tryAgain = askChoices("\nWould you like to try again? (y/n) ",
                              yn, nope)
        if tryAgain:
            register()
        else:
            main()

def login():
    while True:
        name = input("What is your player name? ")
        if name in accounts:
            pw = getpass.getpass("Please enter your password. ")
            if pw == accounts[name][1]:
                print(accounts[name]) # debug placeholder until quiz functionality is added
                break
        else:
            print("Account not found.")
            registerNew = askChoices("Would you like to register a new account? (y/n) ",
                                     yn, nope)
            if registerNew:
                register()
                break
            else:
                pass

def main():
    if os.stat('players').st_size == 0:
        register()
    else:
        player = askChoices("Would you like to REGISTER or LOG IN? ",
                            {'register': True, 'log in': False, 'login': False},
                            nope)
        if player:
            register()
        else:
            login()
    print("\nShutting down...")
    time.sleep(3)

if __name__ == '__main__':
    main()

大量不同的参考资料和网页被用来实现程序中的一些特性,例如几个堆栈溢出帖子,甚至来自一般Arqade聊天室的常客的帮助。

回想起来,这与课堂上给出的原始示例有很大的偏离(并且有充分的理由;考试板设置了这个任务有很差的编码标准)。

我希望我能把这作为一个全面工作的智力游戏应用程序在某个时候。

EN

回答 2

Code Review用户

回答已采纳

发布于 2015-12-01 21:47:19

避免全局变量

他们太难理了。

p = Player()从全局范围移到register()的开头

Player类中使用self

代码语言:javascript
复制
def write(self):
    accounts[self.name] = [self.email, self.password, self.age, self.gender]
    with open('players', 'wb') as f:
        pickle.dump(accounts, f)

球员应该知道如何打印自己

以下是实现细节:

代码语言:javascript
复制
print("\nName:", p.name,
      "\nEmail:", p.email,
      "\nPassword:", ('*' * len(p.password)),
      "\nAge:", p.age,
      "\nGender:", p.gender)

更清楚的是:

代码语言:javascript
复制
print(p)

要允许这样做,您应该在__str__类中实现一个Player方法。

使用一个函数来处理输入验证

所有用于输入验证的代码都会引起代码的噪音,而且很难遵循代码的高级别流程,编写general_input函数可能更好:

代码语言:javascript
复制
p.name = general_input(
    "What is your name? ",
    validation = lambda name: name not in accounts,
    error_message = "Name already taken. Please try again."
)

p.email = general_input(
    "What is your e-mail? ",
    validation = lambda email: '@' in email or '.' in email,
    error_message = "(Input must contain '@' and '.')"
)

p.password = getpass.getpass('Please enter a password. ')

p.age = general_input(
    "How old are you? ",
    validation = lambda age: all(i in '1234567890' for i in age)
    error_message = 'Age should be a positive integer'
)

有什么叫什么吗?

register可以调用登录,login可以调用寄存器,它感觉不干净.用户交互菜单功能可以自由调用,只是美化而已。

我建议只有main可以给loginregister打电话,他们可能不会打电话给对方,而只会给main回电话。它将简化代码,甚至可能使程序在/如果增长时使用更可预测(当您不确定如何执行操作时,只需返回主菜单,您就会知道如何使用)

例如,当您使login无条件地跳回main时,它变得多么简单:

代码语言:javascript
复制
def login():
    while True:
        name = input("What is your player name? ")
        if name not in accounts:
            print("Account not found.")
            main()

        pw = getpass.getpass("Please enter your password. ")
        if pw == accounts[name][1]:
            print(accounts[name]) # debug placeholder until quiz functionality is added

微型助手函数

不要为编写使您的代码更加可读性更高的小函数感到难过,它们是好的!例如:

代码语言:javascript
复制
os.stat('players').st_size == 0

理解起来需要一些时间,阅读并不流利,但如果我定义:

代码语言:javascript
复制
def is_file_empty(filename):
    return os.stat('players').st_size == 0

读取is_file_empty('players')是即时的。

同样的情况也适用于:

代码语言:javascript
复制
f = open('players', 'wb')
f.close()

打开一个文件再关闭一次是很奇怪的..。一个适当命名的小函数将使您的意图更加清晰。

票数 3
EN

Code Review用户

发布于 2015-12-01 21:53:01

创建一个空的Player然后在外部填充它并不是一个好主意--我倾向于使用类方法作为替代构造函数,将所有与播放器相关的逻辑保持在一个地方,例如:

代码语言:javascript
复制
class Player(object):

    def __init__(self, name, email, password, age, gender):
        self.name = name
        self.email = email
        self.password = password
        self.age = age
        self.gender = gender

    @classmethod
    def from_input(cls):
        # ... take user input
        return cls(name, email, password, age, gender)

然后你可以使用:

代码语言:javascript
复制
p = Player.from_input()

尽量减少信息的重复。例如:

代码语言:javascript
复制
askChoices("What gender are you? ('m' for male, 'f' for female, 'o' for other) ",
           {'m': "Male", 'f': "Female", 'o': "Other"},
           nope)

在第一个和第二个参数中有相同的信息;为什么不使用这些选项构建字符串呢?您还混合了单引号(')和双引号(");尽量保持一致。您可以将nope (它是一个常量,因此应该在UPPERCASE中)设置为默认参数值,以避免每次传递它。这样的话,一个更整洁的电话将是:

代码语言:javascript
复制
askChoices("What gender are you?",
           {"m": "Male", "f": "Female", "o": "Other"})

在你的控制流程中保持一致。比较:

代码语言:javascript
复制
while True:
    p.name = input("What is your name? ")
    if p.name in accounts:
        print("Name already taken. Please try again.")
    else:
        break

通过以下方式:

代码语言:javascript
复制
isEmailValid = False
while not isEmailValid:
    p.email = str(input("What is your email address? "))
    if '@' in p.email and '.' in p.email:
        isEmailValid == True
        break
    else:
        print(nope, "(Input must contain '@' and '.')")

第二个变量有一个明显不必要的变量,因为不管怎么说,变量一发生变化,您就会break。此外,您的验证允许'@.'作为电子邮件地址。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/112494

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档