51

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Ваш вариант не ходит по подкаталогам. В условии задачи было указано, что параметром является каталог, с которого начинать поиск, а не каталог, которым все и ограничивается.

Разбор параметров командной строки лучше получить стандартному парсеру: http://www.python.org/doc/2.5/lib/module-optparse.html

В Питоне придерживаются принципа EAFP (Easier to Ask Forgiveness than Permission) - легче попросить прощения, чем разрешения. Поэтому вот такой код:

if not sys.argv[2].isdigit():
    print 'Eto ne integer'
    sys.exit()
else: maxfilecont = int(sys.argv[2])

В Питоне обычно выглядит как-нибудь так:

try:
    maxfilecont = int(sys.argv[2])
except ValueError:
    print "%s - eto ne integer" % sys.argv[2]
    sys.exit(1)

Я понимаю, что это все уйдет в парсер, но все равно показательно.

На одной строке условные выражение тоже не принято писать.

Вообще всем участникам рекомендую глянуть сюда: http://www.python.org/dev/peps/pep-0008/ и придерживаться стиля, который там описан. Это фактически стандарт для Питонового кода.

Манипуляции с путями лучше производить с помощью os.path.join и других функций из os.path. Это во-первых системо-независимо, во вторых не понадобится вот таких вещей: if pathtodir[-1] != '/': pathtodir = pathtodir + '/'

О Питоне говорят 'Batteries included' - 'батарейки в комплекте'. Эти батарейки - это стандартная библиотека. Ее нужно знать и уметь, потому что там есть все или почти все. От вещей типа os.path.join, до готового HTTP сервера.

Почитайте вот это для ознакомления с общей структурой и идеологией языка: http://ru.wikipedia.org/wiki/Python
Осознайте Zen of Python, это поможет программировать и не только на Питоне.

770/800/810/900

52 Отредактировано alex2ndr (12-01-2009 23:22:41)

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Исправил вроде все что сказали - критикуйте wink

#!/usr/bin/env python2.5
# -*-coding: utf-8 -*-

import os
import sys

from optparse import OptionParser

def parseOptions():
    parser = OptionParser()
    # Парсим параметры ком строки, заодно проверяя их тип
    parser.add_option('--directory', '-d', dest='path', type="string")
    parser.add_option('--count', '-c', dest='mflct', type="int")
    (options, args) = parser.parse_args()
    
    #print args
    # А вот здесь у меня затык - почему то при выводе я получаю пустой список
    # хотя должен вроде быть не пустой - я конечно и без этого обошелся -но непонятно
    # прошу пояснить
 
    # Проверяем полученные параметры
    if not (options.path and options.mflct):
        parser.error("options --directory and --count not present")
    if not os.path.isdir(options.path):
    parser.error(options.path, "it`s not directory")
    return options
# Функция сортировки
def filesorter(filelist, dirname, names):
        # Запускаем цикл по всем элем текущего каталога
        for i in range(0,len(names)):
    # Получаем полный путь - я осознаю что переменную р можно было не использовать
    # но мне так читабельнее
        p = os.path.join(dirname, names[i])
    # Получаем самый маленкий файл сверху
    filelist.sort()
    # Сравниваем разм наименьшего файла с размером текущего файла - если больше заменяем
        if os.path.isfile(p):
        if int(os.path.getsize(p)) > filelist[0][0]:
            filelist[0] = (int(os.path.getsize(p)), p)
#Получаем параметры ком строки в основной модуль
opt = parseOptions()
maxfilecont = opt.mflct
pathtodir = opt.path
# Инициализируем наш список кортежей
filelist = [(0 , '')] * (maxfilecont + 1)
# Проходим по всем папкам вглубь от заданного пути
os.path.walk(pathtodir, filesorter, filelist)
# Переворачиваем список
filelist.reverse()
# Отбрасываем нули если они есть - зачем их печатать то?
for j in range(0,len(filelist)):
    if filelist[j][0] == 0:
    break
#Выводим на печать наш список кортежей (размер , путь) без нулей
for i in range(0,j):
    print "%d        %s" % (filelist[i])

Натравил на исходники Wesnoth и сказал вывести 320000 файлов - скрипт пахал минут 5-7 и показывал загрузку проца -100% , но памяти жрал немного - 1-2% от моих 2 гб. Я так понимаю что основной затык в сортировке такого массива - интересно как это можно оптимизировать - пока ничего не приходит в голову(впрочем я уже спать хочу - может завтра чего придумаю)

Nokia N800 OS 5.2008.43-7 / Nokia 3110 Classic / Debian 5.0.0 Lenny

53

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

хммм в части

....
    if not os.path.isdir(options.path):
        parser.error(options.path, "it`s not directory")
    return options
....

в предыдущем посте нету красной строки у строчки parser.error(options.path, "it`s not directory") - но при редактировании сообщения она есть - для тех кто заметит это не ошибка а какой то глюк сайта или у меня кривые ручки

Nokia N800 OS 5.2008.43-7 / Nokia 3110 Classic / Debian 5.0.0 Lenny

54

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Ну, это намного лучше, молодца  smile

#print args
    # А вот здесь у меня затык - почему то при выводе я получаю пустой список
    # хотя должен вроде быть не пустой - я конечно и без этого обошелся -но непонятно
    # прошу пояснить

Все опции, которые парсер обработал он забрал. Они теперь доступны через options. В общем-то это правильно, потому хотя бы, что там у них правильные типы и их не нужно опять конвертировать. В args после этого останется то, что не было обработано.

Например для командной строки типа '-d/ -c10 file_name' после парсинга опций в args останется file_name, что хорошо, не нужно дальше заморачиваться и пропускать уже обработанное парсером. Если нам нужно, скажем имя или имена файлов и мы не хотим делать их опциями, то мы их и прочитаем из этого args, после того, как парсер возьмет свое.

Теперь посмотрим код:

1. Между логическими компонентами кода нужно делать пустые строки, так смотрится понятнее. Видимо читали Zen of Python невнимательно, пункты 6 и 7 как раз об этом.

2. Вот такие вещи:

for i in range(0,len(names)):
    p = os.path.join(dirname, names[i])

в Питоне делаются так:

for fname in names:
   p = os.path.join(dirname, fname)

Правда же, так понятнее?
   
3. Сортировка нужна только, когда список меняется, а у вас она происходит всегда.

4. В Питоне, как и в других языках условия можно комбинировать с помощью логических операций:

if os.path.isfile(p):
    if int(os.path.getsize(p)) > filelist[0][0]:
        filelist[0] = (int(os.path.getsize(p)), p)

лучше сделать так:

if os.path.isfile(p) and os.path.getsize(p) > filelist[0][0]:
        filelist[0] = (os.path.getsize(p), p)

Я еще убрал приведение к int. getsize возвращает число и без этого.

5. maxfilecont и pathtodir на мой взгляд не нужны. Если нравятся эти имена, то нужно просто сделать так, чтобы в парсере атрибуты так же назывались и использовать их просто из opt. К тому же они используются по одному разу.

6. Два последних цикла страдают той же болезнью, что описана в пункте 2. Питон - простой и выразительный язык. Если получаются такие конструкции, то скорее всего что-то сделано не так.

7. вместо двух последних циклов достаточно одного.

8. Вот такие сравнения в Питоне делаются крайне редко:

if filelist[j][0] == 0:

Все пустое (строка, число, список, словарь и так далее) проверяется просто так:

if not var:

А не пустое так:

if var:

Что-то я смотрю остальные ученики разбежались. А зря - дальше будет интереснее.

770/800/810/900

55

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

mosfet пишет:
filelist = MAXFILES * [(0, None)]

for i in reversed( range(MAXFILES) ):

Ы?

Извините, пропустил ваш пост. Первое - да. Второе - нет.

770/800/810/900

56

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Ну хорошо

...
for i in reversed(filelist):
   print '%10d\t%s' % i

Как еще выравнивание размеров по правому краю сделать не знаю.

И еще: может здесь кто-нибудь объяснит назначение функции lambda ? Везде, где читал так и не понял. О функциональном программировании общее представление имею.

N800 N900

57

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

