Ruby vs. Python - operacje na plikach
Posted by Jarosław Zabiełło Tue, 11 Apr 2006 19:47:00 GMT
Ostatnio miałem potrzebę napisania skryptu kopiującego całe pliki z całego drzewa folderów. Problem w tym, że chciałem kopiować tylko pliki, które nie miały ustawionych atrybutów tylko do odczytu. I to musiało być zrobione pod Windowsami. Zwykle jestem przyzwyczajony że tego typu zadania to piszę w Pythonie w kilka minut. Nie spodziewałem się że tu będzie inaczej….
Okazało się że Python (2.4.3) nie ma porządnie zaimplementowanych metod sprawdzania atrybutów pliku. Na próżno szukałem w manualu, Python Cookbook , internecie.
Zgodnie z prawami Murphego rozwiązanie znalazłem jak już było niepotrzebne (w międzyczasie zdążyłem napisać to w Ruby).
>>> os.stat(r'c:\tmp\test1')[stat.ST_MODE] & stat.S_IWRITE
128
>>> os.stat(r'c:\tmp\test2')[stat.ST_MODE] & stat.S_IWRITE
0Wygląda to raczej paskudnie na tle analogicznego kodu Rubiego:
>>> File.writable?('c:\tmp\test1')
true
>>> File.writable?('c:\tmp\test2')
falseMoże to szczególny przypadek, ale jakoś nie sprawdziła się w tym wypadku prostota Pythona. Metody Rubiego w tym temacie są znacznie bardziej intuicyjne. Zresztą zobaczmy poniższy przykład z manuala Pythona:
import os, sys
from stat import *
def walktree(top, callback):
for f in os.listdir(top):
pathname = os.path.join(top, f)
mode = os.stat(pathname)[ST_MODE]
if S_ISDIR(mode):
walktree(pathname, callback)
elif S_ISREG(mode):
callback(pathname)
else:
print 'Skipping %s' % pathname
def visitfile(file):
print 'visiting', file
if __name__ == '__main__':
walktree(sys.argv[1], visitfile)Ten sam kod w języku Ruby wygląda tak:
require 'find'
if $0 == __FILE__
Find.find(ARGV[0]) do |f|
if File.file?(f)
puts 'visiting ' + f
elsif not File.directory?(f)
puts 'skipping ' + f
end
end
endI kto tu powie, że Ruby jest mniej czytelny od Pythona?


Kanały IRC![[Dilber w Onecie]](/images/larry.png)


Co do pierwszego, to będzie wyglądać paskudnie, póki nie użyjesz przeznaczonej do tego funkcji. A jest to os.access.
Co zaś do tej pętli, to też wymyśliłeś na nowo koło. Istnieje w bibliotece os funkcja walk. Kod wtedy znacznie się upraszcza:
Jeżeli zaś zapiszę to podobnie jak Ty zapisałeś to w Ruby’m, to będzie nawet krócej:
To, że znasz lepiej bibliotekę standardową jednego języka nie znaczy od razu, że jest on bardziej czytelny.
Co do tego drugiego przykładu, to faktycznie os.walk() upraszcza sprawę (nie wiem dlaczego w manualu do Python 2.4.3 wciąż widnieje stary, mętny przykład) Ale podany przykład nie jest do końca odpowiednikiem tego z artykułu. Powinien np. wyświetlać “missing ” dla obiektów nie będących plikami ani folderami.
Pierwszy też da się uprościć do:
Nie ma już zatem takiego kontrastu, ale nadal uważam, że konstrukcja File.writable?() jest czytelniejsza i bardziej intuicyjna. Guido mógłby używać jakieś lepsze nazwy.
Co do czytelności ‘is_writable’, ‘is_readable’ to kwestia gustu i podejścia. Można stosować różne funkcje, i mnożyć byty nad potrzebę (jak w PHP), albo zastosować jedną funkcję, spełniającą dokładnie taką samą rolę. Mi osobiście nie robi różnicy.
A o co chodzi z mętnym przykładem os.walk() ? Nie wiem czy zwróciłeś uwagę, że w module os jest jedna funkcja walk(), a w os.path – druga. I w manualu wyrażnie jest napisane, której lepiej używać.
W głównym manualu do Pythona wypowiadającym się na temat interpretacji wyników funkcji stat() widnieje przykład taki, jaki podałem w artykule. Nie wspominają nic o os.walk().
Ruby nie ma żadnego is_writable, ma za to writable? (Znaki zapytania dotyczą metod które zwracają wartość boolowską). Poza tym Python powinien (zgodnie ze swoimi założeniami) minimalizować ilość metod wykonujących tą samą czynność. Może to i banał, ale trochę musiałem się naszukać aby odnaleźć właściwy moduł do sprawdzania czy plik ma ustawiony atrybut do zapisu. I wiem, że nie tylko ja byłem tu zdezorientowany.
is_writable etc to było nawiązanie do PHP. Co do manuala: manual pokazuje funkcje które są omawiane, i akurat ktoś kto dokumentował moduł stat wolał sam rekurencyjnie ‘biegać’ po katalogach. A może w czasach gdy go opisywał nie było jeszcze os.walk ? Nie wiem, nie wnikam. Jak dla mnie, jeśli chcę dokonać operacji na katalogach/plikach, to zaczynam szukać w os lub os.path. Stamtąd mnie odeślą najwyżej na stat, shutils czy inne.
A co do dezorientacji: zaczynałem uczyć się pythona od operacji właśnie na plikach i katalogach, i jakoś nie miałem problemu ze sprawdzaniem praw do pliku. Ani grama dezorientacji :)
E-e, wolimy pythona ;)
Eeee, my wolimy Ruby.
Zdecydowanie wolimy Pythona. Jest piekny.