区分python函数和类函数

区分python函数和类函数,python,function,class,python-3.x,methods,Python,Function,Class,Python 3.x,Methods,我试图找出如何区分python模块级函数和尚未绑定到对象实例的方法。当函数是未绑定的实例方法时,我需要定义该方法的类的句柄inspect.ismethod()不起作用,因为该方法尚未绑定到对象实例type()为模块级函数和未绑定方法返回“function” 用例是一个使用方法和函数装饰器的插件框架。我有一个通用的“Model”类,可以将其子类化以添加功能。插件“actions”是使用@register\u action(name)装饰器在子类中定义的。在导入时调用decorator函数来注册操作

我试图找出如何区分python模块级函数和尚未绑定到对象实例的方法。当函数是未绑定的实例方法时,我需要定义该方法的类的句柄
inspect.ismethod()
不起作用,因为该方法尚未绑定到对象实例
type()
为模块级函数和未绑定方法返回“function”

用例是一个使用方法和函数装饰器的插件框架。我有一个通用的“Model”类,可以将其子类化以添加功能。插件“actions”是使用
@register\u action(name)
装饰器在子类中定义的。在导入时调用decorator函数来注册操作。然后,gui会为字典中的每个操作添加菜单项——但gui只应在gui的模型类是注册函数/方法的类的实例时添加操作

下面是一些示例代码。现在我的解决方案是解析fcn描述符的文本,然后检查
class\u str==str(model.\uu class\uuuuu).split('.')[-1].strip('>)
。我还尝试将SpecialModel传递给decorator,但decorator函数运行时未定义SpecialModel,因此无法工作。注册类方法操作必须有更好的解决方案

注意:由于未定义
SpecialMethod
而无法将
SpecialMethod
传递到
register\u action
装饰器中,因此在gui中注册操作时,我可能需要调用
get\u class\u from\u函数

ACTIONS = dict()

### HACK -- best I could do, but want actual Class, not class_name ###
# FIXME : want to return None, Model, SpecialModel, etc. 
def get_class_from_function( fcn ):
    qname = fcn.__qualname__.split( '.' )
    if len( qname ) > 1:     # this is (likely) a class function
        cls_name = qname[0]
        return cls_name
    else:
        return None

def register_action( name ):
    def register_decorator( fcn ):
        global ACTION
        cls = get_class_from_function( fcn )
        ACTION[ name ] = ( fcn, cls )
        return fcn
    return register_decorator

@register_action( "Help/About" )
def help_about_function( model ):
    pass

class Model( object ):
    def __init__( self ):
        pass

    @register_action( "File/Load" )
    def load( self ):
        pass

class SpecialModel( Model ):
    @register_action( "Special/Custom Action" )
    def specialact( self ):
        pass

这有助于区分模块中定义的函数和类中定义的函数:

import sys
import types

def is_module_func(obj):
    mod = sys.modules[obj.__module__]
    return isinstance(obj, types.FunctionType) and hasattr(mod, obj.__name__)
现在:


我认为你可以通过这样一个装饰师来完成你的最终目标:

def register_action( name ):
    def register_decorator( fcn ):
        fcn._action_name = name
        return fcn
    return register_decorator
然后,在您的gui代码中,当您实际拥有对象实例时,迭代其实例方法并查找任何具有
\u action\u name
的实例,并为其创建特定于gui的代码:

for method_name, method in inspect.getmembers(my_specific_instance, predicate=inspect.ismethod):
   if hasattr(method, '_action_name'):
       add_to_gui_menu(method._action_name, method)

您是否考虑过检查第一个参数是否为
self
(例如
args=inspect.getargspec(thing.args;args和args[0]='self'
)?我相信在Python3中,自由函数和类定义中定义的函数之间没有区别。事实上,您可以在模块级别定义一个函数并将其“固定”到类中,它的工作方式就好像它被定义为一个方法一样。也许这不是最好的方法。。。也许注册方法的操作应该由类完成。也就是说,只要定义了
模型
,就应该注册它的方法。这可以通过类装饰器或者元类来完成。类方法是一个艺术术语。据我所知,您使用该术语是不正确的,只是混淆了问题。@jonrsharpe--是的,这是我们使用inspect模块所能找到的唯一区别之一。如果我们小心地使用“self”而不是slf、s等,它就解决了第一个问题,但这并不能解决问题的第二部分,我们需要检查我们的模型是否是SpecialModel等的子类。@swinman您无法从3.x中的未绑定方法访问该类-请参见例如,谢谢-不幸的是,这在@register decorator中不起作用,因为hasattr(mod,obj.\uu name\uuuuuuuuu)返回false,当模块和函数具有相同的名称时会产生混淆,需要澄清的是:hasattr返回false,因为当decorator运行hanks时,对象尚未添加到模块中,这是有效的(在经过少量语法修复后)
inspect.getmembers()
返回
(mname,method)
元组。另外,将
\uuuuuuuuuuuuuuuuu动作名称更改为
\uuuu动作名称
,因为尾部的
\uuuuuuuuuu
是python专用的,前导的
\uuuuuuuuuuuuuuuuuuu
会损坏变量名称
for method_name, method in inspect.getmembers(my_specific_instance, predicate=inspect.ismethod):
   if hasattr(method, '_action_name'):
       add_to_gui_menu(method._action_name, method)