4

假设我正在声明一个类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对象包裹的函数,然后才能调用它。

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

4

6 回答 6

14

很简单,解决方案是 f 不需要是类的成员。我假设您的思维过程已经通过了 Java 语言过滤器,从而导致了心理障碍。它有点像这样:

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

class C(object):

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

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

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

我认为这个故事的寓意是“在 Python 中,您不必将所有内容强制归入一个类”。

于 2008-11-20T08:50:18.190 回答
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,但没有其他权限(除非对其方法进行相当复杂的自省 ( C.method_using_f.im_func.func_closure))

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

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

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

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

于 2008-11-20T12:00:16.200 回答
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 不搭调

于 2008-11-20T13:09:46.683 回答
1

这是一种可能性:

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()
于 2008-11-20T11:37:17.777 回答
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
于 2008-11-20T23:21:16.373 回答
0

让我们从头开始。

“在类中声明一个函数,在其声明期间使用它,稍后在类中使用它”

对不起。做不到。“在课堂上”与“在声明期间使用”相矛盾。

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

目前尚不清楚 Cw 和 Cv 应该是什么。它们只是字符串吗?如果是这样,外部函数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 是一个适当的、可以扩展的一流的东西。不是我们试图避免暴露的“隐藏”事物。这是生活中的事实,所以我们不妨遵循 Open/Closed 原则,让它对扩展开放。

于 2008-11-20T12:15:14.627 回答