【问题标题】:Python: Hack to call a method on an object that isn't of its classPython:在不属于其类的对象上调用方法
【发布时间】:2011-02-16 11:20:39
【问题描述】:

假设你定义了一个类,它有一个方法可以做一些复杂的处理:

class A(object):
    def my_method(self):
        # Some complicated processing is done here
        return self

现在你想在另一个类的某个对象上完全使用该方法。比如,你想做A.my_method(7)

这就是你会得到的:TypeError: unbound method my_method() must be called with A instance as first argument (got int instance instead)

现在,有没有可能破解一些东西,以便您可以7 上调用该方法?我想避免移动函数或重写它。 (请注意,该方法的逻辑确实依赖于self。)

注意:我知道有些人会想说,“你做错了!你在滥用 Python!你不应该这样做!”所以是的,我知道,这是我想做的一件可怕的事情。我问的是是否有人知道该怎么做,而不是如何向我宣扬我不应该这样做。

【问题讨论】:

  • 我看到大多数答案都建议我将逻辑移到单独的函数中。可以,是的,但我更愿意避免它,我想知道是否可以将其保留为一种方法,但仍可在 7 上调用它。

标签: python class object methods


【解决方案1】:

当然,我不建议在实际代码中这样做,但是是的,当然,您可以进入类内部并将其方法用作函数:

class A(object):
    def my_method(self):
        # Some complicated processing is done here
        return 'Hi'

print(A.__dict__['my_method'](7))
# Hi

【讨论】:

  • 我要你做我孩子的父亲! :)
  • xyld,我在其他值得尊敬的软件包中看到了一些严重的黑客攻击。这玩意儿还挺有礼貌的。
  • @cool-RR 我也见过一些严重的hack,但这太荒谬了,因为它和A.my_method(self)完全一样,你还是要传入self...跨度>
【解决方案2】:

这就是所谓的staticmethod

class A(object):
    @staticmethod
    def my_method(a, b, c):
        return a, b, c

但是在静态方法中,您不会获得对 self 的引用。

如果您想要引用class 而不是instance(实例暗示引用self),您可以使用类方法:

class A(object):
    classvar = "var"

    @classmethod
    def my_method(cls, a, b, c):
        print cls.classvar
        return a, b, c

但您只能访问类变量,而不是实例变量(通常在 __init__ 构造函数中创建/定义的变量)。

如果这还不够好,那么您将需要以某种方式传递“绑定”方法或将“self”传递给方法,如下所示:

class A(object):
    def my_method(self):
        # use self and manipulate the object

inst = A()
A.my_method(inst)

正如一些人已经说过的,只从另一个类继承一个类并不是一个坏主意:

class A(object):
    ... methods ...

class B(A):
    def my_method(self):
        ... use self

newA = B()

【讨论】:

  • 感谢您的回答,但我说:“请注意,该方法的逻辑确实取决于self。”。
【解决方案3】:

在 Python 中函数不需要包含在类中。听起来您需要的是实用程序功能,所以只需将其定义为:

def my_function(object):
    # Some complicated processing is done here
    return object

my_function(7)
my_function("Seven")

只要您的处理使用通过 duck typing 的魔力传递给 my_function 的所有对象上可用的方法和属性,一切都会正常工作。

【讨论】:

    【解决方案4】:
    def some_method(self):
        # Some complicated processing is done here
        return self
    
    class A(object):
        my_method = some_method
    a = A()
    
    print some_method
    print a.my_method
    print A.my_method
    print A.my_method.im_func
    print A.__dict__['my_method']
    

    打印:

    <function some_method at 0x719f0>
    <bound method A.some_method of <__main__.A object at 0x757b0>>
    <unbound method A.some_method>
    <function some_method at 0x719f0>
    <function some_method at 0x719f0>
    

    听起来您正在查找类的方法并获得unbound methodunbound method 需要一个适当类型的对象作为第一个参数。

    如果你想将函数作为函数应用,你必须得到它的函数版本的句柄。

    【讨论】:

      【解决方案5】:

      你为什么不能这样做

      class A(object):
          def my_method(self,arg=None):
              if (arg!=None):
                 #Do Some Complicated Processing with both objects and return something 
              else:
                     # Some complicated processing is done here
              return self
      

      【讨论】:

        【解决方案6】:

        你不能。在 Python 3000 中实际上已经取消了限制,但我想你没有使用它。

        但是,为什么你不能这样做:

        def method_implementation(self, x,y):
           # do whatever
        
        class A():
           def method(self, x, y):
                return method_implementation(self, x, y)
        

        如果你真的想滥用 python,请编写一个实现该行为的描述符类。类似的东西

        class Hack:
           def __init__(self, fn):
               self.fn = fn
           def __get__(self, obj, cls):
               if obj is None: # called staticly
                    return self.fn
               else:
                    def inner(*args, **kwargs):
                         return self.fn(obj, *args, **kwargs)
                    return inner
        

        请注意,这是完全未经测试的,可能会打破一些极端情况,而且是邪恶的。

        【讨论】:

        • 感谢您提供有关 Python 3 的信息,这很有趣,但我不知道。
        【解决方案7】:
        >>> class A():
        ...     me = 'i am A'
        ... 
        >>> class B():
        ...     me = 'i am B'
        ... 
        >>> def get_name(self):
        ...     print self.me
        ... 
        >>> A.name = get_name
        >>> a=A()
        >>> a.name()
        i am A
        >>> 
        >>> B.name = get_name
        >>> b=B()
        >>> b.name()
        i am B
        >>> 
        

        【讨论】:

        • 个人而言,如果我想要几种类型的对象继承标准 API,我会使用类继承,以便 A 和 B 从某个第三个基类继承 name 方法。这只是一个例子。
        • OP 不是在寻找合理的答案 - 他想破解,所以对于这个问题的任何答案,您几乎都应该遮住眼睛。
        • 可能是这样,但问题是可以不应该这样做。
        【解决方案8】:

        您可以将该方法放入需要调用它的两个对象的超类中,不是吗?如果它如此重要以至于您无法复制它,也无法将其更改为不使用 self,那是我能看到的唯一其他选择。

        【讨论】:

        • 不好,这是一个特定于它所定义的类的方法。
        猜你喜欢
        • 1970-01-01
        • 2016-12-28
        • 1970-01-01
        • 2013-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-07
        • 2014-06-30
        相关资源
        最近更新 更多