J'essaie de créer un système utilisateur, qui utilise un paramètre et un module Gui, et lorsque le module GUI demande que le fichier se charge à l'aide de cornichon, je continue à recevoir une erreur d'attribut. cela provient du module des paramètres:
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)
et voici le module 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_())
chaque utilisateur est une classe et est mis dans une liste, puis la liste est enregistrée à l'aide de cornichon lorsque je charge juste le fichier de paramètres et vérifie la connexion, tout fonctionne correctement, mais lorsque j'ouvre le module GUI et essaie de vérifier qu'il ne fonctionne pas laissez-moi, l'erreur que je reçois:
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)>
Le problème est que vous décapez les objets définis dans les paramètres en exécutant en fait le module 'Paramètres' , alors vous essayez de décoller les objets du GUI
module.
Rappelez-vous que le cornichon ne stocke pas réellement les informations sur la façon dont une classe/un objet est construit, et a besoin d'accéder à la classe lors du débrochage. Voir wiki sur l'utilisation de Pickle pour plus de détails.
Dans les données pkl, vous voyez que l'objet référencé est __main__.Manager
, car le module "Paramètres" était principal lorsque vous avez créé le fichier pickle (c'est-à-dire que vous avez exécuté le module "Paramètres" comme script principal à invoquer) la fonction addUser
).
Ensuite, vous essayez de décompresser dans 'Gui' - pour que le module ait le nom __main__
, et vous importez Setting dans ce module. Alors bien sûr, la classe Manager sera en fait Settings.Manager
. Mais le fichier pkl ne le sait pas et recherche la classe Manager dans __main__
, et lance une AttributeError car elle n'existe pas (Settings.Manager
oui, mais __main__.Manager
non).
Voici un ensemble de codes minimal à démontrer.
Le class_def.py
module:
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()
Vous exécutez ce qui précède pour générer les données de cornichon. Le main_module.py
module:
import pickle
import class_def
if __name__=='__main__':
with open('test_data.pkl', 'rb') as f:
users = pickle.load(f)
Vous exécutez ce qui précède pour tenter d'ouvrir le fichier de cornichons, ce qui génère à peu près la même erreur que vous voyiez. (Légèrement différent, mais je suppose que c'est parce que je suis sur Python 2.7)
La solution est soit:
Settings.addUser
depuis l'interface graphique ou class_def.main
de main_module). Cela signifie que le fichier pkl enregistrera les objets sous Settings.Manager
ou class_def.Foo
, qui peut ensuite être trouvé dans l'espace de noms GUI
`main_module`.Exemple de l'option 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)
Exemple de l'option 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)
Veuillez d'abord lire la réponse mentionnée par zehnpaard pour connaître la raison de l'erreur d'attribut. Autre que la solution qu'il a déjà fournie, en python3
vous pouvez utiliser le pickle.Unpickler
classe et remplacer le find_class
méthode telle que mentionnée ci-dessous:
import pickle
class CustomUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if name == 'Manager':
from settings import Manager
return Manager
return super().find_class(module, name)
pickle_data = CustomUnpickler(open('file_path.pkl', 'rb')).load()
Si vous avez une classe définie en dehors du module, dont l'objet est dans des données de pickle, vous devez importer la classe
from outside_module import DefinedClass1, DefinedClass2, DefinedClass3
with open('pickle_file.pkl', 'rb') as f:
pickle_data = pickle.load(f)