python学习笔记-函数,递归和内置函数 函数和过程 参数与可变长参数 局部变量与全局变量 函数嵌套与作用域 函数递归 匿名函数 函数式编程 内置函数

过程:就是没有返回值的函数

python中过程也是函数,就算没有返回值,也要返回个None

例子:

def test(x):
    y=x+1
    return y
print(test)   #这是打印函数在内存中的地址


def test1():
    pass

def test2():
    return 0

def test3(x):
    msg="hello"
    print(msg,x)
    return 1,2,3,'a',["steven","bob"],None

t1=test1()
t2=test2()
t3=test3("jobs")
print(t1)  #None
print(t2)  #0
print(t3)  #打印返回的值,是一个元组:(1, 2, 3, 'a', ['steven', 'bob'], None)

总结:

   返回值数=0:返回None

   返回值数=1:返回object

   返回值数>1:返回tuple

参数与可变长参数

过量的参数

在运行时知道一个函数有什么参数,通常是不可能的。另一个情况是一个函数能操作很多对象。更有甚者,调用自身的函数变成一种api提供给可用的应用。

对于这些情况,python提供了两种特别的方法来定义函数的参数,允许函数接受过量的参数,不用显式声明参数。这些“额外”的参数下一步再解释。

注意args和kwargs只是python的约定。任何函数参数,你可以自己喜欢的方式命名,但是最好和python标准的惯用法一致,以便你的代码,其他的程序员也能轻松读懂。

位置参数

在参数名之前使用一个星号,就是让函数接受任意多的位置参数。

def multiply(*args):
    total = 1
    for arg in args:
        total *= arg
    return total

print(multiply(2, 3))
print(multiply(2, 3, 4, 5, 6))

python把参数收集到一个元组中,作为变量args。显式声明的参数之外如果没有位置参数,这个参数就作为一个空元组

关键字参数

python在参数名之前使用2个星号来支持任意多的关键字参数。

def accept(**kwargs):
    for keyword, value in kwargs.items():
        print("%s => %r" % (keyword, value))

accept(foo='bar', spam='eggs')

注意:kwargs是一个正常的python字典类型,包含参数名和值。如果没有更多的关键字参数,kwargs就是一个空字典。

混合参数类型

任意的位置参数和关键字参数可以和其他标准的参数声明一起使用。混合使用时要加些小心,因为python中他们的次序是重要的。参数归为4类,不是所有的类别都需要。他们必须按下面的次序定义,不用的可以跳过。

1)必须的参数
2)可选的参数
3)过量的位置参数
4)过量的关键字参数

练习:

#例1
def add(x,y,z=5):
    res=x+y+z
    print(res)

add(1,z=2,y=9)       #位置参数必须在关键字参数的左边

#例2
def test(x,*args):
    #print(x)
    print(args)

test(3,[4,5,6,7])    #结果为:([4, 5, 6, 7],)
test(3,*[4,5,6,7])   #结果为:(4, 5, 6, 7),和test(3,4,5,6,7)一样
test(3)              #结果为()

#例3
def test(x,**kwargs):
    #print(x)
    print(kwargs)

test(1,a=3,b=4,c=5)  #{'a': 3, 'b': 4, 'c': 5}
#test(1,a=3,b=4,c=5,c=5) #报错,一个参数不能传两个值

#例4
def test(x,*args,**kwargs):
    #print(x)
    print(args)
    print(kwargs)

test(1,10,11,12,13,a=30,b=40,c=50)
test(1,*[10,11,12,13],**{"a":30,"b":40,"c":50})
'''结果为:
(10, 11, 12, 13)
{'a': 30, 'b': 40, 'c': 50}
(10, 11, 12, 13)
{'a': 30, 'b': 40, 'c': 50}
'''

局部变量与全局变量

在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。

全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。
当全局变量与局部变量同名时:
在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。
name='steven'
def change_name():
    print('名字',name)

change_name() #名字 steven


def change_name():
    name='帅哥一枚'
    print('名字',name)

change_name()
print(name) #steven


def change_name():
    global name          #操作的是全局变量
    name='帅哥一枚'
    print('名字',name)

change_name()
print(name) #帅哥一枚

补充:

NAME=["jobs","steven"]

def test():
    NAME.append("mark")
    print("我的朋友有:",NAME)

test()

总结:如果函数的内部无global关键字,优先读取局部变量;

          可读取全局变量,无法对全局变量重新赋值,但是对于可变类型,可以对全局变量的内部元素进行操作

如果函数中有global关键字,变量本质上就是全局的那个变量,可读取可赋值

#1、无global关键字
#---有声明局部变量
NAME=["jobs","steven"]
def test():
    NAME=["zhou"]
    NAME.append("mark")
    print("我的朋友有:",NAME)
