利用函数来减少代码复用

在 Python 中,当声明一个类时,我们可能会遇到代码复用的问题。例如,我们想声明一个类 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 参数(出于明显的原因不能接受)。一种可能性是在使用 f 之后将其删除:

>>> 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 对象包装的函数。

  1. 解决方案

答案1:

最简单的解决方案是,f 不需要成为类的成员。我们可以直接使用函数 f:

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

class C(object):

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

当我们想要再次使用 f 时,直接使用即可:

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

答案2:

如果我们真的想避免在模块命名空间中使用 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 是内部的应该是足够的。

答案3:

我们可以尝试以下方法:

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

然后我们就可以使用 C.v 和 C.f(25) 了。

答案4:

另一种可能性是编写一个更好的 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

现在我们可以像这样使用它:

class C(object):
    @staticfunc
    def f(cls):
        return 'boo'

C.f()  # 'boo'

答案5:

我们还可以直接使用函数 f:

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

class C(object):
    v = f(9)

然后我们就可以使用 C.v 了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值