根据开放封闭原则,选择装饰器模式,A像B,但A还不够像B
def foo():
"""
Δ~~~~Δ
ξ •ェ• ξ
ξ ~ ξ
ξ ξ
ξ “~~~~〇
ξ ξ
ξ ξ ξ~~~ξ ξ
ξ_ξξ_ξ ξ_ξξ_ξ
ヽ(´•ω•)ノ
| /
UU
"""
print('GoodGoodStudy,DayDayUp in foo')
foo()
print(foo.__doc__)
print('-------------------------------------')
def bar(func):
def wrapper(*args, **kwargs):
print('GoodGoodStudy,DayDayUp in bar')
return func(*args, **kwargs)
return wrapper
@bar
def foo():
"""
Δ~~~~Δ
ξ •ェ• ξ
ξ ~ ξ
ξ ξ
ξ “~~~~〇
ξ ξ
ξ ξ ξ~~~ξ ξ
ξ_ξξ_ξ ξ_ξξ_ξ
ヽ(´•ω•)ノ
| /
UU
"""
print('GoodGoodStudy,DayDayUp in foo')
foo()
print(foo.__doc__)
输出结果:
GoodGoodStudy,DayDayUp in foo
Δ~~~~Δ
ξ •ェ• ξ
ξ ~ ξ
ξ ξ
ξ “~~~~〇
ξ ξ
ξ ξ ξ~~~ξ ξ
ξ_ξξ_ξ ξ_ξξ_ξ
ヽ(´•ω•)ノ
| /
UU
-------------------------------------
GoodGoodStudy,DayDayUp in bar
GoodGoodStudy,DayDayUp in foo
None
为了更像,用上functools中的wraps(被装饰的函数)
from functools import wraps
def far():
"""
Δ~~~~Δ
ξ •ェ• ξ
ξ ~ ξ
ξ ξ
ξ “~~~~〇
ξ ξ
ξ ξ ξ~~~ξ ξ
ξ_ξξ_ξ ξ_ξξ_ξ
ヽ(´•ω•)ノ
| /
UU
"""
print('GoodGoodStudy,DayDayUp in far')
far()
print(far.__doc__)
print('-------------------------------------')
def boo(func):
def wrapper(*args, **kwargs):
print('GoodGoodStudy,DayDayUp in boo')
return func(*args, **kwargs)
return wrapper
@boo
def far():
"""
Δ~~~~Δ
ξ •ェ• ξ
ξ ~ ξ
ξ ξ
ξ “~~~~〇
ξ ξ
ξ ξ ξ~~~ξ ξ
ξ_ξξ_ξ ξ_ξξ_ξ
ヽ(´•ω•)ノ
| /
UU
"""
print('GoodGoodStudy,DayDayUp in far')
far()
print(far.__doc__)
print('-------------------------------------')
def boo1(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('GoodGoodStudy,DayDayUp in boo')
return func(*args, **kwargs)
return wrapper
@boo1
def far():
"""
Δ~~~~Δ
ξ •ェ• ξ
ξ ~ ξ
ξ ξ
ξ “~~~~〇
ξ ξ
ξ ξ ξ~~~ξ ξ
ξ_ξξ_ξ ξ_ξξ_ξ
ヽ(´•ω•)ノ
| /
UU
"""
print('GoodGoodStudy,DayDayUp in far')
far()
print(dir(boo))
GoodGoodStudy,DayDayUp in foo
Δ~~~~Δ
ξ •ェ• ξ
ξ ~ ξ
ξ ξ
ξ “~~~~〇
ξ ξ
ξ ξ ξ~~~ξ ξ
ξ_ξξ_ξ ξ_ξξ_ξ
ヽ(´•ω•)ノ
| /
UU
-------------------------------------
GoodGoodStudy,DayDayUp in bar
GoodGoodStudy,DayDayUp in foo
None
-------------------------------------
GoodGoodStudy,DayDayUp in bar
GoodGoodStudy,DayDayUp in foo
Δ~~~~Δ
ξ •ェ• ξ
ξ ~ ξ
ξ ξ
ξ “~~~~〇
ξ ξ
ξ ξ ξ~~~ξ ξ
ξ_ξξ_ξ ξ_ξξ_ξ
ヽ(´•ω•)ノ
| /
UU
getattr
PyObject *
_PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
PyObject *dict, int suppress)
{
/* Make sure the logic of _PyObject_GetMethod is in sync with
this method.
When suppress=1, this function suppress AttributeError.
*/
PyTypeObject *tp = Py_TYPE(obj);
PyObject *descr = NULL;
PyObject *res = NULL;
descrgetfunc f;
Py_ssize_t dictoffset;
PyObject **dictptr;
if (!PyUnicode_Check(name)){
PyErr_Format(PyExc_TypeError,
"attribute name must be string, not '%.200s'",
name->ob_type->tp_name);
return NULL;
}
Py_INCREF(name);
if (tp->tp_dict == NULL) {
if (PyType_Ready(tp) < 0)
goto done;
}
descr = _PyType_Lookup(tp, name);
f = NULL;
if (descr != NULL) {
Py_INCREF(descr);
f = descr->ob_type->tp_descr_get;
if (f != NULL && PyDescr_IsData(descr)) {
res = f(descr, obj, (PyObject *)obj->ob_type);
if (res == NULL && suppress &&
PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
}
goto done;
}
}
if (dict == NULL) {
/* Inline _PyObject_GetDictPtr */
dictoffset = tp->tp_dictoffset;
if (dictoffset != 0) {
if (dictoffset < 0) {
Py_ssize_t tsize;
size_t size;
tsize = ((PyVarObject *)obj)->ob_size;
if (tsize < 0)
tsize = -tsize;
size = _PyObject_VAR_SIZE(tp, tsize);
assert(size <= PY_SSIZE_T_MAX);
dictoffset += (Py_ssize_t)size;
assert(dictoffset > 0);
assert(dictoffset % SIZEOF_VOID_P == 0);
}
dictptr = (PyObject **) ((char *)obj + dictoffset);
dict = *dictptr;
}
}
if (dict != NULL) {
Py_INCREF(dict);
res = PyDict_GetItem(dict, name);
if (res != NULL) {
Py_INCREF(res);
Py_DECREF(dict);
goto done;
}
Py_DECREF(dict);
}
if (f != NULL) {
res = f(descr, obj, (PyObject *)Py_TYPE(obj));
if (res == NULL && suppress &&
PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
}
goto done;
}
if (descr != NULL) {
res = descr;
descr = NULL;
goto done;
}
if (!suppress) {
PyErr_Format(PyExc_AttributeError,
"'%.50s' object has no attribute '%U'",
tp->tp_name, name);
}
done:
Py_XDECREF(descr);
Py_DECREF(name);
return res;
}
setattr
int
_PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
PyObject *value, PyObject *dict)
{
PyTypeObject *tp = Py_TYPE(obj);
PyObject *descr;
descrsetfunc f;
PyObject **dictptr;
int res = -1;
if (!PyUnicode_Check(name)){
PyErr_Format(PyExc_TypeError,
"attribute name must be string, not '%.200s'",
name->ob_type->tp_name);
return -1;
}
if (tp->tp_dict == NULL && PyType_Ready(tp) < 0)
return -1;
Py_INCREF(name);
descr = _PyType_Lookup(tp, name);
if (descr != NULL) {
Py_INCREF(descr);
f = descr->ob_type->tp_descr_set;
if (f != NULL) {
res = f(descr, obj, value);
goto done;
}
}
if (dict == NULL) {
dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
if (descr == NULL) {
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%U'",
tp->tp_name, name);
}
else {
PyErr_Format(PyExc_AttributeError,
"'%.50s' object attribute '%U' is read-only",
tp->tp_name, name);
}
goto done;
}
res = _PyObjectDict_SetItem(tp, dictptr, name, value);
}
else {
Py_INCREF(dict);
if (value == NULL)
res = PyDict_DelItem(dict, name);
else
res = PyDict_SetItem(dict, name, value);
Py_DECREF(dict);
}
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
PyErr_SetObject(PyExc_AttributeError, name);
done:
Py_XDECREF(descr);
Py_DECREF(name);
return res;
}
hasattr
分配空间:分配记录slots内容指针的大小即可
看对象是否存在descr,若是(查找slots的属性正是如此),调用descr身上的tp_descr_get方法,并将方法的返回值作为这次属性查找的结果返回。
看一下tp_descr_get是什么样子
slots对应的member->type是T_OBJECT_EX,根据member所记录的偏移值和类型,访问属性内存的代码了