webapi 怎么设置可选uri参数,默认值

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webapi 怎么设置可选uri参数,默认值相关的知识,希望对你有一定的参考价值。

参考技术A 在.net平台下,有大量的技术让你创建一个HTTP服务,像Web Service,WCF,现在又出了Web API。在.net平台下,你有很多的选择来构建一个HTTP Services。我分享一下我对Web Service、WCF以及Web API的看法。

  Web Service

  1、它是基于SOAP协议的,数据格式是XML

  2、只支持HTTP协议

  3、它不是开源的,但可以被任意一个了解XML的人使用

  4、它只能部署在IIS上

  WCF

  1、这个也是基于SOAP的,数据格式是XML

  2、这个是Web Service(ASMX)的进化版,可以支持各种各样的协议,像TCP,HTTP,HTTPS,Named Pipes, MSMQ.

  3、WCF的主要问题是,它配置起来特别的繁琐

  4、它不是开源的,但可以被任意一个了解XML的人使用

  5、它可以部署应用程序中或者IIS上或者Windows服务中

  WCF Rest

  1、想使用WCF Rest service,你必须在WCF中使用webHttpBindings

  2、它分别用[WebGet]和[WebInvoke]属性,实现了HTTP的GET和POST动词

  3、要想使用其他的HTTP动词,你需要在IIS中做一些配置,使.svc文件可以接受这些动词的请求

  4、使用WebGet通过参数传输数据,也需要配置。而且必须指定UriTemplate

  5、它支持XML、JSON以及ATOM这些数据格式

  Web API

  1、这是一个简单的构建HTTP服务的新框架

  2、在.net平台上Web API 是一个开源的、理想的、构建REST-ful 服务的技术

  3、不像WCF REST Service.它可以使用HTTP的全部特点(比如URIs、request/response头,缓存,版本控制,多种内容格式)

  4、它也支持MVC的特征,像路由、控制器、action、filter、模型绑定、控制反转(IOC)或依赖注入(DI),单元测试。这些可以使程序更简单、更健壮

  5、它可以部署在应用程序和IIS上

  6、这是一个轻量级的框架,并且对限制带宽的设备,比如智能手机等支持的很好

  7、Response可以被Web API的MediaTypeFormatter转换成Json、XML 或者任何你想转换的格式。

  

  WCF和WEB API我该选择哪个?

  1、当你想创建一个支持消息、消息队列、双工通信的服务时,你应该选择WCF

  2、当你想创建一个服务,可以用更快速的传输通道时,像TCP、Named Pipes或者甚至是UDP(在WCF4.5中),在其他传输通道不可用的时候也可以支持HTTP。

  3、当你想创建一个基于HTTP的面向资源的服务并且可以使用HTTP的全部特征时(比如URIs、request/response头,缓存,版本控制,多种内容格式),你应该选择Web API

  4、当你想让你的服务用于浏览器、手机、iPhone和平板电脑时,你应该选择Web API本回答被提问者采纳

如何检查是不是设置了可选功能参数

【中文标题】如何检查是不是设置了可选功能参数【英文标题】:How to check whether optional function parameter is set如何检查是否设置了可选功能参数 【发布时间】:2013-01-22 20:19:41 【问题描述】:

在 Python 中是否有一种简单的方法来检查可选参数的值是来自其默认值,还是因为用户在函数调用时明确设置了它?

【问题讨论】:

因为我当然想在那个函数中检查它:) 只需使用None 作为默认值并检查它。如果你真的可以设置这个测试,你也会排除用户显式传递调用默认行为的值的任何可能性。 这可以以比您接受的答案更可重用和更美观的方式完成,至少对于 CPython 而言。请参阅下面的答案。 @Volatility:如果你有两组默认值,这很重要。考虑一个递归类:Class My(): def __init__(self, _p=None, a=True, b=True, c=False) 用户用x=My(b=False) 调用它。如果函数可以检测到 b 未显式设置并且未设置的变量将从顶层向下传递,则类方法可以使用 x=My(_p=self, c=True) 调用自身。但如果不能,递归调用必须显式传递每个变量:x=My(a=self.a, b=self.b, c=True, d=self.d, ...) @Dave 但这就是问题所在吗?据我了解,问题在于如何区分x=My()x=My(a=True)。您的方案涉及为可选参数分配一个不同于其默认值的值。 【参考方案1】:

