函数如何访问自己的属性?
是否可以从函数作用域内访问 python 函数对象属性?
例如
def f():
return SOMETHING
f._x = "foo"
f() # -> "foo"
,如果我们想要返回 _x 属性内容“foo”,那么现在我们必须要做什么?如果有可能(简单地)
谢谢
更新:
我也想要以下工作:
g = f
del f
g() # -> "foo"
更新2:
声明这是不可能的(如果是这样的话),为什么,比提供一种如何伪造它的方法更令人满意,例如使用与函数不同的对象
is it possible to access the python function object attributes from within the function scope?
e.g. let's have
def f():
return SOMETHING
f._x = "foo"
f() # -> "foo"
now, what SOMETHING has to be, if we want to have the _x attribute content "foo" returned? if it's even possible (simply)
thanks
UPDATE:
i'd like the following work also:
g = f
del f
g() # -> "foo"
UPDATE 2:
Statement that it is not possible (if it is the case), and why, is more satisfying than providing a way how to fake it e.g. with a different object than a function
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
这使用了一些黑客方法,但鉴于它也适用于
g()
调用,因此它可能是迄今为止最正确的方法。它之所以有效,是因为它依赖于 dis 模块,作为快捷方式。它看起来比实际情况更黑客化,部分原因是
dis.disassemble()
调用打印到 stdout,所以我将其重定向到 StringIO。我使用disassemble()
来突出显示最后一条指令(在其中添加print text
行以查看其外观),这样可以更轻松地获取上一条指令LOAD_NAME
及其使用的变量。可以使用更干净的字节码检查库来完成此操作,而无需使用
dis
模块,但这证明了这是可能的。这可能不是最可靠的方法,但也许它在大多数情况下都有效。我还没有花足够的时间深入研究 Python 内部结构或字节码来了解大多数 CALL_FUNCTION 字节码是否紧接着正则表达式技巧会挑选出的指令。这会生成以下输出:
This uses a bit of a hackish approach, but it's possibly the most correct so far given that it works with the
g()
call as well. It works because it's relying on whatever bytecode inspection is performed by the dis module, as a shortcut.It looks more hackish than it really is partly because the
dis.disassemble()
call prints to stdout, so I redirect that into a StringIO. I usedisassemble()
for its feature of highlighting the last instruction (add aprint text
line in there to see how it looks) and that makes it easier to grab the previousLOAD_NAME
and the variable it used.It would be possible to use a cleaner bytecode inspection library to do this without using the
dis
module at all, but this proves that it's possible. This might not be the most robust approach, but then again maybe it will work in most cases. I haven't spent enough time poking into Python internals or bytecode to know whether mostCALL_FUNCTION
bytecodes are preceded immediately by instructions that the regex trick would pick out.This generates the following output:
使用类而不是函数并滥用 __new__ 方法使类可作为函数调用怎么样?由于 __new__ 方法获取类名作为第一个参数,因此它可以访问所有类属性,
中
就像在this
一样,你可以这样做。
问题是,即使对象的行为像函数,它不是。因此 IDE 无法为您提供签名。
How about using a class instead of a function and abusing the
__new__
method to make the class callable as a function? Since the__new__
method gets the class name as the first parameter, it can access all the class attributeslike in
this works as in
then you can do
The issue is that even if the object behaves like a function, it is not. Hence IDEs fail to provide you with the signature.
实现此目的的另一种方法是在另一个函数内定义该函数,并让外部函数返回内部函数。然后内部函数可以通过闭包访问自身。这是一个简单的例子:
那么:
Another way to accomplish this is to define the function inside another function, and have the outer function return the inner one. Then the inner function can access itself via a closure. Here's a simple example:
Then:
如果只需要一种方法,但您想要一个具有共享类状态和单独实例状态的轻量级类,您可以尝试像这样的闭包模式:
If there is only one method needed but you want a light-weight class with shared class state plus individual instance state, you might try the closure pattern like this:
这是一个可能比 func_defaults 想法更糟糕的策略,但仍然很有趣。这很老套,但我想不出它有什么实际问题。
我们可以实现一个函数,该函数可以使用单个 __new__ 方法(通常创建该类的新对象的方法)将自身引用为类。
也许这种模式对于日志记录功能很有用......
Here is a strategy that is probably worse than the
func_defaults
idea, but is interesting nonetheless. It's hacky but I can't think of anything practically wrong with it.We can implement a function that can refer to itself as a class with a single
__new__
method (the method that normally creates a new object of that class).Perhaps this pattern could be useful for a logging function...
只需在闭包中定义您的函数:
Just define your function inside a closure:
我非常喜欢这个。
I like this alot.
很抱歉回复晚了,但我只是偶然发现了这一点。我不得不说“g”的工作方式是非Pythonic的。在函数内部,名称“f”指的是调用函数时全局变量的值。鉴于此,请考虑以下事项:
希望没有人认为这是不正确的行为。鉴于这一事实,我只投票支持任何需要在函数内使用不同变量名称(例如“self”)的答案。
Sorry for the late reply but I just stumbled upon this. I would have to argue that the way that “g” is asked to work is non-Pythonic. Inside function, the name “f“ refers to the value of a global variable at the time the function is called. Given that, consider the following:
Hopefully, no one argues that this is incorrect behavior. Given that fact, I cam only vote for any answer that requires the use of a different variable name (e.g. “self”) inside the function.
解决方案
使函数的默认参数之一成为对函数本身的引用。
用法示例:
解释
原始发布者想要一个不需要全局名称查找的解决方案。简单的解决方案
在每次调用时都执行全局变量
f
的查找,这不满足要求。如果f
被删除,则该函数将失败。更复杂的inspect
提案也以同样的方式失败。我们想要的是执行早期绑定并将绑定引用存储在对象本身内。从概念上讲,以下是我们正在做的事情:
在上面,
self
是一个局部变量,因此不执行全局查找。但是,我们不能按原样编写代码,因为当我们尝试将self
的默认值绑定到它时,f
尚未定义。相反,我们在定义f
后设置默认值。装饰器
这是一个简单的装饰器可以为您完成此操作。请注意,
self
参数必须位于最后,这与self
位于最前面的方法不同。这也意味着如果任何其他参数采用默认值,则必须给出默认值。例子:
Solution
Make one of the function's default arguments be a reference to the function itself.
Example usage:
Explanation
The original poster wanted a solution that does not require a global name lookup. The simple solution
performs a lookup of the global variable
f
on each call, which does not meet the requirements. Iff
is deleted, then the function fails. The more complicatedinspect
proposal fails in the same way.What we want is to perform early binding and store the bound reference within the object itself. The following is conceptually what we are doing:
In the above,
self
is a local variable, so no global lookup is performed. However, we can't write the code as-is, becausef
is not yet defined when we try to bind the default value ofself
to it. Instead, we set the default value afterf
is defined.Decorator
Here's a simple decorator to do this for you. Note that the
self
argument must come last, unlike methods, whereself
comes first. This also means that you must give a default value if any of your other arguments take a default value.Example:
你可以只使用一个类来做到这一点
You could just use a class to do this
好吧,让我们看看函数是什么:
啊哈!因此,该属性已添加到函数对象中,但它不会看到它,因为它正在寻找全局
x
。我们可以尝试抓住函数执行的框架并尝试查看那里有什么(本质上是 Anthony Kong 建议的,但没有
inspect
模块):啊哈!那么也许我们可以从代码块的名称中获取函数的名称,然后以迂回的方式查找属性?果然:
太好了!但它能忍受原有功能的重命名和删除吗?
啊,非常怀疑。函数对象及其代码对象仍然坚持称为
foo
。果然,问题就在这里:当当!所以一般来说它不能通过执行框架的内省来完成。问题似乎在于函数对象和代码对象之间存在差异 - 代码对象是执行的对象,并且只是一个属性
func_code
函数对象的属性,因此无法访问func_dict
属性,其中我们的属性x
是:当然,您还可以采取其他诡计,使其看起来像函数 - 特别是类定义的技巧......但这本身不是一个函数。这完全取决于您真正需要做什么。
Well, let's look at what function is:
Aha! So the attribute was added to the function object but it won't see it because it is looking for global
x
instead.We can try to grab the frame of the function execution and try to look what's there (essentially what Anthony Kong suggested but w/o
inspect
module):Aha! So maybe we can get the name of the function from the name of the code block and then look in round-about way for the attribute? Sure enough:
That's great! But would it stand the renaming and deletion of original function?
Ah, very doubtful. The function object and its code object still insist they are called
foo
. Sure enough, here is where it breaks:Dang! So in general it can't be done through introspection via the execution frames. The problems seems to be that there is a difference between function object and code object - code objects are what is executed and is just one attribute
func_code
of the function-object and as such has no access to thefunc_dict
attribute, where our attributex
is:There is of course other chicanery you can do so that it seems as function - in particular the trick with class definition... but that is not a function per se. It all depends on what do you really need to do with that.
作为解决方法,您可以使用工厂函数来修复您的范围:
As a workaround you could use a factory function to fix your scope:
我怀疑这是实现此目的的最佳方法,但您可以通过在方法中使用方法名称来访问属性:
I doubt this is the best way to accomplish this, but you can access the attributes by using the method's name within the method:
这是一个装饰器,它在执行函数之前将 current_fun 注入到函数全局变量中。这是非常巧妙的做法,但也非常有效。
这是一个使用示例
Here's a decorator that injects current_fun into the functions globals before executing the function. It's quite the hack, but also quite effective.
Here's a usage example
答案相当简单。只需使用在执行时查找的事实名称,而不是编译时:
The answer is rather simple. Just use the fact name is looked for at execution time, not compile time:
如果你希望它完全独立于函数名称,你需要一些框架魔法。例如:
If you want it to be totally independent of the function name, you need some frame magic. For example: