我知道在静态语言中,接收文件对象而不是表示路径的字符串(从软件设计角度来看)总是更好。但是,在像python这样的动态语言中,你看不到变量的类型,传递文件的“正确”方法是什么?
传递函数对象是不是有问题,因为你需要记住之后关闭它(你可能不会因为你看不到类型而没有)?
答案 0 :(得分:2)
理想情况下,无论何时打开文件,您都会使用with语句,因此关闭将由此处理。
with open('filepath', 'r') as f:
myfunc(f)
otherstuff() # f is now closed
最好在处理文件时使用with关键字 对象。这样做的好处是文件在之后正确关闭 它的套件即使在路上引发异常也会完成。
答案 1 :(得分:1)
然而,在像python这样的动态语言中你看不到 变量的类型,传递文件的“正确”方法是什么?
简短的回答是 - 你没有。
在大多数面向对象的语言中,有一个对象契约,它保证如果对象有一个方法quack
,它就知道如何嘎嘎叫。有些语言在执行此合同(例如Java)和其他语言时非常严格。
最后,它归结为Python的一个原则EAFP
:
E a sk f orgiveness p ermission。这个常见的Python 编码风格假定存在有效的键或属性 如果假设被证明是假的,则捕获异常。这干净又快 风格的特点是存在许多尝试和除外 声明。该技术与许多人共同的LBYL风格形成鲜明对比 其他语言,如C.
LBYL =在你跳跃之前看看
这意味着如果您的方法需要一个“文件”(并在文档中说明这一点),假设您正在传递“类似对象的文件”。尝试对对象执行文件操作(如read()
或close()
),然后在引发异常时捕获它。
EAFP方法的一个要点是,你可能会传递一个像文件一样工作的对象,换句话说 - 调用者知道他们在做什么。因此,如果您花时间检查确切的类型,那么您将拥有无法正常工作的代码。现在,呼叫者有责任满足您的“对象合同”;但是,如果他们不使用文件但使用内存缓冲区(与文件具有相同的方法)呢?或者是请求对象(同样,具有相同的文件类方法)。您无法检查代码中的所有这些变体。
这是首选方法 - 而不是LBYL方法,它首先进行类型检查。
因此,如果您的方法的文档声明它期望文件对象,它应该与任何“文件类似”的对象一起使用,但是当有人将字符串传递给文件路径时,您的方法应该引发适当的异常。
此外,更重要的是 - 您应该避免关闭方法中的对象;因为它可能不像前面解释过的“文件”。但是,如果您绝对必须,请确保您的方法的文档非常清楚地说明了这一点。
以下是一个例子:
def my_method(fobj):
''' Writes to fobj, which is any file-like object,
and returns the object '''
try:
fobj.write('The answer is: {}\n'.format(42))
except (AttributeError, TypeError):
raise TypeError('Expected file-like object')
return fobj
答案 2 :(得分:1)
像任何其他类型一样传递文件对象。
def f(myfile):
myfile.write('asdf')
ofs = open(filepath, 'w') # ofs is file object
f(ofs) # passes file object
ofs.close()
也可以使用闭包。
def f():
return open(filepath, 'w') # returns file object
ofs = f()
ofs.write('something')
ofs.close()
答案 3 :(得分:0)
您可以使用file objects in Python。当它们(自动)被垃圾收集时,文件将被关闭。
文件对象使用C的stdio包实现,可以使用内置的open()函数创建。