LINUX.ORG.RU

Питонья задачка

 ,


0

1

Изначально она звучит так:

В Unix-подобных ОС права доступа к ресурсу могут быть заданы в восьмеричной системе, например число 644 означает разрешение на чтение и запись для владельца ресурса и разрешает только чтение для всех остальных.

Напиши программу, которая будет переводить права, заданные в восьмеричной системе, в их текстовое описание, например decode_unix_rights('644') должна будет вывести что-то типа такого:

User:
    + can read
    + can write
    - cannot execute

Group:
    + can read
    - cannot write
    - cannot execute

Others:
    + can read
    - cannot write
    - cannot execute

Вот как я решил это — тупо и топорно:

#!/bin/env python
rights = 0b110100100
def compare_owner(num):
    if num == 0b000:
        return "Нет прав"
    elif num == 0b001:
        return "Права на исполнение для владельца"
    elif num == 0b010:
        return "Права на запись для владельца"
    elif num == 0b011:
        return "Права на запись и выполнение для владельца"
    elif num == 0b100:
        return "Права на чтение для владельца"
    elif num == 0b101:
        return "Права на чтение и выполнение для владельца"
    elif num == 0b110:
        return "Права на чтение и запись для владельца"
    elif num == 0b111:
        return "Полный доступ для владельца"
def compare_group(num):
    if num == 0b000000:
        return "Нет прав"
    elif num == 0b000001:
        return "Права на исполнение для группы"
    elif num == 0b000010:
        return "Права на запись для группы"
    elif num == 0b000011:
        return "Права на запись и выполнение для группы"
    elif num == 0b000100:
        return "Права на чтение для группы"
    elif num == 0b000101:
        return "Права на чтение и выполнение для группы"
    elif num == 0b000110:
        return "Права на чтение и запись для группы"
    elif num == 0b000111:
        return "Полный доступ для группы"
def compare_others(num):
    if num == 0b000000:
        return "Нет прав"
    elif num == 0b000000001:
        return "Права на исполнение для остальных"
    elif num == 0b000000010:
        return "Права на запись для остальных"
    elif num == 0b000000011:
        return "Права на запись и выполнение для остальных"
    elif num == 0b000000100:
        return "Права на чтение для остальных"
    elif num == 0b000000101:
        return "Права на чтение и выполнение для остальных"
    elif num == 0b000000110:
        return "Права на чтение и запись для остальных"
    elif num == 0b000000111:
        return "Полный доступ для остальных"
compare_owner(rights)
compare_group(rights)
compare_others(rights)

Изначально вместо return было print, однако всё равно нихера оно не делало. Пожалуйста, объясните кому не сложно мне про двоичные числа. Я могу в уме всё это делать, типа всякие там and, xor и прочее и понимаю как это устроено, а как это использовать не понимаю. Почему нихера не пишет? И как решить это с использованием and? Потому что мне недвусмысленно намекали, что именно так надо. Я просто нихрена не понял.

P.S. Походу подсветка синтаксиса у лора не прожёвывает двоичные, таки баг.

Deleted

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

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

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat
def decode_unix_rights(s):
    n = int(s, 8)
    if n & 0b_100_000_000:
        print('Owner can read')
    else:
        print("Owner can't read")

Вы слишком сложно выражаетесь.) У меня мозгов чуть больше чем у вышибалы в баре на краю какой-нибудь дыры на границе с Мексикой. Мне уже прямо намекнули, но разве этот варинат не означает перечислить все комбинации, коих дофига?

Хорошо, как мне разбить длинное bin(420) на три части? Для владельца, группы и пользователя? Я просто не понимаю.

Deleted
()
Последнее исправление: Romashev (всего исправлений: 1)
Ответ на: комментарий от Deleted

как мне разбить длинное bin(420) на три части? Для владельца, группы и пользователя? Я просто не понимаю.

Сдвинуть вправо на 6, 3 или 0 бит и сделать битовое and с числом 0b111.

i-rinat ★★★★★
()

Я могу в уме всё это делать, типа всякие там and, xor и прочее

Отлично. Теперь прикажи их делать питону и дело в шляпе.

thesis ★★★★★
()
Ответ на: комментарий от Deleted

Забудем про двоичную систему: как разбить число 123456789 на три части: 123, 456 и 789?

Если ответить на этот вопрос, то дальше будет просто.

Davidov ★★★★
()
Ответ на: комментарий от Deleted

Достаточно двух операций: целочисленного деления (в питоне 2 «/», в питоне 3 «//») и деления по модулю («%»).

>>> a=123456789
>>> (a / 1000) % 1000
456
Davidov ★★★★
()
Ответ на: комментарий от Davidov

Похоже, нужно всё переписывать. Спасибо, с каждым числом в отдельности будет работать легче.

Deleted
()

1) Права доступа в Unix записываются в восьмиричном виде.

2) Тебе надо получить три трехбитовых числа, каждое из которых показывает правда доступа для одного из трех возможных случаев - пользователь, группа, остальные.

3) для отладки тебе пригодится функция bin(int number), возвращающая бинарное представление. Ну и её родственник oct(int number)

4) Что бы занулить биты в числе на определенной позиции тебе надо сделать логическое или с соотвествующей маской


In [23]: oct(0644 & 0007)
Out[23]: '04'

In [22]: oct(0644 & 0700)
Out[22]: '0600'

5) Дальше тебе надо проверить биты на определенной позиции.


In [32]: (4 & 0b100) >> 2 == 1
Out[32]: True

6) Если ты после этих подсказок не справишься с задачей - стоит задуматься о том, нужно ли учиться на программиста.

TheKnight ★★★
()
Последнее исправление: TheKnight (всего исправлений: 1)
user_rights = oct_rights >> 6;
group_rights = oct_rights >> 3 mod 8
other_rights = oct_rights mod 8

tuple for_user(exec, write, read) = (user_rights>>2, user_rights >> 1 mod 2, user_rights mod 2)
...

println("User:")
   println(for_user(exec)?"+":"-" " Can execute") 
println(for_user(write)?"+":"-" " Can write") 
println(for_user(read)?"+":"-" " Can read") 
...
xmikex ★★★★
()
Ответ на: комментарий от TheKnight

Я когда-то не мог со 100 метров в ведро попасть, а сейчас если ветра нет на 600 в пятирублёвую монету попадаю. Учиться всегда стоит.

Deleted
()
Ответ на: комментарий от i-rinat

Не скажи, снайперская стрельба это прежде всего матан и физика. Это больше напоминает артиллерийскую стрельбу, нежели чем стрельбу из лука, например. Хотя на самом деле есть просто готовые формулы, но их же тоже вкурить надо.:)

Deleted
()
Ответ на: комментарий от Deleted

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

Просто я расписал практически все нужные базовые операции, осталось только собрать воедино. Куда уж дальше объяснять - не знаю.

TheKnight ★★★
()
Ответ на: комментарий от TheKnight

5) Дальше тебе надо проверить биты на определенной позиции.

А зачем проверять на каждой позиции отдельно? Я бы сделал три кортежа по 8 строк и брал бы group_rights[rights] и т.п.

