【问题标题】:Variable/optional arguments in a function within a function函数内函数中的变量/可选参数
【发布时间】:2021-02-16 16:15:33
【问题描述】:

我正在编写一个脚本,让我可以连接到 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,
                         )

我的问题取决于我将使用哪种“卫星”输入,这将改变哪些其他参数是必要的、必需的甚至是允许的。有些不需要“sensormode”,有些可能需要“cloudcoverage”。我将如何在函数内的函数中编写带有变量/可选参数的干净代码?我必须列出所有可能的论点吗?

【问题讨论】:

  • “函数中的函数”是什么意思?是什么决定了需要哪些参数?

标签: python function arguments sentinel1 sentinelsat


【解决方案1】:

我相信 **kwargs 会很好地解决这个问题。这允许您将任何 keywork 参数传递给函数,而无需在函数签名中指定 then 即:

def foobar(foo, **kwargs):
   bar = kwargs["bar"]
   return foo + bar


barfoo = foobar(foo='something', bar='other_thing')

【讨论】:

  • 感谢您的回答!使用 **kwargs 似乎是最简单的选择。我在函数外部创建了一个字典,并将其作为 **kwarg 提供给要在 API 中使用的函数。到目前为止似乎正在工作
【解决方案2】:

那个 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 类。

【讨论】:

  • 感谢您的快速答复!我会调查你的代码。足迹只是一个多边形的 geojson 文件,其中包含我想要从中获取卫星图像的坐标。
【解决方案3】:

我发现 Crawl Cycle 的答案非常 Pythonic 和漂亮,所以我建议这样做。无论如何,我在这方面工作很开心,所以这是我对您正在寻找的内容的解释:)

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))

Try it Online

有一些限制可以使这个实现尽可能简洁:

  • 所有 API 签名都必须是唯一的。
  • 所有 API 签名只接受关键字参数

【讨论】:

    猜你喜欢
    • 2011-10-12
    • 1970-01-01
    • 2019-01-17
    • 1970-01-01
    • 2014-10-18
    • 2011-01-09
    • 2022-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多