Python 笔记 — 函数进阶

目录

一、名称空间(Namespace)

是一个存储变量和函数名称的容器,用于在程序中对标识符(例如变量名、函数名)进行组织和管理。它使得不同部分的代码可以具有相同名称的标识符,而不会引起冲突。

1、内置名称空间(Built-in Namespace)

包含了 Python 解释器中预定义的函数、变量和异常名称。这些名称在任何 Python 程序中都是可用的,无需导入。

2、全局名称空间(Global Namespace)

是在模块级别定义的名称空间,它包含了在整个模块中定义的变量、函数等标识符。这些标识符可以在整个模块中访问。

3、局部名称空间(Local Namespace)

是在函数内部定义的名称空间,它包含了在函数内部定义的变量、函数等标识符。这些标识符只在函数内部可见。

4、嵌套名称空间(Enclosing Namespace)

发生在嵌套的函数内部,它包含了在外部函数中定义的变量、函数等标识符。内部函数可以访问外部函数的名称空间,但外部函数不能访问内部函数的名称空间。

名称空间通过层次结构组织起来,形成了名称解析的规则。当引用一个标识符时,Python 解释器会根据从内到外的顺序搜索相应的名称空间,找到第一个匹配的标识符。

这些名称空间和层次结构共同构成了 Python 的变量查找和访问机制。

二、作用域(Scope)

作用域是指在程序中定义变量的区域,它决定了在何处可以访问或引用变量。

1、内置作用域(Built-in Scope)

是 Python 中预定义的变量和函数的作用域,例如内置的函数和异常名称。

result = sum([1, 2, 3])  # sum 是内置函数,可以在任何地方访问

try:
    x = 1 / 0  # 除以零会引发内置异常 ZeroDivisionError
except ZeroDivisionError as e:
    print(e)  # 可以访问内置异常 ZeroDivisionError

2、全局作用域(Global Scope)

是在模块(文件)级别定义的变量的作用域。这些变量可以在整个模块中访问。

z = 15  # z 在模块顶层定义,是全局变量

def another_function():
    print(z)  # 可以在函数内部访问全局变量 z

another_function()
print(z)  # 可以在模块顶层访问全局变量 z

3、局部作用域(Local Scope)

是在函数内部定义的变量的作用域。这些变量只能在函数内部访问,函数外部无法直接访问这些变量。

def my_function():
    x = 10  # x 在函数内部定义,是局部变量
    print(x)  # 可以在函数内部访问 x

my_function()
# print(x)  # 这里会报错,x 在函数外部无法访问

4、嵌套作用域(Enclosing Scope)

发生在函数内部嵌套的函数中。内部函数可以访问外部函数的变量,但是外部函数不能访问内部函数的变量。

def outer_function():
    y = 5  # y 在外部函数定义
    def inner_function():
        print(y)  # 内部函数可以访问外部函数的变量 y
    inner_function()

outer_function()
# print(y)  # 这里会报错,y 在内部函数外部无法访问

三、全局变量和局部变量

1、全局变量

(1)定义

在模块的顶层(即没有嵌套在其它结构内部)定义的变量,既能在一个函数中使用,也能在其它的函数中使用,可以在模块内部的任何地方访问和修改这些变量。

(2)作用范围

在函数外边定义的变量叫做全局变量,可以在任何位置使用。

(3)作用

全局变量能够在所有的函数中进行访问。

# 例一:
a = 100
def funa():
	# 函数内部如果使用一个变量,会先从函数内部找,如果有直接使用;
	# 如果函数内部没有找到,会到函数外面找(全局变量),没找到就报错
	print(a)  # 100
def funb():
	print(a)  # 100
    
funa()
funb()
# 运行结果:
# 100
# 100

# 例二:
a = 100
def funa():
	a = 200  # 定义了一个和全局变量名相同的局部变量
	print(a)  # 200
def funb():
	print(a)  # 100
    
funa()
funb()
# 运行结果:
# 200
# 100

当函数内出现局部变量和全局变量相同名字时,函数内部中的 变量名 = 数据 此时理解为定义了一个局部变量,而不是修改全局变量的值。

2、局部变量

(1)定义

是在函数内部通过赋值语句定义的变量。这些变量只在包含它们的函数内部可见和可用。

(2)作用范围