2 Wall Спасибо Большое за Ваши пояснения и замечания.
По поводу Ваших замечаний:
1. Ну в файле программы у меня есть пустые строки - кудаж без них то. Но когда я вставил это на форум мне показалось что если удалить пустые строки то скролить меньше - ну и удалил smile. Теперь не буду.

3. Готовлю новую оптимизацию - постараюсь сегодня вечером - в ней эта проблемма уйдет.

4. я конечно знаю про and и тд. Но код -

if os.path.isfile(p):
    if int(os.path.getsize(p)) > filelist[0][0]:
        filelist[0] = (int(os.path.getsize(p)), p)

Сделан таким не просто так. Мне нужна была именно ПОСЛЕДОВАТЕЛЬНАЯ обработка условий. Т е если это не файл то его размер вычислять не надо т к это лишнее обращение к харду а значит лишнее время ( размер / будет долго вычисляться). Я прочитал про "ленивое" вычисление условий но до конца не уверен что если я напишу if os.path.isfile(p) and os.path.getsize(p) > filelist[0][0]: то os.path.getsize(p) не будет вычислен при os.path.isfile(p)=false. Поясните пожалуйста

Остальное принял к сведению и правлю - постараюсь выложить вечером.

И еще один вопросик.

os.path.walk(path, visit, arg)
    Calls the function visit with arguments (arg, dirname, names) for each directory in the directory tree rooted at path (including path itself, if it is a directory). The argument dirname specifies the visited directory, the argument names lists the files in the directory (gotten from os.listdir(dirname)). The visit function may modify names to influence the set of directories visited below dirname, e.g. to avoid visiting certain parts of the tree. (The object referred to by names must be modified in place, using del or slice assignment.)

я правильно понял что arg возвращает в тело основной проги какую либо переменную(ну или забирает ее из __main__). Когда писал свою прогу был уверен что через это буду возвращать свой filelist - но потом посмотрел сообщение mosfet #47 то что-то засомневался - там функция из __main__ так вызывается - os.path.walk(BASEDIR, processDirectory, None) - написано что не оттестированно - это ошибка? Прокоментируйте кто разбирается

Nokia N800 OS 5.2008.43-7 / Nokia 3110 Classic / Debian 5.0.0 Lenny

58

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

os.walk просто прохаживается по всем файлом, начиная с path,  вызывая каждый раз функцию visit с аргументами arg. Аргументы dirname и names передаются в нее автоматом, поэтому в данном случае

os.path.walk(BASEDIR, processDirectory, None)

(никакие другие аргументы не нужны - None)

N800 N900

59

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

mosfet пишет:

Ну хорошо

...
for i in reversed(filelist):
   print '%10d\t%s' % i

Угу. Только вместо i я бы поставил нечто более вразумительное.

И еще: может здесь кто-нибудь объяснит назначение функции lambda ? Везде, где читал так и не понял. О функциональном программировании общее представление имею.

В моем представлении это функция без имени с определенными ограничениями.

Вот простой пример:

In [15]: lambda x: x*x
Out[15]: <function <lambda> at 0xb7b81f44>

In [16]: f = lambda x: x*x

In [17]: f(2)
Out[17]: 4

In [18]: f(3)
Out[18]: 9

Я бы не советовал ею пользоваться, если вы не программируете в функциональном стиле. Во большинстве случаев можно найти более выразительные и более быстрые конструкции языка, которые ее заменят.

770/800/810/900

60

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

alex2ndr пишет:

Я прочитал про "ленивое" вычисление условий но до конца не уверен что если я напишу if os.path.isfile(p) and os.path.getsize(p) > filelist[0][0]: то os.path.getsize(p) не будет вычислен при os.path.isfile(p)=false. Поясните пожалуйста

Раз прочитали, но не поверили, то нужно было просто проверить. Если появляются такие вопросы, то просто запускайте Python и проверяйте прямо в нем:
Смотрите как легко:

In [24]: def foo(value):
   ....:     print 'foo', value
   ....:     return value
   ....: 

In [25]: if foo(False) and foo(True):
   ....:     print 'foo was called twice'
   ....:     
   ....:     
foo False

In [26]: if foo(True) and foo(True):
   ....:     print 'foo was called twice'
   ....:     
   ....:     
