python基本的内置函数,说明python中内置函数的运用
本文主要介绍Python内置函数的详细分析。Python自带了很多内置函数,大大方便了我们的开发。下面小编总结了一些内置函数的相关内容,有需要的可以参考一下。
00-1010 1.本地和全局8 .哈希9.sum10.getattr,setattr,delattr前言:
Python自带了很多内置函数,极大的方便了我们的开发。让我们挑选几个内置函数来看看底层是如何实现的。
内置函数位于Python/bitlinmodule.c中
目录
abs的作用是取整数的绝对值或复数的模。
静态对象*
builtin _ ABS(py object *模块,PyObject *x)
{
返回py number _ Absolute(x);
}
该函数调用PyNumber_Absolute。
//Objects/abstract.c
对象*
PyNumber_Absolute(PyObject *o)
{
PyNumberMethods * m;
if (o==NULL) {
返回null _ error();
}
//通过类型对象获取操作集群PyNumberMethods
m=o-ob _ type-TP _ as _ number;
//调用nb_absolute
if (m m-nb_absolute)
返回m-nb _ absolute(o);
return type _ error( ABS():“% . 200s”的错误操作数类型,o);
}
我们以整数为例。它的nb _ absoulte指向long_absolute。
//Objects/longobject.c
静态对象*
long_abs(PyLongObject *v)
{
if (Py_SIZE(v) 0)
//如果v小于0,则取倒数
返回long _ neg(v);
其他
//否则返回自身
返回long _ long((py object *)v);
}
因为Python3的整数是以数组的形式存储的,所以它并不直接取倒数,需要做一些额外的处理,但在数学上可以直接理解为取倒数。
1.abs
接收一个iterable对象,如果其中的所有元素都为true,则返回true;只要有一个不为真,就返回False。
静态对象*
builtin _ all(py object *模块,PyObject *iterable)
{
PyObject *it,* item
py object *(* ITER next)(py object *);
int cmp
//获取iterable对象的迭代器
it=py object _ GetIter(iterable);
if (it==NULL)
返回NULL
//获取内部__next__方法
ITER next=* Py _ TYPE(it)-TP _ ITER next;
for(;) {
//迭代元素
item=ITER next(it);
//返回NULL,表示异常。
//一个是迭代后抛出的StopIteration。
//另一种是迭代过程中发生的异常。
if (item==NULL)
打破;
//确定项目的布尔值是否为真
//cmp 0表示真。
//cmp==0为假。
//c
mp < 0 表示解释器调用出错(极少发生)
cmp = PyObject_IsTrue(item);
Py_DECREF(item);
if (cmp < 0) {
Py_DECREF(it);
return NULL;
}
//只要有一个元素为假,就返回 False
if (cmp == 0) {
Py_DECREF(it);
Py_RETURN_FALSE;
}
}
Py_DECREF(it);
//PyErr_Occurred() 为真表示出现异常了
if (PyErr_Occurred()) {
//判断异常是不是 StopIteration
if (PyErr_ExceptionMatches(PyExc_StopIteration))
//如果是,那么表示迭代正常结束
//PyErr_Clear() 负责将异常清空
PyErr_Clear();
else
return NULL;
}
//走到这,说明所有的元素全部为真
//返回 True,等价于 return Py_True
Py_RETURN_TRUE;
}
因此 all 就是一层 for 循环,但它是 C 的循环,所以比我们写的 Python 代码快。
3.any
接收一个可迭代对象,只要里面有一个元素为真,则返回 True;如果全为假,则返回 False。
static PyObject *builtin_any(PyObject *module, PyObject *iterable)
{
//源码和 builtin_all 是类似的
PyObject *it, *item;
PyObject *(*iternext)(PyObject *);
int cmp;
//获取可迭代对象的迭代器
it = PyObject_GetIter(iterable);
if (it == NULL)
return NULL;
//拿到内部的 __next__ 方法
iternext = *Py_TYPE(it)->tp_iternext;
for (;;) {
//迭代元素
item = iternext(it);
if (item == NULL)
break;
cmp = PyObject_IsTrue(item);
Py_DECREF(item);
if (cmp < 0) {
Py_DECREF(it);
return NULL;
}
//只要有一个为真,则返回 True
if (cmp > 0) {
Py_DECREF(it);
Py_RETURN_TRUE;
}
}
Py_DECREF(it);
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_StopIteration))
PyErr_Clear();
else
return NULL;
}
//全部为假,则返回 False
Py_RETURN_FALSE;
}
4.callable
判断一个对象是否可调用。
static PyObject *builtin_callable(PyObject *module, PyObject *obj)
{
return PyBool_FromLong((long)PyCallable_Check(obj));
}
PyBool_FromLong 是将一个整数转成布尔值,所以就看 PyCallable_Check 是返回 0,还是返回非 0。
int
PyCallable_Check(PyObject *x)
{
if (x == NULL)
return 0;
return x->ob_type->tp_call != NULL;
}
逻辑非常简单,一个对象是否可调用,就看它的类型对象有没有实现 __call__。
5.dir
如果不接收任何对象,返回当前的 local 空间;否则返回某个对象的所有属性的名称。
static PyObject *builtin_dir(PyObject *self, PyObject *args)
{
PyObject *arg = NULL;
//要么不接收参数,要么接收一个参数
//如果没有接收参数,那么 arg 就是 NULL,否则就是我们传递的参数
if (!PyArg_UnpackTuple(args, "dir", 0, 1, &arg))
return NULL;
return PyObject_Dir(arg);
}
该函数调用了 PyObject_Dir。
//Objects/object.cPyObject *
PyObject_Dir(PyObject *obj)
{
//当 obj 为 NULL,说明我们没有传参,那么返回 local 空间
//否则返回对象的所有属性的名称
return (obj == NULL) ? _dir_locals() : _dir_object(obj);
}
先来看看 _dir_locals 函数。
//Objects/object.cstatic PyObject *
_dir_locals(void)
{
PyObject *names;
PyObject *locals;
//获取当前的 local 空间
locals = PyEval_GetLocals();
if (locals == NULL)
return NULL;
//拿到所有的 key,注意:PyMapping_Keys 返回的是列表
names = PyMapping_Keys(locals);
if (!names)
return NULL;
if (!PyList_Check(names)) {
PyErr_Format(PyExc_TypeError,
"dir(): expected keys() of locals to be a list, "
"not %.200s", Py_TYPE(names)->tp_name);
Py_DECREF(names);
return NULL;
}
//排序
if (PyList_Sort(names)) {
Py_DECREF(names);
return NULL;
}
//返回
return names;
}
还是比较简单的,然后是 _dir_object,它的代码比较多,这里就不看了。但是逻辑很简单,就是调用对象的dir方法,将得到的列表排序后返回。
6.id
查看对象的内存地址,我们知道 Python 虽然一切皆对象,但是我们拿到的都是指向对象的指针。比如 id(name) 是查看变量 name 指向对象的地址,说白了不就是 name 本身吗?所以直接将指针转成整数之后返回即可,
static PyObject *builtin_id(PyModuleDef *self, PyObject *v)
{
//将 v 转成整数,返回即可
PyObject *id = PyLong_FromVoidPtr(v);
if (id && PySys_Audit("builtins.id", "O", id) < 0) {
Py_DECREF(id);
return NULL;
}
return id;
}
7.locals 和 globals
这两者是查看当前的 local 空间和 global 空间,显然直接通过栈帧的 f_locals 和 f_globals 字段即可获取。
static PyObject *builtin_locals_impl(PyObject *module)
{
PyObject *d;
//在内部会通过线程状态对象拿到栈帧
//再通过栈帧的 f_locals 字段拿到 local 空间
d = PyEval_GetLocals();
Py_XINCREF(d);
return d;
}
static PyObject *
builtin_globals_impl(PyObject *module)
{
PyObject *d;
//和 PyEval_GetLocals 类似
d = PyEval_GetGlobals();
Py_XINCREF(d);
return d;
}
8.hash
获取对象的哈希值。
static PyObject *builtin_hash(PyObject *module, PyObject *obj)
{
Py_hash_t x;
//在内部会调用 obj -> ob_type -> tp_hash(obj)
x = PyObject_Hash(obj);
if (x == -1)
return NULL;
return PyLong_FromSsize_t(x);
}
9.sum
接收一个可迭代对象,计算它们的和。但是这里面有一个需要注意的地方。
print(sum([1, 2, 3])) # 6try:
print(sum(["1", "2", "3"]))
except TypeError as e:
print(e) # unsupported operand type(s) for +: int and str
咦,字符串明明也支持加法呀,为啥不行呢?其实 sum 还可以接收第二个参数,我们不传的话就是 0。
也就是说 sum([1, 2, 3]) 其实是 0 + 1 + 2 + 3;那么同理,sum(["a", "b", "c"]) 其实是 0 + "a" + "b" + "c";所以上面的报错信息是不支持类型为 int 和 str 的实例进行相加。
try:print(sum(["1", "2", "3"], ""))
except TypeError as e:
print(e) # sum() cant sum strings [use .join(seq) instead]
# 我们看到还是报错了,只能说明理论上是可以的
# 但 Python 建议我们使用 join
# 我们用列表举例吧
try:
print(sum([[1], [2], [3]]))
except TypeError as e:
print(e) # unsupported operand type(s) for +: int and list
# 告诉我们 int 的实例和 list 的实例不可以相加
# 将第二个参数换成空列表
print(sum([[1], [2], [3]], [])) # [1, 2, 3]
# 如果不是空列表呢?
print(
sum([[1], [2], [3]], ["古明地觉"])
) # [古明地觉, 1, 2, 3]
所以 sum 是将第二个参数和第一个参数(可迭代对象)里面的元素依次相加,然后看一下底层实现。
static PyObject *builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
{
//result 就是返回值,初始等于第二个参数
//如果可迭代对象为空,那么返回的就是第二个参数
//比如 sum([], 123) 得到的就是 123
PyObject *result = start;
PyObject *temp, *item, *iter;
//获取可迭代对象的类型对象
iter = PyObject_GetIter(iterable);
if (iter == NULL)
return NULL;
//如果 result 为 NULL,说明我们没有传递第二个参数
if (result == NULL) {
//那么 result 赋值为 0
result = PyLong_FromLong(0);
if (result == NULL) {
Py_DECREF(iter);
return NULL;
}
} else {
//否则的话,检测是不是 str、bytes、bytearray 类型
//如果是的话,依旧报错,并提示使用 join 方法
if (PyUnicode_Check(result)) {
PyErr_SetString(PyExc_TypeError,
"sum() cant sum strings [use .join(seq) instead]");
Py_DECREF(iter);
return NULL;
}
if (PyBytes_Check(result)) {
PyErr_SetString(PyExc_TypeError,
"sum() cant sum bytes [use b.join(seq) instead]");
Py_DECREF(iter);
return NULL;
}
if (PyByteArray_Check(result)) {
PyErr_SetString(PyExc_TypeError,
"sum() cant sum bytearray [use b.join(seq) instead]");
Py_DECREF(iter);
return NULL;
}
Py_INCREF(result);
}
#ifndef SLOW_SUM
//这里是快分支
//假设所有元素都是整数
if (PyLong_CheckExact(result)) {
//将所有整数都迭代出来,依次相加
//...
}
if (PyFloat_CheckExact(result)) {
//将所有浮点数都迭代出来,依次相加
//...
}
#endif
//如果不全是整数或浮点数,执行通用逻辑
for(;;) {
//迭代元素
item = PyIter_Next(iter);
if (item == NULL) {
/* error, or end-of-sequence */
if (PyErr_Occurred()) {
Py_DECREF(result);
result = NULL;
}
break;
}
//和 result 依次相加
temp = PyNumber_Add(result, item);
Py_DECREF(result);
Py_DECREF(item);
result = temp;
if (result == NULL)
break;
}
Py_DECREF(iter);
//返回
return result;
}
一个小小的 sum,代码量还真不少呢,我们还省略了一部分。
10.getattr、setattr、delattr
这几个应该已经很熟悉了,先来看看 getattr,它是获取对象的某个属性,并且还可以指定默认值。
static PyObject *builtin_getattr(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *v, *name, *result;
//参数个数必须是 2 或 3
//对象、属性名、可选的默认值
if (!_PyArg_CheckPositional("getattr", nargs, 2, 3))
return NULL;
//获取对象和属性名
v = args[0];
name = args[1];
//name必须是字符串
if (!PyUnicode_Check(name)) {
PyErr_SetString(PyExc_TypeError,
"getattr(): attribute name must be string");
return NULL;
}
//调用对象的 __getattr__,找不到返回默认值
if (nargs > 2) {
if (_PyObject_LookupAttr(v, name, &result) == 0) {
PyObject *dflt = args[2];
Py_INCREF(dflt);
return dflt;
}
}
else {
result = PyObject_GetAttr(v, name);
}
return result;
}
同理 setattr 是调用对象的 __setattr__,delattr 是调用对象的 __delattr__。
到此这篇关于Python内置函数详细解析的文章就介绍到这了,更多相关Python内置函数内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。