test() #['zhou', 'mark']
#--未声明局部变量
NAME=["jobs","steven"]
def test():
    NAME.append("mark")
    print("我的朋友有:",NAME)
test() #['jobs', 'steven', 'mark']
#2、有global关键字
#---有声明局部变量
NAME=["jobs","steven"]
def test():
    global NAME
    NAME = ["zhou"]
    NAME.append("mark")
    print("我的朋友有:",NAME)
test()#['zhou', 'mark']
#--错误的例子
# NAME=["jobs","steven"]
# def test():
#     NAME = ["zhou"]
#     global NAME
#     NAME.append("mark")
#     print("我的朋友有:",NAME)
# test()#报错,局部变量在全局变量声明之前报错,不知道找哪个
#规范:全局变量变量名全部大写,局部变量变量名小写
#--未声明局部变量
NAME=["jobs","steven"]
def test():
    global NAME
    NAME.append("mark")
    print("我的朋友有:",NAME)
test()#['jobs', 'steven', 'mark']
View Code

函数嵌套与作用域

#1、
def test1():
    print("in the test1")
def test():
    print("in the test")
    return test1

res=test()
print(res)

#2、
name="jobs"
def foo():
    name="mark"
    def bar():
        #name="steven"
        print(name)
    return bar
a=foo()
print(a)
a()   #bar()
#定义是一部分,执行是一部分。虽然在最外面执行的bar().但是输出结果还是“mark”不论在那个位置调用函数。函数的作用域跟声明的时候有关。

#3、
def foo():
    name="steven"
    def bar():
        name="mark"
        def tt():
            print(name)
        return tt
    return bar

bar=foo()
tt=bar()
print(tt)
tt()   #mark
foo()()() #mark

函数递归

在函数内部,可以调用其他函数。如果在调用一个函数的过程中直接或间接调用自身本身,就是递归

def calc(n):
    print(n)
    if int(n/2) == 0:
        return n
    res=calc(int(n/2))
    return res

r=calc(10)
print(r)

例子:问路

import time
person_list=["zhou","steven","jobs","mark","sandy"]
def ask_way(person_list):
    print("-"*60)
    if len(person_list)==0:
        return "根本没人知道"
    person=person_list.pop(0)
    if person=="sandy":
        return "%s说:我知道,就在来福士,下地铁就是"%person

    print("Hi,美男[%s]:敢问路在何方" %person)
    print("%s回答说:我不知道,我帮你问问%s"%(person,person_list))
    time.sleep(1)
    res=ask_way(person_list)
    print("%s问的结果是:%s"%(person,res))

    return res
res=ask_way(person_list)
print(res)

结果为:

------------------------------------------------------------
Hi,美男[zhou]:敢问路在何方
zhou回答说:我不知道,我帮你问问['steven', 'jobs', 'mark', 'sandy']
------------------------------------------------------------
Hi,美男[steven]:敢问路在何方
steven回答说:我不知道,我帮你问问['jobs', 'mark', 'sandy']
------------------------------------------------------------
Hi,美男[jobs]:敢问路在何方
jobs回答说:我不知道,我帮你问问['mark', 'sandy']
------------------------------------------------------------
Hi,美男[mark]:敢问路在何方
mark回答说:我不知道,我帮你问问['sandy']
------------------------------------------------------------
mark问的结果是:sandy说:我知道,就在来福士,下地铁就是
jobs问的结果是:sandy说:我知道,就在来福士,下地铁就是
steven问的结果是:sandy说:我知道,就在来福士,下地铁就是
zhou问的结果是:sandy说:我知道,就在来福士,下地铁就是
sandy说:我知道,就在来福士,下地铁就是
View Code

递归特性

1、必须有一个明确的结束条件

2、每次进入更深一层递归时,问题规模相比上次递归都应有所减少

3、递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调动是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会增加一层,每当函数返回,栈就会减少一层。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

匿名函数

匿名函数就是不需要显式的指定函数

def calc(x):
    return x+1
print(calc(10))
#换成匿名函数
func=lambda x:x+1
print(func(10))

#print(lambda x:x+1) #输出函数地址

test=lambda x,y,z:(x+1,y+1,z+1) #返回多个值时当做元组处理。lambda用法时要手动加括号
print(test(1,2,3))#(2, 3, 4)

匿名函数主要是和其它函数搭配使用的

函数式编程

编程的三种方法论:

面向过程

函数式

面向对象

函数式编程可读性查,精简

特性:

1、不可变,不用变量保存状态,不修改变量

#非函数式
a=1
def incr_test1():
    global a
    a+=1
    return a
print(incr_test1())
#函数式
n=1
def incr_test2(n):
    return n+1
print(incr_test2(2))
print(n)

