引言

现如今在python学得越久,越是感觉到一些基础函数的重要性,不论学什么框架,当真正进入源码的时候,如果不懂得一些内置函数的含义,那将寸步难行,所以这里,我将主要总结内置函数的用法。

思维导图总结

快速查看 python 调用关系_默认值

虽然本着做一个全面的python总结,但当我画完流程图后发现,这里有些python函数比我想象中要偏门,至少在我的职业生涯中基本没碰过,虽然过一遍还是知道怎么用,可这篇博文就相当于新手教程了。我还是写一篇自备的给我后续查的东西,里面会出现一些比较跳脱的解释,也可能不对,后续改正补充。

和数字转换有关

int:

>>> int(1.75)		# 1
>>> int()		# 0
>>> int(3*4)		# 12
>>> int("3*4")		# 报错为invalid literal for int() with base 10
>>> int("12",)

int首先它的底层是__init__,它有两个重要的指标分别是int(x=0) -> integer和int(x, base=10) -> integer,也即是说当调用这个函数的时候一般都是采取base=10的十进制整数的形式转换,然后传递的参数应该是整型或者是字符串的整型基数,否则将会报错。

bool:

>>> bool()		# False
>>> bool("")		# False
>>> bool(None)		# False
>>> bool("  ")		# True
>>> bool("0.1")	# True

bool函数会返回两种值,False和True,只要有值,那么就返回True。另外bool的底层是C写的,其实很多内置函数都是cpython解释器里的。

float和complex

>>> float(1.983434242421144345)	# 结果为1.9834342424211444
>>> complex(36)	# (36+0j)

float只会返回小数点后16位的数字,它代表浮点数(有限循环小数,无限循环小数),如果超过16位,那么不管四舍五入,16位直接进位。

complex是复数类型函数,当传入一个实数的时候,会创建一个新的复数,这个东西对我这类学电气的很亲切,仿佛又回到了复变函数中的复平面中,傅里叶和拉普拉斯,然而从我敲python,还没用过这个函数。。。

chr、ord、str、:

tmp_list = []
for i in range(5):
    u = chr(random.randint(65, 90))  # 生成大写字母
    l = chr(random.randint(97, 122))  # 生成小写字母
    n = str(random.randint(0, 9))  # 生成数字,注意要转换成字符串类型
    tmp = random.choice([u, l, n])	# 在u、l、n里面继续随机
    tmp_list.append(tmp)
print(tmp_list)	# ['y', '8', 'd', 'w', '6']

这是我上一篇django登录源码与第三方登录验证源码中生成一个随机验证码的代码,基本上很好的概括了这三种类型的用法。

内置高级函数相关

这里我将 filter、sorted、map、zip、enumerate 分为一类,是因为我觉得这些算python里面比较常用的高级函数,因为它们的用法多样,下面就来详细解释这些函数的语法与功能。

sorted:

>>> L = [5,2,3,1,4]
>>> sorted(L)	# [1, 2, 3, 4, 5] 
>>> L.sort()	# [1, 2, 3, 4, 5]

>>> L = [5,2,6,4,5]
>>> print(L.sort())  # None
>>> print(L)    # [2, 4, 5, 5, 6]

>>> L = [5,2,6,4,5]
>>> print(sorted(L))    # [2, 4, 5, 5, 6]
>>> print(L)    # [5, 2, 6, 4, 5]

sorted参数说明:

  1. cmp:用于比较的函数,比较什么由key决定,有默认值,迭代集合中的一项;
  2. key:用列表元素的某个属性和函数进行作为关键字,有默认值,迭代集合中的一项;
  3. reverse:排序规则. reverse = True 或者 reverse = False,有默认值为False,即默认是从小到大
  4. 返回值:是一个经过排序的可迭代类型,与iterable一样。

而与之相似的是sort,它们两个都是排序,但sort没有返回值,所以返回为None,并且它会改变原列表本身的性质,也就是说在原列表中做了排序,而sorted是产生了新的列表,原列表没有变化。

fliter:

from math import sqrt
def func(num):
    res = sqrt(num)
    return res % 1 == 0
ret = filter(func,range(1,101))

# new_ret = list(ret)
# print(new_ret)     # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
for i in ret:
    print(i)    
"""
1
4
9
...
"""

filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。

该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。

map: 下面我们来看在python2下的例子,因为map在python2中会返回一个列表,但如果是python3中就是一个map对象,需要加list转换成列表类型,也可以是tuple类型:

***将元组转换成list***
>>> map(int, (1,2,3))
[1, 2, 3]
***将字符串转换成list***
>>> map(int, '1234')
[1, 2, 3, 4]
***提取字典的key,并将结果存放在一个list中***
>>> map(int, {1:2,2:3,3:4})
[1, 2, 3]
***字符串转换成元组,并将结果以列表的形式返回***
>>> map(tuple, 'agdf')
[('a',), ('g',), ('d',), ('f',)]

在说明之前不如来看个题目: 给你一字典a,如a={1:1,2:2,3:3},输出字典a的key,以’,‘连接,如‘1,2,3’。要求key按照字典序升序排列(注意key可能是字符串)。

