簡體   English   中英

Python語法糖:函數arg別名

[英]Python syntactic sugar: function arg aliases

是否存在別名函數args的語法? 如果沒有,是否有任何PEP提案? 我不是編程語言理論家,所以我的觀點可能不知情,但我認為實現某種函數arg別名可能很有用。

我正在對libcloud進行一些更改,我的想法可以幫助我在修改API時避免破壞其他人。

例如,假設我正在重構並想將函數arg'foo'重命名為'bar':

原版的:

def fn(foo):
    <code (using 'foo')>

我可以:

def fn(foo, bar=None):
    if foo and bar:
        raise Exception('Please use foo and bar mutually exclusively.')
    bar = foo or bar
    <code (using 'bar')>

# But this is undesirable because it changes the method signature to allow
# a new parameter slot.
fn('hello world', 'goodbye world')

我的未定義的句法糖想法:

def fn(bar|foo|baz):
    # Callers can use foo, bar, or baz, but only the leftmost arg name
    # is used in the method code block. In this case, it would be bar.
    # The python runtime would enforce mutual exclusion between foo,
    # bar, and baz.
    <code (using 'bar')>

# Valid uses:
fn(foo='hello world')
fn(bar='hello world')
fn(baz='hello world')
fn('hello world')

# Invalid uses (would raise some exception):
fn(foo='hello world', bar='goodbye world')
fn('hello world', baz='goodbye world')

不,沒有這樣的語法糖。

您可以使用**kwargs來捕獲額外的關鍵字參數,並在其中查找已棄用的名稱(如果沒有,則引發異常)。 您甚至可以使用裝飾器自動執行此操作。

from functools import wraps

def renamed_argument(old_name, new_name):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if old_name in kwargs:
                if new_name in kwargs:
                    raise ValueError(
                        "Can't use both the old name {} and new name {}. "
                        "The new name is preferred.".format(old_name, new_name))
                kwargs[new_name] = kwargs.pop(old_name)
            return func(*args, **kwargs)
        return wrapper
    return decorator

@renamed_argument('bar', 'foo')
def fn(foo=None):
    <method code>

演示:

>>> @renamed_argument('bar', 'foo')
... def fn(foo=None):
...     return foo
...
>>> fn()  # default None returned
>>> fn(foo='spam')
'spam'
>>> fn(bar='spam')
'spam'
>>> fn(foo='eggs', bar='spam')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in wrapper
ValueError: Can't use both the old name bar and new name foo. The new name is preferred.

沒有persopses,你可以使用裝飾器(如上所示),或第一手使用kwargs:

def fn (**kw):
    arg = kw.get("foo") or kw.get("bar") or kw.get("baz")
    if arg==None: raise TypeError, "foo nor bar nor baz given az argument"
    print arg

Here the order of precedence is: "if foo exists, arg is foo. if it doesn't but bar exists, arg is bar, if neither foo nor bar exists, the arg is baz. If baz doesn't, i.e. all 3 are missing, arg is None.

Of course, you may check whether either one exists and force the mutual exclusion, but I don't see why would you need such a thing.

You are clever and you will never pass them in together. Even if you do, some will be ignored.

您也可以使用可調用對象來執行此操作,如果需要,甚至可以在運行時將語法和行為引入解釋器。

但在我看來,將此作為有效的Python語法引入並不是Pythonic,即使有PEP也不會發生。

如您所見,您可以執行您想要的操作而不會弄臟Python語法。

我並不是說你的例子在語法上不清楚,只是沒必要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM