Python : is this local variable static? - python

My First Attempt :
def generate_id():
""" Create unique id of alphanumeric characters """
i = 0
id = ''
while i!=10:
id = id + random.choice(string.ascii_letters + string.digits)
i+=1
if check_unique(id):
return id
id = generate_id()
return id
def check_unique(id):
"""Check if id is unique"""
try:
instances = SomeModel.objects.get(id=id)
except ObjectDoesNotExist:
return True
return False
Second Way :
def generate_id():
""" Create unique id of alphanumeric characters """
i = 0
id = ''
while i!=10:
id = id + random.choice(string.ascii_letters + string.digits)
i+=1
if check_unique(id):
return id
generate_id()
def check_unique(id):
"""Check if id is unique"""
try:
instances = SomeModel.objects.get(id=id)
except ObjectDoesNotExist:
return True
return False
If I do it the second way , won't my logic of generating unique id's be wrong ? Because I might loose the id from the last call .
I am new to python and I don't know but I think my recursion concept looks messed up

Follow your code:
if check_unique(id): # If this is `false`, you keep going
return id
generate_id() # Now what? You call the function. Nothing gets returned.
If you want to create a unique ID, don't use recursion. Just use a while loop and generate new IDs as long as they're not unique:
characters = string.ascii_letters + string.digits
def generate_id(length=10):
return ''.join(random.choice(characters) for i in range(length))
def generate_unique_id(length=10):
id = generate_id(length)
while not check_unique(id):
id = generate_id(length)
return id

In the second way you should return a the end of the generate_id function:
return generate_id()
I would also suggest to make an iteration instead of a recursive call... it's seems cleaner in this situation.

Related

Compare randomly generated string to an existing list of strings

I have a form that expects a unique 5-character ID. I have a function that generates this unique ID. Before entering it in the form, I want to compare it with an existing list of IDs. If the generated ID doesn't exist in the list, pass it in a variable; if it does exist and it isn't unique, generate another ID. What's the best way to go about this?
def generate_id():
random_id= ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(5))
return random_id
existing_ids = ['AAAAA', 'BBBBB', 'CCCCC']
for id in existing_ids:
if not generate_id() == id:
unique_id = generate_id()
while True:
a = generate_id()
if a not in set(existing_ids) :
break
Debugging:
for id in existing_ids:
This denotes the execution of the loop for the number of items in the existing_ids, which is definitely not what you want.
if not generate_project_id() == id:
unique_id = generate_project_id()
Apart from the incorrect method name, generate_project_id() should have been generate_id(), this will not do what you think it will, i.e. even if the id is unique it will store a different id in the unique_id since it is calling the method again, unique_id = generate_project_id() and who knows it could be a dupe!
Hence:
If the intention is to keep generating unique id's until one that does not exist in the existing list show up, put it in a loop using set() to exclude any dupes in the existing list:
import string
def generate_id():
random_id = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(5))
return random_id
existing_ids = ['AAAAA', 'BBBBB', 'CCCCC']
while True:
genId = generate_id()
if genId not in set(existing_ids):
unique_id = genId
break
import random
import string
def generate_id():
random_id = ''
random_id = ''.join(random.choice
(string.ascii_uppercase + string.digits) for _ in range(5))
return random_id
existing_ids = ['AAAAA', 'BBBBB', 'CCCCC']
unique_id = generate_id()
while unique_id in existing_ids:
unique_id = generate_id()
if unique_id not in existing_ids:
break;
print(unique_id)
I think you could try bitmap? Because 5 chars could construct a number which < 2**32, so you can generate a random number [0-26**6] and use it to mod 26 to get the only 5 chars,
you can use bitmap to check if it exists.

Loop through One2Many records Odoo 10

