私のクラスの出力をdir()
に変更したいと思います。通常、他のすべてのオブジェクトでは、クラス内で独自の__dir__
メソッドを定義することによって行われます。しかし、私のクラスでこれを行うと、呼び出されません。クラスの__dir__メソッドをオーバーライドする方法は?
dir()
の出力をクラスに変更するにはどうすればよいですか?
私のクラスの出力をdir()
に変更したいと思います。通常、他のすべてのオブジェクトでは、クラス内で独自の__dir__
メソッドを定義することによって行われます。しかし、私のクラスでこれを行うと、呼び出されません。クラスの__dir__メソッドをオーバーライドする方法は?
dir()
の出力をクラスに変更するにはどうすればよいですか?
これは、dir
が入力タイプの__dir__
を呼び出すためです(type(inp).__dir__(inp)
に相当)。クラスのインスタンスの場合はクラス__dir__
を呼び出しますが、クラスで呼び出された場合はメタクラスの__dir__
を呼び出します。
class X(object):
def __dir__(self): # missing self parameter
raise Exception("No!")
dir(X()) # instance!
# Exception: No!
だから、あなたのクラスのdir
(あなたのクラスのインスタンスではなく)をカスタマイズしたい場合は、あなたのX
のためのメタクラスを追加する必要があります。@MSeifertは、すでに説明したように
import six
class DirMeta(type):
def __dir__(cls):
raise Exception("No!")
@six.add_metaclass(DirMeta)
class X(object):
pass
dir(X)
# Exception: No!
それは働いて、ありがとう。しかし、現実には私は何かを "持ち上げたくない"ので、私はちょうど(unittestの検査から)いくつかの方法を取り除きたいので、私は '__dir__'の中で立ち往生しました。しかし、私は 'cls'コンテンツにアクセスする方法を見つけることができませんでした。私は知っていた、私はこの森に入るべきではない... –
ああ、私は 'cls .__ dict __。keys()'を見つけた。正確に私が必要なもの。 –
@GeorgeShuklin代わりに、 'type'の継承を使うこともできます。たとえば 'normal_dir = super().__ dir __()'(これは 'dir'を呼び出すときに通常表示されるものです)を返してから、' normal_dir'を修正する(追加/削除します)。しかし 'cls .__ dict __。keys()'も動作するはずです。 :) – MSeifert
は、dir
呼び出します__dir__
オブジェクトのクラスのattrbiute。したがって、が呼び出され、X.__dir__
ではなく、呼び出されます。興味のある人だけに、正確に何が起こっているのかを見てみましょう。
dir
の実装はbltinmodule.cである:
builtin_dir(PyObject *self, PyObject *args)
{
PyObject *arg = NULL;
if (!PyArg_UnpackTuple(args, "dir", 0, 1, &arg))
return NULL;
return PyObject_Dir(arg);
}
dir
機能は、API関数PyObject_Dir
を呼び出します。 PyObject_Dir
関数はobject.cに実装され:
PyObject *
PyObject_Dir(PyObject *obj)
{
return (obj == NULL) ? _dir_locals() : _dir_object(obj);
}
PyObject_Dir
は、2つのヘルパー関数を用いて定義されます。ここでのようにオブジェクトが渡されると、_dir_object
関数が呼び出されます。また、object.cに実装されています。
static PyObject *
_dir_object(PyObject *obj)
{
PyObject *result, *sorted;
PyObject *dirfunc = _PyObject_LookupSpecial(obj, &PyId___dir__);
assert(obj);
if (dirfunc == NULL) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_TypeError, "object does not provide __dir__");
return NULL;
}
/* use __dir__ */
result = _PyObject_CallNoArg(dirfunc);
Py_DECREF(dirfunc);
if (result == NULL)
return NULL;
/* return sorted(result) */
sorted = PySequence_List(result);
Py_DECREF(result);
if (sorted == NULL)
return NULL;
if (PyList_Sort(sorted)) {
Py_DECREF(sorted);
return NULL;
}
return sorted;
}
部分がに焦点を当てたです。
PyObject *dirfunc = _PyObject_LookupSpecial(obj, &PyId___dir__);
__dir__
特別な方法がルックアップされた場合に渡されたオブジェクトの上にこれがある。これは_PyObject_LookupSpecial
を使用して行われます。 。 _PyObject_LookupSpecial
はtypeobject.cに定義されています。
PyObject *
_PyObject_LookupSpecial(PyObject *self, _Py_Identifier *attrid)
{
PyObject *res;
res = _PyType_LookupId(Py_TYPE(self), attrid);
if (res != NULL) {
descrgetfunc f;
if ((f = Py_TYPE(res)->tp_descr_get) == NULL)
Py_INCREF(res);
else
res = f(res, self, (PyObject *)(Py_TYPE(self)));
}
return res;
}
_PyObject_LookupSpecial
最初の呼び出しで渡されたオブジェクトのPy_TYPE
を探してアップ_PyType_LookupId
を使用して属性を前に。オブジェクトのob_type
を取得するPy_TYPE
is a macroそれが展開だな形式は次のとおりです。
(((PyObject*)(o))->ob_type)
をそして、あなたはおそらく推測として、ob_type
attribute is the class (or type) of the object:あなたは、上から見ることができるよう
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
だから、使用__dir__
属性は、実際にオブジェクトのクラスです。
[*特殊メソッドの参照*](https://docs.python.org/3/reference/datamodel.html#special-lookup)を参照してください。 'type(X).__ dir__'は' X .__ dir__'ではなく、使われます。 –
"通常、他のすべてのオブジェクトでは、クラス内で独自の' __dir__'メソッドを定義することによって行われます。 " - このオブジェクトと同じです。このクラスのクラス、つまりそのメタクラスで '__dir__'メソッドを定義します。 – user2357112