例如:a={1:1,2:2,3:3}, 则输出:1,2,3 (出自pythontip第四题 题目链接)

综合上面的案例是不是立刻就想到了用map?我觉得比较好玩的两种解法:

print(','.join(sorted(map(str,a.keys()))))	# 第一个是先映射成字符串再排序
print(','.join(map(str,sorted(a.keys()))))	# 第二个是先排序再映射成字符串

上面两条语句其实没有本质上的区别,打印的结果都是一样的,所以这也是map好用的地方。在python2中map打印出的结果是转换成了列表,在python3中需要自己手动去转换类型,

filter是执行过后的结果集合 <= 执行之前的个数,它只管筛选,不会改变原来的值。而map是执行前后元素个数不变值,可能发生改变。当map的第一个参数func为None时,这就同zip()函数了。 不论是map、filter、zip在python3中直接打印都是相应的对象,只有自己手动转类型,而在Python2中不需要,默认是列表。

zip:

l = [1,2,3,4,5]
l2 = ['a','b','c','d']
l3 = ('*','**',[1,2])
d = {'k1':1,'k2':2}
for i in zip(l,l2,l3,d):
    print(i)
"""
(1, 'a', '*', 'k1')
(2, 'b', '**', 'k2')
"""

>>> s=['12a','123','234']
>>> print(list(zip(*s)))
[('1', '1', '2'), ('2', '2', '3'), ('a', '3', '4')]

python3中地zip相当于生成器,会在遍历过程中逐次产生元组。而python2中地zip则是直接把这些元组完全生成好,并一次性地返回整份列表。如果匹配结果中海油超过预期的,那么并不会报错,只是不会显示。

enumerate:

a = {'a':1,'b':2}
for i,j in enumerate(a):	# 遍历字典
  print(i,j)
"""
0 a
1 b
"""

a = [1,2,3,4]
for i,j in enumerate(a,1):
    print(i,j)

"""
1 1
2 2
3 3
4 4
"""

enumerate中文意思叫枚举,参数为可遍历的变量,如字符串,列表,字典等; 返回值为enumerate类。那么什么是enumerate类呢?上面的两个例子便是从enumerate取出来的,索引加值,enumerate可以把各种迭代器包装为生成器,以便稍后产生输出值。另外就是第一个参数是遍历的变量,第二个参数即为指定索引,默认为0开始。

好的,这里我们还可能会想到range函数,但range的作用域范围很小,一般用于字符串和数字,如果是列表或者是字典,那要比enumerate麻烦得多,可以看下面的例子:

list = [1, 2, 3, 4, 5, 6]  
for i in range (len(list)):
  print(i ,list[i])

list2 = [1, 2, 3, 4, 5, 6]  
for i,k in enumerate(list2):
    print(i,k)
# 两个的结果最终是一样的,但上面那种比下面的麻烦,并且也比较难懂,所以如果是遍历列表或者字典的话,推荐是用enumerate

字符串类型代码的执行

eval、exec:

>>> print(eval("1+2+3+4"))	# 10
>>> print(exec("1+2+3+4"))	# None

>>> code = '''for i in range(10):
>>>     print(i*'*')
'''
>>> exec(code)
>>> eval(code)  
# *
# **
# ***
# ****
# *****
# ******
# *******	# exec显示
# SyntaxError: invalid syntax	# eval显示

首先它们两个都能执行python代码,但eval()函数只能计算单个表达式的值,而exec()函数可以动态运行代码段。eval()函数可以有返回值,而exec()函数返回值永远为None。

所以eval可以用于有结果的简单运算,而exec可以用做简单的流程控制,另外一半建议不要轻易用eval,只能用在你明确知道你要执行的代码是什么才行,我记得Django中有一次我将它配合local一起用,虽然简单是简单,但一旦出bug,问题就大了。

compile:

code = '1 + 2 + 3 + 4'
compile = compile(code,'','eval')
print(eval(compile))	# 10

code = 'name = input("please input your name:")'
compile = compile(code,'','single')
exec(compile) #执行时显示交互命令,提示输入
print(name)
"""
please input your name:submarineas
submarineas
"""

将字符串编译为代码或者AST对象,使之能够通过exec语句来执行或者eval进行求值。

怎么理解这段话呢?依照我的理解就是compile是将语句转换成了一种编译格式与规则,但没有执行,需要相应的函数去运行这种编译好的规则,或者说调用,比如说exec、eval或者正则中的match匹配。另外这里的第二段代码的意思就是首先在code时拿到了这个name变量,然后通过exec的执行获取到了name,那么就可以调用name变量了,简单说还是挺方便的

反射相关

class func(object):
    name = "小黑"
    def __init__(self):
        self.age = "123"
    def write(self):
        return "helloworld"

func1 = func()

# hasattr
print(hasattr(func1, "name"))   # True
print(hasattr(func1, "self.age"))    # False
print(hasattr(func1, "write"))  # True

