3、【Python】Python 3入门(流程控制/迭代器/生成器/函数/变量作用域)

一、流程控制

1、if 控制
if 表达式1:
    语句
    if 表达式2:
        语句
    elif 表达式3:
        语句
    else:
        语句
elif 表达式4:
    语句
else:
    语句

    1、每个条件语句后面要使用冒号:,表示接下来是满足条件后要执行的语句块。
    2、使用缩进来划分语句块,相同缩进数的语句在一起组成一个语句块。
    3、在python中没有switch-case语句

三元运算符:

<表达式1> if <条件> else <表达式2>

    编写条件语句时,应该尽量避免使用嵌套语句。嵌套语句不便于阅读,而且可能会忽略一些可能性。

2、for 遍历
for <循环变量> in <循环对象><语句1>
else<语句2>

    else语句中,语句2只有循环正常退出(遍历完所有遍历对象中的值)时执行。在字典中遍历时,关键字和对应的值可以使用items()方法同时解读出来:

knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items():
    print(k, v)

    在序列中遍历时,索引位置和对应值可以使用enumerate()函数同时得到:

for i, v in enumerate(['tic', 'tac', 'toe']):
    print (i, v)

    同时遍历两个或更多的序列,可以使用zip()组合:

questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q, a in zip(questions, answers):
    print('What is your {0}?  It is {1}.'.format(q, a))

    要反向遍历一个序列,首先要指定这个序列,然后调用reversed()函数:

for i in reversed(range(1, 10, 2)):
    print (i)

    要按顺序遍历一个序列,使用sorted()函数返回一个已排序的序列,并不修改原值:

basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for f in sorted(set(basket)):
    print(f)
3、while 循环
while <条件>:
    <语句1>
else:
    <语句2>
4、break/continue/pass

    break语句用在while和for循环中,break语句用来终止循环语句,即循环条件没有false条件或者序列还没被完全递归完,也会停止执行循环语句。

    continue语句用在while和for循环中,continue语句用来告诉Python跳过当前循环的剩余语句,然后继续进行下一轮循环。continue语句跳出本次循环,而break语句跳出整个循环。

    pass是空语句,是为了保持程序结构的完整性、pass不做任何事情,一般用作占位语句。

二、迭代器

  • 迭代器是一个可以记住遍历的位置的对象。
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
  • 迭代器有两个基本的方法:iter() 和 next()。
  • 字符串,列表或元组对象都可用于创建迭代器。

    迭代器可以被for循环进行遍历:

li = [1, 2, 3]
it = iter(li)
for val in it:
    print (val)

    迭代器也可以用next()函数访问下一个元素值:

import sys

li = [1,2,3,4]
it = iter(li)

while True:
    try:
        print (next(it))
    except StopIteration:
        sys.exit()

三、生成器

  • 在 Python 中,使用了 yield 的函数被称为生成器(generator)。
  • 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
  • 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行
    next() 方法时从当前位置继续运行。
  • 调用一个生成器函数,返回的是一个迭代器对象。

import sys

def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成

while True:
    try:
        print(next(f))
    except StopIteration:
        sys.exit()

四、函数

1、自定义函数

    函数(Functions)是指可重复使用的程序片段。它们允许你为某个代码块赋予名字,允许你通过这一特殊的名字在你的程序任何地方来运行代码块,并可重复任何次数。这就是所谓的调用(Calling)函数。

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的 return 相当于返回 None。
  • return 可以返回多个值,此时返回的数据未元组类型。
  • 定义参数时,带默认值的参数必须在无默认值参数的后面。
def 函数名(参数列表):
    函数体
2、参数传递

    在Python中,类型属于对象,变量没有类型

a = [1, 2, 3]
a = "Runoob"

    以上代码中,[1,2,3] 是 List 类型,”Runoob” 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),可以是指向 List 类型对象,也可以是指向 String 类型对象。

可更改与不可更改对象
    在Python中,字符串,数字和元组是不可更改的对象,而列表、字典则是可以修改的对象。

  • 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
  • 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la
    的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

Python 函数的参数传递

  • 不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
  • 可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

    Python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