2、第一类对象:函数即变量

函数名可以当做参数传递

返回值可以是函数名

高阶函数:

满足下面一种情形的就是高阶函数(1、函数接收的参数是一个函数名;2、返回值中包含函数)

# 把函数当做参数传给另一个函数
def foo(n):
    print(n)

def bar(name):
    print("my name is %s" % name)

#foo(bar)
foo(bar("steven"))


# 返回值中包含函数
def bar():
    print("from bar")

def foo():
    print("from foo")
    return bar
n = foo()
n()

#返回自己
def handle():
    print("from handle")
    return handle
n = handle()
n()

尾递归调用优化:

在函数的最后一步调用另外一个函数(最后一行不一定是函数的最后一步)

# 非尾调用

def bar(n):
    return n
def foo(x):
    return bar(x) + 1
#尾调用

def test1():
    print("from test1")

def test2():
    print("from test2")
    return test1()

map函数

num_1=[1,2,10,4,3,7]
def map_test(func,array):   #func=lambda x=x+1 arrary=[1,2,10,4,3,7]
    ret=[]
    for i in array:
        res=func(i)  #
        ret.append(res)
    return ret
print(map_test(lambda x:x+1,num_1))

#使用map函数
res=map(lambda x:x+1,num_1)  #获得的是个可迭代对象,在python2获得的就是个列表
print(res)          #<map object at 0x0000021E578A0C18>
print(list(res))    #[2, 3, 11, 5, 4, 8]

msg="ajfaljfiejalf"
print(list(map(lambda x:x.upper(),msg)))#['A', 'J', 'F', 'A', 'L', 'J', 'F', 'I', 'E', 'J', 'A', 'L', 'F']

filter函数

gentleman=["alex_ss","jobs_ss","steven","mark_ss"]

print(filter(lambda n:not n.endswith("ss"),gentleman))#<filter object at 0x000002B2A39D0C18>
res=filter(lambda n:not n.endswith("ss"),gentleman)
print(list(res))                         #['steven']

reduce函数

num_1=[1,2,3,100]
def reduce_test(func,array,init=None):
    if init is None:
        res=array.pop(0)
    else:
        res=init
    for num in array:
        res=func(res,num)
    return res

print(reduce_test(lambda x,y:x*y,num_1,10))   #6000

#reduce 用法
from functools import reduce
print(reduce(lambda x,y:x*y,num_1,10))       #6000

总结:

map函数对一个列表进行特定处理,结果得出一个长度和顺序不变的列表,filter是对一个列表处理筛选一遍得出一个列表出来,reduce把一个完整的序列压缩处理成一个值
map处理序列中的每个元素,得到的结果是一个"列表",该列表元素个数与位置与原来一样
filter遍历序列找那个的每个元素,判断每个元素得到布尔值,如果是true则留下来
reduce处理一个序列,然后把序列进行合并操作

内置函数

python学习笔记-函数,递归和内置函数
函数和过程
参数与可变长参数
局部变量与全局变量
函数嵌套与作用域
函数递归
匿名函数
函数式编程
内置函数

print(abs(-2))
print(all([1,2,'1']))
print(all([1,2,'1',''])) #可迭代对象的每个值是true,返回true
print(all('')) #true
print(all([])) #可迭代对象是空,返回true
print(all([0,'']))#false
print(all([0,'',1]))#false
print(bin(3))  #转化成二进制,结果:0b11 0b表示二进制
print(bool(None)) #空,None,0的布尔值为false,其余都为true
name='你好'
print(bytes(name,encoding='utf-8'))
print(bytes(name,encoding='utf-8').decode('utf-8'))  #decode():python3默认用uft-8解码
print(bytes(name,encoding='gbk'))
print(bytes(name,encoding='gbk').decode('gbk'))
#print(bytes(name,encoding='ascii'))   #错误:ascii不能编码中文
print(chr(109)) #按照ascii码表对应的顺序输出值
print(dir(all)) #输出all下面的所有方法名
print(divmod(10,3)) #结果:(3, 1),得出商和余数
dict_str='{"name":"steven"}'
print(eval(dict_str)) #把字符串中的数据结构提取出来
express="1+2*5-3"
print(eval(express)) #把字符串中的表达式进行运算

#可hash的数据类型即不可变数据类型,不可hash的数据类型即可变数据类型
print(hash("9238121hkjk jkjijojo0"))
help(all)

print(hex(12)) #十进制--》16进制
print(oct(12)) #十进制--》8进制

print(isinstance(1,int))   #true
print(isinstance([],list))
print(isinstance("abc",str))

print(globals())#打印全局变量
print(locals())#打印局部变量

max()