foo True
foo True
foo was called twice
770/800/810/900

61

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Wall пишет:
In [15]: lambda x: x*x
Out[15]: <function <lambda> at 0xb7b81f44>

In [16]: f = lambda x: x*x

In [17]: f(2)
Out[17]: 4

In [18]: f(3)
Out[18]: 9

Всё равно, не понимаю, что мешает написать

def f(x):
   return x*x
N800 N900

62

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Ничего не мешает. Иногда компактнее, вот например:

In [4]: sorted([1,-3,2,-7,4], lambda x, y: cmp(abs(x), abs(y)))
Out[5]: [1, 2, -3, 4, -7]

Бывают и другие случаи.

770/800/810/900

63 Отредактировано alex2ndr (13-01-2009 23:22:58)

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Еще разок оптимизировал заодно постарался поправить все замечания - и теперь прога не боиться больших --count

#!/usr/bin/env python2.5
# -*-coding: utf-8 -*-

import os
import sys

from optparse import OptionParser

def parseOptions():
    parser = OptionParser("usage: %prog options")
    # Парсим параметры ком строки, заодно проверяя их тип
    parser.add_option('--directory', '-d', dest='path', type="string", \
            help="start path" )
    parser.add_option('--count', '-c', dest='mflct', type="int", \
            help="count of files")
    (options, args) = parser.parse_args()
    
    # Проверяем полученные параметры
    if not (options.path and options.mflct):
        parser.error("options --directory and --count not present")
    if not os.path.isdir(options.path):
        parser.error(options.path, "it`s not directory")
    return options

# Функция сортировки
def filesorter(arg, dirname, names):
    # Запускаем цикл по всем элем текущего каталога
        for namesi in names:
            p = os.path.join(dirname, namesi)
            # Проверяем подходит ли нам файл
        if os.path.isfile(p) and os.path.getsize(p) >= filelist[0][0]:
        
        #   Здесь я использовал некоторую избыточность кода - зато получил большую
        # производительность если в параметр --count ввели очень большое число  
        # например 1000000000
                #   Если список файлов меньше чем запрошенное значение - добавляем файл
                if len(filelist) < opt.mflct:
                    filelist.append((os.path.getsize(p), p))
                    filelist.sort()
        # Иначе заменяем первый элемент    
                else:
                    filelist[0] = (os.path.getsize(p), p)
                    filelist.sort()

# Получаем параметры ком строки в основной модуль
opt = parseOptions()
# Инициализируем наш список кортежей
filelist = [(0 , '')]
# Проходим по всем папкам вглубь от заданного пути
os.path.walk(opt.path, filesorter, None)

# Недостатком моего алгоритам является первый пустой элемент
# когда запрошенный список больше чем файлов найдено - удаляем его
if not filelist[0][1]:
    filelist.pop(0)

# Переворачиваем список
filelist.reverse()
#Выводим на печать наш список кортежей (размер , путь)
for i in filelist:
    print "%d        %s" % (i)

Правда у этого алгоритма есть небольшой недостаток - файлы с одинаковым размером он добавляет с конца так сказать - т е сначала последний встреченный потом предпоследний и тд. Можно исправить - но тогда он не будет работать с файлами с размером 0 байт. Я подумал что такой порядок не противоречит условиям задачи и оставил так.(испавляется просто - в строке if os.path.isfile(p) and os.path.getsize(p) >= filelist[0][0]: знак >= меняется на >)

Nokia N800 OS 5.2008.43-7 / Nokia 3110 Classic / Debian 5.0.0 Lenny

64

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

В общем выглядит хорошо - глаз ни за что не цепляется. Ну, разве что сортировка там дублируется, i невразумительное в последнем цикле, неиспользуемый импорт sys, p опять же из той серии непонятных коротких имен, но это мелочи. Алгоритм по-прежнему оставляет желать лучшего. Но мы над этим еще поработаем.

Следующие шаги:
1. Сделать так, чтобы вывод подсказки (опция -h) выглядел поприличнее. Кстати, если пользователь ввел что-то не то, то кроме сообщения об этом можно вывести и help. OptionParser это умеет.

