亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何強制某些函數參數僅是位置參數

如何強制某些函數參數僅是位置參數

莫回無 2022-09-06 18:09:40
我想在Python3.7中模仿Python3.8的這種行為僅位置參數是引入的語法,用于指示某些函數參數必須按位置指定,并且不能用作關鍵字參數。/#Python3.8def f(a,b,/,**kwargs):    print(a,b,kwargs)>>> f(1,2,**{'a':100,'b':200,'c':300})# 1 2 {'a': 100, 'b': 200, 'c': 300}a,僅用作位置參數。b我如何在Python3.7中做同樣的事情#Python3.7def f(a,b,**kwargs):    print(a,b,kwargs)>>> f(1,2,**{'a':1,'b':2})# TypeError: f() got multiple values for argument 'a'如何使 , 僅作為位置參數。 在 Python3.8 的下面不起作用ab/是否可以在 Python3.7 中模仿語法?/
查看完整描述

1 回答

?
慕的地6264312

TA貢獻1817條經驗 獲得超6個贊

您可以創建一個自定義修飾器來聲明僅位置參數,并返回一個包裝器,該包裝器解析自己的包裝器,以便它們適合修飾函數的簽名。由于僅位置參數和關鍵字參數之間可能存在名稱沖突,因此無法對此方法使用關鍵字參數打包 ()(這是唯一的限制)。打包的關鍵字參數需要聲明為最后一個位置或關鍵字參數,或者聲明為第一個僅關鍵字參數。下面是兩個示例:*args, **kwargs**


def foo(a, b, kwargs):  # last positional-or-keyword parameter

    pass


def foo(a, *args, kwargs):  # first keyword-only parameter

    pass

該變量將從包裝器函數接收剩余的,即它可以類似地使用,就像直接在修飾函數中使用一樣(如在Python 3.8 +中)。kwargs**kwargs**kwargs


以下裝飾器的實現很大程度上是基于檢查的實現。Signature.bind 通過一些小的調整來處理通過裝飾器聲明的名稱僅位置參數,并處理附加(人為)參數。kwargs


import functools

import inspect

import itertools



def positional_only(*names, kwargs_name='kwargs'):

    def decorator(func):

        signature = inspect.signature(func)


        @functools.wraps(func)

        def wrapper(*args, **kwargs):

            new_args = []

            new_kwargs = {}            


            parameters = iter(signature.parameters.values())

            parameters_ex = ()

            arg_vals = iter(args)


            while True:

                try:

                    arg_val = next(arg_vals)

                except StopIteration:

                    try:

                        param = next(parameters)

                    except StopIteration:

                        break

                    else:

                        if param.name == kwargs_name or param.kind == inspect.Parameter.VAR_POSITIONAL:

                            break

                        elif param.name in kwargs:

                            if param.name in names:

                                msg = '{arg!r} parameter is positional only, but was passed as a keyword'

                                msg = msg.format(arg=param.name)

                                raise TypeError(msg) from None

                            parameters_ex = (param,)

                            break

                        elif param.default is not inspect.Parameter.empty:

                            parameters_ex = (param,)

                            break

                        else:

                            msg = 'missing a required argument: {arg!r}'

                            msg = msg.format(arg=param.name)

                            raise TypeError(msg) from None

                else:

                    try:

                        param = next(parameters)

                    except StopIteration:

                        raise TypeError('too many positional arguments') from None

                    else:

                        if param.name == kwargs_name or param.kind == inspect.Parameter.KEYWORD_ONLY:

                            raise TypeError('too many positional arguments') from None


                        if param.kind == inspect.Parameter.VAR_POSITIONAL:

                            new_args.append(arg_val)

                            new_args.extend(arg_vals)

                            break


                        if param.name in kwargs and param.name not in names:

                            raise TypeError(

                                'multiple values for argument {arg!r}'.format(

                                    arg=param.name)) from None


                        new_args.append(arg_val)


            for param in itertools.chain(parameters_ex, parameters):

                if param.name == kwargs_name or param.kind == inspect.Parameter.VAR_POSITIONAL:

                    continue


                try:

                    arg_val = kwargs.pop(param.name)

                except KeyError:

                    if (param.kind != inspect.Parameter.VAR_POSITIONAL

                            and param.default is inspect.Parameter.empty):

                        raise TypeError(

                            'missing a required argument: {arg!r}'.format(

                                arg=param.name)) from None

                else:

                    if param.name in names:

                        raise TypeError(

                            '{arg!r} parameter is positional only, '

                            'but was passed as a keyword'.format(arg=param.name))


                    new_kwargs[param.name] = arg_val


            new_kwargs.update(kwargs=kwargs)

            return func(*new_args, **new_kwargs)

        return wrapper

    return decorator

以下是如何使用它的示例:


@positional_only('a')

def foo(a, *args, kwargs, b=9, c):

    print(a, args, b, c, kwargs)


foo(1, **dict(a=2), c=3)  # ok

foo(1, 2, 3, 4, 5, c=6)  # ok

foo(1, b=2, **dict(a=3), c=4)  # ok

foo(a=1, c=2)  # error

foo(c=1)  # error


查看完整回答
反對 回復 2022-09-06
  • 1 回答
  • 0 關注
  • 170 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號