2010-01-21

О некоторых недостатках документации Python (по сравнению с Perl)

Этот пост должен бы называться "не могу больше молчать". Извините за здоровенную таблицу, но так надо.

См. таблицу 1:

pydoc os.stat perldoc -f stat
os.stat = stat(...)
stat(path) -> stat result
 
Perform a stat system call on the given path.
stat FILEHANDLE
stat EXPR
stat DIRHANDLE
stat

Returns a 13-element list giving the status info for a file, either the file opened via FILEHANDLE or DIRHANDLE, or named by EXPR. If EXPR is omitted, it stats $_. Returns a null list if the stat fails. Typically used as follows:

    ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
       $atime,$mtime,$ctime,$blksize,$blocks)
           = stat($filename);

Not all fields are supported on all filesystem types. Here are the meanings of the fields:

  0 dev      device number of filesystem
  1 ino      inode number
  2 mode     file mode  (type and permissions)
  3 nlink    number of (hard) links to the file
  4 uid      numeric user ID of file's owner
  5 gid      numeric group ID of file's owner
  6 rdev     the device identifier (special files only)
  7 size     total size of file, in bytes
  8 atime    last access time in seconds since the epoch
  9 mtime    last modify time in seconds since the epoch
 10 ctime    inode change time in seconds since the epoch (*)
 11 blksize  preferred block size for file system I/O
 12 blocks   actual number of blocks allocated

(The epoch was at 00:00 January 1, 1970 GMT.)

(*) Not all fields are supported on all filesystem types. Notably, the ctime field is non-portable. In particular, you cannot expect it to be a "creation time", see "Files and Filesystems" in perlport for details.

If stat is passed the special filehandle consisting of an underline, no stat is done, but the current contents of the stat structure from the last stat, lstat, or filetest are returned. Example:

    if (-x $file && (($d) = stat(_)) && $d < 0) {
        print "$file is executable NFS file\n";
    }

(This works on machines only for which the device number is negative under NFS.)

Because the mode contains both the file type and its permissions, you should mask off the file type portion and (s)printf using a "%o" if you want to see the real permissions.

    $mode = (stat($filename))[2];
    printf "Permissions are %04o\n", $mode & 07777;

In scalar context, stat returns a boolean value indicating success or failure, and, if successful, sets the information associated with the special filehandle _.

The File::stat module provides a convenient, by-name access mechanism:

    use File::stat;
    $sb = stat($filename);
    printf "File is %s, size is %s, perm %04o, mtime %s\n",
        $filename, $sb->size, $sb->mode & 07777,
        scalar localtime $sb->mtime;

You can import symbolic mode constants (S_IF*) and functions (S_IS*) from the Fcntl module:

    use Fcntl ':mode';

    $mode = (stat($filename))[2];

    $user_rwx      = ($mode & S_IRWXU) >> 6;
    $group_read    = ($mode & S_IRGRP) >> 3;
    $other_execute =  $mode & S_IXOTH;

    printf "Permissions are %04o\n", S_IMODE($mode), "\n";

    $is_setuid     =  $mode & S_ISUID;
    $is_directory  =  S_ISDIR($mode);

You could write the last two using the -u and -d operators. The commonly available S_IF* constants are

    # Permissions: read, write, execute, for user, group, others.

    S_IRWXU S_IRUSR S_IWUSR S_IXUSR
    S_IRWXG S_IRGRP S_IWGRP S_IXGRP
    S_IRWXO S_IROTH S_IWOTH S_IXOTH

    # Setuid/Setgid/Stickiness/SaveText.
    # Note that the exact meaning of these is system dependent.

    S_ISUID S_ISGID S_ISVTX S_ISTXT

    # File types.  Not necessarily all are available on your system.

    S_IFREG S_IFDIR S_IFLNK S_IFBLK S_IFCHR S_IFIFO S_IFSOCK S_IFWHT S_ENFMT

    # The following are compatibility aliases for S_IRUSR, S_IWUSR, S_IXUSR.

    S_IREAD S_IWRITE S_IEXEC