不是真的。标准方法是使用用户不希望通过的默认值,例如object 实例:

DEFAULT = object()
def foo(param=DEFAULT):
    if param is DEFAULT:
        ...

通常你可以只使用None 作为默认值,如果它作为用户想要传递的值没有意义。

替代方法是使用kwargs:

def foo(**kwargs):
    if 'param' in kwargs:
        param = kwargs['param']
    else:
        ...

但是,这过于冗长,并且会使您的函数更难使用,因为它的文档不会自动包含 param 参数。

【讨论】:

我还看到有几个人在需要的地方使用 Ellipsis 内置函数并且 None 被认为是有效的输入。这与第一个示例基本相同。 如果你想在 None 被传递的情况下实现特殊行为,但仍然需要一种方法来测试参数是否由用户给出,你可以使用 Ellipsis 单例作为默认值,这是明确设计为用作 skip this 值。 ...Ellipsis 的别名,因此想要使用位置参数的用户只需调用 your_function(p1, ..., p3) 即可,这样一目了然且易于阅读。 However this is overly verbose and makes your function more difficult to use as its documentation will not automatically include the param parameter. 这实际上是不正确的,因为您可以使用inspect 模块设置函数及其参数的描述。它是否可以工作取决于您的 IDE。【参考方案2】:

很多答案都包含完整信息的一小部分,所以我想将它们与我最喜欢的模式结合在一起。

默认值为mutable 类型

如果默认值是一个可变对象,那么你很幸运:你可以利用 Python 的默认参数在定义函数时计算一次这一事实(在最后一节答案的末尾有更多关于此的内容)

这意味着您可以使用is 轻松比较默认可变值,以查看它是作为参数传递还是默认保留,如下面的函数或方法示例:

def f(value=):
    if value is f.__defaults__[0]:
        print('default')
    else:
        print('passed in the call')

class A:
    def f(self, value=):
        if value is self.f.__defaults__[0]:
            print('default')
        else:
            print('passed in the call')

不可变的默认参数

现在,如果您的默认值预期为 immutable 值(请记住,即使是字符串也是不可变的!),它会有点不那么优雅,因为您无法按原样利用这个技巧,但仍有一些东西您可以,仍然利用可变类型;基本上你在函数签名中放置了一个可变“假”默认值,而在函数体中放置了所需的“真实”默认值。

def f(value=):
    """
    my function
    :param value: value for my function; default is 1
    """
    if value is f.__defaults__[0]:
        print('default')
        value = 1
    else:
        print('passed in the call')
    # whatever I want to do with the value
    print(value)

如果你真正的默认值是None,感觉特别好笑,但是None 是不可变的,所以……你仍然需要显式地使用一个可变的作为函数的默认参数,并在代码中切换到 None。

Default 类用于不可变默认值

或者,类似于@c-z 建议,如果 python 文档还不够 :-) ,您可以在两者之间添加一个对象以使 API 更明确(无需阅读文档); used_proxy_Default 类实例是可变的,并且将包含您要使用的真实默认值。

class Default:
    def __repr__(self):
        return "Default Value:  ()".format(self.value, type(self.value))

    def __init__(self, value):
        self.value = value

def f(default=Default(1)):
    if default is f.__defaults__[0]:
        print('default')
        print(default)
        default = default.value
    else:
        print('passed in the call')
    print("argument is: ".format(default))

现在:

>>> f()
default
Default Value: 1 (<class 'int'>)
argument is: 1

>>> f(2)
passed in the call
argument is: 2

上述方法也适用于Default(None)

其他模式

显然,上面的模式看起来比它们应该的更丑,因为所有的print 只是为了展示它们是如何工作的。否则我发现它们足够简洁和可重复。

您可以编写一个装饰器以更简化的方式添加@dmg 建议的__call__ 模式,但这仍然需要在函数定义本身中使用奇怪的技巧——您需要拆分出valuevalue_default如果你的代码需要区分它们,所以我看不出有多大优势,我不会写例子:-)

可变类型作为 Python 中的默认值

更多关于#1 python gotcha! 的信息,上面是为了你自己的乐趣而滥用的。 您可以通过执行以下操作查看由于 定义时的评估会发生什么:

def testme(default=[]):
    print(id(default))

