finalWords is not defined, how do I avoid this? - python

import random
import requests
from bs4 import BeautifulSoup
import random
import time
class Game(object):
def __init__(self):
words = []
finalWords = []
def getWords(self,url):
sourceCode = requests.get(url).text
soup = BeautifulSoup(sourceCode, 'html.parser')
words = soup.get_text().lower().split()
[finalWords.append(item) for item in words if item not in finalWords]
print(finalWords)
game = Game()
game.getWords("http://members.optusnet.com.au/charles57/Creative/Techniques/random_words.htm")
when I call game.getWords I get an error that says finalWords is not defined, how do I avoid this? I'm new to using classes. Thanks.

You define finalWords in __init__ but then __init__ ends, and that local variable disappears. You probably want to store it as an attribute of the instance, by using self.finalWords throughout.
BTW, your use of a list comprehension in getWords creates a list of None which you then throw away. Don't use a list comprehension for its side effects. You should use a regular for loop instead, or a set if order isn't important (since a set can contain a particular item only once).

Your finalWords is a local variable in your constructor, not an instance field.
Unlike in Java or C#, you have to always qualify your instance fields with the actual instance, which in methods is normally named self.
This will work:
def __init__(self):
self.words = []
self.finalWords = []
def getWords(self, url):
# your code....
self.finalWords.append(...)
print self.finalWords

Make words and finalWords instance attributes. Like this:
import random
import requests
from bs4 import BeautifulSoup
import random
import time
class Game(object):
def __init__(self):
self.words = []
self.finalWords = []
def getWords(self,url):
sourceCode = requests.get(url).text
soup = BeautifulSoup(sourceCode, 'html.parser')
self.words = soup.get_text().lower().split()
[self.finalWords.append(item) for item in self.words if item not in self.finalWords]
print(self.finalWords)
game = Game()
game.getWords("http://members.optusnet.com.au/charles57/Creative/Techniques/random_words.htm")

Related

AttributeError: 'str' object has no attribute 'soup'

I am just trying to print my raw text from bs4. However, I cant access the attribute from inside one of my methods. But I can access the attribute just fine from outside the class.
import requests
from bs4 import BeautifulSoup
from pprint import pp
import datetime
import time
stocklist = ["wish","clov","baba","pltr",'mu','nio','sofi','tsla','gme','clne',]
class Stock:
def __init__(self,stocklist,s):
self.address = Stock.AG(stocklist,s)
self.soup = Stock.Soup(stocklist,s)
self.volume = Stock.Volume(stocklist,s)
self.price = Stock.Price(stocklist,s)
def AG(stocklist,s):
stockurl = str(('https://robinhood.com/stocks/'+stocklist[s]))
return(stockurl)
def Soup(stocklist,s):
r = requests.get('https://robinhood.com/stocks/'+stocklist[s])
soup = str(BeautifulSoup(r.content, 'lxml'))
return(soup)
def Volume(stocklist,s):
print(stocklist[s].soup) # does not work
def Price(stocklist,s):
pass
for s in range(len(stocklist)):
stocklist[s] = Stock(stocklist,s)
print(stocklist[s].address)
print(stocklist[s].volume)
print(stocklist[s].soup) #works
So this is because when you are calling the volume function stocklist[s] still refers to the string not to the object. Think about when you are calling the init method and hows it being called before the list is overwritten.
The very quick and dirty solution I came up with which should not be deployed but highlights the problem is to change you init method to this.
def __init__(self,stocklist,s):
self.address = Stock.AG(stocklist,s)
self.soup = Stock.Soup(stocklist,s)
stocklist[s] = self
self.volume = Stock.Volume(stocklist,s)
self.price = Stock.Price(stocklist,s)

Recursively calling function on certain condition

I have a function that extracts the content from a random website every time using beautifulsoup library where I get random content every time. I'm successfully able to extract the content..... but let's say (if the output text is 'abc'). I want to re-call the function again and again until I get a different output. I added an if condition to make it done but somehow it's not working as I thought:
class MyClass:
def get_comment(self):
source = requests.get('https://www.example.com/random').text
soup = BeautifulSoup(source, 'lxml')
comment = soup.find('div', class_='commentMessage').span.text
if comment == "abc":
logging.warning('Executing again....')
self.get_comment() #Problem here....Not executing again
return comment
mine = MyClass()
mine.get_comment() # I get 'abc' output
When you call your function recursively you aren't doing anything with the output:
class MyClass:
def get_comment(self):
source = requests.get('https://www.example.com/random').text
soup = BeautifulSoup(source, 'lxml')
comment = soup.find('div', class_='commentMessage').span.text
if comment == "abc":
logging.warning('Executing again....')
return self.get_comment() #Call the method again, AND return result from that call
else:
return comment #return unchanged
mine = MyClass()
mine.get_comment()
I think this should be more like what you're after.

