Hi im new to Python and im trying to figure out python classes.
I have made the following script, and I don't understand when I make the object vejr, outside the while loop, it keeps printing the same value over and over again.
If i make the object inside the while loop it works and print the temperature as it changes.
Inside the loop I make a new vejr object every time the loop runs, I thought it would be enough just make the vejr object once?? or is there a better way to write code like this?
import requests
import json
from datetime import datetime
import time
class Owm_data():
def __init__(self, api_key="api_key", lat="51.507351", lon="-0.127758" ):
self.api_key = api_key
self.lat = lat
self.lon = lon
self.url = "https://api.openweathermap.org/data/2.5/onecall?lat=%s&lon=%s&appid=%s&units=metric" % (lat, lon, api_key)
self.response = requests.get(self.url)
self.data = json.loads(self.response.text)
def get_temperature(self):
return self.data["current"]["temp"]
def get_pressure(self):
return self.data["current"]["pressure"]
vejr = Owm_data()
while True:
print(vejr.get_temperature())
time.sleep(30)
I recommend distinguishing between temperature as an attribute versus a method. For instance:
class Owm_data():
def __init__(self, api_key="api_key", lat="51.507351", lon="-0.127758" ):
self.api_key = api_key
self.lat = lat
self.lon = lon
self.temperature = self.get_temperature()
def get_temperature(self):
self.url = "https://api.openweathermap.org/data/2.5/onecall?lat=%s&lon=%s&appid=%s&units=metric" % (lat, lon, api_key)
self.response = requests.get(self.url)
self.data = json.loads(self.response.text)
self.temperature = self.data["current"]["temp"]
return self.temperature
This way, if you want to access the cached value of the temperature, you can do print(vejr.temperature). If you want to update the value of the temperature, you can do print(vejr.get_temperature()). Although you might want to use a name that makes it clear that the temperature is being updated, such as update_temperature().
You pull the data when you initialize the class, and you only do that outside the loop. So your vejr.get_temperature() call is just reproducing the same cached information you saw at construction. If you want to recheck the data each loop, change from:
vejr = Owm_data()
while True:
print(vejr.get_temperature())
time.sleep(30)
to:
while True:
vejr = Owm_data()
print(vejr.get_temperature())
time.sleep(30)
so the class is reconstructed on each loop and repulls the data.
Other solutions might include pulling the data each call to get_temperature and friends, rather than doing it in the initializer, but leaving the design as is is more useful when you want cached data so you can see both temperature and pressure from a single moment of time with one call.
Related
I've never really used classes before, I just simply went the easy way (global variables), and now I would like to make my code right to avoid future complications.
This is my code:
from dearpygui.core import *
class Engine:
def __init__(self,serial,type,profile):
self.serial = serial
self.type = type
self.profile = profile
def apply_selected_file():
res = []
html_name= "example.html"
path= "C:/"
#Function that reads data from a file and saves selected data in a list
res = html_imp(path + '/' + html_name)
#I would like to remove the code below and use a class for each file instead
setvalue(sn1,es[0]) #shows a label with this value
setvalue(type1,res[1]) #shows a label with this value
setvalue(profile1,res[2]) #shows a label with this value
return res
def button():
#This was my initial idea but it doesn't seem to work.
# res = apply_selected_file()
# E = Engine(res[0],res[1],res[2])
I have in mind reading multiple HTML files so using a class would be much easier than declaring variables for each file:
1- Use apply_selected_file to read a file and assign values (s/n,type,profile) to a new class (E1,E2,E3,...,E20,...)
2- Use another function button() to access those stored class values.
I'm writing a script to find the moving average of different stocks. This script runs continuously, looping through my API call to add the current price to a list before averaging it. This works fine, however I'd like to be able to put this into a function to where the only input I need to give it is the name of the stock. I'd like this script to work for as many stocks as I want to specify, at the same time. That's where I run into issues because for each stock I have I need to have an empty list predefined that can hold the pricing information.
I've been trying to use the name of the stock to then create a related list, but as I now understand it it's not a great idea using one variable name to create another variable, so I'm not sure what to do. I believe the usual solution here would be to use a dictionary, but I'm a beginner to programming in general so I haven't figured out how to fit that into my situation. Any help would be greatly appreciated.
def sma(stock_name):
list_exists = stock_name + "_list" in locals() or stock_name + "_list" in globals()
if list_exists:
print()
else:
stock_name + "_list" = [] # Problem line, I would like for this to create a list called stock_name_list
stock_price = requests.get("myapi.com", params={"stock_name": stock_name, "bla bla": "blah"})
stock_name_list.append(stock_price)
When you have an operation based on a version of the data specific to that operation, that is usually a good time to think about using classes. This particular proposed class will encapsulate the name of a stock, the list of data specific to it, and perform sma on it:
class Stock:
n = 10
def __init__(self, name):
self.name = name
self.data = []
def sma(self):
stock_price = requests.get("myapi.com", params={"stock_name": self.stock_name, "bla bla": "blah"})
self.data.append(stock_price)
window = self.data[-n:]
return sum(window) / len(window)
Now you can maintain a dictionary of these objects. Any time you encounter a new stock, you just add an item to the dictionary:
stocks = {}
def sma(name):
stock = stocks.get(name)
if name is None: # None is what get returns when the key is missing
stock = Stock(name)
stocks[name] = stock
return stock.sma()
The nice thing is that you now have a dictionary of named datasets. If you want to add a different statistic, just add a method to the Stock class that implements it.
I defined a global sma function here that calls the eponymous method on the object it finds in your dictionary. You can carry encapsulation to an exterme by making the method perform the action of the function if called statically with a name instead of an instance. For example:
class Stock:
n = 10
named_stocks = {} # This is a class variable that replaces the global stocks
def __init__(self, name):
self.name = name
self.data = []
def sma(self):
if isinstance(self, str):
self = Stock.get_stock(self)
stock_price = requests.get("myapi.com", params={"stock_name": self.stock_name, "bla bla": "blah"})
self.data.append(stock_price)
window = self.data[-n:]
return sum(window) / len(window)
#classmethod
def get_stock(cls, name):
stock = cls.named_stocks.get(name)
if stock is None:
stock = cls(name)
cls.named_stocks[name] = stock
return stock
Now that there is a check for isinstance(self, str), you can call the sma method in one of two ways. You can all it directly on an instance, which knows its own name:
aapl = Stock('AAPL')
aapl.sma()
OR
Stock.get_stock('AAPL').sma()
Alternatively, you can call it on the class, and pass in a name:
Stock.sma('AAPL')
use defaultdict
from collections import defaultdict
stock_name_to_stock_prices = defaultdict(list)
stock_name_to_stock_prices['STOCK_NAME'].append(123.45)
I have a problem that involves collecting data continuously from multiple sources.
My setup as it is currently, writes each data entry from each source to a MySQL db, and then, with another python program, does Select's that bring all the data together. I need to make INSERT's at roughly 1000/second and as it is my SELECT's can take 15-20 seconds each.
The whole process takes so long the data is obsolete before I get to do anything useful with it.
I have created a toy example to try and demonstrate what I am looking for.
program 1 'generateClasses':
import time
import random
from datetime import datetime
class Race:
def __init__(self,name):
hist = {}
now = datetime.now()
self.name = name
self.now = now
hist[now] = 0
self.v = 0
self.hist = hist # example variable's.
def update(self,name,v):
now = datetime.now()
hist = self.hist
hist[now] = v
self.v = v
self.now - now
self.hist = hist
class Looper:
def __init__(self,name):
self.a = Race(name)
def loop(self,name):
# simulating the streaming API
while True:
v = self.a.v
v += 1
self.a.update(name,v)
print(a,datetime.now(),v) # can i access this stream using the location displayed with the print(a)?
time.sleep(0.1) # this should be more like time.sleep(0.001)
def pickData(self,name):
v = self.v
self.loop(name)
print('The state at {} {} = '.format(self.now,self.v))
return self.hist
if __name__ == "__main__":
x = 'Some_ID'
a = Looper(x)
a.loop(x)
program 2:
from generateClasses import Looper
from datetime import datetime
import time
start_time = int((datetime.now() - datetime(1970, 1, 1)).total_seconds())
print(start_time)
x = 'Some_orher_ID'
a = Looper(x)
print('this will print')
a.loop(x)
print('this wont ever print')
a.pickdata(x)
# this last section is the functionality i am looking for in this program, but, as it is, it will never run.
x = ‘Some_ID’
while True:
now_time = int((datetime.now() - datetime(1970, 1, 1)).total_seconds())
print(start_time)
if int(now_time-start_time) == 10:
a.pickData(x)
# b.pickData(x)
# c.pickData(x)
# d.pickData(x)
# make further actions.....
What happens currently in my examples is that it creates its own loop using the class structure from the first program.
What I want it to do is call the the pickData() method from program 2 at timely intervals of my choosing on a loop running in another program.
Is my best option picking a db located in memory and getting a faster computer?
Maybe something can be done with the object location shown when you print the instance name?
I have uploaded to github if anybody fancies it..
I would be grateful of any suggestions.
also, recommendations for further reading would be appreciated also.
My question is about getter/setter-type functionality in Python. I have a class, Week_Of_Meetings, that takes a blob of data from my Google Calendar and does some calculations on it.
wom = Week_Of_Meetings(google_meetings_blob)
I want to be able to return something like:
wom.total_seconds_in_meetings() # returns 36000
But, I'm not understanding how the getters/setters-type #property decorator can help me do this. In Java, I would use member variables, but you don't interact with them the same way in Python. How can I return calculations without starting with them in the constructor?
Class Week_Of_Meetings:
def __init__(self, google_meetings_blob)
self.google_meetings_blob = google_meetings_blob
def get_meetings_list(self, google_meetings_blob):
meetings_list = []
for meeting_id, meeting in enumerate(self.google_meetings_blob, 1):
summary = self._get_summary(meeting)
start = parse(meeting['start'].get('dateTime', meeting['start'].get('date')))
end = parse(meeting['end'].get('dateTime', meeting['end'].get('date')))
duration = end - start
num_attendees = self._get_num_attendees(meeting.get('attendees'))
m = Meeting(meeting_id, summary, start, end, duration, num_attendees)
meetings_list.append(m)
return meetings_list
def _get_summary(self, meeting):
summary = meeting.get('summary', 'No summary given')
return summary
def _get_num_attendees(self, num_attendees):
if num_attendees == None:
num_attendees = 1 # if invited only self to meeting
else:
num_attendees = len(num_attendees)
return num_attendees
When I add self.total_seconds_in_meetings to the
__init__()
I get "NameError: global name 'total_seconds_in_meetings' is not defined." That makes sense. It hasn't been defined. But I can't define it when it's supposed to be the result of calculations done on the google_meetings_blob. So, I'm confused where the 'total_seconds_in_meetings' goes in the class.
Thank you for the help!
Of course Python has member variables. How would classes work without them? You can set and get any instance data via self, as you are already doing with self.google_meetings_blob in __init__.
I am building my first GUI in pyQT5 and I am pretty new to Python programming.
I am trying to use a set a Variable in one Qthread and using it in another. I figured that pyqtsignal was the way to do it. But i can't get it to work.
class GetCurrentSpeed(QThread):
gpsLatSig = pyqtSignal(str)
def __init__(self):
QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
while True:
####Print a value in lon and lat so that its never empty
lon = "18"
lat = "59"
###Get Current Latitude and Longitude
if report['class'] == 'TPV':
if hasattr(report, 'lat'):
lat = (str(report.lat))
self.gpsLatSig.emit(lat)
else:
lat = "59"
print("No GPS Lock")
self.gpsLatSig.emit(lat)
class PosSignals(QObject):
GetGps = GetCurrentSpeed()
def connectsig(self):
self.GetGps.gpsLatSig[str].connect(self.handle_string)
#pyqtSlot(str)
def handle_string(self, text):
print text
class OverPassApi(QThread):
GetGps = GetCurrentSpeed()
def __init__(self):
QThread.__init__(self)
self.b = PosSignals()
def __del__(self):
self.wait()
def run(self):
while True:
self.b.connectsig()
print b.handle_string()
api = overpy.Overpass()
result = api.query("""<osm-script>
<query type="way">
<around lat="%s" lon="%s" radius="30"/>
<has-kv k="name" v=""/>
</query>
<print/>
</osm-script>""" % (b.handle_string, 18))
This is just a part of the program and this might contain other errors since i have worked hard to get this to work.
My Issue is that I get the output "<main.PosSignals object at 0x72f0c210>" when i try to print the text in the handle function when i remove self like:
#pyqtSlot(str)
def handle_string(text):
print text
and when I keep self I need to provide an argument to the print b.handle_string() which then ofcourse only prints the argument I add.
What I want to achieve is to use the lat variable created in GetCurrentSpeed(QThread): and use it in class OverPassApi(QThread):
Looks like you simply forgot a self argument for handle_string.