Можно, конечно, эти строки как-то генерировать (типа Права на {} для {}".format(...)), и для обучения это может быть полезно, но если это будет реальная программа, которую будут переводить на другие языки, есть риск, что переводчикам будет головняк.

proud_anon ★★★★★
()
Ответ на: комментарий от proud_anon

Ты посмотри исходный вариант вывода. Который в примере. Там удобней именно для каждого бита выводить отдельно.

TheKnight ★★★
()

Повторы - зло. Вот как я бы делал.

"""displays file rights"""

def show_all_rights(rights):
    """main function"""
    owners_list = ['User', 'Group', 'Others']
    owners_rights = {}
    current_rights = rights
    for owner in reversed(owners_list):
        owners_rights[owner] = current_rights % 8
        current_rights >>= 3
    for owner in owners_list:
        show_owner_rights(owner, owners_rights[owner])

def show_owner_rights(owner, rights_value):
    """displays single user rights"""
    rights_list = ['read', 'write', 'execute']
    rights_values = {}
    current_rights_value = rights_value
    for right in reversed(rights_list):
        rights_values[right] = current_rights_value % 2
        current_rights_value >>= 1
    print("{}:".format(owner))
    for right in rights_list:
        show_right(right, rights_values[right])
    print("\n")

def show_right(right, can):
    """displays single right"""
    text = "+ can" if can else "- cannot"
    full_text = "\t" + text + " " + right
    print(full_text)

show_all_rights(0b111110000)
anonymous
()
Ответ на: комментарий от anonymous

Тоже самое одной функцией:

"""displays file rights"""

def show_all_rights(rights_value):
    """main function"""
    owners = ['User', 'Group', 'Others']
    rights = ['read', 'write', 'execute']
    data = {}
    rights_count = len(rights)
    rights_div = 1 << rights_count
    for owner in reversed(owners):
        data[owner] = {}
        owner_rights = rights_value % rights_div
        rights_value >>= rights_count
        for right in reversed(rights):
            data[owner][right] = owner_rights % 2
            owner_rights >>= 1
    for owner in owners:
        print("{}:".format(owner))
        for right in rights:
            txt = "+ can" if data[owner][right] else "- cannot"
            print("\t{} {}".format(txt, right))
        print("\n")

show_all_rights(0b111110000)
anonymous
()

Я это так решил, только почему-то не работает для owner.

#!/bin/env python
rights = 0b110100100
def compare_owner(num):
    if num & 0b111000000 == 0b000:
        return "Нет прав"
    elif num & 0b111000000 == 0b001:
        return "Права на исполнение для владельца"
    elif num & 0b111000000 == 0b010:
        return "Права на запись для владельца"
    elif num & 0b111000000 == 0b011:
        return "Права на запись и выполнение для владельца"
    elif num & 0b111000000 == 0b100:
        return "Права на чтение для владельца"
    elif num & 0b111000000 == 0b101:
        return "Права на чтение и выполнение для владельца"
    elif num & 0b111000000 == 0b110:
        return "Права на чтение и запись для владельца"
    elif num & 0b111000000 == 0b111:
        return "Полный доступ для владельца"
def compare_group(num):
    if (num & 0b111000) >> 3 == 0b000:
        return "Нет прав"
    elif (num & 0b111000) >> 3 == 0b001:
        return "Права на исполнение для группы"
    elif (num & 0b111000) >> 3 == 0b010:
        return "Права на запись для группы"
    elif (num & 0b111000) >> 3 == 0b011:
        return "Права на запись и выполнение для группы"
    elif (num & 0b111000) >> 3 == 0b100:
        return "Права на чтение для группы"
    elif (num & 0b111000) >> 3 == 0b101:
        return "Права на чтение и выполнение для группы"
    elif (num & 0b111000) >> 3 == 0b110:
        return "Права на чтение и запись для группы"
    elif (num & 0b111000) >> 3 == 0b111:
        return "Полный доступ для группы"
def compare_others(num):
    if num & 0b000000111 == 0b000:
        return "Нет прав"
    elif num & 0b000000111 == 0b001:
        return "Права на исполнение для остальных"
    elif num & 0b000000111 == 0b010:
        return "Права на запись для остальных"
    elif num & 0b000000111 == 0b011:
        return "Права на запись и выполнение для остальных"
    elif num & 0b000000111 == 0b100:
        return "Права на чтение для остальных"
    elif num & 0b000000111 == 0b101:
        return "Права на чтение и выполнение для остальных"
    elif num & 0b000000111 == 0b110:
        return "Права на чтение и запись для остальных"
    elif num & 0b000000111 == 0b111:
        return "Полный доступ для остальных"
print(compare_owner(rights))
print(compare_group(rights))
print(compare_others(rights))
Deleted
()
def show_rights(rights):
    r = ('r', 'w', 'x') * 3
    return ''.join(map(lambda x: '-' if x[1] == '0' else r[x[0]],
                       enumerate(f'{int(rights, 8):b}')))
>>> print(show_rights('644'))
rw-r--r--
>>> print(show_rights('755'))
rwxr-xr-x
>>>
vvn_black ★★★★★
()
Ответ на: комментарий от Deleted

Потому, что при доработке (!) потребуется переписывать все строчки. Например при перевода на ангельский, или если кто-то захочет вместо «для группы» писать «для ${group_name}» и т.п.

Потому, существует правило в программировании не использовать повторы.

Deleted
()
Ответ на: комментарий от anonymous

Мда... Ведь говорили мне «не пиши код ночью, козлёнком станешь», но я не слушал... Вот так намного проще и понятнее:

"""displays file rights"""

def show_all_rights(rights_value):
    """main function"""
    owners = ['User', 'Group', 'Others']
    rights = ['read', 'write', 'execute']
    data = {}
    for owner in reversed(owners):
        data[owner] = {}
        for right in reversed(rights):
            data[owner][right] = rights_value % 2
            rights_value >>= 1
    for owner in owners:
        print("{}:".format(owner))
        for right in rights:
            txt = "+ can" if data[owner][right] else "- cannot"
            print("\t{} {}".format(txt, right))
        print("\n")

show_all_rights(0b111110000)
anonymous
()

Хз, может кому интересно, решено это было так

import os
if os.name == 'nt':
    import pyreadline
else:
    import readline
def compare_owner(num):
    if (num & 0b111000000) >> 6 == 0b000:
        return "Нет прав"
    elif (num & 0b111000000) >> 6 == 0b001:
        return "Права на исполнение для владельца"
    elif (num & 0b111000000) >> 6 == 0b010:
        return "Права на запись для владельца"
    elif (num & 0b111000000) >> 6 == 0b011:
        return "Права на запись и выполнение для владельца"
    elif (num & 0b111000000) >> 6 == 0b100:
        return "Права на чтение для владельца"
    elif (num & 0b111000000) >> 6 == 0b101:
        return "Права на чтение и выполнение для владельца"
    elif (num & 0b111000000) >> 6 == 0b110:
        return "Права на чтение и запись для владельца"
    elif (num & 0b111000000) >> 6 == 0b111:
        return "Полный доступ для владельца"
def compare_group(num):
    if (num & 0b111000) >> 3 == 0b000:
        return "Нет прав"
    elif (num & 0b111000) >> 3 == 0b001:
        return "Права на исполнение для группы"
    elif (num & 0b111000) >> 3 == 0b010:
        return "Права на запись для группы"
    elif (num & 0b111000) >> 3 == 0b011:
        return "Права на запись и выполнение для группы"
    elif (num & 0b111000) >> 3 == 0b100:
        return "Права на чтение для группы"
    elif (num & 0b111000) >> 3 == 0b101:
        return "Права на чтение и выполнение для группы"
    elif (num & 0b111000) >> 3 == 0b110:
        return "Права на чтение и запись для группы"
    elif (num & 0b111000) >> 3 == 0b111:
        return "Полный доступ для группы"
def compare_others(num):
    if num & 0b000000111 == 0b000:
        return "Нет прав"
    elif num & 0b000000111 == 0b001:
        return "Права на исполнение для остальных"
    elif num & 0b000000111 == 0b010:
        return "Права на запись для остальных"
    elif num & 0b000000111 == 0b011:
        return "Права на запись и выполнение для остальных"
    elif num & 0b000000111 == 0b100:
        return "Права на чтение для остальных"
    elif num & 0b000000111 == 0b101:
        return "Права на чтение и выполнение для остальных"
    elif num & 0b000000111 == 0b110:
        return "Права на чтение и запись для остальных"
    elif num & 0b000000111 == 0b111:
        return "Полный доступ для остальных"
try:
    while True:
        cmd = input("Что будем переводить? (um - umask, ur - unix rights): ")
        rights = int(input("Введите данные: "), 8)
        rights_from_umask = ~rights 
        if cmd == "ur":
            print(compare_owner(rights))
            print(compare_group(rights))
            print(compare_others(rights))
        elif cmd == "um":
            print(compare_owner(rights_from_umask))
            print(compare_group(rights_from_umask))
            print(compare_others(rights_from_umask))
        else:
            print("Ошибка ввода")
except KeyboardInterrupt:
    print('\nBye')
except EOFError:
    print('EOF Error or ^D pressed. Bye.')

Повторы потому что системы счисления это тема занятия и я вкуривал как оно работает.

Deleted
()

Эх, делать неправильно, так хоть красиво!

RIGHTS = {
    0b000: 'нет прав',
    0b001: 'права на исполнение',
    0b010: 'права на запись',
    0b011: 'права на запись и выполнение',
    0b100: 'права на чтение',
    0b101: 'права на чтение и выполнение',
    0b110: 'права на чтение и запись',
    0b111: 'все права'
}


def compare(mask, shift, num):
    return RIGHTS[(num & mask) >> shift]


def compare_owner(num):
    return 'Владелец: ' + compare(0b111000000, 6, num)


def compare_group(num):
    return 'Группа: ' + compare(0b111000, 3, num)


def compare_others(num):
    return 'Остальные: ' + compare(0b000000111, 0, num)


rights = int('640', 8)

print(compare_owner(rights))
print(compare_group(rights))
print(compare_others(rights))
Владелец: права на чтение и запись
Группа: права на чтение
Остальные: нет прав

Повторы потому что системы счисления это тема занятия и я вкуривал как оно работает.

А это зря, лучше сразу учиться делать нормально.

vvn_black ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.