这个函数内部,即只能在这个函数中使用,在函数的外部是不能使用的,它在函数内部创建,在函数调用结束后被销毁。

因为其作用范围只是在自己的函数内部,所以不同的函数可以定义相同名字的局部变量。

(3)作用

为了临时保存数据需要在函数中定义变量来进行存储,当函数调用时,局部变量被创建,当函数调用完成后,这个变量就不能够使用了。

def funa():
    # 局部变量的作用域(使用范围)在函数的内部,函数的外部无法使用
	a = 1  # 定义一个局部变量
	print('funa第一次的值:%s' % a)  # funa第一次的值:1
	a = 2
	print('funa第二次的值:%s' % a)  # funa第二次的值:2

def funb():
    #在函数内部定义的局部变量名可以和其他函数中的局部变量名相同,是不冲突的
	a = 3
	print('funb第一次的值:%s' % a)  # funb第一次的值:3

funa()
funb()
# 运行结果:
# funa第一次的值:1
# funa第二次的值:2
# funb第一次的值:3

3、修改全局变量 global

局部作用域对全局作用域的变量(此变量只能是不可变的数据类型)只能进行引用,而不能进行改变,只要改变就会报错。-
但是有些时候,在程序中会遇到局部作用域去改变全局作用域的一些变量的需求,这就得用到关键字 global

(1)作用1

在局部作用域中可以更改全局作用域的变量,声明一个全局变量。

# 例一:
a = 1

def funa():
	a = 2  # 声明了一个局部变量,与外面等于1的那个 a 没有关系了
	print(a)  # 2  

funa()
print(a)  # 1
# 运行结果:
# 2
# 1

def funa():
	# 标识函数内部不是定义一个局部变量,其实是对全局的修改
	global a  # 全局的 a 变成了由1变成了2
	a = 2
	print(a)  # 2

funa()
print(a)  # 2
# 运行结果:
# 2
# 2

# 例二:
# 在内部函数修改同名全局变量之前调用变量名称,则引发 Unbound-LocalError
a = 1
def fun():
	print(a)  # 先引用
	a = 2  # 再修改
    
fun()
print(a)
# 运行结果:
# UnboundLocalError: local variable'a' referenced before assignment 
# python 认为 a 不一定能被赋值。

# 例三:
a = 1
def fun():
	global a  # a 为全局变量
	print(a)  # 1
	a = 2  # 改变的是全局变量,因此出了这个局部作用域,仍然有效

fun()
print(a)  # 2
# 运行结果:
# 1
# 2

(2)作用2

在局部作用域想要对全局作用域的全局变量进行修改时,需要用到 global(限于字符串,数字)。

def funa():
	global a
	a = 2
	print(a)  # 2 

funa()
# 函数外没有定义 a,但是还是会打印出 a 的值为2 
print(a)  # 2   
# 运行结果:
# 2
# 2

如果在函数中出现 global 全局变量的名字,那么这个函数中即使出现和全局变量名相同的 变量名 = 数据,也理解为对全局变量进行修改,而不是定义局部变量。-
如果在一个函数中需要对多个全局变量进行修改,那么可以使用一次 global 对多个全局变量进行声明,也可以用多次 global 声明。

a = 1
b = 2
def funa():
    # 使用一次 global 对多个全局变量进行声明
	global a, b
    # 也可以用多次 global 声明
	# global a
	# global b
	a = 2
	b = 3
	print(a, b)  # 1 2

print(a, b)  # 2 3
funa()
print(a, b)  # 2 3
# 运行结果:
# 1 2
# 2 3
# 2 3

4、声明外层的局部变量 nonlocal

是 python3x 新加的功能,只能在封装函数中使用,在外部函数先进行声明,在内部函数进行 nonlocal 声明。

  • 不能更改全局变量。

  • 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下,此变量全部发生改变。

  • 只对局部起作用,离开封装函数,那么该变量就无效。

    a = 10
    def funa():
    a = 1
    def funb():
    nonlocal a # a 为外层变量
    print(‘funb函数中a的值:’, a) # funb函数中a的值: 1
    a = 2
    funb()
    print(‘funa函数中a的值:’, a) # funa函数中a的值: 2

    funa()
    print(a) # 10

    运行结果:

    funb函数中a的值: 1

    funa函数中a的值: 2

    10

错误用法:在外部函数进行声明 nonlocal; 外部函数中变量声明为 global。

