实例方法装饰器在哪里?

3 投票
3 回答
819 浏览
提问于 2025-04-16 15:33

在我的代码中,有一个方法会返回一个类的实例,像这样:

class MyClass:
  def fun( self, *args ): # the method
    return Props( self, *args )

class Props: # the returned object
  def __init__( self, parent, *args ):
    self.parent = parent
    self.args = args

为了保持代码的整洁,我在考虑把Props放进MyClass里。然后我想直接把这个类变成MyClass的一个实例方法,像这样:

class MyClass:
  @instancemethod # does not exist!
  class fun:
    def __init__( self, parent, *args ):
      self.parent = parent
      self.args = args

注意注释 - instancemethod这个装饰器是不存在的。

有没有办法做到这一点,也就是把一个可调用的对象变成实例方法?如果我把@instancemethod改成@classmethod,代码就能运行了,但那样的话,parent就是类,而不是实例。我很惊讶找不到关于这个看起来相反的操作的任何信息。

我很想搞清楚这个问题!

编辑:

看来我的问题不太清楚。我有一个成员函数fun,它返回的不是单个值或元组,而是一个充满数据的对象。这些数据是根据MyClass对象的内容和函数参数生成的。我的初始代码正好实现了我想要的效果。第二段代码是我更希望的写法。

而且我注意到我在找的装饰器其实就是下面这个:

def instancemethod( cls ):
  def f( *args ):
    return cls( *args )
  return f

当然,它和我想要绕过的'fun'方法是一样的。还要注意,简单的'return cls'并不相同,尽管乍一看可能会让人觉得是一样的。

有了这个装饰器,我的第二个类定义是有效的,并且能产生我想要的结果,也就是说,a.fun()返回的对象是(可能)根据a中的数据初始化的:

a = MyClass()
p = a.fun(1,2,3)

print a        # <__main__.MyClass instance at 0xb775b84c>
print p.parent # <__main__.MyClass instance at 0xb775b84c>
print p.args   # (1, 2, 3)

这让我仍然有个疑问,就是这里定义的instancemethod是不是Python内置的,因为它似乎在classmethod和staticmethod旁边被遗漏了。不过,如果没有的话,我想我可以接受这种写法。

3 个回答

0

你不需要一个实例方法的装饰器,这段代码应该可以正常工作:

class MyClass:
  class fun:
    def __init__( self, parent, *args ):
      self.parent = parent
      self.args = args

m = MyClass()
f = m.fun(None, 1, 2, 3)
print f.args

你也可以把你的第一个例子改成

class Props:
    def __init__( self, parent, *args ):
        self.parent = parent
        self.args = args


class MyClass:
    fun = Props

m = MyClass()
f = m.fun(None, 1, 2, 3)
print f.args
1

我觉得你把事情搞得太复杂了,其实没必要;可能是你习惯了其他编程语言,想把那里的习惯带过来。

如果我理解得没错的话,你想做的事情大概是这样的:

class SomeClass:
    # typical stuff
    def __init__(self, other, arg1, arg2, arg3, arg4):
        self.parent= other
        # blah blah

class SomeOtherClass:
    # initialize in __init__, setup stuff
    def __init__(self, initarg1, initarg2):
        self.initarg1= initarg1
        self.initarg2= initarg2

    def fun(self, arg3, arg4):
        # return an instance of SomeClass based on
        # initargs and arguments
        return SomeClass(self, self.initarg1, self.initarg2, arg3, arg4)
1

我不太确定你具体想做什么,但我猜你可能想了解一下描述符

简单来说,描述符是一个类的属性,而这个属性本身也是一个类,它定义了__get____set__这两个方法。在你的情况下,你可以把Props.__init__里的代码移动到Props.__set__里,把Props设置为这个类的fun属性,这样一切就应该能按你想要的方式工作了。

撰写回答