问题:python中有内置的标识函数吗?
我想指出一个什么都不做的函数:
def identity(*args)
return args
我的用例是这样的
try:
gettext.find(...)
...
_ = gettext.gettext
else:
_ = identity
当然,我可以使用identity
上面定义的方法,但是内置方法肯定会运行得更快(并避免我自己引入的错误)。
显然,map
与filter
使用None
的身份,但这是具体到它们的实现。
>>> _=None
>>> _("hello")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
I’d like to point to a function that does nothing:
def identity(*args)
return args
my use case is something like this
try:
gettext.find(...)
...
_ = gettext.gettext
else:
_ = identity
Of course, I could use the identity
defined above, but a built-in would certainly run faster (and avoid bugs introduced by my own).
Apparently, map
and filter
use None
for the identity, but this is specific to their implementations.
>>> _=None
>>> _("hello")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
回答 0
做更多的研究,没有,没有一个功能,问题1673203被问到。来自Raymond Hettinger表示不会:
最好让人们自己编写琐碎的传递,并考虑签名和时间成本。
因此实际上是一个更好的方法(lambda避免为函数命名):
_ = lambda *args: args
- 优点:可以使用任意数量的参数
- 缺点:结果是参数的盒装版本
要么
_ = lambda x: x
- 优点:不会改变参数的类型
- 缺点:只能使用1个位置参数
Doing some more research, there is none, a feature was asked in issue 1673203 And from Raymond Hettinger said there won’t be:
Better to let people write their own trivial pass-throughs
and think about the signature and time costs.
So a better way to do it is actually (a lambda avoids naming the function):
_ = lambda *args: args
- advantage: takes any number of parameters
- disadvantage: the result is a boxed version of the parameters
OR
_ = lambda x: x
- advantage: doesn’t change the type of the parameter
- disadvantage: takes exactly 1 positional parameter
回答 1
如https://en.wikipedia.org/wiki/Identity_function中定义的身份函数,它采用单个参数并返回不变:
def identity(x):
return x
你要签名什么你问,当你说的def identity(*args)
是不是严格意义上的标识功能,只要你想它采取多个参数。很好,但是随后您遇到了一个问题,因为Python函数不会返回多个结果,因此您必须找到一种将所有这些参数塞入一个返回值的方法。
在Python中返回“多个值”的通常方法是返回值的元组-从技术上讲,这是一个返回值,但它可以在大多数情况下使用,就好像它是多个值一样。但是在这里做意味着你得到
>>> def mv_identity(*args):
... return args
...
>>> mv_identity(1,2,3)
(1, 2, 3)
>>> # So far, so good. But what happens now with single arguments?
>>> mv_identity(1)
(1,)
快速解决该问题会带来其他问题,如此处所示的各种答案。
因此,总而言之,Python中没有定义身份函数,因为:
- 形式定义(单个参数函数)不是那么有用,并且编写起来很简单。
- 通常,将定义扩展到多个参数的定义不是很好,因此最好定义自己的版本,使其适合您的特定情况。
为了您的确切情况,
def dummy_gettext(message):
return message
几乎可以肯定是您想要的-一个具有相同的调用约定和return的函数,gettext.gettext
该函数不变地返回其参数,并被明确命名以描述其作用以及打算在何处使用。如果性能在这里是至关重要的考虑因素,我会感到非常震惊。
An identity function, as defined in https://en.wikipedia.org/wiki/Identity_function, takes a single argument and returns it unchanged:
def identity(x):
return x
What you are asking for when you say you want the signature def identity(*args)
is not strictly an identity function, as you want it to take multiple arguments. That’s fine, but then you hit a problem as Python functions don’t return multiple results, so you have to find a way of cramming all of those arguments into one return value.
The usual way of returning “multiple values” in Python is to return a tuple of the values – technically that’s one return value but it can be used in most contexts as if it were multiple values. But doing that here means you get
>>> def mv_identity(*args):
... return args
...
>>> mv_identity(1,2,3)
(1, 2, 3)
>>> # So far, so good. But what happens now with single arguments?
>>> mv_identity(1)
(1,)
And fixing that problem quickly gives other issues, as the various answers here have shown.
So, in summary, there’s no identity function defined in Python because:
- The formal definition (a single argument function) isn’t that useful, and is trivial to write.
- Extending the definition to multiple arguments is not well-defined in general, and you’re far better off defining your own version that works the way you need it to for your particular situation.
For your precise case,
def dummy_gettext(message):
return message
is almost certainly what you want – a function that has the same calling convention and return as gettext.gettext
, which returns its argument unchanged, and is clearly named to describe what it does and where it’s intended to be used. I’d be pretty shocked if performance were a crucial consideration here.
回答 2
你的会很好的。当参数数量固定后,您可以使用如下匿名函数:
lambda x: x
yours will work fine. When the number of parameters is fix you can use an anonymous function like this:
lambda x: x
回答 3
Python中没有内置的标识函数。Haskell id
函数的模仿为:
identity = lambda x, *args: (x,) + args if args else x
用法示例:
identity(1)
1
identity(1,2)
(1, 2)
由于identity
除了返回给定的参数外什么都不做,因此我认为它不会比本机实现慢。
There is no a built-in identity function in Python. An imitation of the Haskell’s id
function would be:
identity = lambda x, *args: (x,) + args if args else x
Example usage:
identity(1)
1
identity(1,2)
(1, 2)
Since identity
does nothing except returning the given arguments, I do not think that it is slower than a native implementation would be.
回答 4
不,没有。
请注意,您的identity
:
- 等价于lambda * args:args
将装箱参数-即
In [6]: id = lambda *args: args
In [7]: id(3)
Out[7]: (3,)
因此,lambda arg: arg
如果您需要真正的身份功能,则可能要使用。
注意:此示例将隐藏内置id
函数(您可能永远不会使用)。
No, there isn’t.
Note that your identity
:
- is equivalent to lambda *args: args
Will box its args – i.e.
In [6]: id = lambda *args: args
In [7]: id(3)
Out[7]: (3,)
So, you may want to use lambda arg: arg
if you want a true identity function.
NB: This example will shadow the built-in id
function (which you will probably never use).
回答 5
如果速度无关紧要,则应该处理所有情况:
def identity(*args, **kwargs):
if not args:
if not kwargs:
return None
elif len(kwargs) == 1:
return next(iter(kwargs.values()))
else:
return (*kwargs.values(),)
elif not kwargs:
if len(args) == 1:
return args[0]
else:
return args
else:
return (*args, *kwargs.values())
用法示例:
print(identity())
None
$identity(1)
1
$ identity(1, 2)
(1, 2)
$ identity(1, b=2)
(1, 2)
$ identity(a=1, b=2)
(1, 2)
$ identity(1, 2, c=3)
(1, 2, 3)
If the speed does not matter, this should handle all cases:
def identity(*args, **kwargs):
if not args:
if not kwargs:
return None
elif len(kwargs) == 1:
return next(iter(kwargs.values()))
else:
return (*kwargs.values(),)
elif not kwargs:
if len(args) == 1:
return args[0]
else:
return args
else:
return (*args, *kwargs.values())
Examples of usage:
print(identity())
None
$identity(1)
1
$ identity(1, 2)
(1, 2)
$ identity(1, b=2)
(1, 2)
$ identity(a=1, b=2)
(1, 2)
$ identity(1, 2, c=3)
(1, 2, 3)
回答 6
单参数函数的存根
gettext.gettext
(OP的示例用例)接受单个参数message
。如果一个人需要为它存根,没有理由退换货[message]
,而不是message
(def identity(*args): return args
)。因此两者
_ = lambda message: message
def _(message):
return message
伏贴。
…但是内置程序肯定会运行得更快(并避免我自己引入的错误)。
在这种琐碎的情况下,错误几乎无关紧要。对于预定义类型的参数,例如str
,我们可以将str()
其自身用作身份函数(因为通过字符串进行交互,它甚至保留了对象身份,请参见id
下面的注释),并将其性能与lambda解决方案进行比较:
$ python3 -m timeit -s "f = lambda m: m" "f('foo')"
10000000 loops, best of 3: 0.0852 usec per loop
$ python3 -m timeit "str('foo')"
10000000 loops, best of 3: 0.107 usec per loop
微优化是可能的。例如,以下Cython代码:
test.pyx
cpdef str f(str message):
return message
然后:
$ pip install runcython3
$ makecython3 test.pyx
$ python3 -m timeit -s "from test import f" "f('foo')"
10000000 loops, best of 3: 0.0317 usec per loop
内置对象识别功能
不要将身份函数与id
返回对象“身份”的内置函数(该对象的唯一标识符,而不是与==
运算符相比,该对象的值,而不是该对象的值)相混淆,后者是CPython中的内存地址。
Stub of a single-argument function
gettext.gettext
(the OP’s example use case) accepts a single argument, message
. If one needs a stub for it, there’s no reason to return [message]
instead of message
(def identity(*args): return args
). Thus both
_ = lambda message: message
def _(message):
return message
fit perfectly.
…but a built-in would certainly run faster (and avoid bugs introduced by my own).
Bugs in such a trivial case are barely relevant. For an argument of predefined type, say str
, we can use str()
itself as an identity function (because of string interning it even retains object identity, see id
note below) and compare its performance with the lambda solution:
$ python3 -m timeit -s "f = lambda m: m" "f('foo')"
10000000 loops, best of 3: 0.0852 usec per loop
$ python3 -m timeit "str('foo')"
10000000 loops, best of 3: 0.107 usec per loop
A micro-optimisation is possible. For example, the following Cython code:
test.pyx
cpdef str f(str message):
return message
Then:
$ pip install runcython3
$ makecython3 test.pyx
$ python3 -m timeit -s "from test import f" "f('foo')"
10000000 loops, best of 3: 0.0317 usec per loop
Build-in object identity function
Don’t confuse an identity function with the id
built-in function which returns the ‘identity’ of an object (meaning a unique identifier for that particular object rather than that object’s value, as compared with ==
operator), its memory address in CPython.
回答 7
线程很旧。但是仍然想发布这个。
可以为参数和对象建立身份方法。在下面的示例中,ObjOut是ObjIn的标识。上面所有其他示例都没有处理dict ** wargs。
class test(object):
def __init__(self,*args,**kwargs):
self.args = args
self.kwargs = kwargs
def identity (self):
return self
objIn=test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n')
objOut=objIn.identity()
print('args=',objOut.args,'kwargs=',objOut.kwargs)
#If you want just the arguments to be printed...
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().args)
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().kwargs)
$ py test.py
args= ('arg-1', 'arg-2', 'arg-3', 'arg-n') kwargs= {'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}
('arg-1', 'arg-2', 'arg-3', 'arg-n')
{'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}
The thread is pretty old. But still wanted to post this.
It is possible to build an identity method for both arguments and objects. In the example below, ObjOut is an identity for ObjIn. All other examples above haven’t dealt with dict **kwargs.
class test(object):
def __init__(self,*args,**kwargs):
self.args = args
self.kwargs = kwargs
def identity (self):
return self
objIn=test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n')
objOut=objIn.identity()
print('args=',objOut.args,'kwargs=',objOut.kwargs)
#If you want just the arguments to be printed...
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().args)
print(test('arg-1','arg-2','arg-3','arg-n',key1=1,key2=2,key3=3,keyn='n').identity().kwargs)
$ py test.py
args= ('arg-1', 'arg-2', 'arg-3', 'arg-n') kwargs= {'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}
('arg-1', 'arg-2', 'arg-3', 'arg-n')
{'key1': 1, 'keyn': 'n', 'key2': 2, 'key3': 3}