and the S_IF* functions are

    S_IMODE($mode)      the part of $mode containing the permission bits
                        and the setuid/setgid/sticky bits

    S_IFMT($mode)       the part of $mode containing the file type
                        which can be bit-anded with e.g. S_IFREG
                        or with the following functions

    # The operators -f, -d, -l, -b, -c, -p, and -S.

    S_ISREG($mode) S_ISDIR($mode) S_ISLNK($mode)
    S_ISBLK($mode) S_ISCHR($mode) S_ISFIFO($mode) S_ISSOCK($mode)

    # No direct -X operator counterpart, but for the first one
    # the -g operator is often equivalent.  The ENFMT stands for
    # record flocking enforcement, a platform-dependent feature.

    S_ISENFMT($mode) S_ISWHT($mode)

See your native chmod(2) and stat(2) documentation for more details about the S_* constants. To get status info for a symbolic link instead of the target file behind the link, use the lstat function.

И так везде: документация Perl — готовые рецепты с исчерпывающим описанием входных параметров и возвращаемых значений, документация Python — список методов для тех, кто наизусть помнит все протоколы, RFC, сисколлы и библиотечные вызовы.

Список использованной литературы:

  • pydoc os.stat
  • perldoc -f stat

11 comments:

morbo said...

Так и запишем: "Выкинуть Python. Изучать Perl".

vnaum said...

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

anarresti said...

Ага, есть такое. Бывает, нужно что-то достаточно простое из stdlib, а в доке ни единого примера, зато reference всех методов и отсылка к RFC. Я в этом случае обращаюсь к effbot guide to Python standard library -- http://effbot.org/zone/librarybook-index.htm

darkk said...

Есть и обратная сторона медали:

darkk@thinkpad ~ $ python
Python 2.6.4 (r264:75706, Dec 17 2009, 22:58:09)
[GCC 4.3.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.stat('/dev/null')
posix.stat_result(st_mode=8703, st_ino=821L, st_dev=11L, st_nlink=1, st_uid=0, st_gid=0, st_size=0L, st_atime=1263054934, st_mtime=1263054934, st_ctime=1263667692)
>>>
darkk@thinkpad ~ $ perl
print stat '/dev/null';
118218703100259012630549341263054934126366769240960darkk@thinkpad ~ $

anarresti said...

darkk, это с Py2.5 появилось, named tuple, причем много где (например, в time.time, urlparse.urlparse), а до этого были унылые кортежи ;)


$ python
Python 2.4.3 (#1, Sep 3 2009, 15:37:12)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.stat('/dev/null')
(8630, 25252100L, 83L, 1, 0, 0, 0L, 1262167329, 1262167329, 1262167329)

buriy.com said...

Не, это появилось с 2.6, в 2.5.2 ещё унылые кортежи:
Python 2.5.2 (r252:60911, Jan 20 2010, 23:33:04)
...
In [1]: import os

In [2]: os.stat('/dev/null')
Out[2]: (8630, 2094, 13L, 1, 0, 0, 0, 1192597200, 1154661541, 1192597645)

Sergey Lilo said...

Когда у меня спрашивают про жизнь после смерти, я показываю на перл (с)

vnaum said...

Слухи о моей смерти сильно преувеличены.
© Марк Твен

Sergey Lilo said...

Марк Твен давно уже как того.
Ничто не вечно под луной.
И perl не исключение :)
RIP

vnaum said...

> Марк Твен давно уже как того.
В писательском смысле — живее многих живых. Издаётся и продаётся в магазинах.

По топику-то есть чё сказать?
Счастлив ли ты с питоновской документацией?

Sergey Lilo said...

>По топику-то есть чё сказать?
Нет, ты же знаешь: "бессмысленные споры - наша стихия" и т.д.

Subscribe / RSS