# getattr
print(getattr(func1,"name"))    # 小黑
print(getattr(func1,"write"))   # <bound method func.write of <__main__.func object at 0x0000026D5E65E438>>
print(getattr(func1,"write")()) # helloworld
print(getattr(func1,"self.age"))     # AttributeError: 'func' object has no attribute 'self.age'
print(getattr(func1,"__init__")())  # None
print(getattr(func1,"age","123"))  # 123

# setattr
print(hasattr(func1,"age")) # False
print(setattr(func1,"age","123"))   # None
print(hasattr(func1,"age"))   # True
print(getattr(func1,"age"))   # 123

# delattr
print(delattr(func1,"age")) # None
print(hasattr(func1,"age")) # False
print(delattr(func1,"write")) # AttributeError: write

总结:hasattr: 判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。如果是方法里的属性并不能获取到。

getattr: 获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,可以在后面添加一对括号。

setattr: 给对象的属性赋值,若属性不存在,先创建再赋值。

delattr: 将对象的属性删除,无法删除方法。

关于反射,一般上述setattr、hasattr、getattr都是成双出现的,并且一般都是源码居多,比如说我之前介绍过的restframework的第三篇中视图部分的ModelViewSet的部分源码就将上述三个用在了一起,还有可能未来我要写的form表单源码中的钩子函数,还有一些基本的单例。所以这几个相当于底层吧,

其它

dir,help: 查看属性

>>> print(dir([]))	 # ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '......
>>> print(help([]))	# 上面方法的名字与方法,以及一些解释
>>> help([])		# 和上面一样

dir是查看内置属性,或者说方法,比如说我有时候忘了某种数据类型的时候,我就可以进行查看和验证。

另外help可以从上面的例子看到,它是自带打印值的,所以里面应该是封装了print方法,另外它和dir不同是它会显示该所有的方法以及详细的解释,所以基本上所有语言里,都会有help,并且我们需要熟练help来查询帮助。

print:

# 1. end和sep关键字
>>> print("青春猪头少年不会梦到兔女郎学姐")	  # 未指定输出的结束符
青春猪头少年不会梦到兔女郎学姐

>>> print("青春猪头少年不会梦到兔女郎学姐",end="")		# 指定以空值结尾。这里的end和sep都是关键字传参
青春猪头少年不会梦到兔女郎学姐
>>> print(1,2,3,4,5,sep="")  	# 指定输出多个值之间的分隔符,输出12345


# 2. file关键字
>>> f = open("file","w")
>>> print("aaaa")
>>> f.close()	# 最后控制台会没有任何东西,而打印出的东西会在当前项目文件下的f文件中,有aaaa,所以这个参数的意思系统默认打印是在控制台的,但如果我们自己制定位置的话,那么控制台就不会打印了。

print 在 Python3.x 是一个函数,但在 Python2.x 版本不是一个函数,只是一个关键字。

参数:

  • objects – 复数,表示可以一次输出多个对象。输出多个对象时,需要用 , 分隔。
  • sep – 用来间隔多个对象,默认值是一个空格。
  • end – 用来设定以什么结尾。默认值是换行符 \n,我们可以换成其他字符串。
  • file – 要写入的文件对象。

input:

python2
>>> user=raw_input("please input:")
please input:submarineas
>>> user
"submarineas"	# 输入成功,返回字符串
>>> user=raw_input("please input:")
please input:123
>>> user
"123"	# 依然是字符串

>>> user=input("please input:")
please input:submarineas	# 会报错
>>> user	# NameError: name 'wei' is not defined

>>> user=raw_input("please input:")
please input:1+2
>>> user
3	# 输出3,是整形

在Python有raw_input( )和input( ),两个函数都存在,其中区别为raw_input( )将所有输入作为字符串看待,返回字符串类型,而input只能接收“数字”的输入,在对待纯数字输入时当成了某种指令,并返回所输入的数字的类型( int, float )。

在python3.x中raw_input( )和input( )进行了整合,去除了raw_input( ),仅保留了input( )函数,其接收任意任性输入,将所有输入默认为字符串处理,并返回字符串类型。

>>> user=raw_input("please input:")
please input:1+2
>>> user
"1+2"
please input:submarineas
"submarineas"

callable:

>>> print(callable(print))	# True
>>> a = 1
>>> print(callable(a))		# False
>>> print(callable(global))	# global会飘红

callable它相当于对当前对象的每一个函数方法做了一次callable(回调),callable也是一个内置函数,可以检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败,它的底层是取决于类是否定义了__call__方法。

当然关键字不能被callable调用,比如说是global、local等,虽然理论上它们是可调用的,但关键字的优先级要高于调用等级。

另外不仅仅只有callable,还有writable、readable等,也就是说可以用这两个函数看看是否文件可以读或者可以写。总之,它只能查变量,如果变量是函数就返回True,如果是值就是False。

总结

额,该总结的都在上面总结完了,那我只能说趁热打铁吧,下面将会开始刷剑指offer。这里的函数就先总结这么多,以后会补充的。

参考文献:

  1. Python map()函数的用法
  2. python中enumerate()的用法
  3. Python3:input()函数
  4. Eva_J内置函数总结