pythonディクショナリを作成します。このディクショナリには、キーのキー値が返されません。
使用例:
dic = smart_dict()
dic['a'] = 'one a'
print(dic['a'])
# >>> one a
print(dic['b'])
# >>> b
dict
sには __missing__
このためのフック:
class smart_dict(dict):
def __missing__(self, key):
return key
なぜ使用しないのですか
dic.get('b', 'b')
確かに、他の人が指摘するようにdict
をサブクラス化できますが、get
にデフォルト値を設定できることを時々思い出すと便利です。
defaultdict
を試してみたい場合は、これを試してください:
dic = defaultdict()
dic.__missing__ = lambda key: key
dic['b'] # should set dic['b'] to 'b' and return 'b'
例外...まあ:AttributeError: ^collections.defaultdict^object attribute '__missing__' is read-only
なので、サブクラス化する必要があります。
from collections import defaultdict
class KeyDict(defaultdict):
def __missing__(self, key):
return key
d = KeyDict()
print d['b'] #prints 'b'
print d.keys() #prints []
最初の回答者はdefaultdict
について言及しましたが、__missing__
dict
のサブクラスの場合:
>>> class Dict(dict):
def __missing__(self, key):
return key
>>> d = Dict(a=1, b=2)
>>> d['a']
1
>>> d['z']
'z'
また、私は2番目の回答者のアプローチが気に入っています。
>>> d = dict(a=1, b=2)
>>> d.get('z', 'z')
'z'
おめでとうございます。標準の_collections.defaultdict
_型の無用さも発見しました。 コードのにおい のその実行可能な中間ヒープが、あなたの繊細な感性を私のものと同じくらい気分を害する場合、これは幸運なStackOverflowの日です。
組み込みのtype()
の- -parameterバリアント の禁止された驚異のおかげで、役に立たないデフォルトの辞書タイプを作成することは楽しくて有益です。
あなたが過剰なボイラープレートと_collections.defaultdict
_の衝撃的な愚かさが好きであると仮定すると、絶対に何もありません–これはshouldは期待どおりに動作しますが、実際には動作しません。公平を期すために、サブクラスdict
の実装 オプション__missing__()
メソッド の Jochen Ritzel の 受け入れられる解 = is単一のデフォルトディクショナリのみを必要とする小規模なユースケースの素晴らしい回避策。
しかし、この種のボイラープレートはスケーリングが不十分です。欠落しているキーと値のペアを生成するための独自のわずかに異なるロジックを持つ複数のデフォルト辞書をインスタンス化していることに気付いた場合、産業用の強度の代替自動化ボイラープレートが必要です。
または少なくともニース。壊れたものを修正しないのはなぜですか?
純粋なPython(docstrings、comments、および空白文字を除く)の10行未満で、ユーザー定義の呼び出し可能オブジェクトで初期化されたDefaultDict
タイプを定義し、欠落のデフォルト値を生成しますキー。標準の_collections.defaultdict
_タイプに渡される呼び出し可能オブジェクトはnoパラメータを無意味に受け入れますが、DefaultDict
タイプに渡される呼び出し可能オブジェクトは次の2つのパラメータを有効に受け入れます。
このタイプの場合、 sorin の質問を解決すると、Pythonの1行に削減されます。
_>>> dic = DefaultDict(lambda self, missing_key: missing_key)
>>> dic['a'] = 'one a'
>>> print(dic['a'])
one a
>>> print(dic['b'])
b
_
正気。 ついに。
_def DefaultDict(keygen):
'''
Sane **default dictionary** (i.e., dictionary implicitly mapping a missing
key to the value returned by a caller-defined callable passed both this
dictionary and that key).
The standard :class:`collections.defaultdict` class is sadly insane,
requiring the caller-defined callable accept *no* arguments. This
non-standard alternative requires this callable accept two arguments:
#. The current instance of this dictionary.
#. The current missing key to generate a default value for.
Parameters
----------
keygen : CallableTypes
Callable (e.g., function, lambda, method) called to generate the default
value for a "missing" (i.e., undefined) key on the first attempt to
access that key, passed first this dictionary and then this key and
returning this value. This callable should have a signature resembling:
``def keygen(self: DefaultDict, missing_key: object) -> object``.
Equivalently, this callable should have the exact same signature as that
of the optional :meth:`dict.__missing__` method.
Returns
----------
MappingType
Empty default dictionary creating missing keys via this callable.
'''
# Global variable modified below.
global _DEFAULT_DICT_ID
# Unique classname suffixed by this identifier.
default_dict_class_name = 'DefaultDict' + str(_DEFAULT_DICT_ID)
# Increment this identifier to preserve uniqueness.
_DEFAULT_DICT_ID += 1
# Dynamically generated default dictionary class specific to this callable.
default_dict_class = type(
default_dict_class_name, (dict,), {'__missing__': keygen,})
# Instantiate and return the first and only instance of this class.
return default_dict_class()
_DEFAULT_DICT_ID = 0
'''
Unique arbitrary identifier with which to uniquify the classname of the next
:func:`DefaultDict`-derived type.
'''
_
キー ...取得、キー? この難解なウィザードの呼び出しは、type()
ビルトインの -パラメータバリアント の呼び出しです。
_type(default_dict_class_name, (dict,), {'__missing__': keygen,})
_
この1行で、新しいdict
サブクラスが動的に生成され、オプションの___missing__
_メソッドが呼び出し元定義の呼び出し可能オブジェクトにエイリアスされます。ボイラープレートの明確な欠如に注意し、DefaultDict
の使用をPythonの1行に減らします。
悪質な勝利のための自動化。
これは簡単にできること、そして何らかの方法で欠損値を変換するさまざまなデフォルトや関数を簡単に設定できることにも同意します。
Cecil Curry の answer に触発されて、私は自分自身に尋ねました。常に異なるクラスを生成していますか?実演させてください:
# default behaviour: return missing keys unchanged
dic = FlexDict()
dic['a'] = 'one a'
print(dic['a'])
# 'one a'
print(dic['b'])
# 'b'
# regardless of default: easy initialisation with existing dictionary
existing_dic = {'a' : 'one a'}
dic = FlexDict(existing_dic)
print(dic['a'])
# 'one a'
print(dic['b'])
# 'b'
# using constant as default for missing values
dic = FlexDict(existing_dic, default = 10)
print(dic['a'])
# 'one a'
print(dic['b'])
# 10
# use callable as default for missing values
dic = FlexDict(existing_dic, default = lambda missing_key: missing_key * 2)
print(dic['a'])
# 'one a'
print(dic['b'])
# 'bb'
print(dic[2])
# 4
どのように機能しますか?それほど難しくありません:
class FlexDict(dict):
'''Subclass of dictionary which returns a default for missing keys.
This default can either be a constant, or a callable accepting the missing key.
If "default" is not given (or None), each missing key will be returned unchanged.'''
def __init__(self, content = None, default = None):
if content is None:
super().__init__()
else:
super().__init__(content)
if default is None:
default = lambda missing_key: missing_key
self.default = default # sets self._default
@property
def default(self):
return self._default
@default.setter
def default(self, val):
if callable(val):
self._default = val
else: # constant value
self._default = lambda missing_key: val
def __missing__(self, x):
return self.default(x)
もちろん、初期化後にデフォルト関数を変更できるようにするかどうかは議論できますが、これは単に@default.setter
を削除し、そのロジックを__init__
に吸収することを意味します。
現在の(定数の)デフォルト値へのイントロスペクションを有効にするには、2つの行を追加します。
サブクラスdict
's __getitem__
方法。たとえば、 dictを適切にサブクラス化して__getitem__&__setitem__をオーバーライドする方法