Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A diff on python 3.7 that adds a __setself__ method to support assignment overloading
diff --git a/Include/object.h b/Include/object.h
index bcf78afe6b..5146e2050b 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -339,6 +339,7 @@ typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
typedef PyObject *(*allocfunc)(struct _typeobject *, Py_ssize_t);
+typedef int (*setselffunc)(PyObject *, PyObject *);
#ifdef Py_LIMITED_API
typedef struct _typeobject PyTypeObject; /* opaque */
@@ -423,6 +424,7 @@ typedef struct _typeobject {
unsigned int tp_version_tag;
destructor tp_finalize;
+ setselffunc tp_setself;
#ifdef COUNT_ALLOCS
/* these must be last and never explicitly initialized */
@@ -565,6 +567,7 @@ PyAPI_FUNC(int) PyObject_GenericSetDict(PyObject *, PyObject *, void *);
#endif
PyAPI_FUNC(Py_hash_t) PyObject_Hash(PyObject *);
PyAPI_FUNC(Py_hash_t) PyObject_HashNotImplemented(PyObject *);
+PyAPI_FUNC(int) PyObject_SetSelf(PyObject *, PyObject *);
PyAPI_FUNC(int) PyObject_IsTrue(PyObject *);
PyAPI_FUNC(int) PyObject_Not(PyObject *);
PyAPI_FUNC(int) PyCallable_Check(PyObject *);
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index eb635263b0..0816f5754c 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1016,6 +1016,21 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
if (ix == DKIX_ERROR)
goto Fail;
+ if (old_value != NULL) {
+ PyTypeObject *tp = Py_TYPE(old_value);
+ if (tp->tp_setself != NULL) {
+ Py_DECREF(key);
+ if (old_value != value) {
+ return PyObject_SetSelf(old_value, value);
+ } else {
+ return 0; // don't pass self to self this seems to happen
+ // in __repr__ something that should be looked
+ // into
+ }
+ }
+ }
+
+
assert(PyUnicode_CheckExact(key) || mp->ma_keys->dk_lookup == lookdict);
MAINTAIN_TRACKING(mp, key, value);
@@ -1059,6 +1074,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value)
return 0;
}
+
if (_PyDict_HasSplitTable(mp)) {
mp->ma_values[ix] = value;
if (old_value == NULL) {
diff --git a/Objects/object.c b/Objects/object.c
index 8a3f8831d6..ed650440ed 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -802,6 +802,14 @@ PyObject_Hash(PyObject *v)
return PyObject_HashNotImplemented(v);
}
+int
+PyObject_SetSelf(PyObject *v, PyObject *value) {
+ PyTypeObject *tp = Py_TYPE(v);
+ if (tp->tp_setself != NULL)
+ return (*tp->tp_setself)(v, value);
+ return -1;
+}
+
PyObject *
PyObject_GetAttrString(PyObject *v, const char *name)
{
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 7065ee518e..881761bc6c 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -70,6 +70,7 @@ _Py_IDENTIFIER(__new__);
_Py_IDENTIFIER(__set_name__);
_Py_IDENTIFIER(__setitem__);
_Py_IDENTIFIER(builtins);
+_Py_IDENTIFIER(__setself__);
static PyObject *
slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
@@ -3615,6 +3616,7 @@ PyTypeObject PyType_Type = {
type_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
(inquiry)type_is_gc, /* tp_is_gc */
+ 0, /* tp_setself */
};
@@ -5727,6 +5729,22 @@ wrap_setattr(PyObject *self, PyObject *args, void *wrapped)
Py_RETURN_NONE;
}
+static PyObject *
+wrap_setself(PyObject *self, PyObject *args, void *wrapped)
+{
+ setselffunc func = (setselffunc)wrapped;
+ int res;
+ PyObject *value;
+
+ if (!PyArg_UnpackTuple(args, "", 1, 1, &value)) {
+ return NULL;
+ }
+ res = (*func)(self, value);
+ if (res < 0)
+ return NULL;
+ Py_RETURN_NONE;
+}
+
static PyObject *
wrap_delattr(PyObject *self, PyObject *args, void *wrapped)
{
@@ -6510,6 +6528,21 @@ slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value)
return 0;
}
+static int
+slot_tp_setself(PyObject *self, PyObject *value)
+{
+ PyObject *stack[1];
+ PyObject *res;
+ _Py_IDENTIFIER(__setself__);
+
+ stack[0] = value;
+ res = call_method(self, &PyId___setself__, stack, 1);
+ if (res == NULL)
+ return -1;
+ Py_DECREF(res);
+ return 0;
+}
+
static _Py_Identifier name_op[] = {
{0, "__lt__", 0},
{0, "__le__", 0},
@@ -6864,6 +6897,8 @@ static slotdef slotdefs[] = {
"__new__(type, /, *args, **kwargs)\n--\n\n"
"Create and return new object. See help(type) for accurate signature."),
TPSLOT("__del__", tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""),
+ TPSLOT("__setself__", tp_setself, slot_tp_setself, wrap_setself,
+ "__setself($self, value)/)\n--\n\nImplement assignment"),
AMSLOT("__await__", am_await, slot_am_await, wrap_unaryfunc,
"__await__($self, /)\n--\n\nReturn an iterator to be used in await expression."),
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.