# ************** 函数 ******************** #位置参数、可变参数、关键字参数、命名关键字参数、 关键字参数 # 1.位置参数、计算x^2的函数x 就是位置参数 def power(x): return x*x print("两个数的平方和:",power(20)) # 2.默认参数 b=2 就是默认参数 def power(a,b=2): s = 1 while b > 0: s = s * a b = b - 1 return s print("5的2次方:",power(5,2)) # ==> 5的2次方: 25 print("6的2次方:",power(2)) # ==> 6的2次方: 4 print("6的3次方:",power(6,3)) # ==> 6的3次方: 216 print("6的1次方:",power(6,1)) # ==> 6的3次方: 6 # 3.可变参数:可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个 为了使参数是可变的需要参数前加* 如calc(numbers) calc(1,2,3) 这么写就需要加* def calc(numbers): sum = 0 for x in numbers: sum += x return sum print("1~100的和:",calc(range(101))) # ==> 1~100的和: 5050 print("1~10的和:",calc([1,2,3,4,5,6,7,8,9,10])) # ==> 1~10的和: 55 def test(L = []): L.append("End") return L print(test()) # ==> ['End'] print(test()) # ==> ['End', 'End'] print(test([1,2,3])) # ==> [1, 2, 3, 'End'] print(test()) # ==> ['End', 'End', 'End'] # 备注:当调用test函数的时候如果传入为空我们可以发现结果就会发生变化,原因是test函数定义的时候指向了一个空的list,如果传入不为空的list那么L会指向传入的list然后执行test的函数内容最后返回,此时如果传入为空那么L仍然指向空的list此时执行test函数拼接"End",此时L的默认参数就不再为空了,而是有一个元素为"End"的list,一次类推,所以默认参数一定要选择不可变对象 # 4.直接把list或者tuple当做参数写入很不方便,我们可以以*list/tuple当做参数写入同时定义函数的地方的参数也要进行修改,def cals(*numbers) def calcc(*numbers): sum = 0 for x in numbers: sum += x return sum numberss = [1,2,4] print("输出*list/tuple为参数的结果:",calcc(*numberss))# *numberss表示把nums这个list的所有元素作为可变参数传进去 # ==> 输出*list/tuple为参数的结果: 7 # 5.关键字参数 可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。eg: def person(name, age, **kw): print('name:', name, 'age:', age, 'other:', kw) person(23,34) # ==> name: 23 age: 34 other: {} person("gfengwei",20,agee=20) # ==> name: gfengwei age: 20 other: {'agee': 20} # 5.1 扩展函数使用 extra = {'city': 'Beijing', 'job': 'Engineer'} person('Jack', 24, **extra) #备注:**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。 ==> name: Jack age: 24 other: {'job': 'Engineer', 'city': 'Beijing'} # 6. 命名关键字 和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了: # 6.1 关键字,在函数的调用者可以传入任意不受限制的关键字参数,例如上面的city,job我们可以任意传,至于到底传入了哪些,我们可以在函数的内部通过kw进行检查. # 以person()函数为例,我们希望检查是否有city和job参数: def person(name,age,**kw): if "city" in kw: print("有city参数然后做出处理") pass if "job" in kw: print("有job参数然后做出处理") pass print("name:",name,"age:",age,'other:',kw) person("fenwei",24,**extra) # ==> 有city参数然后做出处理 有job参数然后做出处理 name: fenwei age: 24 other: {'job': 'Engineer', 'city': 'Beijing'} # 6.2备注:命名关键字参数必须传入参数名 # 7.位置参数 默认参数 可变参数 命名关键字参数**kw 就是一个扩展dict、命名关键字参数 # 顺序:必选参数、默认参数、命名关键字参数、关键字参数 def person(name,age,sex="男",*args,**kw): print("name:",name,"age:",age,"sex:",sex,"args:",args,"kw:",kw) person("gz",24) # ==> name: gz age: 24 sex: 男 args: () kw: {} person("gz",24,"男","nongmin","nomoney") # ==> name: gz age: 24 sex: 男 args: ('nongmin', 'nomoney') kw: {} person("gz",24,"男","nongmin","nomoney",city="hangzhou",country="china") # ==> name: gz age: 24 sex: 男 args: ('nongmin', 'nomoney') kw: {'country': 'china', 'city': 'hangzhou'} args = (1,2,3,4) kw = {"a":"123","b":"456"} person(*args,**kw) # 8.递归函数 递归函数需要注意防止栈溢出,递归调用的次数过多,会导致栈溢出 def func(n): if n == 1: return n return n * func(n-1) print("递归100阶乘:",func(100)) # 1000阶乘导致栈溢出 # 8.1解决栈溢出:尾递归优化 # 9.汉诺塔 def hanoi(n,x,y,z): if n==1: print(x,'-->',z) else: hanoi(n-1,x,z,y)#将前n-1个盘子从x移动到y上 hanoi(1,x,y,z)#将最底下的最后一个盘子从x移动到z上 hanoi(n-1,y,x,z)#将y上的n-1个盘子移动到z上 n=int(input('请输入汉诺塔的层数:')) hanoi(n,'x','y','z')