Python进阶(三)----函数名,作用域,名称空间,f-string,可迭代对象,迭代器

Python进阶(三)----函数名,作用域,名称空间,f-string,可迭代对象,迭代器

一丶关键字:global,nonlocal

global 声明全局变量:

​ 1. 可以在局部作用域声明一个全局变量

​ 2. 可以修改全局变量

# 解释器认为: 如果你在局部作用域对一个变量进行修改,局部作用域已经定义了好这个变量
# 异常:
# UnboundLocalError: local variable 'count' referenced before assignment

####相当于局部声明的变量,剪切到全局
count=0
print(locals())      # count:0
def func():
    global  count    #定义成全局变量
    count+=1         # 此处由于 要修改count的值, 现在函数内没有定义count的变量, 如果想要修改全局变量count 需要global声明一下
    print(locals())  # 查看当前(现在就是局部空间)空间的变量和值,   没count变量
func()
print(locals())      # 查看当前(现在就是全局空间)空间的变量和值 ,count:1

nonlocal 局部作用域如果想对父级作用域的变量(python3x新加的功能):

​ 1.可以对父级别作用域的变量进行修改,并且在当前作用域创建
​ 2.不能操作全局作用域

####复制  , 共用一块内存地址
def func():
    count=0          		#局部变量
    def inner():
        nonlocal  count      #inner函数内 修改 count 变量, 需要nonlocal声明
        count+=3			
        print(count)        
        print(id(count))      #id() 查看这个inene函数中count变的内存地址 -->1952940208(内存地址)
        print(locals())		  #查看当前作用域中的变量和值 {'count': 3}
    inner() 					
    print(locals())	#{'inner':<function func.<locals>.inner at 0x00000140E1ABBD90>, 'count': 3}
    print(id(count)) 		  #id() 查看这个func函数中count变的内存地址 1952940208(内存地址)
func()

二丶形参中---默认参数的坑

###当你的默认参数的数据类型是可变的数据类型时   千万注意,使用的是同一个可变类型数据的内存地址 so看代码👇

#默认参数是字典
def func(a,b={}):
    b[a+1]=a
    return b
print(func(1,))
print(func(2,))
print(func(3,))
print(func(5,))



#默认参数是列表类型
def func(a,b=[]):
    b.append(a)
    return b
print(func(1,))
print(func(1))
print(func(1))
func(1,2)


###例题
#例1
 def extendList(val,list=[]):             #默认创建一个列表
 	list.append(val)
 	return list
 list1 = extendList(10)  # [10 ,'a']        #   往默认列表添加元素
 list2 = extendList(123,[])  # [123,]     #   list被一个新的列表替换,新列表是一个空列表,so 只添加123
 list3 = extendList('a')     #[10,'a']       #   继续往默认的列表添加内容

 print('list1=%s'%list1)                     ##上面的操作完成之后, list1 和list3 使用的是同一个内存地址, 共享一个列表
 print('list2=%s'%list2)                    ##上面的操作完成之后, list2 使用的是新的列表,so .
 print('list3=%s'%list3)                    ##上面的操作完成之后, list1 和list3 使用的是同一个内存地址, 共享一个列表


# 例2  这道题和上面的题一样,但是  ,别忘记了print() 打印当前的操作完成之后的结果.
 def extendList(val,list=[]):
 	list.append(val)
 	return list
 print('list1=%s'% extendList(10))  # [10]      # 往默认列表添加元素, 就直接打印 so  .现在这个默认列表就只有 10
 print('list2=%s'% extendList(123,[]))  #[123]     #往新的列表添加元素, so 和默认列表毫无关系
 print('list3=%s'% extendList('a'))   #[10,'a']     #往默认列表添加元素,之前已经添加了10 ,so 现在追加了'a'元素,so,现在默认列表就有[10,'a']
 

三丶函数名的应用

函数名:就是一个特殊的变量 , 别称:第一类对象

​ 函数名指向的是一个函数的内存地址,函数名加上()就能够执行函数

###废话不多说,上代码👇

## 1. 函数名可以当做一个变量  ,具有变量的赋值功能
def func():
    print('in func ')
print(func)			  #打印函数func的内存地址  自己打
a=func				 # 将函数的内存地址给了a
c=a					 #相当于c变量拿到 a 或者 func的函数内存地址
c()                    #相当于 c()=func(), 执行函数func()


## 2. 函数名容器类类型的元素
def func1():
    print('in func1')
def func2():
    print('in func2')
def func3():
    print('in func3')
li=[func1,func2,func3]

for el in li:   # 循环每个元素,  el就是函数的内存地址
    el()        # 执行每个函数       
#拓展👆:你要是有2000个函数,你总不能写2k个"函数明()". 用for循环执行2k个函数   so easy


