现如今在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参数说明:
cmp:用于比较的函数,比较什么由key决定,有默认值,迭代集合中的一项;
key:用列表元素的某个属性和函数进行作为关键字,有默认值,迭代集合中的一项;
reverse:排序规则. reverse = True 或者 reverse = False,有默认值为False,即默认是从小到大
返回值:是一个经过排序的可迭代类型,与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 版本不是一个函数,只是一个关键字。
参数:
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。这里的函数就先总结这么多,以后会补充的。
参考文献: