在Python类声明中调用方法的最佳方法是什么?

时间:2008-11-20 08:40:40

标签: python class declaration static-methods invocation

假设我正在声明一个类C,并且一些声明非常相似。我想使用函数f来减少这些声明的代码重复。可以像往常一样宣布和使用f

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     w = f(42)
... 
>>> C.v
'<9>'
>>> C.w
'<42>'
>>> C.f(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as first argument (got int instance instead)

糟糕!我无意中将f暴露给外界,但它没有采用self论证(并且由于显而易见的原因不能)。一种可能性是在我使用它后del函数:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     del f
... 
>>> C.v
'<9>'
>>> C.f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'f'

但是如果我想在声明之后再次使用f怎么办?它不会删除该功能。我可以将它设为“私有”(即,用__作为其名称前缀)并给它@staticmethod处理,但通过异常通道调用staticmethod对象变得非常时髦:

>>> class C(object):
...     @staticmethod
...     def __f(num):
...             return '<' + str(num) + '>'
...     v = __f.__get__(1)(9)   # argument to __get__ is ignored...
... 
>>> C.v
'<9>'

我必须使用上面的疯狂,因为作为描述符的staticmethod对象本身不可调用。我需要恢复staticmethod对象包装的函数才能调用它。

必须有更好的方法来做到这一点。如何在类中干净地声明一个函数,在声明过程中使用它,以及稍后在类中使用它?我应该这样做吗?

6 个答案:

答案 0 :(得分:14)

很简单,解决方案是f不需要是该类的成员。我假设你的思维过程经历了一个导致心理障碍的Javaish语言过滤器。它有点像这样:

def f(n):
    return '<' + str(num) + '>'

class C(object):

    v = f(9)
    w = f(42)

然后当你想再次使用f时,只需使用它

>>> f(4)
'<4>'

我认为这个故事的寓意是“在Python中,你没有 强迫一切都进入一个类”。

答案 1 :(得分:3)

扩展Ali A的答案, 如果你真的想避免模块命名空间中的f(并使用像_f这样的非导出名称,或设置__all__是不够的),那么 你可以通过在闭包中创建类来实现这一点。

def create_C():
    def f(num):
        return '<' + str(num) + '>'

    class C(object):
        v = f(9)
        def method_using_f(self, x):  return f(x*2)
    return C

C=create_C()
del create_C

这样C可以在其定义和方法中访问f,但没有其他方法可以访问f(除非涉及内省 其方法(C.method_using_f.im_func.func_closure))

这对于大多数目的来说可能有点过分了 - 通过使用“_”前缀命名约定来记录f是内部的 通常就够了。

[编辑] 另一个选项是在您希望使用它的方法中保存对预包装函数对象的引用。例如,通过将其设置为默认参数:< / p>

class C(object):
    def f(num):
        return '<' + str(num) + '>'

    v = f(9)
    def method_using_f(self, x, f=f):  return f(x*2)

    del f

(虽然我认为封闭方法可能更好)

答案 2 :(得分:2)

这是一种可能性:

class _C:
    # Do most of the function definitions in here
    @classmethod
    def f(cls):
        return 'boo'

class C(_C):
    # Do the subsequent decoration in here
    v = _C.f()

答案 3 :(得分:2)

我相信你正在尝试这样做:

class C():
...     class F():
...         def __call__(self,num):
...             return "<"+str(num)+">"
...     f=F()
...     v=f(9)
>>> C.v
'<9>'
>>> C.f(25)
'<25>'
>>> 

也许有更好或更多的pythonic解决方案......

  

“在类中声明一个函数,在声明过程中使用它,以及稍后在类中使用它”

     

对不起。无法完成。

“无法完成”似乎与Python无法相处

答案 4 :(得分:1)

一种选择:写出更好的staticmethod

class staticfunc(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kw):
        return self.func(*args, **kw)
    def __repr__(self):
        return 'staticfunc(%r)' % self.func

答案 5 :(得分:0)

让我们从头开始。

“在类中声明一个函数,在声明过程中使用它,以及稍后在类中使用它”

对不起。无法做到。 “在课堂上”与“在宣言中使用”相矛盾。

  • 在类中意味着作为声明的一部分创建。
  • 在声明期间使用意味着它存在于课堂之外。通常作为元类。但是,还有其他方法。

目前尚不清楚C.w和C.v应该是什么。它们只是字符串吗?如果是这样,外部函数f是最佳解决方案。 “没有杂乱的命名空间”有点似是而非。毕竟,你想再次使用它。

它与C在同一个模块中。这就是Python有模块的原因。它将功能和类绑定在一起。

import myCmod

myCmod.C.w
myCmod.C.v
myCmod.f(42)

如果w和v不是简单的字符串,那么这是一个非常好的解决方案,可以提供很大的灵活性。

通常,对于像这样的类级别(“静态”)变量,我们可以使用其他类。它不可能完全实现所需的API,但这很接近。

>>> class F(object):
    def __init__( self, num ):
        self.value= num
        self.format= "<%d>" % ( num, )

>>> class C(object):
    w= F(42)
    v= F(9)

>>> C.w
<__main__.F object at 0x00C58C30>
>>> C.w.format
'<42>'
>>> C.v.format
'<9>'

这样做的好处是F是一个可以扩展的适当的,一流的东西。不是我们试图避免暴露的“隐藏”的东西。这是生活中的事实,所以我们不妨遵循开放/封闭原则,并使其向扩展开放。