保留Python

时间:2017-11-17 13:49:35

标签: python python-3.x function

我在Python中有一个函数,当首先被调用时,将文件的内容读取到列表中并检查元素是否在该列表中。

def is_in_file(element, path):
    with open(path, 'r') as f:
        lines = [line.strip() for line in f.readlines()]
    return element in lines

然而,当再次调用该函数时,不应再次读取该文件的内容;该函数应该记住第一次调用时lines的值。

有没有办法在再次调用函数时保留函数的上下文?我不想让全局lines不要丢弃上面的命名空间。我想这与使用生成器和yield语句......

非常相似

5 个答案:

答案 0 :(得分:2)

脏黑客:将变量添加到函数对象并在那里存储值。

def is_in_file(element, path):
    if not hasattr(is_in_file, "__lines__"):
        with open(path, 'r') as f:
            setattr(is_in_file, "__lines__", [line.strip() for line in f.readlines()])
    return element in is_in_file.__lines__

答案 1 :(得分:2)

我的观点是,正确的方法是将其封装在一个类中。路径在实例创建时设置,方法调用使用行列表。这样你甚至可以同时拥有不同的文件

class finder:
   def __init__(self, path):
       with open(path, 'r') as f:
           self.lines = [line.strip() for line in f]
   def is_in_file(self, element):
       return element in lines

这不完全是你所要求的,但更多的是OO。

答案 2 :(得分:1)

您可以将行保存在使用可变默认值声明的关键字参数中:

def is_in_file(element, path, lines=[]):
    if lines:
        return element in lines
    with open(path, 'r') as f:
        lines += [line.strip() for line in f.readlines()]
    return element in lines

<强> 警告: 你必须确保只用一个文件调用这个函数;如果你用第二个文件调用它,它将不会打开它并继续根据打开的第一个文件返回值。

更灵活的解决方案:

更灵活的解决方案可能是使用行字典,其中每个新文件可以使用路径作为键打开一次并存储;然后,您可以使用不同的文件调用该函数,并在记忆内容时获得正确的结果。

def is_in_file(element, path, all_lines={}):
    try:
        return element in all_lines[path]
    except KeyError:
        with open(path, 'r') as f:
            all_lines[path] = [line.strip() for line in f.readlines()]
        return element in lines

OO解决方案:

创建一个类来封装文件的内容,就像@SergeBallesta提出的那样;虽然它没有完全满足您的要求,但从长远来看,它可能是更好的解决方案。

答案 3 :(得分:1)

使用functools.lru_cache装饰器设置一个辅助函数,该函数只读取任何给定文件一次,然后存储结果。

from functools import lru_cache

@lru_cache(maxsize=1)
def read_once(path):
    with open(path) as f:
        print('reading {} ...'.format(path))
        return [line.strip() for line in f]

def in_file(element, path):
    return element in read_once(path)

演示:

>>> in_file('3', 'file.txt')
reading file.txt ...
True
>>> in_file('3', 'file.txt')
True
>>> in_file('3', 'anotherfile.txt')
reading anotherfile.txt ...
False
>>> in_file('3', 'anotherfile.txt')
False

这具有以下重要优势:每次都不必使用相同的文件名调用in_file

如果您希望在任何给定时间缓存多个文件,可以将maxsize参数调整为更高的数字。

最后:如果您感兴趣的是会员资格测试,请考虑设置read_once的返回值。

答案 4 :(得分:1)

这个答案提出了一个类似于Serge Ballesta的想法的课程。

区别在于它完全像功能,因为我们使用它的just before subscribe just after subscribe got value 1 got value 2 got value 3 done 方法而不是点符号来进行搜索。

此外,您可以根据需要添加任意数量的可搜索文件。

设定:

__call__

用法

class in_file:
    def __init__(self):
        self.files = {}

    def add_path(self, path):
        with open(path) as f:
            self.files[path] = {line.strip() for line in f}

    def __call__(self, element, path):
        if path not in self.files:
            self.add_path(path)
        return element in self.files[path]

in_file = in_file()