Writing strings to file using class - empty output - python

Quite new to python, I am trying to create a small function that is meant to write a given number of instances of a string to a file (e.g. as input for a word cloud tool). I have tried doing this with the class below but for some reason do not receive any output, but no error message either.
I thought maybe I am not declaring count correctly as an integer as input? However, no error message is displayed which makes it somewhat confusing.
Again, very new to Python so any help along with some explanation would be greatly appreciated :) Code below!
#Prints multiple instances of a string as input for a word cloud tool
class print_list(object):
wordlist = []
def __init__(int(count), word, self):
self.count = count
self.word = word
def write_list(self):
while count > 0:
wordlist.append(word)
print word + "\n"
count = count - 1
return wordlist
def write_file(self):
my_file = open("cloud.txt", "w")
for word in wordlist:
my_file.write(word + "\n")
my_file.close
Python = print_list(10, "Python")

You have a lot of syntax errors. First of all, self needs to come first, and type conversions don't happen in function definitions. so your __init__ should look like
def __init__(self, count, word):
self.count = int(count)
self.word = word
Second, all attribute, like wordlist count and word need to be accessed as self.wordlist, self.word etc. inside the methods. So for example, write_file should be
def write_file(self):
my_file = open("cloud.txt", "w")
for word in self.wordlist:
my_file.write(word + "\n")
my_file.close
And write_list should be
def write_list(self):
while self.count > 0:
self.wordlist.append(self.word)
print self.word + "\n"
self.count = self.count - 1
return self.wordlist
(I also un-indented the return statement so the loop actually gets executed, but I assume that was a copying into stackexchange error).
Lastly, you are not calling any of your methods that do the things like filling in wordlist and writing it. So to get your class to actually write the file you need to call the write_file method. Making these changes to your code, we have:
#Prints multiple instances of a string as input for a word cloud tool
class print_list(object):
wordlist = []
def __init__(self, count, word):
self.count = count
self.word = word
def write_list(self):
while self.count > 0:
self.wordlist.append(self.word)
print self.word + "\n"
self.count = self.count - 1
return self.wordlist
def write_file(self):
my_file = open("cloud.txt", "w")
for word in self.wordlist:
my_file.write(word + "\n")
my_file.close()
Python = print_list(10, "Python")
Python.write_list()
Python.write_file()

First of all, I did get a syntax error...
class print_list(object):
#int(count) isn't necessary and causes Syntax Error on my python 2.7
def __init__(self, count, word):
self.count = count
self.word = word
#I think wordlist will be more useful here, as a class attribute (1)
self.wordlist = []
def write_list(self):
#I copy the self.count to a local variable (2)
countCopy = self.count
while count > 0:
self.wordlist.append(self.word)
print self.word + "\n"
countCopy = countCopy - 1
def write_file(self):
#nitpick: hardcoding filenames is bad practice, it would be better to pass it as an argument
my_file = open("cloud.txt", "w")
#self.wordlist is the list built in the above function
#so if this function is called first, self.wordlist is an empty list
for word in self.wordlist:
my_file.write(word + "\n")
#you forgot parentheses below
my_file.close()
#More code here... (3)
Remarks:
Making wordlist a class attribute allows you to keep the once build list inside the class, and it is easily accessed by other class methods, like write_file.
Thanks to this, the self.count remains unchanged since the moment __init__ was called.
Simply instancing the class won't call all the methods we've defined. This means, that aside from tool = print_list(10, "word") you'll have to call each method as well. By the way, "Python" is a bad name for a class...
And a general comment:
You seem to get confused with what should be a class attribute (e. i. self.x instead of x) and what should be a local variable. And how to use those. Python, by default, looks for local variables but not class attributes. If you want to access a class attribute you have to prefix its name with self.. Otherwise you'll get a NameError or simply a wrong result.

class PrintList(object):
def __init__(self,count, word):# self comes first in your init method
self.count = count
self.word = word # use self to refer to instance attributes
self.wordlist=[] # make wordlist an attribute
def write_list(self):
while self.count > 0:
self.wordlist.append(self.word)
print self.word + "\n"
self.count -= 1
return self.wordlist
def write_file(self):
with open("cloud.txt", "w") as my_file: # using with automatically closes the file
for word in self.wordlist:
my_file.write(word + "\n")
pl = PrintList(10, "Python") # create instance of Printlist class
print pl.write_list()
pl.write_file()# need to call method on instance to write to the file
Python classes