您可以根据需要多次运行testme(),您将始终看到对同一个默认实例的引用(因此基本上您的默认值是不可变的:-)。

请记住,在 Python 中只有 3 个可变的built-in types:setlistdict;其他一切 - 甚至字符串! - 是不可变的。

【讨论】:

您在“不可变默认参数”中的示例实际上并没有不可变的默认参数。如果是这样,它就行不通了。 @Karol,想详细说明一下吗?该示例中的默认值是1,它应该是不可变的... 我看到函数的签名是def f(value=) 哈,我现在明白了,谢谢。除非有人非常仔细地阅读您的文字,否则这并不容易理解,这在 SO 上可能不会经常发生。考虑改写。 在“if default is f.__defaults__[0]:”中,您必须硬编码要使用的默认参数编号,如果函数签名发生更改,这可能会很脆弱。另一种选择是“如果 f.__defaults__ 中的默认值:”。假设您为每个 arg 使用不同的 Default 实例,“in”应该和“is”一样有效。【参考方案3】:

下面的函数装饰器explicit_checker 为所有显式给出的参数创建一组参数名称。它将结果作为额外参数 (explicit_params) 添加到函数中。只需执行'a' in explicit_params 即可检查参数a 是否已明确给出。

def explicit_checker(f):
    varnames = f.func_code.co_varnames
    def wrapper(*a, **kw):
        kw['explicit_params'] = set(list(varnames[:len(a)]) + kw.keys())
        return f(*a, **kw)
    return wrapper

@explicit_checker
def my_function(a, b=0, c=1, explicit_params=None):
    print a, b, c, explicit_params
    if 'b' in explicit_params:
        pass # Do whatever you want


my_function(1)
my_function(1, 0)
my_function(1, c=1)

【讨论】:

此代码仅适用于 python2。对于 python 3,请参阅下面的答案:***.com/questions/14749328/… 这很酷,但如果可能的话,最好一开始就避免出现更好设计的问题。 @Karol,我同意。在大多数情况下,如果设计合理,则不需要这样做。【参考方案4】:

我有时会使用通用唯一的字符串(如 UUID)。

import uuid
DEFAULT = uuid.uuid4()
def foo(arg=DEFAULT):
  if arg is DEFAULT:
    # it was not passed in
  else:
    # it was passed in

这样,如果用户尝试过,甚至都无法猜测默认值,因此我可以非常确信,当我看到 arg 的值时,它没有被传入。

【讨论】:

Python 对象是引用,您可以只使用object() 而不是uuid4() - 它仍然是一个独特的实例,这是is 检查的内容【参考方案5】:

这种模式我见过几次(例如库unittestpy-flagsjinja):

class Default:
    def __repr__( self ):
        return "DEFAULT"

DEFAULT = Default()

...或等效的单线...:

DEFAULT = type( 'Default', (),  '__repr__': lambda x: 'DEFAULT'  )()

DEFAULT = object() 不同,这有助于类型检查并在发生错误时提供信息——通常在错误消息中使用字符串表示 ("DEFAULT") 或类名 ("Default")。

【讨论】:

【参考方案6】:

@Ellioh 的回答在 python 2 中有效。在 python 3 中,以下代码应该有效:

import inspect
from functools import wraps

def explicit_checker(f):
    varnames = inspect.getfullargspec(f)[0]
    @wraps(f)
    def wrapper(*a, **kw):
        kw['explicit_params'] = set(list(varnames[:len(a)]) + list(kw.keys()))
        return f(*a, **kw)
    return wrapper

@explicit_checker
def my_function(a, b=0, c=1, explicit_params=None):
    print a, b, c, explicit_params
    if 'b' in explicit_params:
        pass # Do whatever you want

此方法可以保留参数名称和默认值(而不是**kwargs),具有更好的可读性。

【讨论】:

【参考方案7】:

我同意 Volatility 的评论。但您可以通过以下方式检查:

def function(arg1,...,**optional):
    if 'optional_arg' in optional:
        # user has set 'optional_arg'
    else:
        # user has not set 'optional_arg'
        optional['optional_arg'] = optional_arg_default_value # set default

【讨论】:

