Python函数基础

函数

1.什么是函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。让繁琐的事情更加简洁。

def func():
    print('这就是一个函数')

 

2.函数的定义和调用

定义:def 关键词开头,空格之后接函数名称和圆括号( ),最后还有一个":"。
   def 是固定的,不能变,他就是定义函数的关键字(用来表示一个函数。)。

   空格 为了将def关键字和函数名分开,必须空(四声),当然你可以空2格、3格或者你想空多少都行,但正常人还是空1格。

   函数名:函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函数名可以随便起,但我们给函数起名字还是要尽量简短,并能表达函数功能

   括号:是必须加的,先别问为啥要有括号,总之加上括号就对了!

注释:每一个函数都应该对功能和参数进行相应的说明,应该写在函数下面第一行。以增强代码的可读性。

调用:就是 函数名() 要记得加上括号。

def func():          #def(define)要和函数名之间有空格
    print('这就是一个函数')  #这是函数内的架构
func()             #调用函数

 

 

3.函数的返回值

没有返回值:不写return的情况下,会默认返回一个None:没有写return,这就是没有返回值的一种情况。

  • 遇到return函数就会结束,不会继续进行
def jianh():
    print('今天是')
    print('2018年-10月-30日')
    return '我就不告诉你时间'  #return可以返回多个结果
jianh()    #今天是 \n 2018年-10月-30日

print(jianh())    #今天是 \n 2018年-10月-30日 \n 我就不告诉你时间(没有print就不会执行return)

 

有一个返回值

有多个返回值

4.函数的参数

  • 实参 :调用时传递的参数为实际参数
  • 形参 :变量定义的参数为形式参数
  • 位置参数
  • 默认参数
    #默认参数    这时只用传一个参数就可以了,默认参数已被定义
    def defult(a,b=10):
        print(a,b)
    defult(1)

     

  • 动态参数(*args,**kwargs)都必须在参数的最后定义
    #args 重复取参数
    def sum(*args):
        s=0
        for i in args:
            s+=i
        return s
    print(sum(1,2,3,4,5,6,7,8,9,))
    #  **kwargs 重复取可定义的参数
    def duocan(**kwargs):
        print(kwargs)
    duocan(a=1,b=2,c=3)

      

参数陷阱

5.命名空间和作用域

1. 名称空间, 局部名称空间, 全局名称空间, 作用域, 加载顺序.

  • 在Python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就 把变量名和值之间的关系记录下来,
  • 当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了,  至于函数内部的变量和逻辑, 解释器是不关心的.
  • 一开始的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间.
  • 函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空

(1)命名空间 :存放名字和值的关系的空间,变量在存储的时候就是存储在这片空间中的.     

  • 全局命名空间-- 直接在py文件中, 函数外声明的变量都属于全局命名空间       
  • 局部命名空间-- 在函数中声明的变量会放在局部命名空间       
  • 内置命名空间-- 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间

(2)加载顺序&取值顺序:

  • 加载顺序:  内置命名空间>全局命名空间 >局部命名空间(函数被执行的时候)
  • 取值顺序:  局部命名空间 >全局命名空间 >内置命名空间

(3)作用域  就是作用范围, 按照生效范围来看分为全局作用域和局部作用域

  •  全局作用域:    全局命名空间 + 内置命名空间       通过globals()函数来查看全局作用域中的内容
  •  局部作用域:    局部命名空间                                 通过locals()来查看局部作用域中的变量和函数信息 

2.函数的嵌套

def outer():
    def inner():
    return inner
return outer

 

1 def mysql():
2     print('in mysql')
3     def mysql2():
4         print('in mysql2')
5     mysql2()
6 mysql()
函数的嵌套以及自我调用

 

nonlocal关键字

1.外部必须有这个变量
2.在内部函数声明nonlocal变量之前不能再出现同名变量
3.内部修改这个变量如果想在外部有这个变量的第一层函数中生效

6.闭包(第一类对象???)

定义:闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)

