Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 5, 2017 07:59:55

worldmind
Зарегистрирован: 2016-12-20
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

В Perl'е есть такой удобный оператор //, обычно он используется для задания дефолтных значений, в питоне можно для параметров функций задавать дефолтные значения, но это не подходит для сложных структур (например когда нужен дефолт для отдельных полей).
Пример того как это выглядит в перле:

 my $var = $struct{key1}{key2} // 'defaul_value';
Это значит, что если $struct{key1}{key2} не определено, то $var получит значение ‘defaul_value’, если кто не заметил, то обычный ИЛИ тут не подходит т.к. $struct{key1}{key2} может иметь значение трактуемое как ложь, а дефолт нужно применить только когда значение не определено.
Т.к. в питоне нет автовивификации то видимо такой оператор должен проверять что ключ в словаре существует и если существует то не имеет значения (is None).

Пытался погуглить, но увидел только всякие try и проверки на существования ключа с помощью in, конечно можно самому написать функцию с такой логикой, но это придётся делать только если точно узнать что в языке нет ничего удобного для этой задачи.

Отредактировано worldmind (Янв. 5, 2017 08:00:26)

Офлайн

#2 Янв. 5, 2017 08:16:05

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9993
Репутация: +  857  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

В словаре можно использовать метод get() вместо квадратных скобок, у него есть значение по умолчанию.

  
>>> {}.get('x')
>>> {}.get('x', 'no')
'no'
>>>

Если же нужно вглубь словаря спускаться, когда там чего-то может не быть, то использует отлов KeyError.
  
>>> try:
...   x = {}['a']['b']['c']
... except KeyError:
...   x = 1
... 
>>> x
1
>>>



Отредактировано py.user.next (Янв. 5, 2017 08:19:02)

Офлайн

#3 Янв. 5, 2017 08:26:59

worldmind
Зарегистрирован: 2016-12-20
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

Да, я тут подумал что надо этот try обернуть в свой оператор и будет что-то похожее

Офлайн

#4 Янв. 5, 2017 08:44:37

worldmind
Зарегистрирован: 2016-12-20
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

worldmind
Да, я тут подумал что надо этот try обернуть в свой оператор и будет что-то похожее
если это можно сделать нормальным способом

Офлайн

#5 Янв. 5, 2017 08:52:59

worldmind
Зарегистрирован: 2016-12-20
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

 from infix import shift_infix as infix
@infix
def exist_or(value, default_value):
    try:
        result = value
    except KeyError:
        result = default_value
    return result

 >>> from existor import exist_or
>>> struct = {'key1': {'key2': 'aaa'}}
>>> var = struct['key1']['key2'] <<exist_or>> '7'
>>> var
'aaa'
>>> var = struct['key1']['key3'] <<exist_or>> '7'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'key3'
т.е. питон вычисляет выражение раньше

Отредактировано worldmind (Янв. 5, 2017 08:53:40)

Офлайн

#6 Янв. 5, 2017 08:55:58

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

 d = {}
x = d.get("a", {}).get("b", {}).get("c", 1)



Офлайн

#7 Янв. 5, 2017 09:04:32

worldmind
Зарегистрирован: 2016-12-20
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

FishHook
Вариант конечно, мой вариант выше можно доработать
 from infix import shift_infix as infix
@infix
def exist_or(value_func, default_value):
    try:
        result = value_func()
    except KeyError:
        result = default_value
    return result
и делать так
 >>> from existor import exist_or
>>> struct = {'key1': {'key2': 'aaa'}}
>>> var = (lambda:struct['key1']['key2']) <<exist_or>> '7'
>>> var
'aaa'
>>> var = (lambda:struct['key1']['key3']) <<exist_or>> '7'
>>> var
'7'
хотя это уже не та читаемость которой хотелось бы достичь

Офлайн

#8 Янв. 5, 2017 09:08:57

ABKorotky
Зарегистрирован: 2017-01-05
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

Можно посмотреть в сторону https://docs.python.org/2/library/stdtypes.html?highlight=setdefault#dict.setdefault

 >>> d = {}
>>> d
{}
>>> val = d.setdefault('key', 'value')
>>> val
'value'
>>> d
{'key': 'value'}
Также есть вот такая штука: https://docs.python.org/2/library/collections.html?highlight=defaultdict#collections.defaultdict
Может быть полезен вот для такого рода вещей:
 >>> from collections import defaultdict
>>> d = defaultdict(list)
>>> d
defaultdict(<type 'list'>, {})
>>> d['list1'].append(1)
>>> d
defaultdict(<type 'list'>, {'list1': [1]})
>>> d['list1'].append(2)
>>> d
defaultdict(<type 'list'>, {'list1': [1, 2]})
Правда, для рекурсивной инициализации не совсем подходит - придётся повозиться…

Офлайн

#9 Янв. 5, 2017 09:17:36

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

worldmind
ну это как-то извращением попахивает, если хочется изобрести велосипед, то лучше от dict отнаследоваться.



Офлайн

#10 Янв. 5, 2017 09:27:55

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Аналог перлового оператора defined-or

ABKorotky
Правда, для рекурсивной инициализации не совсем подходит

А в чем проблема?
 d = defaultdict(lambda:defaultdict(list))



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version