Get containing context of a function
在Python中,如何获取对象(在我的例子中是函数)的包含上下文,以便修改它?例如,如果它是一个方法,那么它的上下文就是类;如果它是一个自由函数,那么它的上下文就是模块。
Related question:
Can a Python decorator of an instance method access the class?
- 错了。类方法的上下文不是类。这不是C++。在python中,类方法只是自动传递自参数。类方法的上下文是类本身的上下文(类的创建位置)。
- @NightCracker是的,我知道,方法的名称被破坏并与类放在同一个范围内(基本上变成了自由函数)。
- 显示一些元代码以澄清您想要的内容
- @保罗曼塔,请你确认,你想从相关实体的内部得到一个实体的上下文。因为在外部可能有几个层次,例如在嵌套函数的情况下。
- @我可不想这样。我得到一个对象(例如,通过参数传递),我想访问定义该对象的上下文。
- func(obj),现在你想要访问对象或者拥有一个神奇的函数,它给你一个"上下文",你真正的意思是调用函数func的"上下文"环境。因此,您可以介绍调用函数本身调用的对象/方法,并接受这些变量/属性?
- @保罗曼塔好吧,我明白了。那么,您称之为"访问上下文"的是什么?要做什么?我认为您会对函数的特殊属性感兴趣,在这里的"用户定义函数"部分(docs.python.org/reference/…)中进行了解释。
- @eyquem的意思是包含我的函数的第一个对象(例如,模块、类等)的a句柄。我要做的是使函数重载decorator。特别是,请看我对这个答案的前三条评论,了解我正试图解决的确切问题。
- @保罗·曼塔,你能表达一下你寻找的动机是什么吗?您的目标所涉及的技术过程超出了我对Python的了解,我无法理解所有这些的根本动机。
- @你为什么这么想?重载修饰器还是获取上下文?如果是后者,我的意图并不是一成不变的;我只是在探索所有可能的解决我的装饰问题的方法,看看哪一个更好。现在,似乎修改上下文的解决方案不是最好的解决方案。如果可能的话,我仍然感兴趣,以防将来我需要它。:)
- @保罗曼塔的动机,使一个装修允许超载。顺便问一下,您希望通过装饰器重载哪种对象?
- @我想重载任何类型的函数。我不需要这个修饰器,但在某些情况下,我不能让我的函数忽略它们参数的类型,而且我不喜欢手动检查isinstance几次来确定我应该执行什么代码——我认为如果在自己的函数中单独处理每种类型,就更清楚了。
- @paul manta好吧,你想重载函数。我仍然不完全认为有必要这样做。在我看来,你试图实现一个复杂的目标,从而避免简单的"手动"任务。顺便问一下,通过"手动检查",您的意思是在执行过程中必须进行检查吗?难道不可能根据传递的参数类型编写一个带有"if"部分的函数来确定不同的进程吗?还是在编写函数时简化工作?
- @是的,我想简化函数的编写。
- @保罗曼塔哦!真的?我犹豫着问这个问题,因为我不敢相信你花了很长时间来简化写操作,而这些操作只对每个函数进行了一次快速的处理。现在,我看不出有任何其他的理由让你尝试这样做,除了每天频繁地编写函数。在本例中,我将亲自编写一个程序,根据脚本中的参数类型向函数添加提供不同行为的代码片段,而不是试图通过使用python的可能性以编程方式包含此行为。
- @保罗·曼塔,我的英语不太好理解。对不起的
- @Eyquem认为这是一个有趣的项目,将来会帮助我。:)有点像枚举的PEP 354实现——这不是真正必要的,但是这种健壮的实现现在确实有用。
我认为您需要推出自己的版本,但是标准库inspect模块将为您提供您所需要的大部分内容。
inspect.ismethod()和inspect.isfunction()将有助于确定函数是否绑定(在类中定义),从而确定您是在寻找类还是模块(希望…因为一个函数可能被定义在另一个作用域而不是模块中…例如,作为另一个函数或方法范围内的本地定义函数,或作为lambda(实际上是相同的东西)
特别要注意的是,方法的im_class不会检索到方法定义的类。但是您可以(使用inspect.getmro()按照类层次结构)找到方法定义的"最新"类。
顺便问一下,我想知道修改一个模块是否就是你想要的…在许多情况下,该模块中的名称可能已经导入到其他地方……)特别是,如果您有Ruby元编程经验,并且正在尝试在Python中复制它,我会担心(对于您和您未来的理智),这是非常不同的,最好不要尝试在Python中做一些粗俗的事情。
- 我要做的是使函数重载decorator。特别是,请看我对这个答案的前三条评论,了解我正试图解决的确切问题。
- 好吧,如果你只想在一个装饰器中使用这些东西,那么它是一个非常不同的情况:对于在一个模块中定义的未绑定函数来说更容易(因为你应该能够轻松地计算出当前模块,并向它添加一些东西)。但是对于一个方法,我相信当装饰器接收到该方法时,它还不会出现在类的上下文中…(对类的绑定发生在方法定义之后),因此您可能需要在类的元类中做一些额外的工作。你测试过这个吗(通过打印实例的结果,是方法)
您的意思是函数globals()和locals()。它们都返回一个分别包含全局变量和局部变量的字典。但是,不能对它们进行任何元编程,因为不允许更改它们。
阿法克除了当前的情况外,没有办法了解任何情况(globals/locals的呼叫者)。
- 不允许?但这是可能的。那么,为什么不允许这样做呢?
- @eyquem:阅读globals()和locals()的文档。它包含一个注释,说明对听写的更改可能不会反映出来。所以如果你依赖它,你会把自己放在非常薄的冰上。
- @整个语言不是这样设计的吗?
- @夜曲注释只存在于locals()的描述中。上面写着"不应该修改"和"可能不会影响",并不是说这是完全非法的。我认为,如果有人对python的数据模型、名称空间和执行模型有一个透彻的理解,他就可以大胆地利用在globals()和locals()中进行更改的可能性。我承认我的脚太热了,不能假装自信地这么做。
- @Eyquem:好吧,这是C定义的季度,也是"特定于实现"的季度。你可以使用它,但是依赖它是愚蠢的,除非你确定你的产品将使用什么版本和什么解释程序/编译器。
- @我倾向于回答"相当肯定"。但是,虽然我没有很多例子,但是肯定有很多严格的规则是不能被侵犯的,否则语言就不是一种语言,而是一种无法使用的弹性材料。例如,不允许对字典使用不可显示的键,我发现这个问题表示了另一种不可能的情况:(stackoverflow.com/q/2223300/551449)
- @晚上好吧,你可能比我更了解Python。在实例上考虑具体的案例是很有趣的。然而,我没有时间深入研究这个问题。