Best way to define multiple list variables inside class in Python

I have created a script that stores and edits meta-data in a system. I am now cleaning up my code by defining a class and methods, previously I only used separate functions.
In the script I am storing old and new values of certain types of metadata in lists, which I print out after the script has completed its run. I have defined multiple lists (16 to be exact), which I realized is quite a lot when passing them through a method. I was wondering what is the most pythonic way to approach this.
These are the following list variables that i define in the beginning. In the function/method I append values to them. In the end I print the stored valued out as a report.
split_name = []
split_name_new = []
name = []
name_new = []
meta = []
meta_new = []
series = []
series_new = []
product = []
owner = []
desc = []
desc_new = []
keywords = []
keywords_new = []
no_edit_page =[]
no_edit_page_name = []
In a class i figured it will look something like (if I define all the list separately)
class Metadata_editor():
def __init__(self,url):
self.split_name = []
self.split_name_new = []
self.name = []
self.name_new = []
self.meta = []
self.meta_new = []
self.series = []
self.series_new = []
self.product = []
self.owner = []
self.desc = []
self.desc_new = []
self.keywords = []
self.keywords_new = []
self.no_edit_page =[]
self.no_edit_page_name = []
#Ugly solution because the method gets crowded by all the variables passed through
def data_edit(self, split_name, split_name_new, name, name_new,.. etc):
#Not the whole method, but just to give some idea..
#Selenium function that locates meta
md = driver.find_element_by_xpath("//input[#name='metadata-name']")
meta_data = md.get_attribute("value")
#replace_words translate the word using a dictionary object
meta_data_new = replace_words(meta_data,c)
meta.append(meta_data)
meta_new.append(meta_data_new)
The solution above I realized would not be ideal.
I found an alternative way that I could use, which is I define a list of lists. The solution would then look something like this (see below). However 'data_list[10]' is not as self-explanatory as for say 'owner'. My question is, is this the 'best' way to solve this, or do you have any other suggestions? I don't really have anything against this solution, but was wondering if there is a more 'pythonic' way to approach this.
class Metadata_editor():
def __init__(self,url):
self.data_list=[[] for _ in range(16)] #Creates a list, that contains 16 lists
# More eloquent solution, as only one variable is passed through. However finding
# the right data from data_list is perhaps not as easy before
def data_edit(self, data_list):
md = driver.find_element_by_xpath("//input[#name='metadata-name']")
meta_data = md.get_attribute("value")
meta_data_new = replace_words(meta_data,c)
data_list[5].append(meta_data)
data_list[6].append(meta_data_new)
You could store it as a dictionary. That would have the advantage of being able to reference the keys by name rather than having to remember the indexes.
class Metadata_editor():
def __init__(self, url):
keys = [
'split_name', 'split_name_new', 'name', 'name_new' 'meta', 'meta_new',
'series', 'series_new', 'product', 'owner', 'desc', 'desc_new',
'keywords', 'keywords_new', 'no_edit_page', 'no_edit_page_name',
]
self.data_dict = dict((x, []) for x in keys)
def data_edit(self):
md = driver.find_element_by_xpath("//input[#name='metadata-name']")
meta_data = md.get_attribute("value")
meta_data_new = replace_words(meta_data,c)
self.data_dict['meta'].append(meta_data)
self.data_dict['meta_new'].append(meta_data_new)
A few extra points to note:
class names generally follow the UpperCaseCamelCase convention. So Metadata_editor would more conventionally be written as MetadataEditor
Using self sets an attribute on the class, it can be accessed in the class using self and the attribute does not need to be passed into the method. I have shown this in the example above, accessing self.data_dict in the data_edit method.
You can also use setattr to set attributes to the class as shown in some of the other answers.
You can initialize multiple lists as below:
class Metadata_editor():
def __init__(self,list_names):
[setattr(self,name,[]) for name in list_names]
me = Metadata_editor(['split_name','split_name_new']) # initialize two lists
me.split_name.append(5) # add value to a list
print(me.split_name, me.split_name_new)
>>[5], [ ]
Once set as part of the class via self.list_name, the list(s) can be accessed globally within the class - no longer requiring to be 'passed in'. To initialize lists to specific values, you can do:
def __init__(self,list_names,list_values):
[setattr(self,name,value) for name,value in zip(list_names,list_values)]
Use setattr:
...
def __init__(self, url):
names = '''split_name split_name_new name
name_new meta meta_new series series_new
product owner desc desc_new keywords
keywords_new no_edit_page
no_edit_page_name'''.split()
for name in names:
setattr(self, name, [])
...