# 错误使用
a = 1
def funa():
	global a
	a = 2
	def funb():
		nonlocal a
		print(a)
		a = 3
	funb()
	print(a)
    
funa()
print(a)
# 运行结果: 
# SyntaxError: no binding for nonlocal 'a' found

原因分析:-
当使用 nonlocal 声明变量 a 时,就会往上最近一层局部作用域寻找局部变量 a,-
此时外层局部作用域虽然能找到变量 a,但是这找到的这个 a 已经被 global 声明为全局变量了,-
nonlocal 不能改变全局变量,所以报错。

5、global 和 nonlocal 的区别

1、功能不同。

global 关键字修饰变量后,标识该变量是全局变量,对该变量进行修改就是修改全局变量。

nonlocal 关键字修饰变量后,标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal 位置会发生错误(最上层的函数使用 nonlocal 修饰变量必定会报错)。

2、使用的范围不同。

global 关键字可以用在任何地方,包括最上层函数中和嵌套函数中,即使之前未定义该变量,global 修饰后也可以直接使用。

nonlocal 关键字只能用于嵌套函数中,并且外层函数中定义了相应的局部变量,否则会发生错误。

3、作用对象不同。

global 关键字可以将局部变量变成一个全局变量。

nonlocal 关键字可以在内函数中修改外层(非全局)变量。

四、匿名函数

就是没有名字的函数,匿名函数 lambda,也叫一句话函数。

因为函数没有名字,不必担心函数名冲突。通常情况下,这样的函数只使用一次。

匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数。

语法:

函数名 = lambda 参数:返回值

1)此函数也可以有名字,它的名字就是给其设置的变量,比如 funa。

2)lambda 是定义匿名函数的关键字,相当于函数的 def。

3)lambda 后面直接加形参,形参加多少都可以,只要用逗号隔开就行。

案例:

1、求和

# 函数求和:
def func(a,b):
	return a + b
print(func(1,2))  # 3

# 匿名函数求和:
funa = lambda a,b:a+b # a,b 就是它们的参数(形参),a+b 是返回值
# 匿名函数不需要 return 来返回值,表达式本身结果就是返回值
print(funa(1,2))  # 3

2、在字符串中,返回索引为0跟2的对应的元素(列表形式)

str1 = 'abcde'

# 方法一:
a = []
a.append(str1[0])
a.append(str1[2])
print(a)  # ['a','c']

# 方法二:
li = list(str1[0:3])
li.remove('b')
print(li)  # ['a','c'] 

# 方法三:
func = lambda x: [x[0], x[2]]
print(func('abcde'))  # ['a','c'] 

3、接收两个 int 参数,将较大的数据返回

a = 4
b = 3

# 三目运算
print(a) if a > b else print(b)  # 4

# 匿名函数
func = lambda x,y: x if x > y else y
print(func(4,3))  # 4
 
# 嵌套 if else
we = lambda a,b: a if a > b else b
print(we(4, 3))  # 4

4、求平方值

a = lambda x: x**2
print(a(10))  # 100

5、在 sorted 函数中使用匿名函数,对列表中的元组按第二个元素排序

data = [(2, 5), (1, 9), (4, 3)]
sorted_data = sorted(data, key=lambda x: x[1])
print(sorted_data)  # [(4, 3), (2, 5), (1, 9)]

五、内置函数

是 Python 解释器内置的一组函数,它们无需导入模块即可在任何地方直接使用。

内置函数提供了各种功能,从基本的数学运算到字符串处理、列表操作、文件操作等,是直接可以拿来使用的函数。

# 查看所有的内置函数
import builtins
print(dir(builtins))
# 大写字母开头的是 python 的内置常量名,
# 小写字母开头的是 python 的内置函数名。

列举常用的内置函数:

1、数学函数

  • abs(x): 返回 x 的绝对值。
  • round(x, n): 返回 x 的四舍五入值,n 为小数点后保留的位数。

2、类型转换函数

  • int(x): 将 x 转换为整数。
  • float(x): 将 x 转换为浮点数。
  • str(x): 将 x 转换为字符串。

3、序列操作函数

  • len(seq): 返回序列 seq 的长度。
  • sorted(iterable): 返回一个排序后的列表,可用于各种可迭代对象。
  • max(iterable) 和 min(iterable): 返回可迭代对象中的最大和最小值。