2. Выделить основной код в функцию main и вызывать ее так, как описано здесь: http://www.artima.com/weblogs/viewpost.jsp?thread=4829
Это, кстати, автор языка написал, Гвидо Ван Россум. У него там используется getopt, у нас OptionParser, но идею понять, думаю можно.

3. Прочитать отсюда: http://www.python.org/doc/2.5/tut/node1 … 0000000000 и до конца страницы. Очень сильно подумать. Следующее задание будет на эту тему.

770/800/810/900

65

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Wall пишет:

Что-то я смотрю остальные ученики разбежались. А зря - дальше будет интереснее.

Скорее наблюдается дисперсия результативности. Работа началась, времени мало для дальнейшего продвижения.

Не мотай на ус то, что вешают на уши.
Nokia N810 + SE M600i

66

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

torovec пишет:

Скорее наблюдается дисперсия результативности. Работа началась, времени мало для дальнейшего продвижения.

Можем притормозить и подождать остальных. Но нужно знать кого. Вопросы они не задают, код не показывают sad

Люди, не стесняйтесь! Если у вас что-то не получается - спрашивайте. Или если все развивается слишком быстро для вас - говорите. Я ориентируюсь по фактам, а не по домыслам. Факты таковы - работает 2 человека, остальные отвалились. Если это не так - только рад буду.

770/800/810/900

67

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Wall пишет:

3. Прочитать отсюда: http://www.python.org/doc/2.5/tut/node1 … 0000000000 и до конца страницы. Очень сильно подумать. Следующее задание будет на эту тему.

И, пожалуй, еще про list comprehensions здесь: http://www.python.org/doc/2.5/tut/node7 … 0000000000
Там чуть-чуть.

Все вышеперечисленное очень часто используется в Python и отличает его от остальных языков. Это так называемый syntactic sugar: http://ru.wikipedia.org/wiki/%D0%A1%D0% … 0%B0%D1%80

И это то, что мы будем использовать, чтобы наша программа приобрела вид питоновской.

Я не совсем согласен с авторами этой статьи в википедии в той части, что использование этого ничего не дает. Как минимум не в Python. В этом языке использование таких конструкций - норма, это то, что отличает его от других.

770/800/810/900

68

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Wall пишет:

Ну, разве что сортировка там дублируется, ..... Алгоритм по-прежнему оставляет желать лучшего.

Он потому и оставляет желать лучшего что дублируется (IMHO). Изначально моя идея выглядела так

if os.path.isfile(p) and os.path.getsize(p) >= filelist[0][0]:
    if len(filelist) < opt.mflct:
        filelist.append((os.path.getsize(p), p))
     else:
        filelist[0] = (os.path.getsize(p), p)
        filelist.sort()

Это очень сильно оптимизирует по производительности при росте списка.
Но вчера мне не хватило времени ее оттестировать нормально. Поэтому запостил так( т е с 2-я сортировками). Сегодня вечером поправлю.

По поводу остальных - я предлагаю подождать до конца выходных, а потом вывесить второе задание - если кто нить присоединиться позже - пусть выполняет первое самостоятельно, с учетом тех решений что мы уже напостили. Окончательное решение по первому пока не вывешивать(ну или послать в личку для самообразования). Это если никто не напишет что тоже изучает но не успевает.

Nokia N800 OS 5.2008.43-7 / Nokia 3110 Classic / Debian 5.0.0 Lenny

69

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Вот до чего дошел. Словарь-то сделал, а сортировку по нему пока не очень. Данный скрипт сортирует по всему значению ключа. Бьюсь второй день, пытаюсь сделать сортировку именно по 2 элементу списка, каждого значения.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
from operator import itemgetter
from heapq import nlargest

# Константы
PathFiles = '/home/aouser/users/'
Number = 10

listFiles = {}
# Формирую словарь, где {полный_путь : [имя_файла, размер_файла], ...}
for dirPath, dirName, fileName in os.walk(PathFiles):
    for name in fileName:
        pathFile = os.path.join(dirPath, name)
        listFiles[pathFile] = ([name, os.path.getsize(pathFile)])

print nlargest(Number, listFiles.iteritems(), itemgetter(1))