(想想Erlang的外层函数传入一个参数a, 内层函数依旧传入一个参数b, 内层函数使用a和b, 最后返回内层函数)

  函数可以作为另一个函数的参数或返回值,接受另一个函数作为输入并调用他。

def foo():  
    a = [1]  
    def bar():  
        a[0] = a[0] + 1  
        return a[0]  
    return bar 

  

 

7.装饰器warpper

装饰器是一个函数,其主要用途是包装一个函数或类。这种包装的首要目的是透明的修改或增强被包装对象的行为。表示装饰器的语法是特殊符号@。

最简单的装饰器

def a(func):
	print(1)
	def b():
		print(2)
		func()
		print(3)
	return b
@a  #语法糖Syntactic sugar  调用装饰器
def c():
	print(4)
c()
'''
1
2
4
3
'''

  

装饰器模板(加入参数的装饰器)

def a(func):
    print(1)
    def b(*args,**kwargs):
        print(2)
        func(*args,**kwargs)    #传所有的参数,让别人说去吧
        print(3)
    return b    #ruturn b是不能带括号
@a
def c(a,b):
    print(a+b)
c(3,4)
'''
1
2
7
3
'''
View Code

基本搞懂

装饰器为什么不带括号???

8.生成器与yield

  函数使用yield关键字可以定义生成器对象。生成器是一个函数,它生成一个值的序列。以便在迭代中使用。生成器的本质就是迭代器。

def countdown(n):
    print('Counting down from %d'% n )
    while n>0:
        yield n
        n -= 1
    return
c=countdown(10)
#如果调用函数,就会发现其中的代码不会执行。
#这是为什么呢,老李捋了捋他的胡子说:这就告诉你。

它会返回一个生成器的对象。接着,该生成器对象就会在__next__()被调用时执行函数。

调用__next__()时,生成器将不断执行语句,直至遇到yield为止。yield语句在函数执行停止的地方生成一个结果,直到再次调用__next__()。然后继续执行yield之后的语句。

通常不会在生成器上直接调用__next__()方法,而是在for语句、sum()或一些使用序列其他操作中使用。

send方法      send和__next__()一样都可以让生成器执行到下一个yield

def eat():
    print("我吃什什么啊")
    a = yield "馒头"
    print("a=",a)
    b = yield "⼤大饼"
    print("b=",b)
    c = yield "⾲菜盒⼦"
    print("c=",c)
    yield "GAME OVER"
gen = eat()     # 获取生成器
ret1 = gen.__next__()
print(ret1)                 #我吃什什么啊   馒头
ret2 = gen.send("胡辣汤")
print(ret2)                 #a= 胡辣汤     ⼤大饼
ret3 = gen.send("狗粮")
print(ret3)                 #b= 狗粮     ⾲菜盒⼦
ret4 = gen.send("猫粮")
print(ret4)                 #c= 猫粮   GAME OVER

  

send和__next__()区别:

  • 1. send和next()都是让生成器向下走1次
  • 2. send可以给上⼀个yield的位置传递值, 不能给后⼀个yield发送值. 在第⼀次执行生成器代码的时候不能使用send()

推导式——

 (1) 列表推导式  [结果 for循环 if筛选]

#列表中取出偶数
list1=[1,2,3,4,5,6,7,8,9,10,11,12,13,1,4]
res=[i for i in  list1 if i%2==0]
print(res)

(2)字典推导式    {key: value for循环 if 筛选}

#与zip功能相似
lst1 = ["东北", "陕西", "山西", "开封", "杭州", "广东", "济南"]
lst2 = ['大拉皮', "油泼面", "老陈醋", "灌汤包", "西湖鲤鱼", "早茶", "胶东一锅鲜"]
dic = {lst1[i]:lst2[i] for i in range(len(lst1))}
print(dic)

(4)集合推导式

lst = ["2","4","5","3","4","4","2","3"]
s = {el for el in lst}
print(s)                         #起到去重的作用

  

posted @ 2018-10-29 19:41  WHY7NG  阅读(140)  评论(0编辑  收藏  举报