4、字符串处理函数

  • len(s): 返回字符串 s 的长度。
  • str.capitalize(): 返回字符串的副本,首字母大写。
  • str.upper() 和 str.lower(): 返回字符串的大写和小写版本。

5、列表操作函数

  • list.append(x): 将元素 x 添加到列表末尾。
  • list.extend(iterable): 将可迭代对象的元素添加到列表末尾。
  • list.pop(index): 删除并返回指定位置的元素。

6、字典操作函数

  • dict.keys(), dict.values(), dict.items(): 返回字典的键、值、键值对视图。
  • dict.get(key, default): 返回键 key 对应的值,如果不存在则返回默认值 default。

7、文件操作函数

  • open(file, mode): 打开文件并返回文件对象,用于读写文件。
  • file.read(), file.readline(), file.readlines(): 读取文件内容。
  • file.write(text): 将文本写入文件。

8、其他函数

  • print(): 打印输出到控制台。
  • input(prompt): 从用户获取输入。

案例:-
1、zip()

拉链函数,用于将多个可迭代对象(如列表、元组等)按元素顺序进行配对,生成一个新的迭代器。这个迭代器生成的元素是一个个元组,每个元组包含来自各个输入可迭代对象的对应位置的元素。

常见用途是将多个列表按索引位置进行组合,从而便于同时迭代多个列表的元素。

# 例一:
a = [1, 2, 3]
b = ['a','b','c']
print(list(zip(a, b)))
# 运行结果: 
# [(1,'a'), (2,'b'), (3,'c')]

# 例二:
a = [1, 2, 3]
b = ['a','b','c','d']
c = (6, 5, 4, 3, 2, 1)
for i in zip(a, b, c):
    print(i)
# 运行结果:
# (1, 'a', 6)
# (2, 'b', 5)
# (3, 'c', 4)

注意:

  • 当输入的可迭代对象长度不一致时,zip() 函数会按最短的可迭代对象的长度来组合元素。
  • 如果需要获取完整的组合元素,可以使用 list() 函数将迭代器转换为列表。

2、map()

映射函数,可以对可迭代对象中的每一个元素进映射,分别去执行 function 把函数依次作用在 list 中的每一个元素上,得到一个新的 list 并返回。

这个函数在需要对一个序列中的每个元素执行相同操作时非常有用。

# 计算列表中每个元素的平方,返回新列表
li = [1, 2, 3, 4]
def funa(x):
    return x*x
mp = map(funa,li )
print(list(mp))
# 运行结果:
# [1, 4, 9, 16]

# lambda 函数:
a = [1, 2, 3, 4,]
print(list(map(lambda s:s*s, a)))
# 运行结果:
# [1, 4, 9, 16]

注意:

  • map() 函数会将传入的函数应用于每个可迭代对象对应位置的元素。如果输入的可迭代对象长度不一致,map() 函数会按最短的可迭代对象的长度来生成结果。
  • 如果需要获取完整的结果列表,可以使用 list() 函数将迭代器转换为列表。

3、filter()

用于过滤序列,过滤掉不符合条件的元素, 返回由符合条件元素组成的新列表。

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

# 筛选出列表中的偶数元素
numbers = [1, 2, 3, 4, 5, 6, 7, 8]
def is_even(x):
    return x % 2 == 0
even_numbers = filter(is_even, numbers)
print(list(even_numbers))
# 运行结果:
# [2, 4, 6, 8]

# lambda 函数:
numbers = [1, 2, 3, 4, 5]
filtered_numbers = filter(lambda x: x > 2, numbers)
print(list(filtered_numbers))
# 运行结果:
# [3, 4, 5]

注意:

  • filter() 函数将可迭代对象中的元素依次应用 function 函数,并保留返回值为 True 的元素。如果 function 函数未提供,filter() 函数会默认保留为真值的元素。
  • 如果需要获取完整的筛选结果列表,可以使用 list() 函数将迭代器转换为列表。

4、enumerate()

用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。

li = ['a','b','c','d']
for i, j in enumerate(li):
    print(i, j)
print(list(enumerate(li)))  # [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
print(dict(enumerate(li)))  # [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
# 运行结果:
# 0 a
# 1 b
# 2 c
# 3 d
# [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
# {0: 'a', 1: 'b', 2: 'c', 3: 'd'}

