为什么我不能将 self 作为命名参数传递给 Python 中的实例方法?

发布于 2024-08-25 20:36:12 字数 742 浏览 3 评论 0原文

这有效:

>>> def bar(x, y):
...     print x, y
...
>>> bar(y=3, x=1)
1 3

这有效:

>>> class Foo(object):
...     def bar(self, x, y):
...             print x, y
...
>>> z = Foo()
>>> z.bar(y=3, x=1)
1 3

甚至这有效:

>>> Foo.bar(z, y=3, x=1)
1 3

但为什么这在 Python 2.x 中不起作用?

>>> Foo.bar(self=z, y=3, x=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)

这使得元编程变得更加困难,因为它需要特殊情况处理。我很好奇它是否是 Python 语义所必需的,或者只是实现的一个产物。

This works:

>>> def bar(x, y):
...     print x, y
...
>>> bar(y=3, x=1)
1 3

And this works:

>>> class Foo(object):
...     def bar(self, x, y):
...             print x, y
...
>>> z = Foo()
>>> z.bar(y=3, x=1)
1 3

And even this works:

>>> Foo.bar(z, y=3, x=1)
1 3

But why doesn't this work in Python 2.x?

>>> Foo.bar(self=z, y=3, x=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)

This makes metaprogramming more difficult, because it requires special case handling. I'm curious if it's somehow necessary by Python's semantics or just an artifact of implementation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

居里长安 2024-09-01 20:36:12

z.bar 是一个绑定方法 - 它已经有一个 im_self 属性,该属性成为第一个参数(通常命名为 self) 到底层函数对象,即绑定方法的 im_func 属性。要覆盖它,您显然需要重新绑定 im_self编辑:或改为调用 im_func)——无论您在参数方面做什么当然,通过不会对其产生任何影响。是的,这就是 Python 中绑定方法对象工作的记录方式(不仅仅是实现细节:每个正确的 Python 实现都必须完全按照这种方式进行)。所以它是“必要的”,因为它是使 Python 成为真正的语言的一部分,而不是成为一种略有不同或强烈不同的语言。当然,您可以设计一种不同的语言,选择遵循完全不同的规则,但是——当然,它不会是 Python。

编辑:OP 的编辑澄清了他正在调用一个未绑定方法,而不是绑定方法。这仍然不起作用,从尝试得到的错误消息中可以清楚地看出原因:

类型错误:未绑定方法 bar() 必须
首先以 Foo 实例调用
争论(什么也没得到)

这个非常清晰的错误消息背后的规则是该实例必须是第一个参数(所以当然是一个位置参数:命名参数没有顺序) 未绑定方法不“知道”(也不关心)该参数的名称可能是什么(并且使用名称self只是一个约定< /em>,不是 Python 语言的规则):它只关心“第一个参数”的明确条件(当然,在位置参数中)。

这个晦涩的极端情况肯定可以通过使未绑定的方法变得更加复杂来改变(使用Python 3.2补丁,如果并且当语言更改“冻结”结束时;-):他们必须内省并保存第一个参数的名称在创建时,并检查每次调用的关键字参数,以防有人按名称而不是按位置传递 self 。我不认为这会破坏任何现有的工作代码,它只会减慢几乎所有现有的 Python 程序的速度。如果您编写并提出一个实现此复杂性的补丁,并积极参与 python-dev 来倡导它,以对抗必然到来的反对风暴,那么您毫无疑问会站稳脚跟。 0 机会冲过去——祝你好运。

与此同时,我们其他人将继续获取 im_func 属性,作为一个荒谬的微小额外步骤,必须是一个相当复杂的元编程大厦才能保证这样的改变 - 它不是与将命名参数传递给不采用命名参数(并且不公开他们的“参数名称”可以轻松地将命名参数转换为位置参数(现在将是一个值得攻击的风车,恕我直言:在所有可调用对象中,内置函数是最糟糕的元编程,因为!-)。

z.bar is a bound method -- it already has an im_self attribute that becomes the first argument (conventionally named self) to the underlying function object, the bound method's im_func attribute. To override that you obviously need to re-bind im_self (edit: or call the im_func instead) -- whatever you do in terms of argument passing is not going to have any effect on it, of course. Yep, that's the documented way bound methods object work in Python (not just an implementation detail: every correct Python implementation has to do it exactly this way). So it's "necessary" in the sense that it's part of what makes Python exactly the language it is, as opposed to being a slighty or strongly different language. Of course you could design a different language that chooses to play by completely different rules, but -- it wouldn't be Python, of course.

Edit: the OP's edits clarified he's calling an unbound method, not a bound one. This still doesn't work, and the reason is clear from the error message the attempt gets:

TypeError: unbound method bar() must
be called with Foo instance as first
argument (got nothing instead)

The rule underlying this very clear error message is that the instance must be the first argument (so of course a positional one: named arguments have no ordering). The unbound method doesn't "know" (nor care) what that parameter's name may be (and the use of name self for it is only a convention, not a rule of the Python language): it only care about the unambiguous condition of "first argument" (among the positional ones, of course).

This obscure corner case could certainly be altered (with a Python 3.2 patch, if and when the language-changes "freeze" ends;-) by making unbound methods seriously more complicated: they'd have to introspect and save the first-argument's name at creation time, and check keyword arguments on each call just in case somebody's passing self by name instead of by position. I don't think this would break any existing, working code, it would only slow down just about every existing Python program. If you write and propose a patch implementing this complication, and get active on python-dev to advocate for it against the sure-to-come firestorm of opposition, you do no doubt stand a > 0 chance to ram it through -- good luck.

The rest of us, meanwhile, will keep getting the im_func attribute instead, as one absurdly-tiny extra step in what has to be a pretty complicated inded edifice of metaprogramming to warrant such a change -- it isn't a "special case" at all, compared with the horrid difficulties of adapting named-argument passing to builtins that don't take named arguments (and don't expose their "argument names" to easily allow the transformation of named arguments into positional ones (now that would be a windmill worth attacking, IMHO: of all callables, builtins are the worst to metaprogram about, because of that!-).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文