3、参数

必须参数
    必须参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。

关键字参数
    关键字参数和函数调用关系密切,函数调用使用关键字参数来确定传入的参数值。使用关键字参数允许函数调用时参数的顺序与声明不一致,因为Python解释器能够用参数名匹配参数值。

def print_info(name, age):
    "打印任何传入的字符串"
    print("名字: ", name)
    print("年龄: ", age)
    return
print_info(age=50, name="john")

默认参数
    调用函数时,如果没有传递参数,则会使用默认参数。

def print_info(name, age=35):
    print ("名字: ", name)
    print ("年龄: ", age)
    return
print_info(age=50, name="john")
print("------------------------")
print_info(name="john")

不定长参数

  • 加了星号*的参数会以元组的形式导入,存放所有未命名的变量参数。
  • 如果在函数调用时没有指定参数,他就是一个空元组,我们也可以不向函数传递未命名的变量。
def print_info(arg1, *vartuple):
    print("输出: ")
    print(arg1)
    for var in vartuple:
        print (var)
    return
print_info(10)
print_info(70, 60, 50)
  • 加了两个星号*的参数会以字典的形式导入。变量名为键,变量值为字典元素值。
def print_info(arg1, **vardict):
    print("输出: ")
    print(arg1)
    print(vardict)
print_info(1, a=2, b=3)
4、匿名函数

    Python 使用 lambda 来创建匿名函数。

    所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。lambda 只是一个表达式,函数体比 def 简单很多。 lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。 lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

# 语法格式
lambda [arg1 [,arg2,.....argn]]:expression
5、装饰器

    由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数

def now():
    print ('2018-11-13')

f = now
f()#2018-11-13

    函数对象有一个__name__属性可以拿到函数的名字:

>>> now.__name__
'now'
>>> f.__name__
'now'

    在代码运行期间动态增加功能的方式,称为“装饰器”(Decorator)。本质上,decotator就是一个返回函数的高阶函数。例如,我们要定义一个能打印日志的decorator,可以定义如下:

def log(func):
    def wrapper(*args, **kw):
        print ('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

    观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:

@log
def now():
    print ('2018-12-1')

    调用now()函数,不仅会运行now函数本身,还会在运行now函数前打印一行日志:

>>> now()
call now():
2018-12-1

把@log放到now()函数的定义处,相当于执行了语句:

now = log(now)

    由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

    wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。

    如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:

def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

    这个3层嵌套的decorator用法如下:

@log('execute')
def now():
    print ('2018-12-1')

    执行结果如下:

>>> now()
execute now():
2018-12-1

    和两层嵌套的decorator相比,3层嵌套的效果是这样的:

>>> now = log('execute')(now)

    我们来剖析上面的语句,首先执行log(‘execute’),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。

    以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的’now’变成了’wrapper’:

>>> now.__name__
'wrapper'

    因为返回的那个wrapper()函数名字就是’wrapper’,所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

    不需要编写wrapper.name = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下:

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

    或者针对带参的decorator:

import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)#必须放在函数wrapper前面
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

【实例】写一个装饰器可以打印任何函数的执行时间

import time, functools

def metric(func):
    print ('%s executed in %s ms'%(func.__name__, 10.24))
    return func

【测试】

@metric
def fast(x, y):
    time.sleep(0.0012)
    return x + y

@metric
def slow(x, y):
    time.sleep(0.1234)
    return x * y

f = fast(11, 22)
s = slow(11, 22)

if f != 33:
    print ('测试失败')
else s != 242:
    print ('测试失败')

五、变量作用域

  • L (Local) 局部作用域
  • E (Enclosing) 闭包函数外的函数中
  • G (Global) 全局作用域
  • B (Built-in) 内建作用域
        以 L –> E –> G –> B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。

    Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问。

    定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

    局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字。

num = 1
def fun1():
    global num  # 需要使用 global 关键字声明
    print(num) 
    num = 123
    print(num)
fun1()

如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字。

def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal关键字声明
        num = 100
        print(num)
    inner()
    print(num)
outer()

猜你喜欢

转载自blog.csdn.net/sinat_33924041/article/details/84032657