Да, пока не очень понял философский смысл итератора в Python'е. Как им пользоваться?

Не мотай на ус то, что вешают на уши.
Nokia N810 + SE M600i

70

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

alex2ndr пишет:

По поводу остальных - я предлагаю подождать до конца выходных, а потом вывесить второе задание - если кто нить присоединиться позже - пусть выполняет первое самостоятельно, с учетом тех решений что мы уже напостили. Окончательное решение по первому пока не вывешивать(ну или послать в личку для самообразования). Это если никто не напишет что тоже изучает но не успевает.

Второго задания как такового не будет. Когда мы закончим разбираться с голым питоном на примере этого скрипта, то перейдем к gtk, но это не будет новым заданием, это будет написание gui к нашему скрипту.
Для того, чтобы закончить с голым питоном нам нужно поработать с syntactic sugar и с объектами. После того, как это будет проделано можно двигаться в сторону gtk.

Но все это не значит, что остальные должны за нами гнаться. Я буду смотреть любой код, который сюда положат, на любом уровне. Желательно, чтобы люди читали тред перед тем, как выкладывать код и задавали вопросы, если что непонятно.
Но смотреть и комментировать я постараюсь все. Да и другие, думаю, помогут.

770/800/810/900

71

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

torovec пишет:

Вот до чего дошел. Словарь-то сделал, а сортировку по нему пока не очень. Данный скрипт сортирует по всему значению ключа. Бьюсь второй день, пытаюсь сделать сортировку именно по 2 элементу списка, каждого значения.

Код будет работать очень медленно на большом количестве файлов. Вы добавляете в свой словарь все файлы, а нужны вам только 10. Тут уже были похожие варианты. Память тоже будет кушаться на ура. В остальном хорошо. Код чистый, понятный.
Кстати, а зачем вам хранить имя файла? Оно же нигде не используется.

Да, пока не очень понял философский смысл итератора в Python'е. Как им пользоваться?

Так вы ими уже пользуетесь. Обычные списки, кортежи и словари являются итераторами. Вот, например:

In [16]: print [].__iter__
<method-wrapper '__iter__' of list object at 0x938922c>
In [17]: print {}.__iter__
<method-wrapper '__iter__' of dict object at 0x938a4f4>

Все объекты, которые имеют __iter__ метод - итераторы. Как правило большинство стандартных типов Python, которые можно поставить в цикл for предоставляют интерфейс итератора.

770/800/810/900

72 Отредактировано torovec (14-01-2009 21:33:17)

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Wall, пожалуй да, имена файлов можно не хранить.
А с остальным не совсем понятно.
Как можно узнать наибольший элемент не набрав полную статистику по низлежащему дереву файлов?
А далее... nlargest, насколько я понял, позиционируется авторами, как "быстрая" функция, скомпилированная на С, оптимизированная для поиска наибольших ключей/значений.

Или же Вы считаете, что быстрее будет сразу искать максимальное значение размера файла и тут же запоминать соответствующее название файла?

P.S. А размер файла - это табличное значение в файловой системе или каждый раз расчитывается, при соответствующем запросе?

Не мотай на ус то, что вешают на уши.
Nokia N810 + SE M600i

73

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Гляньте на скрипты других авторов, там все это уже есть. Нет смысла собирать все, чтобы выбрать десять самых больших. Просмотреть все нужно, никто не спорит.

Насчет nlargest - это легко выяснить, глянув во внутренности heapq.
Вот, что у меня там:

def nlargest(n, iterable, key=None):
    """Find the n largest elements in a dataset.

    Equivalent to:  sorted(iterable, key=key, reverse=True)[:n]
    """
    in1, in2 = tee(iterable)
    it = izip(imap(key, in1), imap(neg, count()), in2)      # decorate
    result = _nlargest(n, it)
    return map(itemgetter(2), result)                       # undecorate

Как видите, Си тут и не пахнет. 

Но дело не в nlargest, дело в собирании всех файлов в один большой словарь. Это замедлит работу и сожрет память. Могу ошибаться, но в целом это мне не нравится по вышеописанной причине.