How to resolve attribute error in python

on the begin I'll say that I was looking for the answer but can't find it and sorry for so basic question.I created program with TTS. I created global variable called "list_merge", but most of you said that global variables are BAD. So I decided to put this list in init. PS. ignore whitespaces, they exist only because I copied it here.
the error is:
AttributeError: 'Ver2ProjectWithTTS' object has no attribute 'list_merge'
import json
import pyttsx
from openpyxl import load_workbook
class Ver2ProjectWithTTS(object):
def __init__(self):
self.read_json_file()
self.read_xml_file()
self.say_something()
self.list_merge = []
def read_json_file(self):
with open("json-example.json", 'r') as df:
json_data = json.load(df)
df.close()
for k in json_data['sentences']:
text_json = k['text']
speed_json = int(k['speed'])
volume_json = float(k['volume'])
dict_json = {'text': text_json, 'speed': speed_json, 'volume': volume_json}
self.list_merge.append(dict_json)
def read_xml_file(self):
tree = et.parse('xml-example.xml')
root = tree.getroot()
for k in range(0, len(root)):
text_xml = root[k][0].text
speed_xml = int(root[k][1].text)
volume_xml = float(root[k][2].text)
dict_xml = {'text': text_xml, 'speed': speed_xml, 'volume': volume_xml}
self.list_merge.append(dict_xml)
def say_something(self):
for item in self.list_merge:
engine = pyttsx.init()
engine.getProperty('rate')
engine.getProperty('volume')
engine.setProperty('rate', item['speed'])
engine.setProperty('volume', item['volume'])
engine.say(cleared_text)
engine.runAndWait()
if __name__ == '__main__':
a = Ver2ProjectWithTTS()
I'm getting
AttributeError: 'Ver2ProjectWithTTS' object has no attribute 'list_merge'
Any ideas how to avoid this error? Well i'm not good in objectivity and I just cant move on without fixing this. PS. with global variable before init def it worked properly.
Thanks for help :)
You have to set if first before you use it:
class Ver2ProjectWithTTS(object):
def __init__(self):
# first set it
self.list_merge = []
self.read_json_file()
self.read_xml_file()
self.say_something()
Anyway don't do any advanced logic in constructors, it's not a good practice. Make a method instead:
class Ver2ProjectWithTTS(object):
def __init__(self):
# first set it
self.list_merge = []
def do_the_job(self):
self.read_json_file()
self.read_xml_file()
self.say_something()
...
instance = Ver2ProjectWithTTS()
instance.do_the_job()

next string of a stream in VB.net

I have a some bunch of python files. I need to get all the classes from there and make a list.
its like I have to read with streamreader and then
Imports ActionBlock
I have to take the string ActionBlock and show it in a list. Listing and others hopefully I can do, but I am stuck in this point. Any suggestion please? Thank you.
You could use a regular expression to look for the parts you're interested in.
The following code
Dim path = "c:\path\to\your\file.py"
Dim content = File.ReadAllText(path)
Dim matchClass = "class (?<m>\w+)(:|\()+"
Dim matchImport = "(^|from \w+ )import ((?<m>\w+), )*(?<m>\w+)"
Dim result = Regex.Matches(content, String.Format("({0}|{1})", matchClass, matchImport), RegexOptions.Multiline) _
.Cast(Of Match) _
.SelectMany(Function(m) m.Groups("m").Captures.Cast(Of Capture).Select(Function(c) c.Value)) _
.ToList()
will, given a text file like
import os
import math
from time import clock
from random import randint
import DataArchiving
import TABasicFunctions
import HWDataConveterGate
import GeneralTestDataMapping
from something import FirstClass, SecondClass
def foo():
pass
def bar():
pass
class ClassOne(object):
class NestedClass:
pass
def thisisnotaclass(self):
v = [x.class for x in self]
v = [x.someimport for x in self]
class ClassTwo:
pass
class Class3:
pass
def main():
pass
if __name__ == '__main__':
main()
create a list that looks like:

Categories

Resources