Related

How do I pass variables from the Parent class method to the a Child class method?

I've got a parent class and a child class. I want the child class to take the method from the parent class, perform a operation and apply it. What I'm trying to do is loop through a wordlist file in the parent class method openWordlist(), and for every word in that wordlist file, pass it to the child class method scanDomain() to perform an operation which is to loop through website directories that are available to the public.
class Main:
def __init__(self):
self.wordlistFile = ''
self.word = ''
def openWordlist(self):
with open(self.wordlistFile, 'r') as suppliedWordlist:
for word in suppliedWordlist:
word = word.strip()
self.word = word
class DirectoryScan(Main):
def scanDomain(self):
try:
self.cleanURL = 'https://google.com' + self.word
self.reqURL = requests.get(self.cleanURL)
if self.reqURL.status_code == 200:
print('Found: {self.cleanURL}')
elif self.reqURL.status_code != 200:
pass
except InvalidURL:
print(f'{self.targetURL} does NOT exist.')
if __name__ == '__main__':
s = Main()
d = DirectoryScan()
directoryScan.openWordlist()
directoryScan.scanDomain()
However, the result that I'm getting is just the https://google.com/ back. Is there something wrong with the inheritance that I'm doing?
The name of your input file is '', which can't be opened.
Thus, you never set self.word to anything except ''.
And even if you did open a file, you would only set self.word to the last word in the file.
Do what you say you want to do; "loop through a wordlist file in the parent class method openWordlist(), and for every word in that wordlist file, pass it to the [...] method scanDomain()"
class Main:
def __init__(self, filename):
self.wordlistFile = filename
def scanDomain(self, word):
pass
def openWordlist(self):
with open(self.wordlistFile, 'r') as suppliedWordlist:
for word in suppliedWordlist:
self.scanDomain(word.strip())
class DirectoryScan(Main):
def scanDomain(self, word):
try:
self.cleanURL = 'https://google.com/' + word
self.reqURL = requests.get(self.cleanURL)
if self.reqURL.status_code == 200:
print('Found: {self.cleanURL}')
elif self.reqURL.status_code != 200:
pass
except InvalidURL:
print(f'{self.targetURL} does NOT exist.')
if __name__ == '__main__':
d = DirectoryScan('somefile.txt')
d.openWordlist()
(The point of this inheritance structure is a mystery, though.)
I think your issue is here:
def openWordlist(self):
with open(self.wordlistFile, 'r') as suppliedWordlist:
for word in suppliedWordlist:
word = word.strip()
self.word = word
You are iterating over the suppliedWordList and set self.word = word.
But from the context I get, the suppliedWordList can be longer. So maybe your last line does not contain what you actually want to add there to your url.

In Python, how to set value for one __init__ variable based on another?

def __init__(self):
#self.data = []
self.random_word = random.choice(open("EnglishDictionary.txt").readlines()).strip()
self.length_notice = "The word you're guessing is {} letters long.".format(len(random_word))
This just returns the error: Name 'random_word' is undefined
You set self.random_word, not random_word, so you need to use self.random_word:
self.length_notice = "The word you're guessing is {} letters long.".format(len(self.random_word))
# Add self. ^^^^^
Just use it:
def __init__(self):
#self.data = []
with open("EnglishDictionary.txt") as f:
msg = "The word you're guessing is {} letters long."
self.random_word = random.choice(f).strip()
self.length_notice = msg.format(len(self.random_word))
Ask yourself, though, if self.random_word really needs to be an instance attribute, or if random_word can simply be a local variable inside the function, like msg.

How do you convert a call to a class/function to a string in Python?

