Python 类对象在指定函数时是不规则的

Python 类对象在指定函数时是不规则的,python,function,functional-programming,Python,Function,Functional Programming,假设我有这样一个函数: def id(x): return x def id_(self, x): return x 我希望能把它绑定到任何物体上比如说x x.f = id 并且能够做到 x.f(1) => 1 但是,类不是常规对象,因为它不起作用: class X(object): pass X.f = id x.f(1) => unbound method f() must be called with X instance as first argument (got

假设我有这样一个函数:

def id(x): return x
def id_(self, x):
    return x

我希望能把它绑定到任何物体上比如说x

x.f = id 并且能够做到

x.f(1) => 1 但是,类不是常规对象,因为它不起作用:

class X(object): pass X.f = id x.f(1) => unbound method f() must be called with X instance as first argument (got int instance instead) 所以我不得不这么做

X.f=staticmethod(id) X.f(1) => 1 但是它不适用于常规对象

x.f=staticmethod(f) x.f(1) => 'staticmethod' object is not callable 那么,有没有一种方法可以在通用代码中按预期进行赋值工作 我不知道指定给的对象是否是类对象的常规对象 指定的对象何时可能是函数

import inspect
if inspect.isclass(X):
   X.f = staticmethod(f)
else:
   X.f = f
问题不在于任务;那很好。这是因为类上的函数将self作为它们的第一个参数,而您的函数没有。您可以使用

X.__dict__['f']
<function f at 0x023A52F0>

您得到的是一个未绑定的方法,而不是原始函数,因为在Python2.x中,访问类上的方法时会发生这种情况。在Python3.x中,这一点发生了变化,您只需获得原始函数。我相信这是为了向后兼容老式类

这是一件奇怪的事情:如果你甚至不知道你正在处理的对象是否是一个类,那么你就在一个非常高的抽象级别上工作!对于这个问题,如果传递了一个内置类型,比如字符串,该怎么办?你不能在上面设置属性!我认为你需要在一个稍微低一点的层次上工作

问题不在于任务;那很好。这是因为类上的函数将self作为它们的第一个参数,而您的函数没有。您可以使用

X.__dict__['f']
<function f at 0x023A52F0>

您得到的是一个未绑定的方法,而不是原始函数,因为在Python2.x中,访问类上的方法时会发生这种情况。在Python3.x中,这一点发生了变化,您只需获得原始函数。我相信这是为了向后兼容老式类


这是一件奇怪的事情:如果你甚至不知道你正在处理的对象是否是一个类,那么你就在一个非常高的抽象级别上工作!对于这个问题,如果传递了一个内置类型,比如字符串,该怎么办?你不能在上面设置属性!我认为您需要在稍微低一点的级别上工作。

定义要绑定的函数,如下所示:

def id(x): return x
def id_(self, x):
    return x
现在,您可以执行以下操作:

X.f = id_
x = X()
x.f(1)
=> 1

定义要绑定的函数,如下所示:

def id(x): return x
def id_(self, x):
    return x
现在,您可以执行以下操作:

X.f = id_
x = X()
x.f(1)
=> 1

我同意这是相当奇怪的行为。也许这是有原因的;也许这是一个从未得到充分调查的角落案例,或者,如果它被调查,被认为是如此模糊以至于不值得处理。有时会发生

如果希望将函数指定为类属性总是使其成为静态方法,可以使用元类来实现这一点

class func2static(type):
    def __setattr__(cls, name, value):
        if type(value) is type(lambda: 0):
            value = staticmethod(value)
        type.__setattr__(cls, name, value)

class X(object):
    __metaclass__ = func2static
现在让我们展示类和类的实例都可以有一个分配给它们的函数,然后可以调用该函数

f = lambda x: x

X.f = f
X.f(3)  # no exception

x = X()    
x.g = f
x.g(3)  # also no exception

不幸的是,如果您正在对其他模块中定义的随机类进行猴子补丁,那么这并不能真正解决问题,但您可能不应该这样做-

我同意这是相当奇怪的行为。也许这是有原因的;也许这是一个从未得到充分调查的角落案例,或者,如果它被调查,被认为是如此模糊以至于不值得处理。有时会发生

如果希望将函数指定为类属性总是使其成为静态方法,可以使用元类来实现这一点

class func2static(type):
    def __setattr__(cls, name, value):
        if type(value) is type(lambda: 0):
            value = staticmethod(value)
        type.__setattr__(cls, name, value)

class X(object):
    __metaclass__ = func2static
现在让我们展示类和类的实例都可以有一个分配给它们的函数,然后可以调用该函数

f = lambda x: x

X.f = f
X.f(3)  # no exception

x = X()    
x.g = f
x.g(3)  # also no exception

不幸的是,如果您正在对其他模块中定义的随机类进行猴子补丁,那么这并不能真正解决问题,但您可能不应该这样做-

你不应该重写内置的id方法。我希望能将它绑定到任何对象,真的吗?为什么?是否有任何链接或引用可以设置该期望值?您不应该覆盖内置id方法。我希望能够将其绑定到任何对象?为什么?任何链接或引用都会设定这种期望?这不是重点。关键是这应该是通用的,而不必修改函数。这就是staticmethod调用的目的。@Katrielex:我认为这应该对OP有所帮助,因为从他的问题来看,我认为他不理解为什么他的第一个示例不起作用,所以他认为他可以使用staticmethod来解决这个问题,而不仅仅是像我的答案monkey Matching if x中所示更改函数参数是一个常规对象,它将不起作用,但会导致错误f只接受给定的2个参数1,因为f在分配给常规对象时没有绑定。@Katrielaax:staticmethod只能在它是类对象而不是常规对象时使用。@Eduardo:我现在明白了您要表达的观点;我不建议将函数绑定到常规对象
直接原因是没有使用它,因为您没有访问自实例的权限,即使您使用staticmethod,您也必须知道staticmethod类似于常规模块函数,另一方面,我的答案中的方法在执行动态扩展类的monkey patching时非常有用,希望能有帮助:这不是重点。关键是这应该是通用的,而不必修改函数。这就是staticmethod调用的目的。@Katrielex:我认为这应该对OP有所帮助,因为从他的问题来看,我认为他不理解为什么他的第一个示例不起作用,所以他认为他可以使用staticmethod来解决这个问题,而不仅仅是像我的答案monkey Matching if x中所示更改函数参数是一个常规对象,它将不起作用,但会导致错误f只接受给定的2个参数1,因为f在分配给常规对象时没有绑定。@Katrielaax:staticmethod只能在它是类对象而不是常规对象时使用。@Eduardo:我现在明白了您要表达的观点;我不建议将函数直接绑定到常规对象,因为它没有使用,因为您没有访问自实例的权限,即使您使用staticmethod,您也必须知道staticmethod与常规模块函数类似,另一方面,我的答案中的方法在进行动态扩展类的monkey patching时非常有用,我们希望它能有所帮助:事实上,在Python3中,函数没有变成绑定函数:X.f=f和X.f1=>1,我不认为这与旧样式类的兼容性有关,因为旧样式类在函数绑定方面的行为与新样式类相同。事实上,在Python 3中,函数没有变成绑定函数:X.f=f和X.f1=>1。但是,我认为这与旧样式类的兼容性无关,因为旧样式类在函数绑定方面的行为与新样式类相同。