Варианты использования 'значение setdefault метод дикт
дополнение collections.defaultdict в Python 2.5 значительно уменьшена потребность в dict ' s setdefault метод. Этот вопрос для нашего коллективного образования:
- что это
setdefaultеще полезно, сегодня в Python 2.6/2.7? - какие популярные случаи использования
setdefaultбыли заменены наcollections.defaultdict?
16 ответов:
можно сказать
defaultdictполезно для настроек по умолчанию перед заполнением дикт иsetdefaultполезно для установки значений по умолчанию во время или после заполнения дикт.вероятно, наиболее распространенный вариант использования: группировка элементов (в несортированных данных, иначе используйте
itertools.groupby)# really verbose new = {} for (key, value) in data: if key in new: new[key].append( value ) else: new[key] = [value] # easy with setdefault new = {} for (key, value) in data: group = new.setdefault(key, []) # key might exist already group.append( value ) # even simpler with defaultdict new = defaultdict(list) for (key, value) in data: new[key].append( value ) # all keys have a default alreadyиногда вы хотите убедиться, что определенные ключи существуют после создания dict.
defaultdictне работает в этом случае, потому что он только создает ключи при явном доступе. Думаю, вы используете что-то HTTP-ish со многими заголовками - некоторые из них необязательны, но вы хотите использовать для них значения по умолчанию:headers = parse_headers( msg ) # parse the message, get a dict # now add all the optional headers for headername, defaultvalue in optional_headers: headers.setdefault( headername, defaultvalue )
Я обычно использую
setdefaultдля ключевых слов аргумент диктует, например, в этой функции:def notify(self, level, *pargs, **kwargs): kwargs.setdefault("persist", level >= DANGER) self.__defcon.set(level, **kwargs) try: kwargs.setdefault("name", self.client.player_entity().name) except pytibia.PlayerEntityNotFound: pass return _notify(level, *pargs, **kwargs)это отлично подходит для настройки аргументов в оболочках вокруг функций, которые принимают аргументы ключевых слов.
defaultdictотлично, когда значение по умолчанию является статическим, как новый список, но не так много, если он динамический.например, мне нужен словарь для сопоставления строк с уникальными ints.
defaultdict(int)всегда будет использовать 0 в качестве значения по умолчанию. Аналогично,defaultdict(intGen())всегда производит 1.вместо этого я использовал обычный дикт:
nextID = intGen() myDict = {} for lots of complicated stuff: #stuff that generates unpredictable, possibly already seen str strID = myDict.setdefault(myStr, nextID())отметим, что
dict.get(key, nextID())недостаточно, потому что мне нужно иметь возможность ссылаться на эти значения позже.
intGenкрошечный класс I строит, что автоматически увеличивает int и возвращает его значение:class intGen: def __init__(self): self.i = 0 def __call__(self): self.i += 1 return self.iесли у кого-то есть способ сделать это с
defaultdictЯ хотел бы увидеть это.
как Мухаммад сказал, Есть ситуации, в которых вы только иногда хотите установить значение по умолчанию. Отличным примером этого является структура данных, которая сначала заполняется, а затем запрашивается.
рассмотрим три. При добавлении слова, если подузел необходим, но отсутствует, он должен быть создан для расширения trie. При запросе на наличие слова отсутствующий подузел указывает, что слово отсутствует и его не следует создавать.
defaultdict не может этого сделать. Вместо этого необходимо использовать обычный dict с методами get и setdefault.
теоретически
setdefaultвсе равно будет удобно, если вы иногда хотите установить значение по умолчанию, а иногда и нет. В реальной жизни я не сталкивался с таким прецедентом.однако, интересный случай использования приходит из стандартной библиотеки (в Python 2.6, _threadinglocal.py):
>>> mydata = local() >>> mydata.__dict__ {'number': 42} >>> mydata.__dict__.setdefault('widgets', []) [] >>> mydata.widgets []Я бы сказал, что с помощью
__dict__.setdefault- это очень полезное дело.Edit: как это бывает, это единственный пример в стандартная библиотека и это в комментарии. Так что может быть это не достаточно случая, чтобы оправдать существование
setdefault. Тем не менее, вот объяснение:объекты хранят свои атрибуты в тег . Как это бывает,
__dict__атрибут может быть записан в любое время после создания объекта. Это также словарь неdefaultdict. Для объектов в общем случае нецелесообразно иметь__dict__какdefaultdictпотому что это сделало бы каждый объект, имеющий все законные идентификаторы как атрибуты. Поэтому я не могу предвидеть никаких изменений в объектах Python, избавляющихся от__dict__.setdefault, кроме удаления его вообще, если это было сочтено не полезным.
вот несколько примеров setdefault, чтобы показать его полезность:
""" d = {} # To add a key->value pair, do the following: d.setdefault(key, []).append(value) # To retrieve a list of the values for a key list_of_values = d[key] # To remove a key->value pair is still easy, if # you don't mind leaving empty lists behind when # the last value for a given key is removed: d[key].remove(value) # Despite the empty lists, it's still possible to # test for the existance of values easily: if d.has_key(key) and d[key]: pass # d has some values for key # Note: Each value can exist multiple times! """ e = {} print e e.setdefault('Cars', []).append('Toyota') print e e.setdefault('Motorcycles', []).append('Yamaha') print e e.setdefault('Airplanes', []).append('Boeing') print e e.setdefault('Cars', []).append('Honda') print e e.setdefault('Cars', []).append('BMW') print e e.setdefault('Cars', []).append('Toyota') print e # NOTE: now e['Cars'] == ['Toyota', 'Honda', 'BMW', 'Toyota'] e['Cars'].remove('Toyota') print e # NOTE: it's still true that ('Toyota' in e['Cars'])
Я часто использую setdefault, когда, получите это, устанавливая значение по умолчанию (!!!) в словаре; несколько обычно ОС.энвирон словарь:
# Set the venv dir if it isn't already overridden: os.environ.setdefault('VENV_DIR', '/my/default/path')менее лаконично, это выглядит так:
# Set the venv dir if it isn't already overridden: if 'VENV_DIR' not in os.environ: os.environ['VENV_DIR'] = '/my/default/path')стоит отметить, что вы также можете использовать выходной переменной:
venv_dir = os.environ.setdefault('VENV_DIR', '/my/default/path')но это менее необходимо, чем это было до defaultdicts существовали.
еще один случай использования, который я не думаю, что был упомянут выше. Иногда вы сохраняете Cache dict объектов по их идентификатору, где первичный экземпляр находится в кэше, и вы хотите установить кэш, когда он отсутствует.
return self.objects_by_id.setdefault(obj.id, obj)это полезно, когда вы всегда хотите сохранить один экземпляр на отдельный идентификатор независимо от того, как вы получаете obj каждый раз. Например, когда атрибуты объекта обновляются в памяти и сохранение в хранилище откладывается.
один очень важный прецедент я просто наткнулся:
dict.setdefault()отлично подходит для многопоточного кода, когда вы хотите только один канонический объект (в отличие от нескольких объектов, которые оказываются равными).например,
(Int)Flagперечисление в Python 3.6.0 имеет ошибку: если несколько потоков конкурируют за композитный(Int)Flagучастник, там может оказаться более одного:from enum import IntFlag, auto import threading class TestFlag(IntFlag): one = auto() two = auto() three = auto() four = auto() five = auto() six = auto() seven = auto() eight = auto() def __eq__(self, other): return self is other def __hash__(self): return hash(self.value) seen = set() class cycle_enum(threading.Thread): def run(self): for i in range(256): seen.add(TestFlag(i)) threads = [] for i in range(8): threads.append(cycle_enum()) for t in threads: t.start() for t in threads: t.join() len(seen) # 272 (should be 256)решение заключается в использовании
setdefault()как последний шаг сохранения вычисляемый составной элемент -- если другой уже был сохранен, то он используется вместо нового, гарантируя уникальные члены перечисления.
как большинство ответов государственной
setdefaultилиdefaultdictпозволит вам установить значение по умолчанию, если ключ не существует. Однако я хотел бы указать на небольшое предостережение в отношении случаев использованияsetdefault. Когда интерпретатор Python выполняетsetdefaultОн всегда будет оценивать второй аргумент функции, даже если ключ существует в словаре. Например:In: d = {1:5, 2:6} In: d Out: {1: 5, 2: 6} In: d.setdefault(2, 0) Out: 6 In: d.setdefault(2, print('test')) test Out: 6Как видите,
setdefaultнапример для оптимизации, какmemoization. Если вы добавляете рекурсивный вызов функции в качестве второго аргумента вsetdefault, вы не получите никакой производительности из него, как Python всегда будет вызывать функцию рекурсивно.
[Edit]очень неправильно! setdefault всегда будет вызывать long_computation, Python стремится.
расширение ответа Таттла. Для меня лучшим вариантом использования является механизм кэша. Вместо:
if x not in memo: memo[x]=long_computation(x) return memo[x]который потребляет 3 строки и 2 или 3 поиска,
Я бы с удовольствием написал:return memo.setdefault(x, long_computation(x))
Мне нравится ответ дан здесь:
http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html
короче говоря, решение (в приложениях, не критичных к производительности) должно приниматься на основе того, как вы хотите обрабатывать поиск пустых ключей вниз по течению (то есть.
KeyErrorпо сравнению со значением по умолчанию).
другой вариант использования для
setdefault()и когда вы не хотите перезаписать значение уже установленного ключа.defaultdictперезаписывает, в то время какsetdefault()нет. Для вложенных словарей чаще всего требуется установить значение по умолчанию только в том случае, если ключ еще не установлен, потому что вы не хотите удалять настоящий вспомогательный словарь. Это когда вы используетеsetdefault().пример
defaultdict:>>> from collection import defaultdict() >>> foo = defaultdict() >>> foo['a'] = 4 >>> foo['a'] = 2 >>> print(foo) defaultdict(None, {'a': 2})
setdefaultне перезаписать:>>> bar = dict() >>> bar.setdefault('a', 4) >>> bar.setdefault('a', 2) >>> print(bar) {'a': 4}
я переписал принятый ответ и облегчил его для новичков.
#break it down and understand it intuitively. new = {} for (key, value) in data: if key not in new: new[key] = [] # this is core of setdefault equals to new.setdefault(key, []) new[key].append(value) else: new[key].append(value) # easy with setdefault new = {} for (key, value) in data: group = new.setdefault(key, []) # it is new[key] = [] group.append(value) # even simpler with defaultdict new = defaultdict(list) for (key, value) in data: new[key].append(value) # all keys have a default value of empty list []кроме того, я классифицировал методы как справочные:
dict_methods_11 = { 'views':['keys', 'values', 'items'], 'add':['update','setdefault'], 'remove':['pop', 'popitem','clear'], 'retrieve':['get',], 'copy':['copy','fromkeys'],}
Comments