I want to use a list throughout a program I am writing. Basically, it is a list full of tuples with information regarding different people, each person's information (name, phone, address, etc) is stored as in a tuple. I define this list through an initial function, but i need to use this in my interaction function as well as others.
My question is, is it possible for me to use this list without defining it as a global variable?
def load_friends(filename):
"""imports filename as a list of tuples using the import command"""
import csv
with open(filename, 'Ur')as filename:
friends_list = list(tuple(x) for x in csv.reader(filename, delimiter=','))
def add_friend(friend_info, friends_list):
"""appends the friend_info tupple to the list friends_list"""
new_list = friends_list.append(friends_info)
def interact():
"""interaction function: accepts user input commands"""
while True:
command = raw_input('Command: ')
I should also mention that there is a command to parse the use inputs to perform the functions. Would this affect the use of the list?
You could declare list inside the first function that calls it and return it from there, latter functions should receive this list as an argument then.
def func1():
my_list=[]
"""Do stuff
"""
return list
def func2(my_list):
"""Do stuff with my_list
"""
return
def func3(my_list):
"""Do stuff with my_list
"""
return
def main():
"""First we retrieve the list from func1,
func2/3 get it passed to them as an argument
"""
foo=func1
func2(foo)
func3(foo)
if __name__ == "__main__":
main()
You could do the following:
# you can define the list here, it's global but doesn't require the keyword
my_list_globally = []
def func1(the_list):
pass
def func2(the_list):
pass
def func3(the_list):
pass
# you can use a hub function to pass the list into things that need it
def main():
my_list = []
func1(my_list)
func2(my_list)
func3(my_list)
if __name__ == "__main__":
main()
I don't quite understand the last part of your question but one of those 2 ways will be what you need.
Yes. Pass the "list of friends" back and forth between functions as an argument.
load_friends() would become
def load_friends(filename):
import csv
with open(filename, 'Ur') as f:
return map(tuple, csv.reader(f, delimiter=","))
add_friend() is close, but that assignment to new_list is unnecessary, because list.append() mutates the existing list in place:
def add_friend(friend_info, friend_list):
friend_list.append(friend_info)
would suffice.
interact() would also have a friends_list argument.
def interact(friends_list):
#interaction stuff here...
and you could call it like so:
interact(load_friends("myfile.csv"))
Classes are useful for this kind of thing, and easy to use:
class PersInfo:
def setName(self, name):
self._name = name
def getName(self):
return self._name
def setNumber(self, number):
self._phNumber = number
def getNumber(self):
return self._phNumber
def setAddr(self, address):
self._address = address
def getAddr(self)
return self._address
def main():
# Read in data from your CSV Here
infoList = ([])
for person in person_list: # Assuming person is a tuple here
foo = PersInfo()
foo.setName(person[index1])
foo.setNumber(person[index2])
foo.setAddr(person[index3])
infoList.append(foo)
# To access the info...
for person in infoList:
print(person.getName())
print(person.getNumber())
print(person.getAddr())
You do end up with the list being "global," sort of. It is in the main() function, where the PersInfo objects are being instantiated. This may be more than you wanted, but in the long run it is a good way to organize your code and keep it readable.
Also, you could build the infoList I made directly where you are creating person_list.
Related
I'm trying to create threads to run a class method. However, when I try to pass one class to another, it tries to initialize the class and never gets threaded.
I'm taking a list of tuples and trying to pass that list to the cfThread class, along with the class method that I want to use. From here, I'd like to create a separate thread to run the classes method and take action on one of tuples from the list. The REPLACEME is a placeholder because the class is looking for a tuple but I don't have one to pass to it yet. My end goal is to be able to pass a target (class / function) to a thread class that can create it's own queue and manage the threads without having to manually do it.
Below is a simple example to hopefully do a better job of explaining what I'm trying to do.
#!/bin/python3.10
import concurrent.futures
class math:
def __init__(self, num) -> None:
self.num = num
def add(self):
return self.num[0] + self.num[1]
def sub(self):
return self.num[0] - self.num[1]
def mult(self):
return self.num[0] * self.num[1]
class cfThread:
def __init__(self, target, args):
self.target = target
self.args = args
def run(self):
results = []
with concurrent.futures.ThreadPoolExecutor(10) as execute:
threads = []
for num in self.args:
result = execute.submit(self.target, num)
threads.append(result)
for result in concurrent.futures.as_completed(threads):
results.append(result)
return results
if __name__ == '__main__':
numbers = [(1,2),(3,4),(5,6)]
results = cfThread(target=math(REPLACEME).add(), args=numbers).run()
print(results)
target has to be a callable; you want to wrap your call to add in a lambda expression.
results = cfThread(target=lambda x: math(x).add(), args=numbers)
it does not work. I want to split data as in code in lines attribute.
class movie_analyzer:
def __init__(self,s):
for c in punctuation:
import re
moviefile = open(s, encoding = "latin-1")
movielist = []
movies = moviefile.readlines()
def lines(movies):
for movie in movies:
if len(movie.strip().split("::")) == 4:
a = movie.strip().split("::")
movielist.append(a)
return(movielist)
movie = movie_analyzer("movies-modified.dat")
movie.lines
It returns that:
You can use #property decorator to be able to access the result of the method as a property. See this very simple example of how this decorator might be used:
import random
class Randomizer:
def __init__(self, lower, upper):
self.lower = lower
self.upper = upper
#property
def rand_num(self):
return random.randint(self.lower, self.upper)
Then, you can access it like so:
>>> randomizer = Randomizer(0, 10)
>>> randomizer.rand_num
5
>>> randomizer.rand_num
7
>>> randomizer.rand_num
3
Obviously, this is a useless example; however, you can take this logic and apply it to your situation.
Also, one more thing: you are not passing self to lines. You pass movies, which is unneeded because you can just access it using self.movies. However, if you want to access those variables using self you have to set (in your __init__ method):
self.movielist = []
self.movies = moviefile.readlines()
To call a function you use movie.lines() along with the argument. What you are doing is just accessing the method declaration. Also, make sure you use self as argument in method definitions and save the parameters you want your Object to have. And it is usually a good practice to keep your imports at the head of the file.
import re
class movie_analyzer:
def __init__(self,s):
for c in punctuation:
moviefile = open(s, encoding = "latin-1")
self.movielist = []
self.movies = moviefile.readlines()
#property
def lines(self):
for movie in self.movies:
if len(movie.strip().split("::")) == 4:
a = movie.strip().split("::")
self.movielist.append(a)
return self.movielist
movie = movie_analyzer("movies-modified.dat")
movie.lines()
So I have list of objects in class and I need to print all different songs from one singer.
So far I have this code and I am not sure is it correct
Also I need to use recursion method
def allmusic(listofobjects, name):
nameandsurname=self.name
if(listofobjects.name==nameandsurname):
print(listofobjects.music)
return(listofobjects(music[1:]))
else:
return(listofobjects(name[1:]))
Also I need to print number of singers in that class and code I have is
def allmusic(listofobjects):
numberofsingers=0
for s in listofobjects:
numberofsingers+=1
return(listofobjects()[1:])
print(numberofsingers)
I think this is what you want. It recursively prints the all songs of a specific singer provided in the arguments. Here listOfMusic is the list of Music objects.
def PrintSinger(self, listOfMusic, name):
if(listOfMusic[0].nameOfSinger == name):
print(listOfMusic[0].music)
if(len(listOfMusic) == 1):
return
else:
return self.PrintSinger(listOfMusic[1:], name)
Long story short, I need to write a data analysing tool using mainly OOP principles. I'm not quite a beginner at python but still not the best. I wrote a function which returned true or false value based on what the user inputted (below):
def secondary_selection():
"""This prints the options the user has to manipulate the data"""
print("---------------------------")
print("Column Statistics [C]")
print("Graph Plotting [G]")
d = input(str("Please select how you want the data to be processed:")).lower()
# Returns as a true/false boolean as it's easier
if d == "c":
return True
elif d == "g":
return False
else:
print("Please enter a valid input")
This function works the way I want it to, but I then tried to import it into different file for use with a class (below):
class Newcastle:
def __init__(self, data, key_typed):
self.data = data[0]
self.key_typed = key_typed
def newcastle_selection(self):
# If function returns True
if self:
column_manipulation()
# If function returns False
if not self:
graph_plotting()
The newcastle_selection(self) function takes the secondary_selection() function as a argument, but the only way I got it to work was the if self statement. As writing something like if true lead to both the column_manipulation and the graph_plotting functions being printed.
I am wondering if there's any better way to write this as I am not quite a beginner at python but still relatively new to it.
Disclaimer: This is for a first year course, and I asked this as a last result.
I'm not sure I've understood really well your code structure, but it looks like a little factory could helps you:
def column_manipulation():
print("Column manipulation")
def graph_plotting():
print("Graph plotting")
class Newcastle:
def __init__(self, data, func):
self.data = data[0]
self._func = func
def newcastle_selection(self):
return self._func()
#classmethod
def factorize(cls, data, key_typed):
if key_typed is True:
return cls(data, column_manipulation)
elif key_typed is False:
return cls(data, graph_plotting)
else:
raise TypeError('Newcastle.factorize expects bool, {} given'.format(
type(key_typed).__name__
))
nc = Newcastle.factorize(["foo"], True)
nc.newcastle_selection()
nc = Newcastle.factorize(["foo"], False)
nc.newcastle_selection()
Output
Column manipulation
Graph plotting
The main idea is to define your class in a generic way, so you store a function given as __init__ parameter within self._func and just call it in newcastle_selection.
Then, you create a classmethod that takes your data & key_typed. This method is in charge of choosing which function (column_manipulation or graph_plotting) will be used for the current instance.
So you don't store useless values like key_typed in your class and don't have to handle specific cases everywhere, only in factorize.
Cleaner and powerful I think (and btw it answer your question "Is this pythonic", this is).
This is simple and basic example of secondary_selection method using class. This would help probably.
class castle:
def __init__(self):
self.data = ''
def get_input(self):
print("1: Column Statistics")
print("2: Graph Plotting")
self.data = input("Please select how you want the data to be processed: ")
def process(self):
if self.data == 1:
return self.column_manipulation()
else:
return self.graph_plotting()
def column_manipulation(self):
return True
def graph_plotting(self):
return False
c = castle()
c.get_input()
result = c.process()
print(result)
To be specific in my case, the class Job has a number of Task objects on which it operates.
import tasker
class Job(object):
_name = None
_tasks = []
_result = None
def __init__(self, Name):
self._name = Name
def ReadTasks(self):
# read from a Json file and create a list of task objects.
def GetNumTasks(self):
return len(self._tasks)
def GetNumFailedTasks(self):
failTaskCnt = 0
for task in self._tasks:
if task.IsTaskFail():
failTaskCnt += 1
To make GetNumFailedTasks more succinct, I would like to use a filter, but I am not sure what is the correct way to provide filter with IsTaskFail as the first parameter.
In case, this is a duplicate, please mark it so, and point to the right answer.
You can use a generator expression with sum:
failTaskCnt = sum(1 for task in self._tasks if task.IsTaskFail())