I am trying to loop through my One2Many records to avoid duplication.
class sales_target(models.Model):
_name = 'sales.target'
_description = 'Sales Target'
name = fields.Char(string='Name',required=True)
from_date = fields.Date(string='From Date',required=True)
to_date = fields.Date(string='To Date',required=True)
sales_team = fields.Many2one('crm.team',required=True)
sales_record_ids = fields.One2many('sales.target.record','sales_target_rec_id',string='Sales Record')
#api.one
def check_duplication(self,result):
count = 0
if self.sales_record_ids:
for record in self.sales_record_ids:
if result.id == record.sales_person_p_id:
count = 1
if count == 0:
self.write({'sales_record_ids':[(0,0,{'sales_person':result.name})]})
#api.one
def get_sales_person(self):
for res in self.sales_team.member_ids:
self.check_duplication(res)
The other class is as:
class sales_target_record(models.Model):
_name = 'sales.target.record'
sales_target_rec_id = fields.Many2one("sales.target")
sales_person = fields.Char(string='Sales Person',readonly=True,required=True)
sales_person_p_id = fields.Char(compute='get_value',store=True)
#api.onchange('sales_person')
#api.depends('sales_person')
def get_value(self):
res = self.env['res.partner'].search([('name','=',self.sales_person)])
self.sales_person_p_id = res[0].id
Now when I am hitting the button i still have duplicate records. However I tried to compare with name and things work good but I cannot compare with names since its not correct because names can be same but id cannot. That function was as:
#api.one
def check_duplication(self,result):
count = 0
if self.sales_record_ids:
for record in self.sales_record_ids:
if result.name == record.sales_person:
count = 1
if count == 0:
self.write({'sales_record_ids':[(0,0,{'sales_person':result.name})]})
Hope for guidance on this.
Can you try like this
#api.multi
def check_duplication(self,result):
if self.sales_record_ids:
for record in self.sales_record_ids:
if not result.name == record.sales_person:
self.write({'sales_record_ids':[(0,0,{'sales_person':result.name})]})
Concluding from the fact that for name it works properly, something might be wrong with your if condition.
sales_person_p_id is of type char, however you seem to compare it with an integer: result.id.
Have you made sure that both objects in your if condition are of the same type?
Try to make sales_person_p_id an integer field (e.g. via sales_person_p_id = fields.Integer(compute='get_value',store=True) or do some kind of type casting before comparing the objects.

Why is the if clause being skipped?

# in file contactList.py
import contact
class ContactList:
def __init__(self):
self.added = True
self.list = []
def add(self, newContact):
added = 1
self.list.append(newContact)
def __str__(self):
if (self.added == True):
returnedString = ""
for contact in self.list:
returnedString = returnedString + "\n" + str(contact)
return returnedString
def find(self, name):
self.name = name
for contact in self.list:
if self.name == (str(contact))[0]: # I also tried if self.name in str(contact)
return str(contact)
else:
return "Invalid input"
if __name__ == "__main__":
myFriends = ContactList()
friend1 = contact.Contact("Mickey", "650-345-3333", "Mickey#disneyland.com", "Disneyland, California")
friend2 = contact.Contact("Minnie", "650-345-3344", "Minnie#disneyworld.com", "Disneyworld, Florida")
friend3 = contact.Contact("Donald", "650-345-3333", "Donald#EuroDisney.com", "EuroDisney, France")
myFriends.add(friend1)
myFriends.add(friend2)
myFriends.add(friend3)
print (myFriends)
print (myFriends.find("Mickey"))
I'm wondering why the last call, print (myFriends.find("Mickey")), is not be iterated by the shell; instead, it's skipped no matter what I put in the parameter. For example, when I enter "Mickey", "Minnie", or "Donald" in the parameter, I'm supposed to get the corresponding personal information about them, but the "if" clause under the find() function is never iterated. What's the problem here? Besides, since it was a snippet code to which I added find(), I'm not really sure what the purpose of the self.added = True in __init__ and the added = 1 in add().
Below is the contact() imported to this file contactList.py
#in file contact.py
class Contact:
"""
One object of class Contact represents one person's contact info.
"""
def __init__(self, name, phone, email, streetAddress):
self.name = name
self.phone = phone
self.email = email
self.streetAddress = streetAddress
def __str__(self):
return "%s\n%s\n%s\n%s\n" % (self.name, self.phone,self.email,self.streetAddress)
if __name__ == "__main__":
friend1 = Contact("Mickey", "650-345-3333", "Mickey#disneyland.com", "disneyland, CA")
print (friend1)
Your code as it is written will only check the first contact in the list. I'll just repeat what you have written here for clarity:
def find(self, name):
self.name = name
for contact in self.list:
if self.name == (str(contact))[0]:
return str(contact)
else:
return "Invalid input"
Now to be extra clear let's just keep the important parts:
if :# some condition is true
return str(contact)
else: # some condition is false
return "Invalid input"
As you can see in either case you get a return value. So you're not going to be finding your value if it's not the first one in your list, doesn't matter if the "some condition" referred to above is correct or buggy.
Edit: to be crystal clear, you need to put your failure condition (returning "invalid input" or whatever) after the for loop, not inside of it. This is left as an exercise to the reader.
Now as for the condition you're checking, based on the structure of the Contact class you posted I'd guess the right check would be:
if name == contact.name:
Nice and neat like python should be :)
Good luck
(str(contact))[0] gives the first character of the string representation of contact. So one character is never equal to a name with more than one character.
If contact has index access and the first index is actually the name, you should write:
def find(self, name):
for contact in self.list:
if name == contact[0]:
return contact
else:
return "Invalid input"
Why do you put if statement in (). you dont have to do it.
if self.added == True:
This way it will be enought.
Try this:
if self.name == str(contact[0])
Instead of this
if self.name == (str(contact))[0]

Retrieving a class object from a dictionary

