Найти - Пользователи
Полная версия: Покомментируйте код
Начало » Python для новичков » Покомментируйте код
1 2 3
l1nx
Скрипт для копирования фото с телефона на nas и сортировкой по папкам с датой
#!/usr/bin/env python
import sys, os.path, shutil, re
from PIL import Image
from PIL.ExifTags import TAGS
# ./phone_photos_to_nas.py input_dir output_dir
inputdir  = sys.argv[1]
outputdir = sys.argv[2]
def main ():
    if os.path.isdir(inputdir):
        for root, dirs, files in os.walk(inputdir):
            for f in files:
                # if filename like 20141111_191402.jpg
                match_obj = re.match(r"\d{8}_\d{6}", f)
                if match_obj:
                    year  = f[0:4]
                    month = f[4:6]
                    day   = f[6:8]
                    date  = day + '.' + month + '.' + year
                else:
                    # get date from exif data
                    img_info = {}
                    i = Image.open(os.path.join(root, f))
                    info = i._getexif()
                    for tag, value in info.items():
                        decoded = TAGS.get(tag, tag)
                        img_info[decoded] = value
                    raw_date = img_info['DateTimeDigitized'] # 2014:11:11 19:14:02
                    year  = raw_date[0:4]
                    month = raw_date[5:7]
                    day   = raw_date[8:10]
                    date  = day + '.' + month + '.' + year
                dirs = os.walk(outputdir).next()[1]
                if date in dirs:
                    shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
                else:
                    os.makedirs(os.path.join(outputdir, date))
                    shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
    print "Done!"
main()
terabayt
сразу бросается
                match_obj = re.match(r"\d{8}_\d{6}", f)
                if match_obj:
                    year  = f[0:4]
                    month = f[4:6]
                    day   = f[6:8]
                    date  = day + '.' + month + '.' + year
                    year  = raw_date[0:4]
                    month = raw_date[5:7]
                    day   = raw_date[8:10]
                    date  = day + '.' + month + '.' + year
как миниму нужно вынести в отдельнуюю функцию, но лучше как-то сделать красивее!

if os.path.isdir(inputdir):
а что если будет передано что-то что не проходит условие?
выведет Done!
а нужно предупреждение или ошибку

import sys, os.path, shutil, re
os.makedirs(os.path.join(outputdir, date))
ну я думаю вы поняли
py.user.next
l1nx
match_obj = re.match(r"\d{8}_\d{6}", f)
if match_obj:
    year  = f[0:4]
    month = f[4:6]
    day   = f[6:8]
    date  = day + '.' + month + '.' + year

>>> import re
>>> 
>>> s = '20141111_191402.jpg'
>>> 
>>> match = re.match(r'(\d{4})(\d{2})(\d{2})_\d{6}', s)
>>> day, month, year = match.groups()[::-1]
>>> date = '{}.{}.{}'.format(day, month, year)
>>> date
'11.11.2014'
>>>


l1nx
import sys, os.path, shutil, re
1) Это всё надо на разных строках писать. (прочитай PEP8 и PEP20 из списка)
2) os.path не надо импортировать, так как он доступен при импорте os.


Ещё код слишком большой. Нужно делать функции, где каждая функция целиком помещается на экране (25 строк) и выполняет только одну задачу.
l1nx
Версия 2. Разбила функцию на функции и добавлена обработка ошибок
#!/usr/bin/env python
import os
import re
import shutil
import sys
from PIL import Image
from PIL.ExifTags import TAGS
# ./phone_photos_to_nas.py input_dir output_dir
if len(sys.argv) == 2 and (sys.argv[1] == '-h' or sys.argv[1] == 'help'):
    exit("Need 2 arguments: input_dir and output_dir")
elif len(sys.argv)!= 3:
    exit("Error: need 2 arguments: input_dir and output_dir")
inputdir = sys.argv[1]
outputdir = sys.argv[2]
date = ''
def main():
    if os.path.isdir(inputdir):
        for root, dirs, files in os.walk(inputdir):
            for f in files:
                # if filename like 20141111_191402.jpg
                match_obj = re.match(r"\d{8}_\d{6}", f)
                if match_obj:
                    format_date(f)
                else:
                    # get date from exif data
                    img_info = {}
                    i = Image.open(os.path.join(root, f))
                    info = i._getexif()
                    for tag, value in info.items():
                        decoded = TAGS.get(tag, tag)
                        img_info[decoded] = value
                    format_date(img_info['DateTimeDigitized']) # 2014:11:11 19:14:02
                copy_files(root, f, date)
    else:
        print inputdir +" is not dir"
