Python函数参数与默认参数

3

我是初学者,想要用Python定义一个带有“from”和“to”日期的函数。如果我只传递一个参数调用该函数,它应该将该参数视为“to”日期。如果我传递两个参数,它应该将其分配给“from”和“to”日期。

我定义如下:

def __init__(self,fdate="",edate):
        self.fdate = fdate
        self.edate = edate

我遇到了以下错误:

    def __init__(self,fdate="",edate):
                ^
SyntaxError: non-default argument follows default argument

我理解这个错误。但是在Python中,我该如何定义一个符合我的要求的函数?


交换 edatefdate 的位置。 - heemayl
1
具有默认值的参数必须放在没有默认值的参数后面。 - Tim
7个回答

1

1
当您传递一个值默认参数时,其右侧的所有参数也应具有默认值。这同样适用于C ++。
例如:
有效 def example(a = 1, b = 2):pass 有效 def example(a, b = 2):pass
错误 def example(a = 1, b):pass

0
当您传递一个值默认参数时,其右侧的所有参数也应具有默认值。
对于任何其他编程语言也是如此。这种限制的原因是否则将无法确定您正在尝试传递哪些参数。假设以下函数:
def foo(first = 'default', second = 'default', third) 
    pass

现在我们正在调用它

foo('custom_value', 'another_value')

parameters 中的 another_value 显然是 third 参数的值,但 custom_value 代表哪个参数呢?是 first 还是 second?你只能猜测,而猜测对于编程语言来说是非常糟糕的事情,因为它限制了程序员的可预测性。

解决这个问题的方法是使用命名参数传递。在像 PHP 这样的任何其他编程语言中,它可能看起来像:

foo($first='custom_value', 'another_value');

现在清楚了你要覆盖哪个默认值。

Python支持这种语法。

foo(first='custom_value', third='another_value')

但例如,PHP目前还没有这个功能。因此,在调用函数时,您需要每次都注意这一步骤,这会给程序员带来不必要的开销。这就是为什么将所有默认参数放在右侧是一个好习惯。

以下是一些有效和无效参数的示例。

有效

def example(a = 1, b = 2):
    pass

有效

def example(a , b = 2):
    pass

无效

def example(a = 1, b):
    pass

如需了解C++中参数顺序的更多信息,请查看此处

如需了解Python中参数顺序的更多信息,请查看此处


0
语法错误:默认参数后面跟随非默认参数。
您的默认参数必须放在非默认参数后面。
原因是:如果混淆了参数,解释器将很难分配它们。所以它不支持并会抛出语法错误。
只需将其更改为
def __init__(self, edate, fdate=""):

@编辑1:像 Kotlin 这样的一些语言允许您在非默认参数之前拥有默认参数。在这种情况下,您将使用命名参数来设置函数参数。


0

正如错误信息所说, 默认参数应该跟在非默认参数后面,像这样:

def __init__(self, edate, fdate=""):
    self.fdate = fdate
    self.edate = edate

请参考文档,其中清晰地描述了这种行为。

0
这是我的解决方案:我会编写一个小类和两个工厂函数,调用类构造函数并返回结果:
class DateRange:
    def __init__(self, dfrom='', dto=''):
        self.dfrom = dfrom
        self.dto = dto

def date_from_to(dfrom, dto):
    return DateRange(dfrom, dto)

def date_to(dto):
    return DateRange(dto=dto)

从错误信息中可以看出,您无法定义一个按照您想要的方式运行的函数。如果您使用两个函数,很容易对它们进行文档化并记住如何使用它们。


0

你可以得到想要的功能,但代码会变得更长,如果你想添加参数,那么维护起来会变得非常困难。你可以捕获所有的参数和关键字参数,然后决定如何处理它们:

class Test:
    def __init__(self, *args, **kwargs):
        self.__args, self.__kwargs = args, kwargs
        self.edate = ""
        self.fdate = ""

        # Sanity checking the arguments
        if len(args) + len(kwargs) < 1:
            raise ValueError('Too few arguments.')
        if len(args) + len(kwargs) > 2:
            raise ValueError('Too many arguments.')
        if any(i not in {'edate', 'fdate'} for i in kwargs):
            raise ValueError('Unrecognized keyword arguments.')
        if 'edate' not in kwargs and len(args) < 1:
            raise ValueError('"edate" must be defined either by a keyword'
                             ' argument or by passing an argument.')

        if kwargs.get('edate'):
            self.edate = kwargs['edate']
        if kwargs.get('fdate'):
            self.fdate = kwargs['fdate']

        if len(args) == 2:
            self.fdate = args[0]
            self.edate = args[1]
        elif len(args) == 1:
            if not self.edate:
                self.edate = args[0]
            else:
                self.fdate = args[0]

    def __repr__(self):
        args = ', '.join(str(i) for i in self.__args)
        kwargs = (', '.join(f'{key}={repr(value)}' 
                  for key, value in self.__kwargs.items()))
        return (f'Test({args}, {kwargs}) ->'
                f' self.fdate={repr(self.fdate)},'
                f' self.edate={repr(self.edate)}')

print(Test(1, 2))
print(Test(1))
print(Test(1, edate=3))
print(Test(1, fdate=3))
print(Test(edate=4))

# Will raise exceptions:
#print(Test())
#print(Test(fdate=3))
#print(Test(1, 2, fdate=3))
#print(Test(1, 2, 3))
#print(Test(cdate=4, edate=1))

输出:

Test(1, 2, ) -> self.fdate=1, self.edate=2
Test(1, ) -> self.fdate='', self.edate=1
Test(1, edate=3) -> self.fdate=1, self.edate=3
Test(1, fdate=3) -> self.fdate=3, self.edate=1
Test(, edate=4) -> self.fdate='', self.edate=4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接