一、背景引入

函数在python中称为一等公民,意思就是哪里都能用,所谓一等公民在英文中是(First-Classs Object).什么是一等公民呢?对你有优待,什么样的优待呢?一等公民指身份特殊享有权利。

我们说函数是对象,而且还是可调用对象,函数名呢?有两层意思,一个是函数的真正名字就是字符串形式的,还有一层意思是函数名这个名指的是标识符,这个标识符指向一个可调用的函数对象,这个标识符就是给程序员用的。

比如:

def abc():
    pass

   	abc是标识符,它指向一个函数对象,这个函数对象类型就是function
    <function __main__.abc()>,function

    函数可以作为普通变量,也可以作为函数的参数、返回值
    		
	abc的类型是function,  
	__main__.abc():表示在main模块中定义的abc()函数

二、高阶函数

我们来看高阶函数,什么叫做高阶函数呢? High-order-Function 高阶函数,在数学和计算机科学中,高阶函数应当是至少满足下面一个条件的函数就是高阶函数。

      什么意思呢?

     它的参数可以接受函数作为参数,就是函数的参数可以写函数对象

     返回值必须是一个函数,满足一个就是高阶函数

高阶函数:满足下面两个条件之一就行了
    	1.接受一个或者多个函数作为参数
    	2.return 输出一个函数

我们继续来看代码来理解高阶函数的概念

def counter(base):
	def inc(step=1):
	    base+=step
	    return base
	return inc 

问题: 1 是高阶函数吗?
    		是高阶函数,因为返回的是一个函数对象,return inc 
      2 有没有嵌套函数,有闭包吗?
    	  有闭包这个base+=step,用到了base,因为base是形参,形参
          是局部变量.内层函数用到了外层函数的局部变量就有闭包了
      3 代码对吗?如果不对,怎么改?
    	自己认为代码这样写是没问题的,可以执行的
        如果自己使用的话,这样使用
            c=counter(10) 
            print(c())
  这段代码我放到编译器执行的时候,直接报错了,为什么代码会出问题呢?
  	问题出来base+=step这里,base=base+step python是赋值即定义
    inc函数里的base和counter函数形参base,名字虽然一样,但是由于出现
    赋值语句,所以inc里面的base,不是counter的形参base了。这是一个未
    进行初始化的base,未初始化变量你就使用。所以才会报错。
    
    怎么解决呢?
    	就是对这个base变量声明为nonlocal 类型,这样一来就说明base+=step
      这里的base 是counter函数的形参base了。
 
def counter(base):
	def inc(step=1):
	    nonlocal base
      base+=step
	    return base
	return inc 

	这样一来代码就正确了,要记住内层函数要使用外层局部变量,用nonlocal声明

上面这个就是一个典型的高阶函数应用,这个高阶函数用了哪些知识点呢?

函数定义、形参定义、局部变量、作用域、闭包、嵌套函数、返回值类型包括传参这些概念。

继续研究上面的代码

def counter(base):
	def inc(step=1):
	    nonlocal base
      base+=step
	    return base
	return inc 

f1=counter()
f2=counter()

print(f1==f2) 这个输出什么? f1和f2一样吗?
	自己认为会输出false,是不等于的,原因是进行了两次函数调用,会生成两个不
    同的地址空间,所以不同。

print(f1 is f2 ) 这个又输出什么呢?true还是false

	通过在编译器进行运行发现,f1==f2 f1 is f2都输出了false,为什么?
    
    我们先来理解f1=counter() 这句代码
    它的意思是:
      f1指向了inc所指向的对象,inc标识符,随着counter的调用结束而消亡
	  inc所指向的内部函数对象,没有消亡,被f1记住了。
	  每次函数调用都是独立的。
      每一次counter 执行时,才会生成inc标识符,也就是说内部函数inc对象
      才会真的在内存中生成。

   我们来描述一下函数的执行过程:
	内存空间中有堆和栈这两个空间,当然栈是有深度的。第一次调用counter()
   的时候。counter函数会第一次压栈,压栈的时候base=10局部变量进栈,
   还有局部变量inc,但是inc是一个地址,然后函数就进行返回了把inc地址返回
   到了堆中的f1。f1是全局变量。然后由于闭包技术的存在,函数执行完,
   inc指向的空间没有释放,依然被保存下来了。至此counter函数第一次就调用
   结束了

		在看第二次,我们说函数的调用是独立的,第二次函数调用又开辟了一段新的栈
      空间base=10,inc指向的空间在堆中开辟。inc保存的是地址。然后函数就进行
      返回了把inc地址返回到了堆中的f2.至此counter函数第二次就调用结束了 
    	
    
	is 比较的是内存地址  id(f1) == f(2) 是这样的比较
	== 是内容进行比较,两个函数对象,不能直接进行内容比较。
		如果你使用了 == 在不能比较的对象上,他会使用 is比较 
    
   所以两个print(f1==f2) print(f1 is f2) 输出false就能解释了
   
   两次函数调用后内存地址是不一样的