I am new to programming and self taught. I have used Stack Exchange to find answers to many of my questions without ever needing to ask (it is a great community), but I cannot seem to find the answer to this anywhere. I apologize if this is a duplicate.
I am trying to assign a method to a variable, but I want to save it to a text file for access later. I am using open() to access the text file and eval() to change it from a string when loading the information. I just cannot figure out how to do the opposite.
from random import randint
class Example (object):
def __init__(self):
self.name = ""
self.lucky_number = ""
def create_person(self):
self.name = input("What is your name?")
self.lucky_number = randint(1,10)
save_person = [self.name, self.lucky_number]
with open("example.txt", "w") as f:
for i in save_person:
f.write(i + '\n')
def load_person(self):
with open("example.txt", 'r') as f:
person_list = f.readlines()
if len(person_list) <= 1:
create_person()
else:
self.name = person_list[0].strip('\n')
self.lucky_number = eval(person_list[1].strip('\n'))
person = Example()
person.load_person()
I want to keep the randint(1,10) part because I want to reuse the function, but I may change the value to something else later depending on user selection (such as changing self.lucky_number = randint(1,10) to self.lucky_number = randint(1,30)).
I know I can just change it to self.lucky_number = randint(1,var) and then save the value of var instead, but it made me wonder if the way I'm trying is possible.
Thanks in advance for any assistance. I am using Python 3.5.
Edit: For clarification I am looking to store the actual function, i.e. randint(1,10), in the text file, not the value of the function.
EDIT 2: I am going to close this as answered because I found a way to do what I needed, but it is not a direct way.
I was able to find a way to accomplish what I was looking for, but it is a roundabout way. I changed the call to the function into a string, then created a new class variable that calls the variable with the function string. The other class variable meant to run the function now has eval() around it and calls the new class variable I created. I save the new class variable instead.
from random import randint
# Now a string instead of a function call
prog = "randint(1,10)"
class Example (object):
def __init__(self):
self.name = ""
"""Added self.temp to grab the string from outer
variable and will change self.temp to get the desired
functions as strings"""
self.temp = prog
"""self.lucky_number grabs new class variable and
eval() turns it into callable function"""
self.lucky_number = eval(self.temp)
def create_person(self):
self.name = input("What is your name?")
self.temp = prog
self.lucky_number = eval(self.temp)
""" Saves new class variable now and stores actual
function, eg randint(1,10)"""
save_person = [self.name, self.temp]
with open("example.txt", "w") as f:
for i in save_person:
f.write(str(i) + '\n')
def load_person(self):
with open("example.txt", 'r') as f:
person_list = f.readlines()
if len(person_list) <= 1:
self.create_person()
else:
self.name = person_list[0].strip('\n')
self.temp = person_list[1].strip('\n')
person = Example()
person.load_person()
Its roundabout, but gets the job done. I can change self.temp to whatever variable (formatted properly) I need and the code will work. If anyone can think of a direct way please let me know.

Fixing Python Code

I'm trying to implement an iterator class named CharCounter. This class opens a textfile and provides an iterator that returns words from the text file containing a user specified number of characters. It should output a word per line. Which is not what's it's doing, it's outputting the words as a list and then it continuously outputs 'a'. How can I fix my code?
class CharCounter(object):
def __init__(self, fileNm, strlen):
self._fileNm = fileNm
self._strlen = strlen
fw = open(fileNm)
text = fw.read()
lines = text.split("\n")
words = []
pwords =[]
for each in lines:
words += each.split(" ")
chkEnd = ["'",'"',",",".",")","("]
if words[-1] in chkEnd:
words = words.rstrip()
for each in words:
if len(each) == strlen:
pwords.append(each)
print(pwords)
def __iter__(self):
return CharCounterIterator(self._fileNm)
class CharCounterIterator(object):
def __init__(self,fileNm):
self._fileNm = fileNm
self._index = 0
def __iter__(self):
return self
def next(self):
try:
ret = self._fileNm[self._index]
return ret
except IndexError:
raise StopIteration
if __name__=="__main__":
for word in CharCounter('agency.txt',11):
print "%s" %word
Code posted on SO should not read a file unless the question is about reading files. The result cannot be duplicated and verified. (See MCVE.) Instead, define a text string as a stand-in for the file.
Your code prints the words of length n as a list because that is what you ask it to do with print(pwords). It repeatedly prints the first char of the filename because that is what you ask it to do in the __next__ method.
Your class __init__ does more than you describe. The attempt to strip punctuation from words does not do anything. The code below defines a class that turns a text into a list of stripped words (with duplicates). It also defines a parameterized generator method that filters the word list.
class Words:
def __init__(self, text):
self.words = words = []
for line in text.split('\n'):
for word in line.split():
words.append(word.strip(""",'."?!()[]{}*$#"""))
def iter_n(self, n):
for word in self.words:
if len(word) == n:
yield word
# Test
text = """
It should output a word per line.
Which is not what's it's doing!
(It outputs the words as a [list] and then continuously outputs 'a'.)
How can I fix my #*!code?
"""
words = Words(text)
for word in words.iter_n(5):
print(word)
# Prints
Which
doing
words