def copy_files(root, f, date):
    if os.path.isdir(outputdir):
        dirs = os.walk(outputdir).next()[1]
        if date in dirs:
            shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
        else:
            os.mkdir(os.path.join(outputdir, date))
            shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
    else:
        print outputdir +" is not dir"
def format_date(s):
    match = re.match(r'(\d{4}):?(\d{2}):?(\d{2})[_|\s]\d{2}:?\d{2}:?\d{2}', s)
    day, month, year = match.groups()[::-1]
    global date
    date = '{}.{}.{}'.format(day, month, year)
    return date # '11.11.2014'
main()
terabayt
date = ''
global date
не нужно так делать
____________
def format_date(s):
    match = re.match(r'(\d{4}):?(\d{2}):?(\d{2})[_|\s]\d{2}:?\d{2}:?\d{2}', s)
    day, month, year = match.groups()[::-1]
    global date
    date = '{}.{}.{}'.format(day, month, year)
    return date # '11.11.2014'
очень большая, нужно воспользоваться функциями модуля datetime
_____________
                    i = Image.open(os.path.join(root, f))
                    info = i._getexif()
                    for tag, value in info.items():
                        decoded = TAGS.get(tag, tag)
                        img_info[decoded] = value
                    format_date(img_info['DateTimeDigitized']) # 2014:11:11 19:14:02
а попробуйте
                    i = Image.open(os.path.join(root, f))
                    info = i._getexif()
                    img_info = dict(info.items())
                    format_date(img_info['DateTimeDigitized']) # 2014:11:11 19:14:02
или же так как у меня
______________
вот мой вариант, не проверял
но думаю понятно что я хочу сказать :)
#!/usr/bin/env python
import os
import re
import shutil
import sys
from datetime import datetime
from PIL import Image
from PIL.ExifTags import TAGS
# ./phone_photos_to_nas.py input_dir output_dir
if len(sys.argv) == 2 and (sys.argv[1] == '-h' or sys.argv[1] == 'help'):
    exit("Need 2 arguments: input_dir and output_dir")
elif len(sys.argv)!= 3:
    exit("Error: need 2 arguments: input_dir and output_dir")
def main(inputdir, outputdir):
    if os.path.isdir(inputdir):
        for root, dirs, files in os.walk(inputdir):
            for f in files:
                # if filename like 20141111_191402.jpg
                match_obj = re.match(r"\d{8}_\d{6}", f)
                if match_obj:
                    date = format_date(f, "%Y%m%d_%H%M%S")
                else:
                    info = Image.open(os.path.join(root, f))._getexif()
                    for tag, value in info.items():
                        if TAGS.get(tag, tag) == 'DateTimeDigitized':
                            date = format_date(value, "%Y:%m:%d %H:%M:%S")
                            break
                copy_files(root, f, date, outputdir)
    else:
        print inputdir +" is not dir"
def copy_files(root, f, date, outputdir):
    if os.path.isdir(outputdir):
        dirs = os.walk(outputdir).next()[1]
        if date in dirs:
            shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
        else:
            os.mkdir(os.path.join(outputdir, date))
            shutil.copy2(os.path.join(root, f), os.path.join(outputdir, date))
    else:
        print outputdir +" is not dir"
def format_date(s, r):
    return datetime.strftime(datetime.strptime(s, r), "%d.%m.%Y")
main(sys.argv[1], sys.argv[2])
py.user.next
terabayt
нужно воспользоваться функциями модуля datetime
Не, ей просто надо переставить символы в имени файла. С датой/временем она не работает никак.
Просто функцию надо назвать не format_date(), а translate_name() или около того.

l1nx
if len(sys.argv) == 2 and (sys.argv[1] == '-h' or sys.argv[1] == 'help'):
    exit("Need 2 arguments: input_dir and output_dir")
elif len(sys.argv)!= 3:
    exit("Error: need 2 arguments: input_dir and output_dir")
