I am trying to get the user to make an object called a NoteSet, each NoteSet will be put into a global list called db. This is my attempt at making this:
import sys
import datetime
db = list()
class NoteSet:
nextseqNum = 0
def __init__(self,name,description,hidden):
global db
self.seqNum = Note.nextseqNum
self.name = name
self.description = description
self.dateCreated = datetime.date.today()
self.hidden = hidden
self.notes = list()
db[self.seqNum] = self
print(self)
print(len(db))
Note.nextseqNum += 1
When I try to create an object for example:
NoteSet('example','ex',True)
It gives me the error
Traceback (most recent call last):
File "", line 1, in
NoteSet('example','ex',True)
File "C:\Users\Brandon\Desktop\step5.py", line 22, in init
db[self.seqNum] = self
IndexError: list assignment index out of range
Is this the right way to make a global list of objects?
As #aruisdante said you will need to append to the list
Try this:
db = []
class ListObj:
def __init__(self, name, msg, hide=False):
self.name = name
self.msg = msg
self.hide = hide
db.append(self)
Good Luck!
You get this error because db has no elements in it (python lists are initialized to length 0), so when you try and replace the element at location self.seqNum, you are acessing an invalid index. It has nothing to do with the global-ness of it.
If we assume that this global list is only ever going to be accessed in a thread-safe manner, you should simply be able to do:
db.appened(self)
Instead. However, as mentioned in the comments, it makes more sense in this use case to make db a class variable if this class is the 'gate keeper' to interfacing with the db list.
UPDATE
To address the OP's question in the comments,
I am looking to be able to keep track of the location of the objects in the list by the seqNum
As currently written, seqNum will always increment linearly, forever, with each new NoteSet instance. If we assume thread-safe access of Note.nextseqNum, then what you're trying to do via db[self.seqNum] is already implicitly done via db.append(self), because len(db) == Note.nextseqNum, always. For now, we're going to ignore what happens if you cand remove elements from db, because right now your system doesn't account for that at all and would completely break anyway.
If, however, in the future seqNum doesn't just increase monotonically forever each time you make a new instance, you can simply make db a dict instead of a list:
db = dict()
And then insert the new instance to it exactly as you are currently,
db[self.seqNum] = self
db now represents a mapping of a seqNum to a NoteSet explicitly, rather than an implicit relationship based on an array index.
I would actually recommend doing it this way anyway, as it will also solve the problem of removing items from db for 'free'. As is, doing del db[instance.seqNum] will completely invalidate all mappings of seqNum into db for any instance that came after the removed instance. But if db is a dict, then this operation does what you expect it to and all of the seqNum values still map to the correct instance in db.
So, to bring it all together, I would recommend you alter your class to look like the following:
import sys
import datetime
class NoteSet:
nextseqNum = 0
db = dict()
def __init__(self,name,description,hidden):
self.seqNum = NoteSet.nextseqNum
self.name = name
self.description = description
self.dateCreated = datetime.date.today()
self.hidden = hidden
self.notes = list()
NoteSet.db[self.seqNum] = self
print(self)
print(len(db))
NoteSet.nextseqNum += 1
Related
Apologies if I explain something wrong or use the wrong wording, my programmer vocabulary isn't the best. If anyone understands my problem and has better ways of explaining it feel free to do so. I have a problem similar to a problem here. I want to remove items from a list that occur in another list. But one list will have strings that reference the variable "name" within class objects.
class sword:
name = 'swordName'
class bow:
name = 'bowName'
class axe:
name = 'axeName'
inventory = [sword, bow, sword, axe]
select = ['bowName', 'swordName']
I want to be able to create a list "selectedItems" with the class objects out of inventory based off of the strings in "select" that are equal to the "name" of the class objects. It also needs to work if "inventory" and "select" both have duplicates in them.
Output:
>> inventory = [bow, axe]
>> selectedItems = [bow, sword]
One other thing I would like the program to ignore if there are more "name"s in select than there are corresponding class objects in "inventory", and to ignore if a string in "select" has no corresponding class objects.
For example, if "inventory" is [sword, axe] and "select" is ['bowName', 'non-existent', 'axeName'], the result is that "inventory" is [sword] and "selectedItems" is [axe].
A simple way of explaining this is that select will take from inventory, but if select can't take from inventory nothing happens.
You may make base class with magic methods __eq__ and __hash__ which can allow you to manage comparing your objects as you want:
class BaseItem:
name = None
def __init__(self):
self.__name = self.name
def __eq__(self, other):
return self.__name == other
def __hash__(self):
return id(self.__name)
def __repr__(self):
return f"'{self.__name}'"
class Sword(BaseItem):
name = "swordName"
class Bow(BaseItem):
name = "bowName"
class Axe(BaseItem):
name = "axeName"
inventory = [Sword(), Bow()]
select = ["swordName", "bowName", "axeName", "swordName", "bowName"]
# casting lists into sets and getting difference between them
result = set(inventory) - set(select)
print(result) # output {'swordName', 'bowName'}
eq - actually is unused here but i added that you can compare your objects with strings, lists etc:
Sword() in ["swordName"] # true
Sword() in ["bowName"] # false
Sword() == "swordName" # true
Sword() == "bowName" # false
hash - need to comparing two objects, actually it use for getting difference between two sets
repr - it is not really required method, it needs just for pretty displaying of objects
selectedItems = list()
# make a new list of the names of the objects in the inventory
# inventory and inventory names have the same index for the same item
inventory_names = [x.name for x in inventory]
for s in select:
if s in inventory_names:
index = inventory_names.index(s)
inventory_names.pop(index)
selectedItems.append(inventory.pop(index))
I'm trying to learn OOP but I'm getting very confused with how I'm supposed to run the methods or return values. In the following code I want to run read_chapters() first, then sendData() with some string content that comes from read_chapters(). Some of the solutions I found did not use __init__ but I want to use it (just to see/learn how i can use them).
How do I run them? Without using __init__, why do you only return 'self'?
import datetime
class PrinceMail:
def __init__(self):
self.date2 = datetime.date(2020, 2, 6)
self.date1 = datetime.date.today()
self.days = (self.date1 - self.date2).days
self.file = 'The_Name.txt'
self.chapter = '' # Not sure if it would be better if i initialize chapter here-
# or if i can just use a normal variable later
def read_chapters(self):
with open(self.file, 'r') as book:
content = book.readlines()
indexes = [x for x in range(len(content)) if 'CHAPTER' in content[x]]
indexes = indexes[self.days:]
heading = content[indexes[0]]
try:
for i in (content[indexes[0]:indexes[1]]):
self.chapter += i # can i use normal var and return that instead?
print(self.chapter)
except IndexError:
for i in (content[indexes[0]:]):
self.chapter += i
print(self.chapter)
return self????? # what am i supposed to return? i want to return chapter
# The print works here but returns nothing.
# sendData has to run after readChapters automatically
def sendData(self):
pass
#i want to get the chapter into this and do something with it
def run(self):
self.read_chapters().sendData()
# I tried this method but it doesn't work for sendData
# Is there anyother way to run the two methods?
obj = PrinceMail()
print(obj.run())
#This is kinda confusing as well
Chaining methods is just a way to shorten this code:
temp = self.read_chapters()
temp.sendData()
So, whatever is returned by read_chapters has to have the method sendData. You should put whatever you want to return in read_chapters in a field of the object itself (aka self) in order to use it after chaining.
First of all, __init__ has nothing to do with what you want to achieve here. You can consider it as a constructor for other languages, this is the first function that is called when you create an object of the class.
Now to answer your question, if I am correct you just want to use the output of read_chapters in sendData. One of the way you can do that is by making the read_chapters a private method (that is if you don't want it to use through the object) using __ in the starting of the name like __read_chapters then make a call to the function inside the sendData function.
Another point to consider here is, when you are using self and don't intend to use the function through the object you don't need to return anything. self assigns the value to the attribute of the current instance. So, you can leave the function read_chapters at self.chapter = i and access the same in sendData.
Ex -
def sendData(self):
print(self.chapter)
I'm not an expert but, the reason to return self is because it is the instance of the class you're working with and that's what allows you to chain methods.
For what you're trying to do, method chaining doesn't seem to be the best approach. You want to sendData() for each iteration of the loop in read_chapters()? (you have self.chapter = i which is always overwritten)
Instead, you can store the chapters in a list and send it after all the processing.
Also, and I don't know if this is a good practice but, you can have a getter to return the data if you want to do something different with (return self.chapter instead of self)
I'd change your code for:
import datetime
class PrinceMail:
def __init__(self):
self.date2 = datetime.date(2020, 2, 6)
self.date1 = datetime.date.today()
self.days = (self.date1 - self.date2).days
self.file = 'The_Name.txt'
self.chapter = []
def read_chapters(self):
with open(self.file, 'r') as book:
content = book.readlines()
indexes = [x for x in range(len(content)) if 'CHAPTER' in content[x]]
indexes = indexes[self.days:]
heading = content[indexes[0]]
try:
for i in (content[indexes[0]:indexes[1]]):
self.chapter.append(i)
except IndexError:
#not shure what you want to do here
for i in (content[indexes[0]:]):
self.chapter.append(i)
return self
# sendData has to run after readChapters automatically
def sendData(self):
pass
#do what ever with self.chapter
def get_raw_chapters(self):
return self.chapter
Also, check PEP 8 Style Guide for naming conventions (https://www.python.org/dev/peps/pep-0008/#function-and-variable-names)
More reading in
Method chaining - why is it a good practice, or not?
What __init__ and self do on Python?
I have been trying my hand at a NASCAR project, where I would have to use a class to create 20 unique vehicles and then have them race ( or to see who would reach 500 miles first, through the means of repeatedly choosing a different speed between 1 and 120 and adding it to an increasing odometer). I made what you see below and ran it, and it boots well into the Python IDLE. However, it will always tell me that NameError: name 'Driver_sponsor' is not defined. See, I have been facing this error for a while now, and I have tried placing the Driver_sponsor list into a class, placing it into the Main def and placing the keyword self. before it. No matter what I did, I faced this error. I am going to go back into my class book to see what I can do, but I am hoping that someone here can tell me what I am missing within my code, since, really, I am extremely lost.
from random import randint
import time
class Car:
def __init__(self,Driver_Name,Sponsor):
self.__Total_Odometer_Miles = 0
self.__Speed_Miles_Per_Hour = 0
self.__Driver_Name = Driver_Name
self.__Sponsor = Sponsor
self.__Driver = ('Drivers name Missing')
self.__Sponsor = ('Sponsor Missing')
self.__Driver_sponsor = {'A.J.Allmendinger:3M','Aric Almirola:Allegiant ','Trevpr Bayne:AMR ','Ryan Blaney:Camping World ','Clint Bowyer:Chevrolet ',
'Chris Buesher:Coca-Cola','Kurt Busch:Coca-light ','Kyle Busch:Credit One ','Landon Cassill:Ford','Matt DiBenedetto:FDP',
'Austin Dillon:','Ty Dillon:','Dale Earnhardt:Jacob Companies ','Chase Elliott: M & M ','Denny Hamlin: Microsoft ',
'Kevin Harvick:GoodYear ','Jimmie Johnson:Nationwide','Erik Jones:SUNOCO','Kasey Kahne:Toyota','Matt Kenseth:Visa ' }
def Name(self,Driver_Name):
self.__Driver_Name = Driver_Name
def Retrieve_Name(self):
return self.__Driver_Name
def __mutualize__(self):
self.__Total_Odometer_Miles = 0
self.__Speed_Miles_Per_Hour = 0
def sponsors(self):
self.__Driver_sponsor = {'A.J.Allmendinger:3M','Aric Almirola:Allegiant ','Trevpr Bayne:AMR ','Ryan Blaney:Camping World ','Clint Bowyer:Chevrolet ',
'Chris Buesher:Coca-Cola','Kurt Busch:Coca-light ','Kyle Busch:Credit One ','Landon Cassill:Ford','Matt DiBenedetto:FDP',
'Austin Dillon:','Ty Dillon:','Dale Earnhardt:Jacob Companies ','Chase Elliott: M & M ','Denny Hamlin: Microsoft ',
'Kevin Harvick:GoodYear ','Jimmie Johnson:Nationwide','Erik Jones:SUNOCO','Kasey Kahne:Toyota','Matt Kenseth:Visa ' }
def Retrieve_sponsor(self,Driver_sponsor):
return self.__Driver_sponsor
def main():
for key in Driver_sponsor():
CurrentCar = Car()
CurrentCar.Driver = key
CurrentCar.Sponsor = val
CurrentCar.MPH = randint(1,120)
time.sleep(.05)
time = 5
currentCar.ODT = 5
CurrentCar.ODT = CurrentCar.ODT + CurrentCar.MPH*Time
print(CurrentCar.Driver,CurrentCar.ODT)
if CurrentCar.ODT >= 500:
print('\ the winner is',key,'t\ sponsored by',val)
main()
There are a few issues with your code.
First, you're getting this error because you're calling a variable that isn't set.
But more importantly, you're trying to access the driver-sponsor dict before you've initialized an instance of Car (which currently only happens inside the loop that iterates over Driver_sponsor!).
If you want to loop over driver-sponsor pairs and initialize a new Car for each one, then do you really need the full Driver_sponsor dict initialized for every Car? If so, just pass it as an argument when constructing Car and populate self.__Driver_sponsor.
For example:
driver_sponsor_pairs = {'A.J.Allmendinger:3M',...,'Matt Kenseth:Visa'}
class Car:
def __init__(self, driver_sponsor):
# ...
self.driver_sponsor = driver_sponsor
CurrentCar = Car(driver_sponsor=driver_sponsor_pairs)
# now refer to CurrentCar.driver_sponsor
Second, you are only asking for key when looping over the Driver_sponsor dict, but you call on both key (for Driver) and val (for Sponsor) in each loop . Extract both key and val in your loop creation. You'll need the .items() dict method to get both values:
for key, val in driver_sponsor_pairs.items():
...
Third, your Car __init__ expects Driver and Sponsor arguments, but you try to define CurrentCar = Car() and then populate CurrentCar.Driver and CurrentCar.Sponsor afterwards. Continuing with the above updates, try instead:
CurrentCar = Car(Driver=key, Sponsor=val)
Fourth, you won't need the Retrieve_sponsor() method if you already have the .Sponsor attribute set.
There are a lot of misunderstandings here about Object syntax and design. You may find it frustrating to try and debug at this level of complexity. I would suggest starting very simply, say, with Car() having just one attribute. Test that, make sure it works as you want, and then build more attributes and methods from there.
Sorry this is the second post in two days.. I am pulling my hair out with this. I am attempting to take data from reddit and put it into an array in a way I can pull the data out later for tensorflow to parse it. Now the issue is my second object inside of the other object is not giving me whats inside it... "<main.Submission" why am I getting this back?
Goals of this post:
1: Why am I getting <main.Submission> and how should I be doing this.
File "C:/automation/git/tensorflow/untitled0.py", line 35, in <module>
submissions[sm.id].addSubSubmission(Submission.addComment(cmt.id, cmt.author.name, cmt.body))
TypeError: addComment() missing 1 required positional argument: 'body'
Sorry for the long winded and most likely basic questions. Going from powershell to python was not as straight forward as I thought..
Thanks
Cody
import praw
# sets log in data for session
reddit = praw.Reddit(client_id='bY',
client_secret='v9',
user_agent='android:com.example.myredditapp:'
'v1.2.3 (by /u/r)')
class Submission(object):
def __init__(self, id, title, author):
self.id = id
self.title = title
self.subSubmission = {}
self.author = author
def addComment(self, id, author, body):
self.id = id
self.author = author
self.body = body
def addSubSubmission(self,submission):
self.subSubmission[submission,id] = submission
def getSubSubmission(self,id):
return self.subSubmission[id]
submissions = {}
for sm in reddit.subreddit('redditdev').hot(limit=2):
# pulls the ID and makes that the head of each
submissions[sm.id] = Submission(sm.id, sm.title, sm.author.name)
mySubmission = reddit.submission(id=sm.id)
mySubmission.comments.replace_more(limit=0)
# Get all the comments and first post and list their id author and body(comment)
for cmt in mySubmission.comments.list():
submissions[sm.id].addSubSubmission(Submission.addComment(cmt.id, cmt.author.name, cmt.body))
# My trying to read what all there??!? ##
for key in submissions.keys():
value = submissions[key]
print(key, "=", value)
for key, value in submissions.items():
print(key, "=", value)
expecting to see:
{Title = test {comment.id = 1111 {Comment = 'blah', Author = 'Bob'}}
{comment.id = 1112 {Comment = 'blah2', Author = 'Bob2'}}
}
It is giving you back the entire Submission object - but then you're printing it. How should a submission object look on screen when printed? This is something you can define in the Submission class - check out the first answer in this post: Difference between __str__ and __repr__ in Python
To explain this further: python doesn't know how to represent a class on screen. Sure, the class has attributes that are strings, lists, dicts etc, but python knows how to print those. Your class you just created? What's important? What should be printed? python doesn't know this, and is smart enough not to make any assumptions.
If you add a __repr__ function to your class, python will call it and print whatever that function returns.
from datetime import datetime
class sms_store:
def __init__(self):
self.store = [] #Keeps resetting / not saving data from previous instances
self.message_count = 0 #Keeps resetting / not saving data from previous instances
def add_new_arrival(self,number,time,text):
self.store.append(("From: "+number, "Recieved: "+time,"Msg: "+text))
self.message_count += 1
newsms = sms_store()
time = datetime.now().strftime('%H:%M:%S')
newsms.add_new_arrival("23456",time, "hello, how are you?")
As seen above in the comment section i want to a list to store information from VARIOUS instances. Not one instance, but SEVERAL seperate instances of information and the list being a list that is accessible and in which I can edit it and it SAVES the information from different instances. Its not doing this. It is resetting after every instance.
I have tried the global variable route but not understanding it and dont think it will work. I have set a global variable OUTSIDE the class and created an object inside the class to store in the list but it gives me an error: UnboundLocalError: local variable 'message_count' referenced before assignment.
I am working on an excercise that requires one to use classes in the interactive python site: http://openbookproject.net/thinkcs/python/english3e/classes_and_objects_I.html#term-class
Please please help me.
You should not create a new instance of sms_store each time:
newsms = sms_store()
newsms.add_new_arrival("23456", datetime.now().strftime('%H:%M:%S'), "hello, how are you?")
newsms.add_new_arrival("65432", datetime.now().strftime('%H:%M:%S'), "I'm fine, thanks")
works just fine
It looks like you want a class variable.
The code should look like this:
from datetime import datetime
class Sms_store:
store = []
message_count = 0
def __init__(self):
pass
def add_new_arrival(self,number,time,text):
Sms_store.store.append(("From: "+number, "Recieved: "+time,"Msg: "+text))
Sms_store.message_count += 1
newsms1 = Sms_store()
time = datetime.now().strftime('%H:%M:%S')
newsms1.add_new_arrival("23456",time, "hello, how are you?")
newsms2 = Sms_store()
time = datetime.now().strftime('%H:%M:%S')
newsms2.add_new_arrival("23456",time, "hello, how are you?")
print Sms_store.store
This way, the variables store and message_count will be shared by all the instances of the Sms_store class.