1、max函数处理的是可迭代对象,相当于一个for循环取出每个元素进行比较,注意,不同类型之间不能进行比较
2、每个元素件进行比较,是从每个元素的第一个位置依次比较,如果这一个位置分出大小,后面的都不需要比较了,直接得出这个元素。

例子:max与zip方法

#max场景1
l=[1,3,100,-3,9]
print(max(l))
print(min(l))

print(list(zip(('a','b','c'),(1,2,3))))  #zip创建一个拉链的对象,左右对齐。结果:[('a', 1), ('b', 2), ('c', 3)]
print(list(zip(('a','b','c'),(1,2,3,4))))#[('a', 1), ('b', 2), ('c', 3)]
print(list(zip(('a','b','c','d'),(1,2,3))))#[('a', 1), ('b', 2), ('c', 3)]
#
p={'name':'steven','age':18,'gender':'none'}
print(list(zip(p.keys(),p.values()))) #[('name', 'steven'), ('age', 18), ('gender', 'none')]
print(list(p.keys()))#['name', 'age', 'gender']
print(list(p.values()))#['steven', 18, 'none']
print(list(zip('hello','12345'))) #zip里传的两个参数是序列类型(列表,字符串,元祖)

#max场景2
age_dic={"age1":18,"age2":20,"age3":100}
print(max(age_dic.values()))#比较的是value,但不知道是哪个key对应的
print(max(age_dic)) #默认比较字典的key

#max场景3,结合zip
print(list(max(zip(age_dic.values(),age_dic.keys()))))
l=["a10","b12","c10"]
print(list(max(l))) #['c', '1', '0']

#如果l=["a10","b12","c10",100].报错,整形和字符串不能比较,只能相同类型进行比较


#max场景4
people=[{"name":"alex","age":1000},{"name":"steven","age":800},{"name":"mark","age":100}]
a=max(people,key=lambda dic:dic["age"])
print(a) #{'name': 'alex', 'age': 1000}

其他内置函数

#ord()
print(ord("a")) #跟chr对应

#pow()
print(pow(3,3)) #3**3
print(pow(3,3,2)) #3**3%2

#reversed() 反转
l=[1,2,3,4]
print(l)
print(list(reversed(l)))#[4, 3, 2, 1]

#round() 四舍五入
print(round(3.6))

#set() 集合
print(set("hello"))#{'h', 'o', 'e', 'l'}

#slice()
#场景1,不使用时,可读性差
l="hello"
print(l[3:5])
#场景2.
l="hello"
s1=slice(3,5)
s2=slice(1,4,2)
print(l[s1])#lo
print(l[s2])#el
print(s2.start) #输出切片的开始,1
print(s2.stop)  #输出切片的结束,4
print(s2.step)  #输出切片的步长,2


#sorted()
l=[3,2,1,5,7]
l1=[3,2,"a",1,5,7]
print(sorted(l))   #[1, 2, 3, 5, 7]
#print(sorted(l1)) #排序本质就是比较大小,不同类型之间不可以比较大小
people=[{"name":"alex","age":1000},{"name":"steven","age":800},{"name":"mark","age":100}]
print(sorted(people,key=lambda dic:dic["age"]))
#结果为:[{'name': 'mark', 'age': 100}, {'name': 'steven', 'age': 800}, {'name': 'alex', 'age': 1000}]

name_dic={"mark":800,"steven":200,"jobs":500}
print(sorted(name_dic)) #结果是按照key排序  ['jobs', 'mark', 'steven']
print(sorted(name_dic,key=lambda key:name_dic[key]))#['steven', 'jobs', 'mark']
print(sorted(zip(name_dic.values(),name_dic.keys())))#[(200, 'steven'), (500, 'jobs'), (800, 'mark')]


#str()转化成字符串
print(str({"a":1}))
dic_str=str({"a":1})
print(eval(dic_str)) #字符串中数据类型提取出来

#sum()
l=[1,2,3,4]
print(sum(l))
print(sum(range(5)))

#type()
msg='123'
if type(msg) is str:
    msg=int(msg)
    res=msg+1
    print(res)

#vars() 跟一个列表对象,返回一个字典:不带参数,相当于locals(),打印局部变量的字典形式。有参数,相当于object.__dict__,查看对象下对所有方法的字典形式,没什么用
def test():
    msg='djfaiefjaleji'
    print(locals())#{'msg': 'djfaiefjaleji'}
    print(vars())#{'msg': 'djfaiefjaleji'}
test()
print(vars(int))

#import 不能导入字符串   运行时import实际上调用操作系统,操作系统会找到__import__()方法去导入:import--->sys--->__import__()
#__import__ 导入字符串的模块名
import os
module_name='elementtreexml'
m=__import__(module_name)
xmlFilePath = os.path.abspath("movie.xml")
root=m.readXml(xmlFilePath)
m.traverseXml(root)