# 3. 函数名 可以作为函数的实参
def func(argv):            
    argv()                  #接收传来的函数名+()  --->执行这个函数
    print('in func')
def inner():
    print('in inner')
func(inner)              	#把其他的函数的名作为参数传给func函数的argv


# 4.函数名可以作为函数的返回值
def func():
    print('in func')
    return inner             #返回 其他函数的函数名,
def inner():
    print('in inner')          
func()()                     # 相当于func()=inner  --->inner() 执行inner函数


#5. 函数名+() 可以执行函数
def func():
       print('被执行了')

func()

四丶python新特性字符串输出:f-string

新特性:f-strings 是python3.6 格式化输出新的写法,效率高,更简化,好用

####看代码👇
#### 用法格式
name='宇宙盖世无敌小keNai,😳嘻嘻'
s=f'我叫 {name}'        # {变量,函数名(),表达式} ,除了特殊的字符如: ;分号 :冒号 ,逗号(变量前) ! 


#用法①: 直接操作字符串
 s1='李四'
 s2=f'哒哒哒哒哒{s1.upper()}'
 print(s2)

#用法②: 放置列表元素
li=['太白',18,176]
s1=f'{li[0]},{li[1]} ,{li[2]}'
print(s1)

#用法③: 可以结合函数
def func(a,b):
     return a+b
 s=f'{func(1,2)}' 
 print(s)

五丶可迭代对象

含义:

​ 可以重复的迭代的实实在在的东西

专业角度:

​ 内部__ iter __ 方法的对象,就是可迭代对象

#常见的可迭代对象: list , tuple ,dict ,str 

# 内置函数 ,查看所有方法,属性   ,得到的所有方法都以字符串的形式放在列表中
print(dir(str))

#验证是不是 可迭代对象
s1 = '不打广告'
i = 100
print('__iter__' in dir(i))  # False
print('__iter__' in dir(s1))  # True

#常用的方法验证 xx 是不是一个可迭代对象
print('__iter__' in dir(str)) 


#可迭代对象的优缺点
#优点:
	1.直观
	2.操作方法多
#缺点:
	1. 消耗内存较大 
	2. 不能迭代取值(索引)

六丶迭代器

含义:

​ 是一个可以迭代取值的工具

专业角度:

​ 内部含有 __iter__方法 并且含有 __next__方法 就是迭代器

#迭代器是看不到内存地址

####可迭代对象转化成迭代器: 
#可迭代对象转化成迭代器 , 内置函数iter()  和 __iter__() 两种方式
li=[1,2,3]
obj=iter(li) 			 	   #把迭代对象转换成迭代器 
objg=li.__iter__()        	    #把迭代对象转换成迭代器 
print(type(obj),type(objg))     #<class 'list_iterator'>
print(obj)					  # <list_iterator object at 0x000002075D219518> 迭代器



####迭代器可以迭代取值, 利用内置函数next()进行取值 .  取完值,值就消失了
li=[1,2,3]
obj=iter(li)
print(next(obj)) 		 # 迭代一次,取值一次,值取完就没了.销毁
print(next(obj))	
print(next(obj))
print(next(obj))  		# 当迭代器中没有值可取了 ,会把报错 StopIteration  



####利用while 模拟 for 循环内部循环可迭代对象的机制
#1.先将可迭代对象转换成迭代器
#2.利用next对迭代对象进行取值
#3.利用异常处理try一下 防止报错~~

#方法1
try:
    li = [1, 2, 3, 4, 5]
    li_itera = iter(li)
    while 1:
        print(li_itera.__next__())
except StopIteration:
    pass

#方法2
li = [1, 2, 3, 4, 5]
li_itera = iter(li)
while 1:
    try:
        print(next(li_itera))
    except:
        break
        
        
        
#迭代器是一条路走到底(记录位置)    
 li=[1,2,3,4,]
 obj=iter(li)
 for index in range(2):          #  1  2  ,取完值,值就销毁
     print(obj.__next__())
 for index in range(1):          #  3
     print(obj.__next__())

七丶可迭代对象与迭代器的对比

####可迭代对象: 
	可迭代对象是一个操作比较灵活(比如列表,字典的增删改查,字符串的常用操作方法等),直观,效率相对高,
	但是占用内存,而且不能直接通过循环迭代取值的这么一个数据集。
####迭代器:   
	可以记录取值位置,以直接通过循环+next方法取,迭代器是一个非常节省内存,满足惰性机制,
	但是相对效率低,操作方法比较单一的数据集。(可参考为什么python把文件句柄设置成迭代器)	
posted @ 2019-06-19 15:42  染指未来  阅读(133)  评论(0编辑  收藏  举报