I am writing a module. how to get json not for each parameter separately. and on all request entirely?

for example, I request temperature and humidity. json is requested 2 times than it consumes a limit of calls to api and slows down the work

import urllib.request, json import datetime def time_converter(time): converted_time = datetime.datetime.fromtimestamp( int(time) ).strftime('%H:%M') return converted_time def geturl(city): #Moscow urll = 'http://api.openweathermap.org/data/2.5/weather?q=' + city +',ru&mode=json&units=metric&lang=ru&appid=*******' with urllib.request.urlopen(urll) as url: data = json.loads(url.read().decode()) return data #print(data) def temp(city): temp = str(geturl(city)['main']['temp'])+'\xb0' + 'C'+'\n' return temp def pressure(city): pressure = str(geturl(city)['main']['pressure'])+' ммРтСт'+'\n' return pressure def humidity(city): humidity = str(geturl(city)['main']['humidity'])+'%'+'\n' return humidity def temp_min(city): temp_min = str(geturl(city)['main']['temp_min'])+'\xb0' + 'C'+'\n' return temp_min def temp_max(city): temp_max = str(geturl(city)['main']['temp_max'])+'\xb0' + 'C'+'\n' return temp_max def visibility(city): visibility = str(geturl(city)['visibility'])+'метров'+'\n' return visibility def wind(city): wind= str(geturl(city)['wind']['speed'])+'м/с'+'\n' return wind def weather(city): weather = str(geturl(city)['weather'][0]['description']) + '\n' return weather def sunrise(city): sunrise = str(time_converter(geturl(city)['sys']['sunrise'])) + '\n' return sunrise def sunset(city): sunset = str(time_converter(geturl(city)['sys']['sunset'])) + '\n' return sunset 
  • If you have geturl(city) everywhere, then make a general method of getting information. And from the information you pull out separately for all data: wind, weather, visibility, etc. Then the request will be one. - gil9red

2 answers 2

If you have geturl (city) everywhere, then make a general method of getting information. And from the information you pull out separately for all data: wind, weather, visibility, etc. Then the request will be one.

Example:

 import urllib.request, json import datetime def get_data(city): urll = 'http://api.openweathermap.org/data/2.5/weather?q=' + city + ',ru&mode=json&units=metric&lang=ru&appid=bd5e378503939ddaee76f12ad7a97608' with urllib.request.urlopen(urll) as url: data = json.loads(url.read().decode()) return data def temp(data): temp = str(data['main']['temp'])+'\xb0' + 'C'+'\n' return temp def pressure(data): pressure = str(data['main']['pressure'])+' ммРтСт'+'\n' return pressure def humidity(data): humidity = str(data['main']['humidity'])+'%'+'\n' return humidity 

Using:

 data = get_data("Moscow") print(temp(data)) print(pressure(data)) print(humidity(data)) 

In addition, this problem is perfectly solved through the classes.

Show here a fantasy example:

 class CityWeatherInfo: def __init__(self, city): self.city = city self.data = None self.sync_data() def sync_data(self): urll = 'http://api.openweathermap.org/data/2.5/weather?q=' + self.city + ',ru&mode=json&units=metric&lang=ru&appid=bd5e378503939ddaee76f12ad7a97608' with urllib.request.urlopen(urll) as url: self.data = json.loads(url.read().decode()) def temp(self): temp = str(self.data['main']['temp'])+'\xb0' + 'C'+'\n' return temp def pressure(self): pressure = str(self.data['main']['pressure'])+' ммРтСт'+'\n' return pressure def humidity(self): humidity = str(self.data['main']['humidity'])+'%'+'\n' return humidity 

Using:

 info = CityWeatherInfo("Moscow") print(info.temp()) print(info.pressure()) print(info.humidity()) 
  • It makes sense to prescribe again the function call sync_data if you call it in __init__ and so call? - Twiss
  • ATP, at first there was a call out, then I decided to add to the constructor so that self.data would not be empty, so I forgot to delete - gil9red

You can separate how data is collected, from how it is displayed. Interesting weather data for the application can be presented in the form of collections.namedtuple :

 from collections import namedtuple Weather = namedtuple('Weather', ['temp', 'pressure', 'humidity', 'temp_min', 'temp_max', 'visibility', 'wind', 'description', 'time']) 

To download weather data from the specified service:

 import datetime as DT import json import os from urllib.parse import quote from urllib.request import Request, urlopen appname = "so-805781-weather-client" __version__ = "0.1.1" appid = os.environ['OPENWEATHERMAP_APPID'] @cache_for(minutes=10) def get_weather_for(city): r = Request('https://api.openweathermap.org/data/2.5/weather?q=' + quote(city) + ',ru&mode=json&units=metric&lang=ru&APPID=' + quote(appid), headers={'User-Agent': f'{appname}/{__version__}'}) with urlopen(r) as response: data = json.loads(response.read().decode()) return Weather(visibility=data['visibility'], wind=data['wind']['speed'], description=data['weather'][0]['description'], time=DT.datetime.now(DT.timezone.utc).astimezone(), **data['main']) 

where @cache_for(minutes=10) caches the results of the function for 10 minutes (see at the end of the answer). Example:

 print(get_weather_for('Moscow')) 

Conclusion:

 Weather(temp=-2.5, pressure=1014, humidity=53, temp_min=-3, temp_max=-2, visibility=10000, wind=2, description='ясно', time=datetime.datetime(2018, 3, 28, 14, 3, 8, 96334, tzinfo=datetime.timezone(datetime.timedelta(0, 10800), 'MSK'))) 

To print the data in the desired format, you can use a simple function:

 from textwrap import dedent def display_weather(info): print(dedent("""\ {temp} ℃ {pressure} ммРтСт {humidity} % {temp_min} ℃ {temp_max} ℃ {visibility} метров {wind} м/с {description} {time:%Y-%m-%d %H:%M:%S}""".format_map(info._asdict()))) 

Example:

 display_weather(get_weather_for('Moscow')) 

Result:

 -2.5 ℃ 1014 ммРтСт 53 % -3 ℃ -2 ℃ 10000 метров 2 м/с ясно 2018-03-28 14:03:08 

If you wish, you can add support for multiple languages, an example .


The implementation of the cache_for() decorator:

 import functools from werkzeug.contrib.cache import FileSystemCache # $ pip install werkzeug cache = FileSystemCache('.cachedir') def cache_for(**timedelta_kwargs): timeout = DT.timedelta(**timedelta_kwargs).total_seconds() def decorator(func): @functools.wraps(func) def wrapper(arg): result = cache.get(key=arg) if not result: result = func(arg) cache.set(arg, result, timeout=timeout) return result return wrapper return decorator