Размер файлов получается вызовом стандартной функции из libc stat(), которая как правило зовет ядерный сисколл, если мне не изменяет память.

770/800/810/900

74 Отредактировано alex2ndr (14-01-2009 22:40:25)

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

Доправил алгоритм - теперь я даже незнаю что можно тут оптимизировать - по сравнению с первой версией производительность теперь определяется в основном скоростью харда.

#!/usr/bin/env python2.5
# -*-coding: utf-8 -*-

import os

from optparse import OptionParser

def parseOptions():
    parser = OptionParser(usage="Usage: %prog -d -c", version="%prog 0.4")
    # Парсим параметры ком строки, заодно проверяя их тип
    parser.add_option('--directory', '-d', dest='path', type="string", \
            help="starting path for search" )
    parser.add_option('--count', '-c', dest='mflct', type="int", \
            help="count of files for print")
    (options, args) = parser.parse_args()
    
    # Проверяем полученные параметры
    if not (options.path and options.mflct):
        parser.print_help()
        parser.error("options --directory and --count not present")
    if not os.path.isdir(options.path):
        parser.print_help()
        parser.error(options.path, "it`s not directory")
    return options

# Функция сортировки
def filesorter(arg, dirname, names):
    # Запускаем цикл по всем элем текущего каталога
    for namesi in names:
            flpath = os.path.join(dirname, namesi)
            # Проверяем подходит ли нам файл
        if os.path.isfile(flpath) and os.path.getsize(flpath) > filelist[0][0]:
        
                # Здесь я использовал некоторую избыточность кода - зато получил большую
                # производительность если в параметр --count ввели очень большое число  
                # например 1000000000
                #   Если список файлов меньше чем запрошенное значение - добавляем файл
                if len(filelist) < opt.mflct:
                    filelist.append((os.path.getsize(flpath), flpath))
        # Иначе заменяем первый элемент    
                else:
                    filelist[0] = (os.path.getsize(flpath), flpath)
                    filelist.sort()

# Получаем параметры ком строки в основной модуль
opt = parseOptions()
# Инициализируем наш список кортежей
filelist = [(-1, '')]
# Проходим по всем папкам вглубь от заданного пути
os.path.walk(opt.path, filesorter, None)

# Недостатком моего алгоритам является первый пустой элемент
# когда запрошенный список больше чем файлов найдено - удаляем его
if not filelist[0][1]:
    filelist.pop(0)

# Сортируем(на случай если знач --count больше 
# чем встретилось файлов) и переворачиваем список
filelist.sort()
filelist.reverse()
#Выводим на печать наш список кортежей (размер , путь)
for filelisti in filelist:
    print "%d        %s" % (filelisti)

Только с help немного непонятно - вывод usage дублируется -

alex@hc-deb-al:~/Desktop/python$ ./zadanie-1-2.py -d /home/alex/Desktop/python/test/
Usage: zadanie-1-2.py -d -c

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -d PATH, --directory=PATH
                        starting path for search
  -c MFLCT, --count=MFLCT
                        count of files for print
Usage: zadanie-1-2.py -d -c

zadanie-1-2.py: error: options --directory and --count not present

Как один из usage убрать?
А теперь о серьезных трудностях. Прочитал статью Гвидо Ван Россума и вроде все понял - мне показалось несложно. Но реализовать у меня не получилось.

alex@hc-deb-al:~/Desktop/python$ cat ./zadanie-1-3.py
#!/usr/bin/env python2.5
# -*-coding: utf-8 -*-

import os

from optparse import OptionParser

def parseOptions():
    parser = OptionParser(usage="Usage: %prog -d -c", version="%prog 0.4")
    # Парсим параметры ком строки, заодно проверяя их тип
    parser.add_option('--directory', '-d', dest='path', type="string", \
                    help="starting path for search" )
    parser.add_option('--count', '-c', dest='mflct', type="int", \
                    help="count of files for print")
    (options, args) = parser.parse_args()

    # Проверяем полученные параметры
    if not (options.path and options.mflct):
        parser.print_help()
        parser.error("options --directory and --count not present")
    if not os.path.isdir(options.path):
        parser.print_help()
        parser.error(options.path, "it`s not directory")
    return options

