Je travaille sur un script qui me permet de me connecter à la base de données satellite Sentinel pour télécharger les fichiers cartographiques demandés.
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,
)
Mon problème est que le type d'entrée "satellite" que je vais utiliser changera quels autres arguments sont nécessaires, requis ou même autorisés. Certains n'auront pas besoin de "sensormode" et d'autres auront peut-être besoin de "cloudcoverage". Comment pourrais-je écrire un code propre avec des arguments variables / optionnels dans une fonction au sein d'une fonction? Dois-je énumérer tous les arguments possibles?
3 Réponses :
Je pense que cela serait bien résolu par ** kwargs. Cela vous permet de passer n'importe quel argument de clavier à une fonction sans spécifier ensuite dans la signature de la fonction, c'est-à-dire:
def foobar(foo, **kwargs): bar = kwargs["bar"] return foo + bar barfoo = foobar(foo='something', bar='other_thing')
Merci pour votre réponse! Utiliser ** kwargs semble être l'option la plus simple. J'ai créé un dictionnaire en dehors de la fonction et je le donnerai simplement comme un ** kwarg à la fonction à utiliser dans l'API. semble fonctionner jusqu'à présent
Cette API semble trop fastidieuse à utiliser. Mieux vaut grouper les arguments avec des classes.
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)
Je n'ai aucune idée de ce qu'est une empreinte. Si différentes requêtes peuvent utiliser une empreinte différente et que les requêtes réutilisent souvent les mêmes empreintes, créez une classe Location pour l'empreinte.
Merci pour votre réponse rapide! Je vais examiner votre code. L'empreinte est juste un fichier geojson d'un polygone avec les coordonnées dont je veux obtenir les images satellite.
Je trouve que la réponse de Crawl Cycle est très pythonique et belle, alors je recommande d'y aller. Quoi qu'il en soit, je me suis amusé à travailler dessus, alors voici mon interprétation de ce que vous recherchiez :)
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))
Démo: http://tpcg.io/AONnvHn9 .
Il y a quelques contraintes qui gardent cette implémentation aussi concise qu'elle est:
Qu'est-ce que "dans une fonction dans une fonction"? Qu'est-ce qui détermine les arguments nécessaires?