Error accessing class objects in python

I am having some problem accessing class instances. I am calling the class from a procedure, name of instance is defined in some variable. I want the instance name to be created of that value and then want to access it, but when i access it is giving error. Can some one please help to resolve this issue.
class myclass:
def __init__(self,object):
self.name = object
def mydef():
global a1
b = "a1"
b = myclass(b)
mydef()
print a1.name
Second Problem:
In my actual script, I have to create a large number of such instances from this function (around 100). So defining their name as global would be painful, is there a way i could access those instances outside function without having to declare them as global.
Modification:
class myclass:
def __init__(self,object,typename):
self.name = object
self.typeid = typename
def mydef():
file_han = open(file,"r")
while True:
line = file_han.readline()
if not line:
break
start = line.find('"')
end = line.find('"',start+1)
string_f = line[start+1:end]
myclass(string_f,'a11')
mydef(file)
print def.name
print def.typeid
File Contents are :
a11 "def"
a11 "ghi"
a11 "eff"
Here's how I'd do it. I don't know why you're messing around with globals, if you'd care to explain, I'll update my answer.
class Myclass(object):
def __init__(self, name):
self.name = name
def mydef():
return Myclass("a1")
a1 = mydef()
print a1.name
Gather your instances in a list:
instances = []
for x in range(1000):
instances.append(Myclass("Instance {0}".format(x)))
print instance[42].name
Note the changes:
Class names should be capitalized
Use object as the base class of your classes (since python 2.2, but no longer necessary in 3.x)
Don't shadow the built-in object with your parameter name
Just use the string "a1" directly as a parameter instead of assigning it to a variable
Return something from the function instead of passing the result by global variable
RE: Comment
You haven't said anything about the format of these files, so I'll just give an example where the file to be read contains one class name per line, and nothing else:
def mydef(filename):
ret = []
with open(filename) as f:
for line in f:
# Call `strip` on line to remove newline and surrounding whitespace
ret.append(Myclass(line.strip()))
return ret
So if you have several files and wish to add all your instances from all your files to a large list, do it like this:
instances = []
for filename in ["myfile1", "myfile2", "myfile3"]:
instances.extend(mydef(filename))
RE: OP Edit
def mydef(filename):
ret = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret.append(Myclass(string_f))
return ret
i = mydef("name_of_file")
RE: Comment
Oh, you want to access them by name. Then return a dict instead:
def mydef(filename):
ret = {}
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
ret[string_f] = Myclass(string_f)
return ret
i = mydef("name_of_file")
print i["ghi"].name # should print "ghi"
RE: Comment
If I understand you correctly, you want to have it both ways -- index by both line number and name. Well then why don't you return both a list and a dictionary?
def mydef(filename):
d = {}
L = []
with open(filename, "r") as file_han:
for line in file_han:
string_f = line.split('"')[1]
instance = Myclass(string_f)
d[string_f] = instance
L.append(instance)
return L, d
L, d = mydef("name_of_file")
print d["ghi"].name
print L[3]
print L.index(d["ghi"])
You could use class as repository for your instances, for example
class Named(object):
def __init__(self,name):
self.name = name
def __new__(cls,name):
instance = super(type,cls).__new__(cls,name)
setattr(cls,name,instance)
return instance
def __repr__(self):
return 'Named[%s]'%self.name
Named('hello')
Named('x123')
Named('this is not valid attribute name, but also working')
print(Named.hello,Named.x123,getattr(Named,'this is not valid attribute name, but also working'))

Categories

Resources