我正在尝试创建一个使用设置和Gui模块的用户系统,并且当GUI模块请求使用pickle加载文件时,我总是遇到属性错误。这来自设置模块:
import pickle import hashlib class User(object): def __init__(self, fname, lname, dob, gender): self.firstname = fname self.lastname = lname self._dob = dob self.gender = gender self.type = 'General' self._username = '' self._hashkey = '' def Report(self): print("Full Name: {0} {1}\nDate of Birth: {2}\nGender: {3}\nAccess Level: {4}".format(self.firstname,self.lastname, self._dob, self.gender, self.type)) print(self._username) def Genusername(self): self._username = str(str(self._dob)[:2] + self.firstname[:2] + self.lastname[:2]) saveUsers(users) def Genhashkey(self, password): encoded = password.encode('utf-8','strict') return hashlib.sha256(encoded).hexdigest() def Verifypassword(self, password): if self._hashkey == self.Genhashkey(password): return True else: return False class SAdmin(User): def __init__(self, fname, lname, dob, gender): super().__init__(fname, lname, dob, gender) self.type = 'Stock Admin' class Manager(User): def __init__(self, fname, lname, dob, gender): super().__init__(fname, lname, dob, gender) self.type = 'Manager' def saveUsers(users): with open('user_data.pkl', 'wb') as file: pickle.dump(users, file, -1) # PICKLE HIGHEST LEVEL PROTOCOL def loadUsers(users): try: with open('user_data.pkl', 'rb') as file: temp = pickle.load(file) for item in temp: users.append(item) except IOError: saveUsers([]) def userReport(users): for user in users: print(user.firstname, user.lastname) def addUser(users): fname = input('What is your First Name?\n > ') lname = input('What is your Last Name?\n > ') dob = int(input('Please enter your date of birth in the following format, example 12211996\n> ')) gender = input("What is your gender? 'M' or 'F'\n >") level = input("Enter the access level given to this user 'G', 'A', 'M'\n > ") password = input("Enter a password:\n > ") if level == 'G': usertype = User if level == 'A': usertype = SAdmin if level == 'M': usertype = Manager users.append(usertype(fname, lname, dob, gender)) user = users[len(users)-1] user.Genusername() user._hashkey = user.Genhashkey(password) saveUsers(users) def deleteUser(users): userReport(users) delete = input('Please type in the First Name of the user do you wish to delete:\n > ') for user in users: if user.firstname == delete: users.remove(user) saveUsers(users) def changePass(users): userReport(users) change = input('Please type in the First Name of the user you wish to change the password for :\n > ') for user in users: if user.firstname == change: oldpass = input('Please type in your old password:\n > ') newpass = input('Please type in your new password:\n > ') if user.Verifypassword(oldpass): user._hashkey = user.Genhashkey(newpass) saveUsers(users) else: print('Your old password does not match!') def verifyUser(username, password): for user in users: if user._username == username and user.Verifypassword(password): return True else: return False if __name__ == '__main__': users = [] loadUsers(users)
这是GUI模块:
from PyQt4 import QtGui, QtCore import Settings class loginWindow(QtGui.QDialog): def __init__(self): super().__init__() self.initUI() def initUI(self): self.lbl1 = QtGui.QLabel('Username') self.lbl2 = QtGui.QLabel('Password') self.username = QtGui.QLineEdit() self.password = QtGui.QLineEdit() self.okButton = QtGui.QPushButton("OK") self.okButton.clicked.connect(self.tryLogin) self.cancelButton = QtGui.QPushButton("Cancel") grid = QtGui.QGridLayout() grid.setSpacing(10) grid.addWidget(self.lbl1, 1, 0) grid.addWidget(self.username, 1, 1) grid.addWidget(self.lbl2, 2, 0) grid.addWidget(self.password, 2, 1) grid.addWidget(self.okButton, 3, 1) grid.addWidget(self.cancelButton, 3, 0) self.setLayout(grid) self.setGeometry(300, 300, 2950, 150) self.setWindowTitle('Login') self.show() def tryLogin(self): print(self.username.text(), self.password.text()) if Settings.verifyUser(self.username.text(),self.password.text()): print('it Woks') else: QtGui.QMessageBox.warning( self, 'Error', 'Incorrect Username or Password') class Window(QtGui.QMainWindow): def __init__(self): super().__init__() if __name__ == '__main__': app = QtGui.QApplication(sys.argv) users = [] Settings.loadUsers(users) if loginWindow().exec_() == QtGui.QDialog.Accepted: window = Window() window.show() sys.exit(app.exec_())
每个用户都是一个类,并放入列表中,然后当我仅加载设置文件并验证登录名时,使用pickle保存该列表,一切正常,但是当我打开GUI模块并尝试验证其是否无效时让我,我得到的错误:
Traceback (most recent call last): File "C:\Users`Program\LoginGUI.py", line 53, in <module> Settings.loadUsers(users) File "C:\Users\Program\Settings.py", line 51, in loadUsers temp = pickle.load(file) AttributeError: Can't get attribute 'Manager' on <module '__main__' (built-in)>
问题在于,您 实际上是通过运行“设置”模块 来 腌制“设置”中定义的对象的 ,然后才尝试从GUI模块中释放对象。
GUI
请记住,泡菜实际上并没有存储有关如何构造类/对象的信息,并且在进行酸洗时需要访问该类。有关更多详细信息,请参见有关使用Pickle的Wiki。
在pkl数据中,您看到所引用的对象是__main__.Manager,因为在创建pickle文件时,“设置”模块是 主要的 (即,您将“设置”模块作为调用该addUser功能的主要脚本运行)。
__main__.Manager
addUser
然后,您尝试取消对’Gui’的选择- 使该模块具有名称__main__,然后在该模块中导入Setting。因此,当然Manager类实际上是Settings.Manager。但是pkl文件不知道这一点,而是在中查找Manager类__main__,并抛出AttributeError,因为它不存在(Settings.Manager确实存在,但__main__.Manager不存在)。
__main__
Settings.Manager
这是演示的最小代码集。
该class_def.py模块:
class_def.py
import pickle class Foo(object): def __init__(self, name): self.name = name def main(): foo = Foo('a') with open('test_data.pkl', 'wb') as f: pickle.dump([foo], f, -1) if __name__=='__main__': main()
您运行上述操作以生成泡菜数据。该main_module.py模块:
main_module.py
import pickle import class_def if __name__=='__main__': with open('test_data.pkl', 'rb') as f: users = pickle.load(f)
您运行上面的内容尝试打开pickle文件,这将引发与您看到的大致相同的错误。(略有不同,但是我猜那是因为我使用的是Python 2.7)
解决方案是:
Settings.addUser
class_def.main
class_def.Foo
GUI``main_module
选项1的示例:
import pickle import class_def from class_def import Foo # Import Foo into main_module's namespace explicitly if __name__=='__main__': with open('test_data.pkl', 'rb') as f: users = pickle.load(f)
选项2的示例:
import pickle import class_def if __name__=='__main__': class_def.main() # Objects are being pickled with main_module as the top-level with open('test_data.pkl', 'rb') as f: users = pickle.load(f)