Переменные / необязательные аргументы в функции внутри функции
Я работаю над сценарием, который позволяет мне подключаться к спутниковой базе данных Sentinel для загрузки запрошенных файлов карты.
from sentinelsat import SentinelAPI, read_geojson, geojson_to_wkt
def get_available(input_geojson, user, password, date_start, date_end, satellite, sensormode, product_type):
# LogIn
api = SentinelAPI(user, password , 'https://scihub.copernicus.eu/dhus')
# Input parameter of the search
footprint = geojson_to_wkt(read_geojson(input_geojson)) # irrelevant to the question
products = api.query(footprint,
date = (date_start, date_end),
platformname = satellite,
sensoroperationalmode = sensormode,
producttype = product_type,
)
Моя проблема в том, что в зависимости от того, какой "вспомогательный" ввод я собираюсь использовать, будут изменены другие аргументы, необходимые, обязательные или даже разрешенные. Некоторым не понадобится "сенсорный режим", а другим, возможно, понадобится "облачный охват". Как мне написать чистый код с переменными / необязательными аргументами в функции внутри функции? Должен ли я перечислять все возможные аргументы?
3 ответа
Я считаю, что ответ Crawl Cycle очень питонический и красивый, поэтому я рекомендую пойти с этим. Тем не менее, мне было весело работать над этим, поэтому вот моя интерпретация того, что вы искали:)
import inspect
def foo_api(*, foo=None):
print(f'foo_api: foo={foo}')
def bar_api(*, bar=None):
print(f'bar_api: bar={bar}')
_API_BY_PARAMETERS = {
frozenset(inspect.signature(api).parameters): api
for api in (foo_api, bar_api)
}
def api(**kwargs):
"""Selects the correct API to call based on the given kwargs."""
actual_params = frozenset(kwargs)
if actual_params in _API_BY_PARAMETERS:
actual_api = _API_BY_PARAMETERS[actual_params]
return actual_api(**kwargs)
else:
param_errors = (
(api.__name__,
', '.join(sorted(expected_params - actual_params)),
', '.join(sorted(actual_params - expected_params)))
for expected_params, api in _API_BY_PARAMETERS.items())
raise TypeError(
'Arguments must match exactly with one of the APIs, but found '
'the following differences: ' +
'; '.join(
f'{api_name} -> missing=[{missing}], unexpected=[{unexpected}]'
for api_name, missing, unexpected in param_errors))
Демо: http://tpcg.io/AONnvHn9.
Есть несколько ограничений, которые делают эту реализацию такой лаконичной:
- Все подписи API должны быть уникальными.
- Все сигнатуры API принимают только аргументы ключевого слова.
Этот api кажется слишком утомительным для использования. Лучше сгруппируйте аргументы по классам.
from sentinelsat import SentinelAPI, read_geojson, geojson_to_wkt
class Satellite:
def __init__(self, name, producttype, sensormode=None, cloudcoverage=None):
self.name = name
self.producttype = producttype
self.sensormode = sensormode
self.cloudcoverage = cloudcoverage
class SentinelConnection:
def __init__(self, input_geojson, user, password):
self.input_geojson = input_geojson
self.user = user
self.password = password
self.api = None
self.footprint = None
def __enter__(self):
self.api = SentinelAPI(self.user, self.password,
'https://scihub.copernicus.eu/dhus')
self.footprint = geojson_to_wkt(read_geojson(self.input_geojson))
def __exit__(self, exc_type, exc_val, exc_tb):
# logout here
pass
def get_available(conn, satellite, date_start, date_end):
s = satellite
products = conn.api.query(conn.footprint,
date=(date_start, date_end),
platformname=satellite,
sensoroperationalmode=s.sensormode,
producttype=s.product_type,
)
def main():
with SentinelConnection("abc.json", "name", "password") as conn:
satellite = Satellite('Sputnik X', 'military satellite')
get_available(conn, satellite, date_start, date_end)
У меня нет никакого представления о том, что такое след. Если разные запросы могут использовать разный отпечаток и запросы часто повторно используют одни и те же посадочные места, создайте класс Location для отпечатка.
Я считаю, что **kwargs решит эту проблему. Это позволяет вам передавать любой аргумент ключевой работы функции, не указывая его в сигнатуре функции, то есть:
def foobar(foo, **kwargs):
bar = kwargs["bar"]
return foo + bar
barfoo = foobar(foo='something', bar='other_thing')