As part of a beginners' university Python project, I am currently creating a database of words, be it Nouns, Verbs, Determiners, Adjectives.
Now the problem I am having is that the words being read into the program via the lexicon.readfromfile method are being put into the dictionary via an instance of a class ( be it noun, verb or adjective ). This created the problem that I have absolutely no idea how to call these objects from the dictionary since they do not have variables as keys, but rather memory locations (see the following):
{<__main__.Verb object at 0x02F4F110>, <__main__.Noun object at 0x02F4F130>, <__main__.Adjective object at 0x02F4F1D0>, <__main__.Noun object at 0x02F4F170>}
Does anyone have any idea how I can call these keys in such a way that I can make them usable in my code?
Here is the part I'm stuck on:
Add a method getPast() to the Verb class, which returns the past tense of the Verb. Your getPast() method can simple work by retrieving the value of ‘past’ from the attributes.
Here is a the majority of the code, leaving out the Noun and Adjective classes:
class Lexicon(object):
'A container clas for word objects'
def __init__(self):
self.words = {}
def addword(self, word):
self.words[word.stringrep] = word
def removeword(self, word):
if word in self.words:
del(word)
print('Word has been deleted from the Lexicon' )
else:
print('That word is not in the Lexicon')
def getword(self,wordstring):
if wordstring in self.words:
return self.words[wordstring]
else:
return None
def containsword(self,string):
if string in self.words:
return True
else:
return False
def getallwords(self):
allwordslist = []
for w in self.words:
allwordslist.append(self.words[w])
return set(allwordslist)
def readfromfile(self, x):
filehandle = open(x, 'r')
while True:
line = filehandle.readline()
if line == '':
break
line = line.strip()
info = line.split(',')
if info[1] == 'CN' or info[1] == 'PN':
noun=Noun(info[0],info[1])
noun.setattribute('regular',bool(info[2]))
self.addword(noun)
elif info[1] == 'A':
adjective=Adjective(info[0],info[1])
adjective.setattribute('comparative', bool(info[2]))
self.addword(adjective)
elif info[1] == 'V':
verb=Verb(info[0],info[1])
verb.setattribute('transitive', bool(info[2]))
verb.setattribute('past', info[3])
self.addword(verb)
def writetofile(self, x):
filehandle = open(x, 'w')
for t in self.words.values():
filehandle.write(t.getFormattedString() + '\n')
filehandle.close()
#---------------------------------------------------------------------------#
class Word(object):
'A word of any category'
def __init__(self,stringrep,category):
self.wordattribute = {}
self.stringrep = stringrep
self.category = category
def setattribute(self, attributename, attributevalue):
self.wordattribute[attributename] = attributevalue
def getvalue(self,name):
if name in self.wordattribute:
return self.wordattribute[name]
else:
return none
def __str__(self):
return self.stringrep + ':' + self.category
def __lt__(self,otherword):
return self.stringrep < otherword.stringrep
class Verb(Word):
'"Represents a Verb."'
def __init__(self, stringrep, category):
super().__init__(stringrep,category)
def istransitive(self):
return self.transitive
def getFormattedString(self):
n = '{stringrep},{category}'
n = n.format(stringrep=self.stringrep, category=self.category)
for i in range(1,2):
for v,b in self.wordattribute.items():
n = n+','+str(b)
return n
You have a set there, not a dictionary. A set will let you check to see whether a given instance is in the set quickly and easily, but, as you have found, you can't easily get a specific value back out unless you already know what it is. That's OK because that's not what the set is for.
With a dictionary, you associate a key with a value when you add it to the dictionary. Then you use the key to get the value back out. So make a dictionary rather than a set, and use meaningful keys so you can easily get the value back.
Or, since I see you are already making a list before converting it to a set, just return that; you can easily access the items in the list by index. In other words, don't create the problem in the first place, and you won't have it.

Calculating the average of a list in Python 3

I am currently trying to calculate the average of a list created by a method in a class. Firstly all information is passed to a Class that records/returns the data passed through from the main function. The issue is what do I pass in from the main function to firstly retrieve the self._marks list and then manipulate it in order for the average to be returned. Also am I using the correct code for the calculateAverageMark section? Thanks in advance
Here is the code:
class Student :
def __init__(self, id):
self._studentId = id
self._marks = []
##
# Converts the student to a string .
# #return The string representation .
#
# Sets the student's ID.
# #param newId is the student's new ID.
#
def setStudentId(self, id):
self._studentId = id
##
# Gets the student's ID.
# #return the student's ID
#
def getStudentId(self, newId):
return self._newId
##
# Appends a mark to the marks list
#
def addMark(self, mark):
self._marks.append(mark)
def __repr__(self) :
# Build a string starting with the student ID
# followed by the details of each mark .
s = "Student ID :" + self._studentId + " "
if len(self._marks) == 0 :
s += " <none \n>"
else :
for mark in self._marks :
s += " Course Module: " + mark.getModule() + " Raw Mark: " + str(mark.getRawMark())
return s
##
# Method to calculate the students average mark
#
def calculateAverageMark(self):
totalMarks = 0
count = 0
for mark in self._marks :
if mark == 0 :
count = count
else :
count = count + 1
totalMarks = totalMarks + mark
average = totalMarks / count
return average
Your current code is incorrect because you divide by count in every iteration (and before count is actually the number of marks). Calculating the average is very easy with a list of values:
def calculateAverageMark(self):
if self._marks: # avoid error on empty list
return sum(self._marks) / float(len(self._marks))
You don't need to pass anything in; all instance attributes are available via self. Unless you have specifically been told to exclude zero scores from the average, you should count them.

Categories