I tried to do a function that takes a list of messages and a list of authors, and puts every message in it's corresponding author's message list.
class Author:
name = ""
msgs = []
files = []
class Message:
line = ""
time = datetime
author = ""
Function mentioned
for au in authorList:
a = 0
for msg in msgList:
if au.name == msg.author:
a += 1
au.msgs.append(msg)
print(a)
for au in authorList:
print(len(au.msgs))
And the output of the program
a=396
a=349
745
745
The function takes au.name and msg.author and compares them, if they are equal, the msg is stored in au.msgs list.
The variable a is incremented everytime a message is added to the user, and as it can be seen, for the first user a = 396 and for the second user a = 349 which sum 745, which is the size of the msgList.
The problem is that each author.msgList ends holding the total number of messages.
I have to mention that I am low skilled in python, so it might be a simple noob problem.
That's because the msgs and files are class variables, not instance variables, so they are shared by all instances of Author.
You can define them as instance variables as follows:
class Author:
def __init__(self):
self.name = ''
self.msgs = []
self.files = []
As suggested by TheGamer007, consider having a look at https://www.geeksforgeeks.org/g-fact-34-class-or-static-variables-in-python/
Related
I have created a class with programs:
class Program:
def __init__(self,channel,start, end, name, viewers, percentage):
self.channel = channel
self.start = start
self.end = end
self.name = name
self.viewers = viewers
Channel 1, start:16.00 end:17.45 viewers: 100 name: Matinee:The kiss on the cross
Channel 1, start:17.45 end:17.50 viewers: 45 name: The stock market today
Channel 2, start:16.45 end:17.50 viewers: 30 name: News
Channel 4, start:17.25 end:17.50 viewers: 10 name: Home building
Channel 5, start:15.45 end:16.50 viewers: 28 name: Reality
I also have created a nested list with the programs:
[[1,16:00, 17,45, 100, 'Matinee: The kiss on the cross'],[1,17:45, 17,50, 45,'The stock market today'],[2,16:45, 17,50, 30,'News'], [4,17:25, 17,50, 10,'Home building'],[5,15:45, 16,50, 28,'Reality']
Now we want the user to be able to write the name of a program:
News
The result should be:
News 19.45-17.50 has 30 viewers
I thought about how you could incorporate a method to avoid the program from crashing if the input is invalid/ not an instance variable
I have tried this:
Check_input():
print('Enter the name of the desired program:')
while True: #Continue asking for valid input.
try:
name = input('>')
if name == #is an instance?
return name
else:
print('Enter a program that is included in the schedule:') #input out of range
except ValueError:
print('Write a word!') #Word or letter as input
print('Try again')
I wonder if I should separate all the program-names from the nested list and check if the user enters a name in the list as input? (Maybe by creating a for-loop to iterate over?)
I also have a question regarding how to print out the selected program when the user enters the correct name? I understand how to rearrange them into the correct order to create the sentence. However, I don't know how to access the correct program in the "memory"
Do you have any suggestions how to combat the problem?
All help is much appreciated!
I wonder if I should separate all the program-names from the nested list and check if the user enters a name in the list as input? (Maybe by creating a for-loop to iterate over?)
Well if all your programs have a unique name then the easiest approach would probably be to store them in a dictionary instead of a nested list like:
programs = {
"News": Program("2", "16:45", "17:50", "News", "30", "60"),
"Reality": <Initialize Program class object for this program>,
...
}
Then you could just use the get dictionary method (it allows you to return a specific value if the key does not exist) to see if the asked program exists:
name = input('>')
program = programs.get(name, None)
if program:
print(program)
else:
# raise an exception or handle however you prefer
And if your programs don't have a unique name then you will have to iterate over the list. In which case I would probably return a list of all existing objects that have that name. A for loop would work just fine, but I would switch the nested list with a list of Program objects since you already have the class.
I also have a question regarding how to print out the selected program when the user enters the correct name? I understand how to rearrange them into the correct order to create the sentence. However, I don't know how to access the correct program in the "memory" Do you have any suggestions how to combat the problem.
I would say that the most elegant solution is to override the __str__ method of your Program class so that you can just call print(program) and write out the right output. For example:
class Program:
def __init__(self,channel,start, end, name, viewers, percentage):
self.channel = channel
self.start = start
self.end = end
self.name = name
self.viewers = viewers
def __str__(self):
return self.name + " " + self.start + "-" + self.end + " has " + self.viewers + " viewers"
should print out
News 19.45-17.50 has 30 viewers
when you call it like:
program = programs.get(name, None)
if program:
print(program)
I'm building a simple blockchain/cryptocurrency to learn about python and blockchain programming.
I've run into an issue regarding appending transaction objects to the list variable 'transactions' in my Block objects.
For whatever reason, when adding a transaction to a block, it is added to every block on the chain.
I have uploaded my code to a github repo:
The project consists of 3 class files: Blockchain.py, Block.py & Transaction.py
I also have a testing file 'test1.py' which reproduces the error.
https://github.com/swooperior/blockchain-py
I suspect the issue is in the Block class file:
#Not intended behaviour. addTransaction seems to add to every block in self.chain
from datetime import datetime
import hashlib
class Block:
hash = ''
txIndex = 0
transactions = []
timeStamp = ''
previous_hash = ''
nonce = 0
def calculateHash(self):
self.hash = str(hashlib.sha256(repr([self.transactions,self.previous_hash,self.nonce]).encode('utf-8')).hexdigest())
def getHash(self):
return self.hash
def addTransaction(self,tx):
#Validate transaction, then pass to transactions list
tx.id = self.txIndex
self.transactions.append(tx)
self.txIndex += 1
def printDetails(self):
print('Block Hash: '+self.getHash())
print('Nonce: '+str(self.nonce))
print('Created: '+ str(datetime.fromtimestamp(self.timeStamp)))
print('Prev_hash: '+self.previous_hash)
print('Transactions ('+str(len(self.transactions))+'):')
self.printTransactions()
def printTransactions(self):
c = 1
for tx in self.transactions:
print('Transaction:'+ str(c))
tx.printDetails()
c += 1
def __init__(self,txlist=[],prev_hash=''):
self.txIndex = 0
self.previous_hash = prev_hash
for tx in txlist:
self.addTransaction(tx)
self.timeStamp = datetime.timestamp(datetime.now())
self.nonce = 1
self.calculateHash()
#print(self.printDetails())
The transactions attribute is a class attribute for all instances of the class. When you instantiate the class, you should create an instance variable instead. You also shouldn’t use a mutable default argument.
class Block:
...
def __init__(self, txlist=None, prev_hash=''):
self.transactions = []
txlist = txlist or []
self.previous_hash = prev_hash
for tx in txlist:
self.addTransaction(tx)
self.timeStamp = datetime.timestamp(datetime.now())
self.nonce = 1
self.calculateHash()
Function defaults are only evaluated once so each instance uses the same default argument unless you give it another one. This only happens to mutable objects as re-assigning them doesn’t copy them.
I'm currently using Python to parse CAN database files. I ran into a problem with lists during implementation and gave it a quick patch that makes it work, but it's kind of ugly and seems as if there's a more elegant solution.
I have defined an object CAN database and one of it's methods takes the file to be parsed, which contains definitions of messages in the database. I loop through each line in the file and when I come across a line indicating a message description, I create a temporary variable referencing an object I've defined for CAN messages, some of the members of which are lists. I put elements in these lists with a method based on the next handful of lines in the file.
Now when I'm done with this temporary object, I add it to the CAN database object. Since I no longer need the data referenced by this variable, I assign the value None to it and reinstantiate the clean slate variable on the next iteration through that detects a message descriptor. Or that was the plan.
When I go through the next iteration and need to use this variable, I add some values to these lists and find that they're not actually empty. It seems that despite assigning the variable to reference None the values in the lists persisted and were not cleaned up.
Below you can see my solution which was to stack more methods on specifically to get rid of the persisting list elements.
Here's some relevant portions of the file:
Parsing Loop
for line in file:
line = line.rstrip('\n')
line_number += 1 # keep track of the line number for error reporting
if line.startswith("BU_:"):
self._parseTransmittingNodes(line)
elif line.startswith("BO_"):
can_msg = self._parseMessageHeader(line).ResetSignals().ResetAttributes()
building_message = True
elif line.startswith(" SG_") and building_message:
can_msg.AddSignal(self._parseSignalEntry(line))
# can_msg.updateSubscribers()
elif line == "":
if building_message:
building_message = False
self._messages += [can_msg]
can_msg = None
Reset Methods
def ResetSignals(self):
"""
Flushes all the signals from the CANMessage object.
"""
self._signals = []
return self
def ResetAttributes(self):
"""
Flushes all the attributes from the CANMessage object.
"""
self._attributes = []
return self
How can I make this variable a fresh object every time? Should I have a method that clears all of it's internals instead of assigning it None like the IDispose interface in C#?
EDIT: Here's the full source for the CANMessage object:
class CANMessage:
"""
Contains information on a message's ID, length in bytes, transmitting node,
and the signals it contains.
"""
_name = ""
_canID = None
_idType = None
_dlc = 0
_txNode = ""
_comment = ""
_signals = list()
_attributes = list()
_iter_index = 0
_subscribers = list()
def __init__(self, msg_id, msg_name, msg_dlc, msg_tx):
"""
Constructor.
"""
self._canID = msg_id
self._name = msg_name
self._dlc = msg_dlc
self._txNode = msg_tx
def __iter__(self):
"""
Defined to make the object iterable.
"""
self._iter_index = 0
return self
def __next__(self):
"""
Defines the next CANSignal object to be returned in an iteration.
"""
if self._iter_index == len(self._signals):
self._iter_index = 0
raise StopIteration
self._iter_index += 1
return self._signals[self._iter_index-1]
def AddSignal(self, signal):
"""
Takes a CANSignal object and adds it to the list of signals.
"""
self._signals += [signal]
return self
def Signals(self):
"""
Gets the signals in a CANMessage object.
"""
return self._signals
def SetComment(self, comment_str):
"""
Sets the Comment property for the CANMessage.
"""
self._comment = comment_str
return self
def CANID(self):
"""
Gets the message's CAN ID.
"""
return self._canID
def AddValue(self, value_tuple):
"""
Adds a enumerated value mapping to the appropriate signal.
"""
for signal in self:
if signal.Name() == value_tuple[0]:
signal.SetValues(value_tuple[2])
break
return self
def AddAttribute(self, attr_tuple):
"""
Adds an attribute to the message.
"""
self._attributes.append(attr_tuple)
return self
def ResetSignals(self):
"""
Flushes all the signals from the CANMessage object.
"""
self._signals = []
return self
def ResetAttributes(self):
"""
Flushes all the attributes from the CANMessage object.
"""
self._attributes = []
return self
def Name(self):
return self._name
def TransmittingNode(self):
return self._txNode
def DLC(self):
return self._dlc
The problem you're seeing is because you used class attributes instead of instance attributes. If you move the initialization of the attributes you don't pass to __init__ from class scope into __init__, each instance will have its own set of lists.
Here's what that would look like:
class CANMessage:
"""
Contains information on a message's ID, length in bytes, transmitting node,
and the signals it contains.
"""
def __init__(self, msg_id, msg_name, msg_dlc, msg_tx):
"""
Constructor.
"""
self._canID = msg_id
self._name = msg_name
self._dlc = msg_dlc
self._txNode = msg_tx
self._name = ""
self._canID = None
self._idType = None
self._dlc = 0
self._txNode = ""
self._comment = ""
self._signals = list()
self._attributes = list()
self._iter_index = 0
self._subscribers = list()
# the rest of the class is unchanged, and not repeated here...
I want the following counter to check the order num class inside a dictionary thats inside a list.
...code...
self.counter = count(1)
def submit(self):
if Database.xoomDatabase[0]["Num Orden"] == next(self.counter):
self.counter = Database.xoomDatabase["Num Orden"]
Database.xoomDatabase.append(ordenOrganiz)
The reason I'm doing this type of counter is because I'm dumping a pickle file everytime the app closes, that contains Database.xoomDatabase. When the app is executed, the pickle dump gets loaded and all the dictionaries inside of it get pushed back into Database.xoomDatabase. This is the dictionary that's saved on Database.xoomDatabase:
global ordenOrganiz
ordenOrganiz = {"Num Order": nicenum,
"Nombre": nombre,
"Email": email,
"Num Tel/Cel": num,
"Orden Creada:": fechacreacion1,
"Fecha de Entrega": fechaentrega}
print(ordenOrganiz["Nombre"])
return dict(ordenOrganiz)
My questions is: How can I start the counter in exactly the last "Order Num" the is loaded from the pickle dump file?
EDIT:
This is how, with the help of Anand S Kumar, I got it it to work:
if len(Database.xoomDatabase) == 0:
newCount = 0
else:
newCount = max(Database.xoomDatabase, key = lambda x:x['Num Orden'])["Num Orden"]
nombre = contents1
nicenum = int(newCount) + 1
This loop checks if there are any saved dictionaries on the list. If there ar no dics., the count starts at 1. If there are already saved dics., the count will start from the last "Orden Num"(Order Number) saved into the pickle dump.
xoomDatabase = []
if path.isfile(file_path) == False:
open(file_path, "w").close()
else:
loadLis = open(file_path, "rb")
dalis = pickle.load(loadLis)
loadLis.close()
xoomDatabase.extend(dalis)
This loops check if there is any file to load, if there isn't, it cretes one. If there's already a saved pickle dump, then it will load the list with previously saved dicts.
You can create a class variable directly inside the class, and then access it using Class.<variable> and also in __init__() function use this Class.<variable> to initialize the counter for each variable and increment the counter.
Example -
class TempClass
counterInit = 0
def __init__(self):
self.counter = TempClass.counterInit
TempClass.counterInit += 1
...
And then at the start of the program, read back the data from the pickle dump and then take the largest counter and set it to counter as given in below example.
Example -
TempClass.counterInit = max(Database.xoomDatabase, key = lambda x:x['Num Orden'])
The above max() gives the largest Num Orden from the list of dictionaries.
class Journey has a list, self.leg_miles
class ManyJourneys has a list of journeys created by
self.journeys = []
for i in range(2):
self.journeys.append(Journey())
from some input I add to the list leg_miles for each Journey kind of like this:
self.journeys[self.count].addLeg(temp)
temp is a number i read from a list. it is always changed to what was inputted right before the above line.
for some reason instead of creating a new list for journey[1] it just adds to the created list.
for example:
if for journey[0] the leg_miles had [4,5,6]
and I moved on to journey[1] to add 4 and 6
it would have :
leg_miles = [4,5,6,4,6]
I do not understand why it is adding on. I have self in it.
I do not understand how to upload code or pictures.
I hope this is enough information to solve the problem
EDIT: Here is the code I have.
class Journey:
def __init__(self,odometer=0,leg_miles=[],leg_gas=[]): #constructor
self.odometer = odometer
self.leg_miles = leg_miles
self.leg_gas = leg_gas
def addLeg(self,miles,gas):
#adds to a list of miles and gas
self.leg_miles.append(miles)
self.leg_gas.append(gas)
def getLists(self):
#returns the list of miles and the list of gas
return self.leg_miles,self.leg_gas
def calculate(self):
#calculate the miles per litre for the journey and return
miles_per_litre = 0
for i in range(len(self.leg_miles)): #calcs miles per litre for each leg and adds to total
miles_per_litre += int(self.leg_miles[i]/self.leg_gas[i])
return miles_per_litre
class ManyJourneys:
def __init__(self,name):
self.myfile = open(name,"r")
self.content = self.myfile.read().split("\n")
self.journeys = []
for i in range(self.content.count("")+1):
self.journeys.append(Journey())
self.count = 0
for i in self.content:
if i == "":
self.count+=1
else:
temp = i.split(" ")
self.journeys[self.count].addLeg(int(temp[0]),int(temp[1]))
def statistics(self):
sum = 0
for i in self.journeys:
sum += i.calculate()
return sum/len(self.journeys)
def main():
filename = input("Please enter a file name. (Eg: test.txt): ")
manyJourneys1 = ManyJourneys(filename)
print("You got {0} miles per litre.".format(manyJourneys1.statistics()))
main()
and a sample text file would be
100 54
340 109
23 4
333 33
4500 678
There is an unobvious feature in Python regarding default values - they represent the same object each time, which causes surprising behavior when using mutable values as defaults:
def add(value, l=[]):
l.append(value)
return l
add(1) # [1]
add(2) # [1, 2]
To not fall into this trap do not use list or any other mutable value this way. If you need to initialize something to an empty list do it in a function/method body:
def __init__(self, odometer=0, leg_miles=None, leg_gas=None):
self.odometer = odometer
self.leg_miles = leg_miles or []
self.leg_gas = leg_gas or []
You screwed up your definition of Journey. Mutable types must be assigned in the initializer or in methods, not in the class or default arguments.