函数作用域
python中的作用域分4种情况
- L:local,局部作用域,即函数中定义的变量
- E:enclosing,嵌套作用域
- G:global,全局作用域
- B:built-in,内置作用域
优先级:LEGB
作用域局部>外层作用域>当前模块中的全局>python内置作用域
# str = 90 #built-in作用域
# print(str)
g_counter = 33 #全局作用域
# o_count = 77
def outer():
o_count = 0#嵌套作用域
# g_counter = 334
def inner():
i_counter = 5 #局部作用域
o_count = 90
# print(i_counter)
# print('out' + str(o_count))
# print(o_count)
print('before inner')
print(o_count)
inner()
print('after inner')
print(o_count)
outer()
python内可以执行,如下程序
if 2 > 1:
x = 3
print(x)
#3
解释:在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如if、try、for等)是不会引入新的作用域的
变量的修改
注意:下面程序会报错
x = 90
def f2():
print(x)
x = 88
f2()
#程序会报错
#local variable 'x' referenced before assignment
这里调用f2函数的print(x)时,解释器会在局部作用域找,找到 x = 88,但x调用函数之前就已经声明了,所以报错
global关键字
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下
count = 10
def outer():
global count
print(count)
count = 100
print(count)
outer()
#10
#100
nonlocal关键字
global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量怎么办呢,这时就需要nonlocal关键字了
a =666
def outer():
out_count = 3
def inner():
nonlocal out_count
out_count+=3
inner()
print(out_count)
outer()
#6
递归函数
定义:在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归函数的优点: 是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
- 求n的阶乘
def factorial (n):
if n == 1:
return 1
return n * factorial(n - 1)
result = factorial(6)
print(result)
#720
- 斐波那契数列
不是用递归的情况下
def fibo(n):
before=0
after=1
for i in range(n-1):
ret=before+after
before=after
after=ret
print(before, end='\t')
# 1 1 2 3 5 8 13 21
return ret
print(fibo(8))
#21
使用递归
def fibo(n):
if n <= 1:
return n
return(fibo(n-1) + fibo(n-2))
print(fibo(8))
#21
特点:
①.必须有一个明确的结束条件
②.每次进入更深一层递归时,问题规模相比上次递归都应有所减少
③.,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返 回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。)
#避免重复计算,加速
cache = {}
def fibo(n):
if n <= 1:
return n
if (n - 1) not in cache:
cache[n - 1] = fibo(n - 1)
if (n - 2) not in cache:
cache[n - 2] = fibo(n - 2)
return cache[n - 1] + cache[n - 2]
print(fibo(100))
练习:水仙花数也被称为超完全数字不变数、自恋数、自幂数、阿姆斯壮数或阿姆斯特朗数,水仙花数是指一个 3 位数,它的每个位上的数字的 3次幂之和等于它本身(例如:1^3 + 5^3+ 3^3 = 153)。
方法一
import math
for i in range(100, 1000):
x = math.floor(i / 100)
y = math.floor((i - x * 100) / 10)
z = i - math.floor(i / 10) * 10
if i == x ** 3 + y ** 3 + z ** 3:
print(i, end=', ')
方法二
flowers = []
def flower():
for i in range(100,1000):
baiwei = i // 100
gewei = i % 10
shiwei = (i // 10) % 10
if gewei*gewei*gewei + shiwei*shiwei*shiwei + baiwei*baiwei*baiwei == i:
flowers.append(i)
flower()
print(flowers)
将函数存在模块中
要让函数是可导入的,得先创建模块。模块是扩展名为.py的文件,包含要导入到程序中的代码。
我们将之前写的斐波那契数列和阶乘程序保存为.py文件,然后创建main.py,我们将在main内调用我们要使用的斐波那契数列和阶乘模块
# 使用import 引入模块
import jiecheng
import fibo
此时当我们只引入这两个模块后运行程序,会得到两个返回值
这是因为我们在斐波那契数列和阶乘程序内都执行了print(),当main导入这两个模块时,直接运行了print,我们可以将两个模块内print修改成
if __name__ == '__main__':
print()
这样既可以在模块内运行,也可以倒入模块后调用后再执行
- 导入特定的函数
from 模块 import 特定函数
模块.特定函数
#多个函数时
from 模块 import 特定函数1,特定函数2,特定函数...
- 使用as给函数指定别名
回顾之前学的给模块起别名,同样也可以给函数起别名
import pandas as pd
from pizza import make_pizza as mp
- 导入模块中的所有函数
使用星号(*)运算符可让Python导入模块中的所有函数
from pizza import *
这种方法不建议使用
最佳的做法是,要么只导入你需要使用的函数,要么导入整个模块并使用句点表示法。这能让代码更清晰,更容易阅读和理解。
练习:
# -*- coding: utf-8 -*-
# @Time : 2019/11/11 13:02
# @Author : WenTing Men
# @Email : wentingmen@163.com
# @File : 练习.py
# @Software: PyCharm
'''
1.有一分数序列:2/1,3/2,5/3,8/5,13/8,21/13…求出这个数列的前20项之和。
'''
fenzi = 2 # 分子
fenmu = 1 # 分母
sum_t = 0
for i in range(1, 21):
a = fenzi
b = fenmu
sum_t += (a / b)
fenzi = a + b
fenmu = a
print(sum_t)
答案:
from functools import reduce
def compute():
result = 0
lst = []
fenzi = 2
fenmu = 1
lst.append(fenzi/fenmu)
for i in range(19):
fenmu, fenzi = fenzi, fenmu + fenzi
# tmp = fenzi
# fenzi = tmp + fenmu
# fenmu = tmp
lst.append(fenzi/fenmu)
#for k in lst:
# result += k
#
result = reduce(lambda x, y: x + y, lst )
return result
print(compute())
'''
2.给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。
'''
num = input('输入一个不多于5位的正整数:')
l = len(num)
print(f'这个数是{l}位数')
n = num[::-1]
for i in n:
print(i)
'''
3.有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
'''
n = int(input('请输入人数n:'))
l1 = list(range(1, n+1))
count = 0
while len(l1) >= 1:
l = l1[:]
for i in range(0, len(l)):
count = count + 1
if count % 3 == 0:
l1.remove(l[i])
print(f'最后留下的是原来的第 {l[0]} ')
'''
4.题:编写一个程序,根据控制台输入的事务日志计算银行帐户的净金额。 事务日志格式如下所示:
D 100
W 200
D表示存款,而W表示提款。
假设为程序提供了以下输入:
D 300
D 300
W 200
D 100
然后,输出应该是:
500
'''
total = 0
while True:
d = input('请输入事务日志:')
if not d:
break
event_log = d.split(" ")
nub = int(event_log[1])
if event_log[0] == "D":
total += nub
elif event_log[0] == "W":
total -= nub
print (total)
'''
5.机器人从原点(0,0)开始在平面中移动。 机器人可以通过给定的步骤向上,向下,向左和向右移动。 机器人运动的痕迹如下所示:
UP 5
DOWN 3
LEFT 3
RIGHT 2
方向之后的数字是步骤。 请编写一个程序来计算一系列运动和原点之后距当前位置的距离。如果距离是浮点数,则只打印最接近的整数。
例:如果给出以下元组作为程序的输入:
UP 5
DOWN 3
LEFT 3
RIGHT 2
然后,程序的输出应该是:2
'''
import math
while True:
dirction = input("请输入方向:")
if not dirction:
break
dirction = dirction.split(" ")
if dirction[0] == "UP":
u = int(dirction[1])
elif dirction[0] == "DOWN":
d = int(dirction[1])
elif dirction[0] == "LEFT":
l = int(dirction[1])
elif dirction[0] == "RIGHT":
r = int(dirction[1])
#
x = abs(u-d)
y = abs(l-r)
print(int(math.sqrt(x**2+y**2)))