7.9 将�方法的类转�为函数¶

问题¶

你有一个除 __init__() 方法外�定义了一个方法的类。为了简化代�,你想将它转��一个函数。

解决方案¶

大多数情况下,�以使用闭包�将�个方法的类转��函数。 举个例�,下�示例中的类�许使用者根��个模�方案�获�到URL链接地�。

from urllib.request import urlopen

class UrlTemplate:
    def __init__(self, template):
        self.template = template

    def open(self, **kwargs):
        return urlopen(self.template.format_map(kwargs))

# Example use. Download stock data from yahoo
yahoo = UrlTemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}')
for line in yahoo.open(names='IBM,AAPL,FB', fields='sl1c1v'):
    print(line.decode('utf-8'))

这个类�以被一个更简�的函数�代替:

def urltemplate(template):
    def opener(**kwargs):
        return urlopen(template.format_map(kwargs))
    return opener

# Example use
yahoo = urltemplate('http://finance.yahoo.com/d/quotes.csv?s={names}&f={fields}')
for line in yahoo(names='IBM,AAPL,FB', fields='sl1c1v'):
    print(line.decode('utf-8'))

讨论¶

大部分情况下,你拥有一个�方法类的原因是需�存储�些�外的状��给方法使用。 比如,定义UrlTemplate类的唯一目的就是先在�个地方存储模�值,以便将��以在open()方法中使用。

使用一个内部函数或者闭包的方案通常会更优雅一些。简��讲,一个闭包就是一个函数, ��过在函数内部带上了一个�外的��环境。闭包关键特点就是它会记�自己被定义时的环境。 因此,在我们的解决方案中,opener() 函数记�了 template �数的值,并在接下�的调用中使用它。

任何时候��你碰到需�给�个函数增加�外的状�信�的问题,都�以考虑使用闭包。 相比将你的函数转��一个类而言,闭包通常是一�更加简�和优雅的方案。