I'm not sure how to describe the issue but I'll try it.
Background info
I have in my Django web application a function where the user can import other users. The user can via drag and drop import a .csv file which gets converted to a JSON 2D Array (with Papaparse JS)
In the view, I loop through the elements in the 2D array and create an "Importuser" which contains some properties like "firstname", "lastname", email and so on.
class Importuser:
firstname = None
lastname = None
email = None
import_errors = []
def __init__(self, fn, ln, e):
self.firstname = fn
self.lastname = ln
self.email = e
class Importerror:
message = None
type = None
def __init__(self, m, t):
self.message = m
self.type = t
In the for-loop, I also validate the email-address, so that there are no doubled users.
data = jsonpickle.decode(method.POST["users"])
users = []
for tempuser in data:
u = validate(Importuser(tempuser[0], tempuser[1], tempuser[2])
users.append(u)
In the validate function I check if there any user with the same email
def validate(user : Importuser):
user_from_db = User.objects.filter(email=user.email)
if user_from_db:
user.import_errors.append(Importerror("The user exists already!", "doubleuser"))
return user
Issue
After the for-loop finished all user have the same error but not when I print each user while doing the for-loop. The Importerror-Object in each user refers to the same memory location but in my test import should only have one user an error.
test.csv:
Dave,Somename,dave#example.com
Joe,Somename2,joe#example.com
Yannik,Somename3,yannik#example.com <<That's me (exsiting user)
What I'm doing wrong? can someone help me to understand why this happens?
You've defined import_errors as a class-level static, so it's shared between all instances of Importuser.
See: Static class variables in Python
For your particular problem, rewrite your classes as
class Importuser:
def __init__(self, firstname, lastname, email):
self.firstname = firstname
self.lastname = lastname
self.email = email
self.import_errors = []
class Importerror:
def __init__(self, message, type):
self.message = message
self.type = type
import_errors is a class-attribute of ImportUser. It should be a instance-attribute:
class Importuser:
def __init__(self, fn, ln, e):
self.firstname = fn
self.lastname = ln
self.email = e
self.import_errors = []
Related
I am generating a class of persons and want to get information about a certain person by input. I would like to use the str funtction because I am trying to understand it better. My Idea goes as follows:
class Person:
__init__(self, f_name, l_name):
self.f_name = f_name
self.l_name = l_name
__str__(self):
return "The persons full name is:" + f_name + l_name
person1 = Person(Peter, Punk)
person2 = Person(Mia, Munch)
person = input("What persons full name would you like to know?")
print(person) #I am aware that this just fills in the string saved in person, but how do I connect it to the variable?
another idea was to do it as follows:
#class stays the same except:
__init__(self, f_name, l_name):
self.f_name = f_name
self.l_name = l_name
list.append(self)
#and then for the main:
list = []
person1 = Person(Peter, Punk)
person2 = Person(Mia, Munch)
person = input("What persons full name would you like to know?")
index = list(person)
print(list[index])
Thankful for any edvice since I am obviously new to Python :D
I think OP has some concept problems here which this answer may go some way to help with.
Start by building a robust class definition. Simple in this case as there are just 2 attributes. Note the use of setters, getters and str, repr and eq dunder overrides.
A small function that checks if a given Person can be found in a list of Persons and reports accordingly.
Create a list with 2 different Person instances
Create another Person that is known not to match anything already in the list.
Run check()
Modify the 'standalone' Person to make it equivalent to something previously constructed.
Run check()
class Person:
def __init__(self, forename, surname):
self._forename = forename
self._surname = surname
#property
def forename(self):
return self._forename
#forename.setter
def forename(self, forename):
self._forename = forename
#property
def surname(self):
return self._surname
#surname.setter
def surname(self, surname):
self._surname = surname
def __str__(self):
return f'{self.forename} {self.surname}'
def __repr__(self):
return f'{self.forename=} {self.surname=}'
def __eq__(self, other):
if isinstance(other, type(self)):
return self.forename == other.forename and self.surname == other.surname
return False
def check(list_, p):
if p in list_:
print(f'Found {p}')
else:
print(f'Could not find {p}')
plist = [Person('Pete', 'Piper'), Person('Joe', 'Jones')]
person = Person('Pete', 'Jones')
check(plist, person)
person.surname = 'Piper'
check(plist, person)
Output:
Could not find Pete Jones
Found Pete Piper
You probably want a mapping between a name and an object. This is what Python's dict dictionary structure is for:
people = {} # an empty dictionary
people[f'{person1.f_name} {person1.l_name}'] = person1
people[f'{person2.f_name} {person2.l_name}'] = person2
This is creating a string of the first and last name.
You can then lookup the Person object using the full name:
print(people['Peter Punk'])
You could do this with list comprehension like so (also allowing multiple people to have the same first name)
class Person:
__init__(self, f_name, l_name):
self.f_name = f_name
self.l_name = l_name
__str__(self):
return "The persons full name is:" + f_name + l_name
personList= []
personList.append(Person(Peter, Punk))
personList.append(Person(Mia, Munch))
personName = input("What persons full name would you like to know?")
print([str(person) for person in personList if person.f_name == personName])
class User:
def __init__(self, username):
self.username = username
#classmethod
def get_user(cls):
return cls(input("Username: "))
class Budget(User):
def __init__(self, monthtly_income):
super().__init__(User.get_user())
self.monthly_income = monthtly_income
self.perc_lis = []
self.category_obj_lis = []
self.category_name_lis = []
self.value_lis = []
...
# creates objects and adds them to a list
for i in range(len(self.category_name_lis)):
self.category_obj_lis.append("")
self.category_obj_lis[i] = Category(self.category_name_lis[i], self.monthly_income)
...
class Category(Budget):
def __init__(self, name, monthly_income):
super().__init__(monthly_income)
self.name = name
self.perc = 0
self.amt = 0
self.left = 0
self.max = 0
# defines the percentage for each category
def get_perc(self):
self.perc = float(input(f"{self.name}: "))
When I run this it asks for username 3 times after I have asked for the categories because I create each Category object in a loop. Username is asked for at the start of the code. I need the category class to be a child class because I need the monthly_income variable to use in code not posted. I am not very good at inheritance so i could easily be missing something obvious. Is there a way for each instance of Category to not ask for username and just use the one already asked in the beginning? I apologize if this is somewhat confusing but idk where to go from here.
I'm using jsonpickle as a database for my small project and encountered some weird behavior when encoding a complex class, basically Book from a User instance is encoded correctly but books in db list are encoded as strange {"py/id":4}-s.
Could someone please explain where I went wrong and how do I fix this
import jsonpickle
from random import randint
admin_ids = [302115492]
def gen_id():
return randint(1, 2**64)
class Book():
def __init__(self, name, author, img, oid):
self.name = name
self.author = author
self.img = img
self.id = gen_id()
self.owner_id = oid
class User():
id = 0
name = ""
books = []
requests = []
def __init__(self, name, uid):
self.id = uid
self.name = name
self.books = []
class Database():
def __init__(self):
self.u_dir = "users"
self.b_dir = "books"
self.users = []
self.books = []
def add_book(self, book):
self.books.append(book)
for user in self.users:
if(user.id == book.owner_id):
user.books.append(book)
def add_user(self, user):
self.users.append(user)
db=Database()
db.add_user(User('John',123))
db.add_book(Book('name','author','img.png',123))
print(jsonpickle.encode(db))
Output:
{
"py/object":"__main__.Database",
"u_dir":"users",
"b_dir":"books",
"users":[
{
"py/object":"__main__.User",
"id":123,
"name":"John",
"books":[
{
"py/object":"__main__.Book",
"name":"name",
"author":"author",
"img":"img.png",
"id":8045585124766781176,
"owner_id":123
}
]
}
],
"books":[
{
"py/id":4
}
]
}
So apparently jsonpickle uses this id thing to compactly store objects that are already stored somewhere inside object's encoding. To store all objects explicitly one can use make_refs flag when encoding. In the code above it would look like this: print(jsonpickle.encode(db), make_refs=False)
I want to create some users just to populate my database, so using decorators I created a method inside a class for it. I returned the results into a list and used the information without a problem. But after a while I thought that once I was working with classes wouldn't be dumb to use lists? I feel that I am kind of moving backwards since, at least in my understanding, it might be possible to access those values directly.. But the truth is I struggled on attempting to instantiate dynamically and access those instances. So, how could I do that properly? Here is the code I wrote in the first attempt:
class User:
def __init__(self, user_name, password, email, i=0):
self.user_name = user_name
self.password = password
self.email = email
#classmethod
def from_generate(cls, amount):
user_name = 'user' + str(amount)
password = 'password000.' + str(amount)
email = 'user' + str(amount) + "#whatever.com"
return cls(user_name, password, email)
in another file:
def user_generator(user_qty=0):
user_list = []
for i in range(1, user_qty + 1):
# call the class method to generate users
instance = User.from_generate(i)
user_list.append(instance)
return(user_list)
users = user_generator(5)
if __name__ == "__user_generator__":
user_generator()
Newbie..
code:
class User:
def __init__(self, emailAddress, fName):
parts = emailAddress.split('#')
if len(parts) != 2:
raise Exception("Invalid email address: %s" % emailAddress)
self.emailAddress = emailAddress
self.emailMd5 = hashlib.md5(emailAddress).hexdigest()
self.domain = parts[1]
self.fName = fName
I want to be able to access 'fName', and return the value thats stored in it. Obviously this is not the way to do it! Working with example API code, and trying to extend it. I pass into user(emailAddress, fName) (First Name).
There code later goes on to use:
emailData['recipient'] = users[emailData['recipientMd5']].emailAddress
Which works, so I figured what I would do would also?
I know this should be a simple fix. Not sure what to google though, and example class tutorials I've read haven't covered what I'm trying to do.
import hashlib
class User:
def __init__(self, emailAddress, fName):
parts = emailAddress.split('#')
if len(parts) != 2:
raise Exception("Invalid email address: %s" % emailAddress)
self.emailAddress = emailAddress
self.emailMd5 = hashlib.md5(emailAddress).hexdigest()
self.domain = parts[1]
self.fName = fName
u = User("me#you.com","uname") # create instance
print u.fName # print instance attribute
You can access attributes directly from each instance.