三、sorted函数原理

仿照内建函数sorted,请自行实现一个sort函数 (不用使用内建函数), 能够为列表元素排序.

思考:通过练习,思考sorted函数的实现原理,map、 filter函数的实现原理

思路:

编程原则:先简单后复杂
		def sort(iterable,*,key=None,reverse=False):
    		newlist=[]

    		return newlist

		怎么写呢?先简单后复杂,怎么个先简单法呢?就是key参数和reverse
        	参数先不考虑
		先解决排序问题,注意这个排序不是就地解决,是在互相作用下实现的。
			
			新建一个列表,遍历原列表,注意新列表的值是增加的
思路:			
	# 从原列表iterable遍历元素,每个元素插入到newlist合适的位置
		newlist中的元素是在增长,从原来没有到逐渐增加
	# 生成一个升序或者降序的新列表,原列表不表
	# 如果可以,先实现 reverse。reverse是用来控制升序还是降序的
	# 如果可以,在实现key。key用来控制对元素的比较

	三步走:
		1.实现核心算法
		2.实现降序升序的控制
		3.实现对比较的控制

	假设原列表是[1,2,3]  enumerate() 函数返回下标索引
	细节:	
		从原列表当中拿来一个个元素,把他插入到目标列表合适的位置

		for x in iterable:    #从原列表中遍历拿到这个元素
								第一次 x=1 插入到newlist的合适位置
			for i,y in enumerate(newlist):
				在newlist当中从第一个元素开始,一定要保证有序。
                  要保证插入完之后有序。要把newlist理解
                    为有序区。 x就相当于是一个待排序数。对于列表来讲,
                    如果插入要用insert函数,我们需要知道索引才能插入

		def sort(iterable,*,key=None,reverse=False):
    		newlist=[]
    		for x in iterable:
        		for i,y in enumerate(newlist):
            		#if x >y:   #降序
            		 if x < y:   #大于号和小于号调换下位置是什么 升序
                		newlist.insert(i,x)
                			break                 
                            #找到合适的位置就插入后break
        		else:
            		newlist.append(x)     
                    #如果没有break出去 ,则末尾追加
    		return newlist

				x=[5,4,3,2,1]
				print(x)
				print(sort(x))								

看一下完整代码

def sort(iterable,*,key=None,reverse=False):
    		newlist=[]
    		for x in iterable:
        		for i,y in enumerate(newlist):
            		#if x >y:   
            		 if x < y:  
                		newlist.insert(i,x)
                			break                 
        		else:
            		newlist.append(x)    
    		return newlist

我们的问题在于怎么实现这个reverse,通过这个变量来控制,
我输出的列表到底是升序还是逆序的。

		直接加一个变量就行了 
			comp= x>y if reverse else x < y
				x>y 降序 x<y升序
            
key的实现:			
		最后一个问题key的实现,我们说key指参与比较,但是不影响结果
		用key的意思就是 比如:数字1和字符1进行比较要转为字符串类型
		这样比较是可以的

		key=str 会把元素一个个str(x) 转为字符串
		key后面要传入函数参数,key=int或者str 做类型转换的内建函数
			cx =key(x)
			cy =key(y)

		sort([1,2,3,4],key=lambda x:str(x))
			这就是原理

		按照整数比较:
			key=lambda x int(x,16) is isinstance(x,str) else x

			通过讲的例题可以知道sorted原理

			由于sorted执行完不会返回原来的列表,我们会经常使用,他会返
            回一个新的列表。
		
		sort([1,2,3,4,5],key=lambda x:6-x)
			这个参数 6-x怎么理解呢?

			给你了列表[1,2,3,4,5],这个6-x只用于比较,什么意思?
				6-1得5 6-2得4 做升序 4小所以 2去了前面 6-5得1 
				所以这里出来是降序,是6-x以后的值小,所以5在最前面
				先做6-x在进行比较