# Функция сортировки
def filesorter(arg, dirname, names):
    # Запускаем цикл по всем элем текущего каталога
    for namesi in names:
        flpath = os.path.join(dirname, namesi)
        # Проверяем подходит ли нам файл
        if os.path.isfile(flpath) and os.path.getsize(flpath) > filelist[0][0]:
        # Здесь я использовал некоторую избыточность кода - зато получил большую
        # производительность если в параметр --count ввели очень большое число
        # например 1000000000
        #   Если список файлов меньше чем запрошенное значение - добавляем файл
            if len(filelist) < opt.mflct:
                filelist.append((os.path.getsize(flpath), flpath))
        # Иначе заменяем первый элемент
            else:
                filelist[0] = (os.path.getsize(flpath), flpath)
                filelist.sort()

def main():
    # Получаем параметры ком строки в основной модуль
    opt = parseOptions()

    # Инициализируем наш список кортежей
    filelist = [(-1, '')]

    # Проходим по всем папкам вглубь от заданного пути
    os.path.walk(opt.path, filesorter, None)

    # Недостатком моего алгоритам является первый пустой элемент
    # когда запрошенный список больше чем файлов найдено - удаляем его
    if not filelist[0][1]:
        filelist.pop(0)

    # Сортируем(на случай если знач --count больше
    # чем встретилось файлов) и переворачиваем список
    filelist.sort()
    filelist.reverse()
    #Выводим на печать наш список кортежей (размер , путь)
    for filelisti in filelist:
        print "%d        %s" % (filelisti)

if __name__ == "__main__":
    main()
alex@hc-deb-al:~/Desktop/python$ ./zadanie-1-3.py -d /home/alex/Desktop/python/test/ -c 130
Traceback (most recent call last):
  File "./zadanie-1-3.py", line 68, in <module>
    main()
  File "./zadanie-1-3.py", line 52, in main
    os.path.walk(opt.path, filesorter, None)
  File "/usr/lib/python2.5/posixpath.py", line 290, in walk
    func(arg, top, names)
  File "./zadanie-1-3.py", line 32, in filesorter
    if os.path.isfile(flpath) and os.path.getsize(flpath) > filelist[0][0]:
NameError: global name 'filelist' is not defined
alex@hc-deb-al:~/Desktop/python$

Основная проблема как я понимаю передать между функциями переменные - т е у меня из main в filesorter надо передать filelist, opt.mflct(ну еще конечно opt.path но он передается автоматически) а обратно получить filelist. Но как это сделать я не знаю так как filesorter специфическая функция и список ее входных параметров строго описан(в os.path.walk.__doc__), а как туда еще что-то добавить неизвестно. Прошу помощи - мозга за мозгу заходит

Nokia N800 OS 5.2008.43-7 / Nokia 3110 Classic / Debian 5.0.0 Lenny

75 Отредактировано alex2ndr (14-01-2009 23:08:00)

Re: Рекомендованные (знатоками) книги/ресурсы для новичков

2 torovec
Мне кажется ваш подход не совсем верен - Словари не поддерживают порядок следования записей. Т е их весьма сложно будет отсортировать. Смотрите в сторону списков и кортежей (подсказка - а точнее списка кортежей)

Насчет хранения всего списка файлов - ну тут мое мнение такое - памяти он конечно сожрет - но не очень много - зато при сортировке он СОЖРЕТ ну очень много процессорного времени. Вам надо понять это на практике - протестируйте свою прогу на каком-нить каталоге с большим кол-вом файлов. Очень хорошо подходят исходники какой нить проги (я тестирую на исходниках Wesnoth - 11371 файл, 418 подпапок, 385,9 Мб - последняя версия моего скрипта сортирует это меньше чем за 6 сек., а первая - с хранением и сортировкой всего списка - примерно 7-8 мин. хотя оперативы скрипт занимал ~1-2% от 2Гб).

2 Wall
Посоветуйте нам пожалуйста какое нить средство оценки производительности алгоритма - а то я кроме timer ничего придумать не могу.

Nokia N800 OS 5.2008.43-7 / Nokia 3110 Classic / Debian 5.0.0 Lenny