inputdir = sys.argv[1]
outputdir = sys.argv[2]
Вот это всё надо заменить на argparse; там всё красиво, удобно и компактно.
Посмотришь примеры, он простой.

l1nx
inputdir = sys.argv[1]
outputdir = sys.argv[2]
date = ''
Глобальных переменных и ссылок на них вообще не должно быть.
Функции должны зависеть только от себя самих, иначе они будут ломаться из-за изменений в других функциях.

l1nx
print outputdir +" is not dir"
Старайся делать функции такими, чтобы они ничего не выводили, а либо возвращали значение True/False, 0 (успех) / 1 2 3 4 … (ошибка), либо порождали исключение в случае ошибки, а в случае успеха не возвращали ничего.
А вывод уже основывается снаружи на этих значениях.
terabayt
py.user.next
Не, ей просто надо переставить символы в имени файла. С датой/временем она не работает никак.
Просто функцию надо назвать не format_date(), а translate_name() или около того.
img_info = {}
i = Image.open(os.path.join(root, f))
info = i._getexif()
for tag, value in info.items():
    decoded = TAGS.get(tag, tag)
    img_info[decoded] = value
format_date(img_info['DateTimeDigitized']) # 2014:11:11 19:14:02
а это? я сильно не вникал
строковое представление лучше же переделать через модуль datetime чем переставлять местами символы?!
py.user.next
terabayt
а это? я сильно не вникал
А, она, походу, слила две функции в одну.

l1nx
match = re.match(r'(\d{4}):?(\d{2}):?(\d{2})[_|\s]\d{2}:?\d{2}:?\d{2}', s)
А я ещё думаю, что это регулярка у неё такая странная с двоеточиями для имён файлов.

Значит надо две функции: одна переделывает имя, а другая метаданные изображения. И у них должны быть разные регулярки.

terabayt
строковое представление лучше же переделать через модуль datetime чем переставлять местами символы?!
Когда у тебя есть целые числа, обозначающие временные величины, и тебе нужно сформировать на их основе строку - тогда да. А когда у тебя строки, которые просто нужно переставить местами, - тогда нет.

Модуль datetime отвечает за пределы значений (не даёт им вылазить) и знает роль каждого значения (при формировании минуты не окажутся секундами).

Вот пример:
>>> s = '1.12.2015'
>>> 
>>> d, m, y = s.split('.')
>>> 
>>> out = '{}_{}_{}'.format(y, m, d)
>>> out
'2015_12_1'
>>>
Для того, чтобы просто переставить части, не нужно знать, что это - дата. А ты говоришь, что, раз это дата, то нужно использовать datetime. А зачем его тут использовать?
terabayt
py.user.next
А зачем его тут использовать?
для облегчения и универсальности
py.user.next
Вот пример
это хороший пример, все красиво, но
напишите как это
20141111_191402
2014:11:11 19:14:02
можно так же красиво обработать

py.user.next
А зачем его тут использовать?

а если измениться формат имени файла? легче и удобнее будет заменить пару символов, чем переписывать функцию для перестановки
py.user.next
terabayt
для облегчения и универсальности
А если там вдруг появятся имена файлов/директорий, которые вообще ничего из даты/времени не содержат?

terabayt
напишите как это
20141111_191402
2014:11:11 19:14:02
можно так же красиво обработать
Это делается канонизация и всё:
>>> import re
>>> 
>>> def trans_name(s):
...     match = re.match(r'(\d{4})(\d{2})(\d{2})\d{6}', s)
...     day, month, year = match.groups()[::-1]
...     out = '{}.{}.{}'.format(day, month, year)
...     return out
... 
>>> def canon(s):
...     return re.sub(r'[ :_]', r'', s)
... 
>>> lst = ['20141111_191402',
...        '2014:11:11 19:14:02',
...        '2014_11_11_19_14_02.jpg']
>>> 
>>> out = [trans_name(canon(i)) for i in lst]
>>> out
['11.11.2014', '11.11.2014', '11.11.2014']
>>>

Но это не её случай всё равно, у неё как бы две части программы друг с другом не связаны, поэтому одну функцию тут лучше не юзать. Иначе если формат метаданных поменяется, то соответствующее изменение кода зацепит формат имени директории и наоборот.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB