でコードを参照することにより
http://initd.org/psycopg/docs/extras.html#dictionary-like-cursor
>>> rec['data']
"abc'def"
>>> rec[2]
"abc'def"
タプルとディクショナリの両方の特性を持つデータ構造をどのように作成しているのか疑問に思っていました。
でコードを参照することにより
http://initd.org/psycopg/docs/extras.html#dictionary-like-cursor
>>> rec['data']
"abc'def"
>>> rec[2]
"abc'def"
タプルとディクショナリの両方の特性を持つデータ構造をどのように作成しているのか疑問に思っていました。
Pythonでは、[]
ルックアップは__getitem__
マジックメソッドによって処理されます。つまり、カスタムクラスにインデックスを付けると、Pythonが呼び出しinstance.__getitem__(...)
て値を返します。これにより、たとえば
>>> class Foo:
... def __getitem__(self, value):
... return value
...
>>> foo = Foo()
>>> foo["1"]
'1'
>>> foo[0]
0
実際のデータ構造を維持するための自然な方法はいくつかあります。おそらく最も簡単なのは、dictとlistの両方を維持し、キーのタイプに応じてそれらの1つにインデックスを付けることです。
これは不自然であることに注意してください。dictのようなオブジェクトがキーとして扱われることを期待し0
ます。index
インデックス作成を処理するなど、別のメソッドを作成する価値があるかもしれません。
__setitem__
and__contains__
メソッドを実装することもできます。
demasの回答の修正版は次のとおりです(私は思う)順序を維持します(ただし、効率的ではありません):
class TupleDict(collections.OrderedDict):
def __getitem__(self, key):
if isinstance(key, int):
return list(self.values())[key]
return super(TupleDict, self).__getitem__(key)
コードを読んでください。それが私の最高の提案です。
例えば:
class cursor(_2cursor):
"""psycopg 1.1.x cursor.
Note that this cursor implements the exact procedure used by psycopg 1 to
build dictionaries out of result rows. The DictCursor in the
psycopg.extras modules implements a much better and faster algorithm.
"""
def __build_dict(self, row):
res = {}
for i in range(len(self.description)):
res[self.description[i][0]] = row[i]
return res
.....
そしてそれがどこから来ているのか..
class connection(_2connection):
"""psycopg 1.1.x connection."""
def cursor(self):
"""cursor() -> new psycopg 1.1.x compatible cursor object"""
return _2connection.cursor(self, cursor_factory=cursor)
これを削除する原因となった回答に関する Glenn Maynard のコメントを読んだ後、私はそれを復活させることにしました。これは通常のリストを使用してインデックスを格納するため、同じ O(1) アクセスを持ちます。
これが私の見解です。エラー処理はおそらく改善される可能性がありますが、コードをあまり混乱させたくありませんでした。元のコードがそれをどのように処理したかはわかりませんが、先に進んでスライスも処理してみませんか。新しいキーを作成しない (つまり、アイテムの数を変更しない) スライスのスライス割り当てのみを処理できますが、任意のスライス ルックアップを処理できます。整数キーも実質的に許可しないことに注意してください。これが動作中の小さなデモです。
class IndexedDict(object):
def __init__(self, *args, **kwargs):
d = dict(*args, **kwargs)
self._keys = d.keys() # list(d.keys()) in python 3.1
self._d = d
def __getitem__(self, item):
if isinstance(item, int):
key = self._keys[item]
return self._d[key]
elif isinstance(item, slice):
keys = self._keys[item]
return tuple(self._d[key] for key in keys)
else:
return self._d[key]
def __setitem__(self, item, value):
if isinstance(item, int):
key = self._keys[item]
self._d[key] = value
elif isinstance(item, slice):
# we only handle slices that don't require the creation of
# new keys.
keys = self._keys[item]
if not len(keys) == len(value):
raise ValueError("Complain here")
for key, v in zip(keys, value):
self._d[key] = v
else:
self._d[item] = value
if item not in self._keys:
# This is the only form that can create a new element
self._keys.append(item)
def __delitem__(self, item):
if isinstance(item, int):
key = self._keys[item]
del self._keys[item]
del self._d[key]
elif isinstance(item, slice):
keys = self._keys[item]
del self._keys[item]
for key in keys:
del self._d[key]
else:
del self._d[item]
self._keys.remove(item)
def __contains__(self, item):
if isinstance(item, int):
return i < len(self._keys)
else:
return i in self._d
# Just for debugging. Not intended as part of API.
def assertions(self):
assert len(self._d) == len(self._keys)
assert set(self._d.keys()) == set(self._keys)
実装するものはまだあります。keys
、items
、iteritems
、update
などですが、難しすぎてはいけません。self._keys
リストカンプとジェネレータ式を操作して使用するだけです。たとえば、更新についてiteritems
は(self._d[key] for key in self._keys)
、辞書のようなオブジェクトを扱っていることを確認してから、として更新self._keys
しself._keys += [key for key in other.keys() if key not in self._keys]
ます。__add__
本質的に同じ方法で定義するところまで行くかもしれません。
ディクショナリは、任意のPythonタイプを他のPythonタイプに対してマップできるため、キーが整数である値を簡単に取得できます。
v = {}
v[0] = 'a'
v[1] = 'b'
v['abc'] = 'def'
>>> v[0]
'a'
そんな感じ:
class d(dict):
def __getitem__(self, key):
if str(key).isdigit():
return self.values()[key]
else:
return super(d, self).get(key)
cls = d()
cls["one"] = 1
print cls["one"]
print cls[0]