注意:

  • 默认情况下,enumerate() 函数从索引 0 开始对元素进行编号。可以通过设置 start 参数来指定起始索引。
  • enumerate() 返回的枚举对象可以使用 list() 函数转换为列表,或用于其它迭代操作。

5、eval()

用来执行一个字符串表达式,并返回表达式的值。

# 1、可以把 list、tuple、dict 和 string 相互转化。
a = '[1, 2, 3]'
a1 = eval(a)
print(a1)  # [1, 2, 3]
print(type(a1))  # <class 'list'>

b = '(1, 2, 3)'
b1 = eval(b)
print(b1)  # (1, 2, 3)
print(type(b1))  # <class 'tuple'>

c = "{'a':'zs','b':12}"
c1 = eval(c)
print(c1)  # {'a': 'zs', 'b': 12}
print(type(c1))  # <class 'dict'>

d = "([1,2], [3,4], [5,6], [7,8], (9,0))"
d1 = eval(d)
print(d1)  # ([1, 2], [3, 4], [5, 6], [7, 8], (9, 0))
print(type(d1))  # <class 'tuple'>


# 2、将 string 变成算术表达式来执行
print(eval('1+2'))  # 3
a = 1
b = 2
print(eval('a+b'))  # 3

六、应用

1、名片管理器

print('名片管理系统')
print('1、添加名片')
print('2、删除名片')
print('3、修改名片')
print('4、获取名片')
print('5、退出系统')

Ncard = ['a','b','c']

# 获取选择
def choice():
    inp = int(input('请输入你要进行的操作:'))
    return inp

# 添加
def add():
    newcard = input('请输入姓名:')
    Ncard.append(newcard)
    
# 删除
def rem():
    delcard = input('请输入姓名:')
    Ncard.remove(delcard)
    
# 修改
def upd():
    name = input('请输入原名:')
    index = Ncard.index(name)
    newname = input('请输入修改后的名字:')
    Ncard[index] = newname
    
# 获取
def get():
    print(Ncard)
    
i = 0
while i < 2:
    key = choice()
    if key == 1:
        add()
    elif key == 2:
        rem()
    elif key == 3:
        upd()
    elif key == 4:
        get()
    elif key == 5:
        print('感谢您的使用,欢迎下次再来')
        break
    else:
        print('输入有误,请重新输入')

2、编写函数,实现接收一个字符串,分别统计大写字母、小写字母、数字、 其它字符的个数,并以元组的形式返回结果(利用函数,判断,循环实现)。

分析:

1、定义一个函数

2、在函数里面定义4个变量,分别表示大写字母,小写 字母,数字,其它字符的个数

3、for循环遍历字符串

4、if语句判断变量的到字符是大写字母、小写字母、 数字、还是其他字符

5、根据判断的结果,让对应的变量加1

6、循环结束,返回这4个变量组成的元组

# 1.定义一个函数 funa()
def funa(st):
    # 2. 在函数里面定义4个变量,分别表示大写字母、小写字母、数字、其它字符的个数
    up = 0
    lo = 0
    nu = 0
    oh = 0
    # 3. for 循环遍历字符串
    for i in st:
        # 4. if 语句判断变量的到字符是大写字母、小写字母、数字、还是其它字符
        if i.isupper():  # isupper() 方法检测字符串中所有的字母是否都为大写。
            # 5. 根据判断的结果,让对应的变量加1
            up += 1
        elif i.islower():  # islower() 方法检测字符串是否由小写字母组成。
            # 5. 根据判断的结果,让对应的变量加1
            lo += 1
        elif i.isdigit():  # isdigit() 方法检测字符串是否只由数字组成。
            # 5. 根据判断的结果,让对应的变量加1
            nu += 1
        else:
            # 5. 根据判断的结果,让对应的变量加1
            oh += 1
    print(up, lo, nu, oh)

funa('ab QW123')


# while 循环实现
a1 = []
b1 = []
c1 = []
d1 = []

def funa(a):
    i = 0
    while i < len(a):
        if a[i].isupper():
            # 大写
            b1.append(a[i])
        elif a[i].islower():
            # 小写
            a1.append(a[i])
        elif a[i].isdigit():
            # 数字
            c1.append(a[i])
        else:
            # 其它
            d1.append(a[i])
        i += 1
        
funa('ab QW123')
print(len(a1),len(b1),len(c1),len(d1))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值