Одна проблема заключается в том, что в приведенном выше коде есть условие гонки, поскольку существует разрыв между тестированием на наличие и созданием файла. Это может иметь последствия для безопасности (подумайте о том, что кто-то злонамеренно вставил символическую ссылку в конфиденциальный файл, который он не смог бы перезаписать, но ваша программа могла бы работать с более высоким уровнем привилегий). ) устарели.
Чтобы обойти это, лучше всего попытаться создать файл таким образом, чтобы в случае сбоя вы получили исключение, а в случае успеха вернуть фактически открытый объект файла. Это можно сделать с помощью функций os.open нижнего уровня, передав флаги os.O_CREAT и os.O_EXCL. После открытия верните фактический файл (и, возможно, имя файла), который вы создали. Например, вот ваш код, модифицированный для использования этого подхода (возвращающий кортеж (файл, имя файла)):
def unique_file(file_name):
counter = 1
file_name_parts = os.path.splitext(file_name) # returns ('/path/file', '.ext')
while 1:
try:
fd = os.open(file_name, os.O_CREAT | os.O_EXCL | os.O_RDRW)
return os.fdopen(fd), file_name
except OSError:
pass
file_name = file_name_parts[0] + '_' + str(counter) + file_name_parts[1]
counter += 1
[Редактировать] На самом деле, лучший способ, который решит вышеуказанные проблемы для вас, это, вероятно, использовать модуль tempfile, хотя вы можете потерять контроль над именованием. Вот пример его использования (с сохранением аналогичного интерфейса):
def unique_file(file_name):
dirname, filename = os.path.split(file_name)
prefix, suffix = os.path.splitext(filename)
fd, filename = tempfile.mkstemp(suffix, prefix+"_", dirname)
return os.fdopen(fd), filename
>>> f, filename=unique_file('/home/some_dir/foo.txt')
>>> print filename
/home/some_dir/foo_z8f_2Z.txt
Единственным недостатком этого подхода является то, что вы всегда будете получать имя файла с некоторыми случайными символами в нем, так как нет никакой попытки сначала создать неизмененный файл (/home/some_dir/foo.txt).
Вы также можете захотеть взглянуть на tempfile.TeoraryFile и NamedTevenFile, которые будут выполнять все вышеперечисленное, а также автоматически удалять с диска при закрытии.