我相信可选参数类似于def func(optional=value) 而不是**kwargs 这有点可以解释。具有默认值的参数和关键字参数之间的实际区别是什么?它们都使用相同的语法“keyword=value”来表示。 我不同意,因为可选参数的用途和**kwargs 有点不同。附言-1 没问题 :) 我给你的 -1 是偶然的 :)【参考方案8】:

您可以通过foo.__defaults__foo.__kwdefaults__查看

看一个简单的例子

def foo(a, b, c=123, d=456, *, e=789, f=100):
    print(foo.__defaults__)
    # (123, 456) 
    print(foo.__kwdefaults__)
    # 'e': 789, 'f': 100
    print(a, b, c, d, e, f)

#and these variables are also accessible out of function body
print(foo.__defaults__)    
# (123, 456)  
print(foo.__kwdefaults__)  
# 'e': 789, 'f': 100

foo.__kwdefaults__['e'] = 100500

foo(1, 2) 
#(123, 456)
#'f': 100, 'e': 100500
#1 2 123 456 100500 100

然后使用运算符=is 可以比较它们

在某些情况下,下面的代码就足够了

例如,您需要避免更改默认值,然后您可以检查是否相等,如果是则复制

    def update_and_show(data=Example):
        if data is Example:
            data = copy.deepcopy(data)
        update_inplace(data) #some operation
        print(data)

此外,使用inspect 中的getcallargs 非常方便,因为它返回将调用函数的真实参数。您将一个函数以及 args 和 kwargs 传递给它(inspect.getcallargs(func, /, *args, **kwds)),它将返回用于调用的真实方法的参数,同时考虑到默认值和其他内容。请看下面的示例。

from inspect import getcallargs

# we have a function with such signature
def show_params(first, second, third=3):
    pass

# if you wanted to invoke it with such params (you could get them from a decorator as example)
args = [1, 2, 5]
kwargs = 
print(getcallargs(show_params, *args, **kwargs))
#'first': 1, 'second': 2, 'third': 5

# here we didn't specify value for d
args = [1, 2, 3, 4]
kwargs = 

# ----------------------------------------------------------
# but d has default value =7
def show_params1(first, *second, d = 7):
    pass


print(getcallargs(show_params1, *args, **kwargs))
# it will consider b to be equal to default value 7 as it is in real method invocation
# 'first': 1, 'second': (2, 3, 4), 'd': 7

# ----------------------------------------------------------
args = [1]
kwargs = "d": 4

def show_params2(first, d=3):
    pass


print(getcallargs(show_params2, *args, **kwargs))
#'first': 1, 'd': 4

https://docs.python.org/3/library/inspect.html

【讨论】:

【参考方案9】:

这是对 stefano 的回答的一个变体,但我觉得更具可读性:

not_specified = 

def foo(x=not_specified):
    if x is not_specified:
            print("not specified")
    else:
            print("specified")

【讨论】:

一个赞成票??我最喜欢这个。很简单,没有反思。可读。【参考方案10】:

有点奇怪的方法是:

class CheckerFunction(object):
    def __init__(self, function, **defaults):
        self.function = function
        self.defaults = defaults

    def __call__(self, **kwargs):
        for key in self.defaults:
            if(key in kwargs):
                if(kwargs[key] == self.defaults[key]):
                    print 'passed default'
                else:
                    print 'passed different'
            else:
                print 'not passed'
                kwargs[key] = self.defaults[key]

        return self.function(**kwargs)

def f(a):
    print a

check_f = CheckerFunction(f, a='z')
check_f(a='z')
check_f(a='b')
check_f()

哪些输出:

passed default
z
passed different
b
not passed
z

现在,正如我所提到的,这很奇怪,但它确实有效。然而,这是非常难以理解的,并且类似于ecatmur 的suggestion 不会被自动记录。

【讨论】:

您可能希望包含check_f('z') 的行为,正如您所说,这也很怪异。 @MichaelJ.Barber 好点。您还必须使用 *args 做一些“魔术”。但是,我的观点是这是可能的,但是现在需要是否传递默认值是一个糟糕的设计。

以上是关于webapi 怎么设置可选uri参数,默认值的主要内容,如果未能解决你的问题,请参考以下文章

Go - options模式(函数式选项模式)

云播 URI POST怎么设置

RatingBar如何设置评分最小值?

设置 C# 可选参数的默认值

我用ABAP可以在SAP标准屏幕中设置默认值吗?比如

js 自定义方法 设置可选参数的方法