Может вызываться как аргумент по умолчанию для dict.get без его вызова, если ключ существует - PullRequest
8 голосов
/ 30 сентября 2011

Я пытаюсь предоставить функцию в качестве аргумента по умолчанию для функции get в словаре, например:

def run():
   print "RUNNING"

test = {'store':1}
test.get('store', run())

Однако, когда он запускается, он отображает следующий вывод:

RUNNING
   1

так что мой вопрос, как говорится в заголовке, есть ли способ предоставить вызываемый элемент в качестве значения по умолчанию для метода get без его вызова, если ключ существует?

Ответы [ 5 ]

9 голосов
/ 25 апреля 2017

Другой вариант, при условии, что вы не собираетесь хранить ложные значения в своем словаре:

test.get('store') or run()

В python оператор or не оценивает ненужные аргументы (это замыкает накоротко)

7 голосов
/ 30 сентября 2011

См. Обсуждение в ответах и ​​комментариях метода dict.get (), возвращает указатель . Вы должны разбить его на два этапа.

Ваши варианты:

  1. Используйте defaultdict с вызываемой функцией, если вы всегда хотите использовать это значение по умолчанию и хотите сохранить его в dict.

  2. Используйте условное выражение:

    item = test['store'] if 'store' in test else run()
    
  3. Использование try / except:

    try:
        item = test['store']
    except KeyError:
        item = run()
    
  4. Использование get:

    item = test.get('store')
    if item is None:
        item = run()
    

И вариации на эти темы.

glglgl показывает способ подкласса defaultdict, вы также можете просто подкласс dict для некоторых ситуаций:

def run():
    print "RUNNING"
    return 1

class dict_nokeyerror(dict):
    def __missing__(self, key):
        return run()

test = dict_nokeyerror()

print test['a']
# RUNNING
# 1

Подклассы действительно имеют смысл, только если вы всегда хотите, чтобы dict имел нестандартное поведение; если вы обычно хотите, чтобы он вел себя как обычный dict и просто хотите, чтобы ленивый get находился в одном месте, используйте один из моих методов 2-4.

2 голосов
/ 30 сентября 2011

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

Существует несколько подходов для этого.Можно было бы использовать defaultdict, который вызывает run(), если ключ отсутствует.

from collections import defaultdict
def run():
   print "RUNNING"

test = {'store':1}
test.get('store', run())

test = defaultdict(run, store=1) # provides a value for store
test['store'] # gets 1
test['runthatstuff'] # gets None

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

test = {'store': lambda:1}
test.get('store', run)() # -> 1
test.get('runrun', run)() # -> None, prints "RUNNING".

Если вы хотите, чтобы возвращаемое значение зависело от отсутствующего ключа, вы должны создать подкласс defaultdict:

class mydefaultdict(defaultdict):
    def __missing__(self, key):
        val = self[key] = self.default_factory(key)
        return val

d = mydefaultdict(lambda k: k*k)
d[10] # yields 100

@mydefaultdict # decorators are fine
def d2(key):
    return -key
d2[5] # yields -5

И если вы не хотите добавлять это значение в dict дляпри следующем вызове вместо этого

def __missing__(self, key): return self.default_factory(key)

, который вызывает фабрику по умолчанию каждый раз, когда пара key: value не была явно добавлена.

0 голосов
/ 29 апреля 2017

У меня есть каталог util в моем проекте с qt.py, general.py, geom.py и т. Д. В general.py у меня есть куча инструментов Python, таких как вам нужно:

# Use whenever you need a lambda default
def dictGet(dict_, key, default):
    if key not in dict_:
        return default()
    return dict_[key]

Добавьте *args, **kwargs, если вы хотите поддерживать вызов по умолчанию более одного раза с разными аргументами:

def dictGet(dict_, key, default, *args, **kwargs):
    if key not in dict_:
        return default(*args, **kwargs)
    return dict_[key]
0 голосов
/ 22 мая 2013

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

    class MyDict(dict):

        def get_callable(self,key,func,*args,**kwargs):
            '''Like ordinary get but uses a callable to 
            generate the default value'''

            if key not in self:
                val = func(*args,**kwargs)
            else:
                val = self[key]
            return val

Это может быть использовано следующим образом: -

     >>> d = MyDict()
     >>> d.get_callable(1,complex,2,3)
     (2+3j)
     >>> d[1] = 2
     >>> d.get_callable(1,complex,2,3)
     2
     >>> def run(): print "run"
     >>> repr(d.get_callable(1,run))
     '2'
     >>> repr(d.get_callable(2,run))
     run
     'None'

Это, вероятно, наиболее полезно, когда вызываемый объект дорогостоящий для вычисления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...