Python学习总结【第三篇】:Python之函数(自定义函数、内置函数、lambda表达式、装饰器、迭代器&生成器)

1、函数

1.1 自定义函数

背景需求:

  在学习函数之前,一直遵循:面向过程编程,即:根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处,如下:

while True:
    if cpu利用率 > 90%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接
  
    if 硬盘使用空间 > 90%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接
  
    if 内存占用 > 80%:
        #发送邮件提醒
        连接邮箱服务器
        发送邮件
        关闭连接

上述代码,if条件语句下的内容可以被提取出来公用,如下:

def 发送邮件(内容)
    #发送邮件提醒
    连接邮箱服务器
    发送邮件
    关闭连接
  
while True:
  
    if cpu利用率 > 90%:
        发送邮件('CPU报警')
  
    if 硬盘使用空间 > 90%:
        发送邮件('硬盘报警')
  
    if 内存占用 > 80%:

对于上述的两种实现方式,第二次必然比第一次的重用性和可读性要好,其实这就是函数式编程和面向过程编程的区别:
函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
面向对象:对函数进行分类和封装,让开发“更快更好更强...”
函数式编程最重要的是增强代码的重用性和可读性

自定义函数练习

1、写函数,计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数 

def func(get_str):
    """
    计算传入字符串中【数字】、【字母】、【空格] 以及 【其他】的个数 
    :param get_str:
    :return:
    """
    digit, alpha, space, other = 0, 0, 0, 0  # 数字 字母 空格 其他
    for i in get_str:
        if i.isdigit():
            digit += 1
        elif i.isalpha():
            alpha += 1
        elif i.isspace():
            space += 1
        else :
            other += 1
    return digit, alpha, space, other


def main():
    get_str = input("请输入一个字符串:")
    result = func(get_str)
    # print(result)
    print(
"""
============================
          数字:%s
          字母:%s
          空格:%s
          其他:%s
============================""" % result)


if __name__ == '__main__':
    main()
View Code

2、写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5 

def func(get_obj):
    """
    判断用户传入的对象(字符串、列表、元组)长度是否大于5 
    :param get_obj:
    :return:
    """
    ret = False
    if isinstance(get_obj, str) or isinstance(get_obj, list) or isinstance(get_obj, tuple):
        if len(get_obj) > 5:
            ret = True
        return len(get_obj), ret


def main():
    # get_obj = "dsfwerqwer"
    # get_obj = (1, 2, 3, 4,)
    get_obj = [1, 2, 3, ]
    result = func(get_obj)
    print("长度为:%s,是否大于5:%s" % result)


if __name__ == '__main__':
    main()
View Code

3、写函数,检查用户传入的对象(字符串、列表、元组)的每一个元素是否含有空内容

def func(get_obj):
    """
    检查用户传入的对象(字符串、列表、元组)的每一个元素是否含有空内容 
    :param get_obj:
    :return:
    """
    ret = False
    if isinstance(get_obj, str) or isinstance(get_obj, list) or isinstance(get_obj, tuple):
        for i in get_obj:
            if i == '':
                ret = True
                break
    return ret


def main():
    get_obj = "ds fwerqwer"
    # get_obj = (1, 2, 3, 4, '',)
    # get_obj = (1, 2, 3, 4,)
    # get_obj = [1, 2, 3, '', 5, ]
    result = func(get_obj)
    print("该对象是否含有空元素%s" % result)


if __name__ == '__main__':
    main()
View Code

4、写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。 
5、写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。
6、写函数,检查传入字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。
7、写函数,利用递归获取斐波那契数列中的第 10 个数,并将该值返回给调用者。

地址:http://www.cnblogs.com/Wxtrkbc/p/5466082.html

1.2 函数的定义与使用

def 函数名(参数):
    ...
    函数体
    ...

函数的定义主要有如下要点:
      def:表示函数的关键字
      函数名:函数的名称,日后根据函数名调用函数
      函数体:函数中进行一系列的逻辑计算,如:发送邮件、计算出 [11,22,38,888,2]中的最大数等...
      参数:为函数体提供数据
      返回值:当函数执行完毕后,可以给调用者返回数据。
以上要点中,比较重要有参数和返回值:

1.2.1 返回值

函数是一个功能块,该功能到底执行成功与否,需要通过返回值来告知调用者。

def 发送短信():
    发送短信的代码...
 
    if 发送成功:
        return True
    else:
        return False
 
while True:
    # 每次执行发送短信函数,都会将返回值自动赋值给result
    # 之后,可以根据result来写日志,或重发等操作
 
    result = 发送短信()
    if result == False:
        记录日志,短信发送失败...

 1.2.2 参数

1)为什么要使用参数?

2)参数类型

普通参数(多个参数将严格按照顺序将实际参数赋值给形式参数)

# 函数定义:name叫做函数func的形式参数,简称:形参
>>> def func(name):
...     print(name)
...

# 函数的调用执行
#  'alex' 叫做函数func的实际参数,简称:实参
>>> func('alex')
alex

默认参数

>>> def func(name, age = 18):
...     print "%s:%s" %(name,age)
...

# 指定参数
>>> func('wupeiqi', 19)
wupeiqi:19

# 使用默认参数
>>> func('alex')
alex:18

注:默认参数需要放在参数列表最后

指定参数赋值

>>> def show(a1,a2):
...     print(a1,a2)
...
>>> show(100,111)              # 按照顺序将多个实参赋值给形参
(100, 111)
>>> show(a2=111,a1=100)        # 指定参数进行赋值,不按照顺序进行赋值
(100, 111) 

动态参数

动态参数一:默认将传入的参数,全部放置在元组中, f1(*[1`1,22,33,44])
>>> def func(*args):
...     print(args)
...

# 执行方式一
>>> func(11,33,4,4454,5)
(11, 33, 4, 4454, 5)

# 执行方式二
>>> li = [11,33,4,4454,5]     # 元组,列表,字典都要做类似处理
>>> func(*li)
(11, 33, 4, 4454, 5)

# 错误执行方法
 >>> func(li)      # 这样并非正确的动态传参,这样函数会把整个列表当做元组的一个元素进行处理
([11, 33, 4, 4454, 5],)

动态参数二:默认将传入的参数,全部放置在字典中   f1(**{"kl":"v1", "k2":"v2"})
>>> def func(**kwargs):
...     print(kwargs)
...

# 执行方式一
>>> func(name='wupeiqi',age=18)
{'name': 'wupeiqi', 'age': 18}

# 执行方式二
>>> li = {'name':'wupeiqi', "age":18, 'gender':'male'}
>>> func(**li)
{'name': 'wupeiqi', 'gender': 'male', 'age': 18}

动态参数三:把元组和字典结合进行传参(元组在前,字典在后)
>>> def show(*args,**kwargs):
...     print(args,type(args))
...     print(kwargs,type(kwargs))
...

>>> show(11,22,33,100,a1=11,abc=100)
(11, 22, 33, 100) <class 'tuple'>
{'abc': 100, 'a1': 11} <class 'dict'>

#str.format()格式化输出  讲解动态参数 *args ,**kwargs

s1 = "I am {0},age {1}".format("alex",18)           # 利用*args进行传参
print(s1)

lis = ["alex",18]
s1 = "I am {0},age {1}".format(*lis)                # 利用*args进行传参
print(s1)

s1 = "I am {name},age {age}".format(name="alex",age=18)    # 利用**kwargs进行传参
print(s1)

dic = {"name":"alex","age":18}
s1 = "I am {name},age {age}".format(**dic)                 # 利用**kwargs进行传参
print(s1)

输出结果都为: I am alex,age 18

邮件代码:

def sendmail(xxoo, content):
    # xxoo = alex
    try:
        import smtplib
        from email.mime.text import MIMEText
        from email.utils import formataddr
        msg = MIMEText(content, 'plain', 'utf-8')
        msg['From'] = formataddr(["武沛齐",'wptawy@126.com'])
        msg['To'] = formataddr(["走人",'424662508@qq.com'])
        msg['Subject'] = "主题"

        server = smtplib.SMTP("smtp.126.com", 25)
        server.login("wptawy@126.com", "WW.3945.59")
        server.sendmail('wptawy@126.com', [xxoo,], msg.as_string())
        server.quit()
    except:
        # 发送失败
        return "失败"
    else:
        # 发送成功
        return "cc"


while True:
    em = input("请输入邮箱地址:")
    result = sendmail(em, "SB")
    if result == "cc":
        print("发送成功")
    else:
        print("发送失败")
View Code

1.2.3 函数与变量定义

1、 def f1
    def f1 (生效)
2、函数传递引用
3、全局变量
    全局变量定义要大写
    读,都可读
    赋值,globals()
    字典,列表等全局变量,可以修改,但是无法重新赋值
    全局变量定义位置:将全局变量在代码开始即进行定义,也可以在函数体内定义,但是不友好,需要阅读全部的代码,找出在各个函数体内定义的全局变量
# 补充问题1:
def f1(a1,a2):
    return a1+a2

def f1(a1,a2):
    return a1*a2

res = f1(8,8)
print(res)  

# 问题:结果多少为什么? # 解答:结果是64 代码是顺序执行,f1被重新指向,第一个f1定义失效,f2生效
# 补充问题2:
def f1(a1):
    a1.append(999)
li = [11,22,33,44]
f1(li)
print(li)  
# 问题:结果多少,为什么? # 解答:结果为[11, 22, 33, 44, 999] # 即:Python是传递一个引用 并非复制一份内容 a1和li的指向是同一块内存地址,修改了a1即修改了li
# 补充问题3:
# 各个函数内定义变量的引用问题:没有结果,name变量只在f1内定义及使用
def f1():
    name = "alex"
    print(name)

def f2():
    print(name)

f1()
alex

f2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f2
NameError: name 'name' is not defined
# 全局变量,所有作用域都能读 name = "alex" def f1(): age =18 print(age,name) def f2(): age =19 print(age,name)
>>> f1()
18 alex
>>> f2()
19 alex # 对全局变量进行重新赋值,需要global
#全局变量和函数体内变量都定义了,优先使用自己函数体内定义的变量
# global说明:
# 1、global---将变量定义为全局变量。可以通过定义为全局变量,实现在函数内部改变变量值。
# 2、一个global语句可以同时定义多个变量,如 global x, y, z
# 执行方式1
>>> NAME = None
>>> def f1():
...     age = 18
...     global NAME
...     NAME = "123"
...     print(age, NAME)
...
>>> def f2():
...     age = 19
...     print(age, NAME)
...
...
>>> f1()
18 123
>>> f2()
19 123

# 执行方式 2
>>> NAME = None
>>> def f1():
...     age = 18
...     global NAME
...     NAME = "123"
...     print(age, NAME)
...
>>> def f2():
...     age = 19
...     print(age, NAME)
...
>>> f2()
19 None
>>> f1()
18 123
# 特殊:列表字典,可修改,不可重新赋值
name = [11,22,33,44]         # 可以在函数体内增加值(name.append(55)),当时无法重新赋值(name = "123")

def f1():
    age =18
    name = "123"
    print(age,name)

def f2():
    age =19
    name.append(55)
    print(age,name)

 函数应用范例

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Alex Li


def login(username, password):
    """
    用于用户登录
    :param username: 用户输入的用户名
    :param password: 用户输入的密码
    :return: true,表示登录成功;false,登录失败
    """
    f = open("db", 'r')
    for line in f:
        line_list = line.strip().split("|")
        if line_list[0] == username and line_list[1] == password:
            return True
    return False


def register(username, password):
    """
    用于用户注册
    :param username: 用户名
    :param password: 密码
    :return: 默认None
    """
    f = open("db", 'a')
    temp = "\n" + username + "|" + password
    f.write(temp)
    f.close()


def main():
    t = input("1:登录;2:注册")
    if t == "1":
        user = input("请输入用户名:")
        pwd = input("请输入密码:")
        r = login(user, pwd)
        if r:
            print("登录成功")
        else:
            print("登录失败")
    elif t == "2":
        user = input("请输入用户名:")
        pwd = input("请输入密码:")
        register(user, pwd)

main()
View Code

1.3 内置函数

官网:http://data.digitser.net/python_3.4.2/zh-CN/library/functions.html

如何查看Python当前版本的内置函数有哪些,可以用下面的指令查看:

C:\Users\Administrator>python
Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec  5 2015, 20:32:19) [MSC v.1500 32 bit (
Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> dir(sys.modules['__builtin__'])
Python 2.x内置函数列表
地址:http://python.usyiyi.cn/python_278/library/functions.html


Python 3.x 内置函数列表
地址:http://python.usyiyi.cn/python_343/library/functions.html
'__package__', 'abs','all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']

 

# abs--求绝对值
>>> print(abs(100))
100
>>> print(abs(-100))
100

# all--集合中的元素都为真的时候为真   
>>> n = all([1,2,3,None])
>>> print(n)
False
>>> n = all([1,2,3,34])
>>> print(n)
True

# any--集合中的元素有一个为真的时候为真 常见为假的对象:[],{},None,0,"",()
>>> n = any([[],0,"",None])      # 全为假
>>> print(n)
False
>>> n = any([[],0,"",1])        # 1 为真
>>> print(n)
True

# cmp(x,y)--如果x < y ,返回负数;x == y, 返回0;x > y,返回正数
# ascii--自动执行对象的 __repr__    python 2.7没有 Python 3.0才有
>>> class Foo:
...     def __repr__(self):
...         return "444"
...
>>> n = ascii(Foo())
>>> print(n)
444

# apply--过期不再叙述
# basestring--str和unicode的超类,不能直接调用,可以用作isinstance判断
# bin--将一个整数转换成一个二进制字符串
# oct--将整数x转换为八进制字符串
# hex-- 将整数x转换为十六进制字符串                   
>>> n = 20
>>> print(bin(n))
0b10100
>>> print(oct(n))
0o24
>>> print(hex(n))
0x14

# bool--将x转换为Boolean类型
# buffer--过期的内置函数,故不说明
# bytearray--过期的内置函数,故不说明
# bytes--字符串转字节类型(重点)
>>> n = bytes("李杰", encoding="utf-8")
>>> print(n)
b'\xe6\x9d\x8e\xe6\x9d\xb0'
>>> n = bytes("李杰", encoding="gbk")
>>> print(n)
b'\xc0\xee\xbd\xdc'

# str--字节转化成字符串
>>> new_str = str(bytes("李杰", encoding="utf-8"), encoding="utf-8")
>>> print(new_str)
李杰

# callable(object)--如果 object 参数可调用,返回True;否则返回False。如果返回True,仍有可能调用失败,但是如果返回False,调用object将永不成功
>>> def f1():
...     print(123)
...
>>> f2 = 123
>>> print(callable(f1))
True
>>> print(callable(f2))
False

# chr()--返回整数i对应的ASCII字符
# ord()--返回ASCII字符对应的整数
# 应用案例:生成一个随机的6位验证码,包含大写字母、数字
最终版本:
import random

li = []                                  # 使用列表用于存储完整的验证码
for i in range(6):                       # 用于生成六位的验证码
    r = random.randrange(0, 5)           # 在0-6位的验证码中,随机生成一个数字,用于指定验证码的第几个位用于生成数字序列
    if r == 2 or r == 4 :                # 进行判断,如果为指定行,则进行如下操作
        num = random.randrange(0, 10)    # 用于在指定序列的生成随机数,即生成1-9之间的一个数字
        li.append(str(num))              # 将生成的随机数字存放到列表中
    else:
        tmp = random.randrange(65, 91)   # 用于在指定序列的生成随机数
        c = chr(tmp)                     # ascii数字-->大写字母
        li.append(c)                     # 将生成的随机大写字母存放到列表中
result = "".join(li)                     # 将列表拼接成字符串
print("你的随机验证码:", result)

# classmethod(function)--将function包装成类方法 暂时无需了解
# compile()--把字符串编译为Python代码
# eval()--执行Python表达式         有返回值      子集
# exec()--执行Python代码或者字符串  没有返回值    父集

>>> s = "print(123)"
>>> r = compile(s, "<string>", "exec")   # 将字符串编译成Python代码 编译,single,eval,exec
>>> print(r)
<code object <module> at 0x02A2C5C0, file "<string>", line 1>
>>> exec(r)  # 执行代码
123

>>> s = "8*8"
>>> res = eval(s)
>>> print(res)
64

# complex()--返回一个复数

# delattr()--删除object对象名为name的属性
# hasattr(object, name)
# setattr()
# getattr(object, name[, default])--返回object的属性值

# divmod(a,b)--参数为两个数值(非复数),返回它们相除后的的商和余数  应用场景:博客分页  (重要)
>>> r = divmod(97, 10)
>>> print(r)
(9, 7)
>>> n1, n2 = divmod(97, 10)
>>> print(n1, n2)
9 7

# enumerate(iterable, start=0)--返回一个枚举对象。iterable 必须是序列、迭代器,或者其他支持迭代的对象
# exit()--退出

# filter(函数,可迭代的对象)--函数返回Ture,将元素添加到结果中
# 需求:有一个列表,要进行筛选,大于22的返回给我

# 自定义方法实现

def f1(args):
    result = []
    for item in args:
        if item > 22:
            result.append(item)
    return result

li = [11, 22, 33, 44, 55]
ret = f1(li)
print(ret)

# 通过filter功能实现需求 def f2(a): if a > 22: return True li = [11, 22, 33, 44, 55] res = filter(f2, li) print(list(res)) # filter和lambda实现需求 li = [11, 22, 33, 44, 55, ] result = filter(lambda a: a > 33, li) print(list(result)) # float--将一个字符串或数转换为浮点数。如果无参数将返回0.0 # format--格式化输出字符串,格式化的参数顺序从0开始,如“I am {0},I like {1}” # frozenset()--内置类,暂时忽略 # locals()--更新并返回表示当前局部符号表的字典。当locals在函数块中而不是类块中被调用时,locals()返回自由变量 # globals()--返回表示当前全局符号表的字典。它总是当前模块的字典(在函数或者方法中,它指定义的模块而不是调用的模块) NAME = "ALEX" def f1(): age = 10 return NAME, age print(f1()) print(locals()) print(globals()) # hash()--返回对象的hash值, 应用场景:字典的key值进行hash,存hash值作为字典key,其他语言也适用 s = "adsafsd" print(hash(s)) # help()--获取详细帮助信息 # dir()--返回对象的功能方法列表 # id()--返回对象的唯一标识 # input([prompt])--如果有prompt参数,则将它输出到标准输出且不带换行。该函数然后从标准输入读取一行,将它转换成一个字符串(去掉一个末尾的换行符),然后返回它 # int()--返回一个由数值或字符串 x 转换而成的整数,如果省略参数,则返回 0 # isinstance()--判断对象是否是某个类的实例,与type()区别 s = "alex" print(isinstance(s, str)) print(isinstance(s, list)) # issubclass--如果class是classinfo的子类(直接的,间接的,或者virtual) ,返回真。忽略 # iter(object[, sentinel])--返回一个iterator对象 # len()--返回一个对象的长度 (元素的个数) . 参数可以是序列(如字符串,字节,元组,列表或者范围)或者集合(如字典,集合或者固定集合) s = "李杰" print(len(s))           # Python 3.x 默认按照字符统计,可以按照字节统计 结果:2 b = bytes(s, encoding="utf-8") # Python 3.x 也可以按照字节统计 结果:6 print(len(b)) print(len(s))           # Python 2.x 按照字节统计 结果:6
)
# Python 2.x
>>> name = "李杰"
>>> for i in name:
...     print(i)
...




>>>

# Python 3.x
>>> name = "李杰"
>>> for i in name:
...     print(i)
...



# map(函数,可迭代的对象(可以for循环))--将函数返回值添加到结果中 # 需求:给一个列表,所有元素+100,返回给我。即:一批数据进行统一的一类操作
# 自己实现
li = [11, 22, 33, 44, 55, ]

def f1(args):
    result = []
    for i in args:
        result.append(100+i)
    return result

print(f1(li))

# map实现
li = [11, 22, 33, 44, 55, ]

def f1(a):
    return a + 100
result = map(f1, li)
print(list(result))

# map和lambda功能实现
li = [11, 22, 33, 44, 55, ]
result = map(lambda a: a + 100, li)
result = map(f1, li)
print(list(result))
[111, 122, 133, 144, 155]

# 其他应用场景:字符串,列表的应用
>>> li_list = ['shuaige','nihao',]
>>> result = map(lambda a: "%s is string" % a,li_list)
>>> print(list(result))
['shuaige is string', 'nihao is string']

>>> li_str = 'abcdefg'
>>> result = map(lambda a: "%s is string" % a,li_str)
>>> print(list(result))
['a is string', 'b is string', 'c is string', 'd is string', 'e is string', 'f i
s string', 'g is string']
# sum(iterable[, start])--将start以及iterable的元素从左向右相加并返回总和。start默认为0 # max()--返回可迭代的对象中的最大的元素,或者返回2个或多个参数中的最大的参数 # min()--返回可迭代的对象中的最小的元素,或者返回2个或多个参数中的最小的参数
>>> r = sum([11,22,33,1])
>>> print(r)
67
>>> r = max([11,22,33,1])
>>> print(r)
33
>>> r = min([11,22,33,1])
>>> print(r)
1 # memoryview()--返回给定参数的“内存视图” # next() # object--返回一个新的无特征的对象 # open--文件操作(重点) # pow(x, y[, z])--返回x 的 y次方; 如果 z 提供的时候,返回 x 的 y 次方,然后对 z取模。(这样比 pow(x, y) % z) 更高效。 pow(x, y)的效果类似于: x**y. >>> print(2**10) 1024 >>> print(pow(2, 10)) 1024 # print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False) # 打印 objects 到文本流对象 file,以 sep 为分隔符,以 end 为结尾符。如果要提供 sep, end 和 file 这三个参数的话,必须使用键值对的形式

# property()--返回一个property 属性

# range(stop) # range(start, stop[, step])--返回一个指定范围内的不可变的序列 # xrange() # raw_input()--接收用户输入 Python 2.7.x # repr(object)--返回一个字符串 >>> r = repr("alex") >>> print(r) 'alex' # reversed(seq)--返回一个反向迭代器 >>> li = [11, 22, 1, 1, ] >>> li.reverse() >>> print(li) [1, 1, 22, 11] >>> li = [11, 22, 1, 1, ] >>> reversed(li) <list_reverseiterator object at 0x02A1F530> >>> print(list(reversed(li))) [1, 1, 22, 11] >>> print(li) [11, 22, 1, 1] # round(number[, ndigits])--返回浮点数 number 四舍五入到小数点之后 ndigits 位的结果 >>> r = round(1.9) >>> print(r) 2 >>> r = round(1.4) >>> print(r) 1 # type()--查看数据类型 # tuple()--元组 # set()--set集合 无序不重复 # list()--列表 # dict()--字典 # slice()--返回一个slice对象 http://i.cnblogs.com/EditArticles.aspx?postid=5515410&update=1 # sorted(iterable[, key][, reverse])--依据iterable中的元素返回一个新的列表 # staticmethod(function)--返回function的一个静态方法# super([type[, object-or-type]])--返回一个代理对象,这个对象指派方法给一个父类或者同类. # vars([object])--返回模块 # zip(*iterables)--利用每个可迭代元素,制作一个迭代器来聚合元素。 >>> l1 = ["alex", 11, 22, 33] >>> l2 = ["is", 11, 22, 33] >>> l3 = ["sb", 11, 22, 33] >>> >>> r = zip(l1, l2, l3) >>> print(list(r)) [('alex', 'is', 'sb'), (11, 11, 11), (22, 22, 22), (33, 33, 33)] # __import__()

1.3.1 reduce(Python 2.x)

对于序列内所有元素进行累计操作

>>> li = [1,2,3,4,5,6,7,8]
>>> result =  reduce(lambda a1,a2:a1+a2,li) #累乘、除、加、减
>>> print result
36

# reduce的第一个参数,函数必须要有两个参数,因为他是两两进行操作
# reduce的第二个参数,要循环的序列
# reduce的第三个参数,初始值

#初始值
>>> li = [1,2,3,4,5,6,7,8]
>>> result =  reduce(lambda a1,a2:a1+a2,li,100000) #累乘、除、加、减
>>> print result
100036

默认参数:

常见的内置函数又分为如下几类,详细介绍参考:http://jianfeihit.iteye.com/blog/1835272

总结:

   内置函数,一般都是因为使用频率比较频繁或是是元操作,所以通过内置函数的形式提供出来,通过对python的内置函数分类分析可以看出来:基本的数据 操 作基本都是一些数学运算(当然除了加减乘除)、逻辑操作、集合操作、基本IO操作,然后就是对于语言自身的反射操作,还有就是字符串操作,也是比较常用 的,尤其需要注意的是反射操作。

2、lambda表达式

学习条件运算时,对于简单的 if else 语句,可以使用三元运算来表示,即:

# 普通条件语句
if 1 == 1:
    name = 'wupeiqi'
else:
    name = 'alex'
 
# 三元运算
name = 'wupeiqi' if 1 == 1 else 'alex'

对于简单的函数,也存在一种简便的表示方式,即:lambda表达式

####################### 普通函数 ######################
# 定义函数(普通方式)
>>> def func(arg):
...     return arg + 1
...
# 执行函数
>>> result = func(123)
>>> print(result)
124
 
####################### lambda ######################
 
# 定义函数(lambda表达式)
>>> my_lambda = lambda arg : arg + 1

# 执行函数
... result = my_lambda(123)
>>> print(result)
124

lambda存在意义就是对简单函数的简洁表示

 

3、yield生成器

3.1 yield介绍

  您可能听说过,带有 yield 的函数在 Python 中被称之为 generator(生成器),何谓 generator ?我们先抛开 generator,以一个常见的编程题目来展示 yield 的概念。
如何生成斐波那契數列?
  斐波那契(Fibonacci)數列是一个非常简单的递归数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到。用计算机程序输出斐波那契數列的前 N 个数是一个非常简单的问题,许多初学者都可以轻易写出如下函数:
清单 1. 简单输出斐波那契數列前 N 个数

 def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        print b 
        a, b = b, a + b 
        n = n + 1
执行 fab(5),我们可以得到如下输出:
>>> fab(5) 1 1 2 3 5

  结果没有问题,但有经验的开发者会指出,直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List。以下是 fab 函数改写后的第二个版本:

清单 2. 输出斐波那契數列前 N 个数第二版

 def fab(max): 
    n, a, b = 0, 0, 1 
    L = [] 
    while n < max: 
        L.append(b) 
        a, b = b, a + b 
        n = n + 1 
    return L

可以使用如下方式打印出 fab 函数返回的 List:

 >>> for n in fab(5): 
 ...     print n 
 ... 
 1 
 1 
 2 
 3 
 5

改写后的 fab 函数通过返回 List 能满足复用性的要求,但是更有经验的开发者会指出,该函数在运行中占用的内存会随着参数 max 的增大而增大,如果要控制内存占用,最好不要用 List来保存中间结果,而是通过 iterable 对象来迭代。例如,在 Python2.x 中,代码:
清单 3. 通过 iterable 对象来迭代

for i in range(1000): pass

会导致生成一个 1000 个元素的 List,而代码:

for i in xrange(1000): pass

      则不会生成一个 1000 个元素的 List,而是在每次迭代中返回下一个数值,内存空间占用很小。因为 xrange 不返回 List,而是返回一个 iterable 对象。利用 iterable 我们可以把 fab 函数改写为一个支持 iterable 的 class,以下是第三个版本的 Fab:
清单 4. 第三个版本

 class Fab(object): 

    def __init__(self, max): 
        self.max = max 
        self.n, self.a, self.b = 0, 0, 1 

    def __iter__(self): 
        return self 

    def next(self): 
        if self.n < self.max: 
            r = self.b 
            self.a, self.b = self.b, self.a + self.b 
            self.n = self.n + 1 
            return r 
        raise StopIteration()

Fab 类通过 next() 不断返回数列的下一个数,内存占用始终为常数:

 >>> for n in Fab(5): 
 ...     print n 
 ... 
 1 
 1 
 2 
 3 
 5

然而,使用 class 改写的这个版本,代码远远没有第一版的 fab 函数来得简洁。如果我们想要保持第一版 fab 函数的简洁性,同时又要获得 iterable 的效果,yield 就派上用场了:
清单 5. 使用 yield 的第四版

def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        yield b 
        # print b 
        a, b = b, a + b 
        n = n + 1 

'''

第四个版本的 fab 和第一版相比,仅仅把 print b 改为了 yield b,就在保持简洁性的同时获得了 iterable 的效果。

调用第四版的 fab 和第二版的 fab 完全一致:
'''

 >>> for n in fab(5): 
 ...     print n 
 ... 
 1 
 1 
 2 
 3 
 5

  简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。

也可以手动调用 fab(5) 的 next() 方法(因为 fab(5) 是一个 generator 对象,该对象具有 next() 方法),这样我们就可以更清楚地看到 fab 的执行流程:
清单 6. 执行流程

>>> f = fab(5) 
 >>> f.next() 
 1 
 >>> f.next() 
 1 
 >>> f.next() 
 2 
 >>> f.next() 
 3 
 >>> f.next() 
 5 
 >>> f.next() 
 Traceback (most recent call last): 
  File "<stdin>", line 1, in <module> 
 StopIteration

当函数执行结束时,generator 自动抛出 StopIteration 异常,表示迭代完成。在 for 循环里,无需处理 StopIteration 异常,循环会正常结束。

我们可以得出以下结论:

一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。

yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰。

如何判断一个函数是否是一个特殊的 generator 函数?可以利用 isgeneratorfunction 判断:
清单 7. 使用 isgeneratorfunction 判断

 >>> from inspect import isgeneratorfunction 
 >>> isgeneratorfunction(fab) 
 True

要注意区分 fab 和 fab(5),fab 是一个 generator function,而 fab(5) 是调用 fab 返回的一个 generator,好比类的定义和类的实例的区别:

清单 8. 类的定义和类的实例

>>> import types
 >>> isinstance(fab, types.GeneratorType)
 False
 >>> isinstance(fab(5), types.GeneratorType)
 True

fab 是无法迭代的,而 fab(5) 是可迭代的:

 >>> from collections import Iterable
 >>> isinstance(fab, Iterable)
 False
 >>> isinstance(fab(5), Iterable)
 True

每次调用 fab 函数都会生成一个新的 generator 实例,各实例互不影响:

 >>> f1 = fab(3)
 >>> f2 = fab(5)
 >>> print 'f1:', f1.next()
 f1: 1
 >>> print 'f2:', f2.next()
 f2: 1
 >>> print 'f1:', f1.next()
 f1: 1
 >>> print 'f2:', f2.next()
 f2: 1
 >>> print 'f1:', f1.next()
 f1: 2
 >>> print 'f2:', f2.next()
 f2: 2
 >>> print 'f2:', f2.next()
 f2: 3
 >>> print 'f2:', f2.next()
 f2: 5

return 的作用

在一个 generator function 中,如果没有 return,则默认执行至函数完毕,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。

另一个例子
另一个 yield 的例子来源于文件读取。如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取:
清单 9. 另一个 yield 的例子

 def read_file(fpath):
    BLOCK_SIZE = 1024
    with open(fpath, 'rb') as f:
        while True:
            block = f.read(BLOCK_SIZE)
            if block:
                yield block
            else:
                return

以上仅仅简单介绍了 yield 的基本概念和用法,yield 在 Python 3 中还有更强大的用法,我们会在后续文章中讨论。

注:本文的代码均在 Python 2.7 中调试通过

3.2 range和xrange的区别

# Python 2.x
>>> print(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> print(xrange(10))
xrange(10)

# range会在内存中创建所有指定的数字,而xrange不会立即创建,只有在迭代循环时,才去创建每个数组

# Python 3.x >>> print(range(10)) range(0, 10) >>> print(xrange(10)) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'xrange' is not defined

 http://i.cnblogs.com/EditArticles.aspx?postid=5515410&update=1

3.3 文件操作的read和xreadlinex的区别

read会读取所有内容到内存
xreadlines则只有在循环迭代时才获取
 
3.4 其他案例
def func():
    print("111")
    yield 1
    print("222")
    yield 2
    print("333")
    yield 3

ret = func()
# print(list(ret))
r1 = ret.__next__()   # 执行到 yield 1 停止
print(r1)

r2 = ret.__next__()   # 执行到 yield 2 停止
print(r2)

r3 = ret.__next__()   # 执行到 yield 3 停止
print(r3)

# 结果
111
1
222
2
333
3

def my_range(arg):
    start = 0
    while True:
        if start > arg:
            return
        yield start
        start += 1

ret = my_range(4)
r1 = ret.__next__()
print(r1)
r1 = ret.__next__()
print(r1)
r1 = ret.__next__()
print(r1)

结果:
0
1
2
 
4、装饰器
  装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。使用装饰器可以在函数执行前和执行后添加相应操作。
  装饰器是函数,只不过该函数可以具有特殊的含义,装饰器用来装饰函数或类,使用装饰器可以在函数执行前和执行后添加相应操作。
装饰器应用场景:
  公司系统管理部包括开发组、测试组、设计组等,公司的基础平台架构,为公司各个组提供的基础的函数库供各个小组进行调研。各个部门的开发工作都会直接调用这些功能的接口,如下:
#######基础平台函数库#########
def func1():
    print('功能1')

def func2():
    print('功能2')

def func3():
    print('功能3')

def func4():
    print('功能4')

# 测试组
def func1()
def func2()
def func3()

# 设计组
def func1()
def func2()
def func3()

需求:基础平台函数库的调用要添加验证机制,只能验证通过才能进行函数调用,在完成这个需求的前提下要满足如下条件

1)各个部门修改自己的代码

2)在每个部门实行的功能上添加最少的代码完成改造

3)追求开放封闭原则,尽可能的不改变原基础函数库内部实现的方法解决方案:利用装饰器功能解决该需求

def login(func):
    def inner():
        # 验证1
        # 验证2
        # 验证3
        return func()
    return inner
@login
def func1(): print '功能1' @login def func2(): print '功能2' @login def func3(): print '功能3' @login def func4(): print '功能4'

当各个组执行各自功能的时候,可以先调用基础平台提供的装饰器函数,完成验证需求

def login(func):
    def inner():
        # 验证1
        return func()
    return inner  

@login
def func1():
     print('功能1')

功能:
    1. 自动执行login函数并且将其下面的函数名func1当作参数传递
    2. 将login函数的返回值,重复赋值给 func1

  当调用功能1的时候 会先把功能1的函数名带入内存地址,之后会执行login函数,func为功能1,之后inner会将功能1的参数带入等待执行inner的验证功能后,会将参数交给func执行功能1的命令。

# 装饰器如何装饰多个参数个数不同的函数
def outer(func):
    def inner(*args, **kwargs):
        print("func before")
        result = func(*args, **kwargs)
        print("func after")
        return result
    return inner

@outer
def f1(arg):
    print(arg)
    # return "f1函数返回值"

@outer
def f2(arg1,arg2):
    print(arg1,arg2)
    # return "f1函数返回值"
应用案例:
LOGIN_USER = {"is_login": False}


def outer(func):
    def inner(*args, **kwargs):
        if LOGIN_USER['is_login']:
            r = func()
            return r
        else:
            print("请登录")
    return inner


def outer1(func):
    def inner(*args, **kwargs):
        if LOGIN_USER['is_login'] and LOGIN_USER['user_type'] == 2:
            r = func()
            return r
        else:
            print("请登录,或者权限不够")
    return inner


@outer1
def order():
    print("欢迎%s登录" % LOGIN_USER['current_user'])


@outer
def changepwd():
    print("欢迎%s登录" % LOGIN_USER['current_user'])


@outer
def manager():
    print("欢迎%s登录" % LOGIN_USER['current_user'])


def login(user, pwd):
    if user == "alex" and pwd == "123":
        LOGIN_USER['is_login'] = True
        LOGIN_USER['current_user'] = user
        manager()
        

def main():
    while True:
        inp = input("1,后台管理;2,登录")
        if inp == '1':
            manager()
        elif inp == '2':
            username = input("请输入用户名")
            pwd = input("请输入密码")
            login(username, pwd)

            
if __name__ == '__main__':
    main()

# 执行结果:

多层装饰器
USER_INFO = {}


def check_login(func):
    def inner(*args, **kwargs):
        if USER_INFO.get("is_login", None):
            # ret = func(*args, **kwargs)
            func(*args, **kwargs)
        else:
            print("请先登录")
    return inner


def check_admin(func):
    def inner(*args, **kwargs):
        if USER_INFO.get("user_type", None):
            # ret = func(*args, **kwargs)
            func(*args, **kwargs)
        else:
            print("请管理员")
    return inner


def login():
    print("登录成功")
    USER_INFO["is_login"] = True


@check_login
def home():
    print("普通查看信息")


@check_login
@check_admin
def admin():
    print("管理员权限")


def main():
    while True:
        choice_num = input("1、登录 2、查看信息 3、管理员权限 请选择")
        if choice_num == "1":
            login()
        elif choice_num == "2":
            home()
        elif choice_num == "3":
            admin()


if __name__ == '__main__':
    main()

更厉害的装饰器
 
5、迭代器
  迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件

特点:
1)访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
2)不能随机访问集合中的某个值 ,只能从头到尾依次访问
3)访问到一半时不能往回退
4)便于循环比较大的数据集合,节省内存
迭代器案例
>>> a = iter([1,2,3,4])
>>> a.__next__()
1
>>> a.__next__()
2
>>> a.__next__()
3
>>> a.__next__()
4
>>> a.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

6、冒泡算法

需求:请按照从小到大对列表 [13, 22, 6, 99, 11] 进行排序

思路:相邻两个值进行比较,将较大的值放在右侧,依次比较!

 

7、递归

特点
  递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。

要求
递归算法所体现的“重复”一般有三个要求:
一是每次调用在规模上都有所缩小(通常是减半);
二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

案例1:利用函数编写如下数列:
斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368
>>> def func(arg1, arg2):
...     if arg1 == 0:
...         print(arg1, arg2)
...     arg3 = arg1 + arg2
...     print(arg3)
...     if arg3 < 1000:
...         func(arg2, arg3)
...
>>> func(0, 1)
0 1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
案例2:
def func(n):
    print(n)
    n += 1
    if n >= 4:
        return "end"
    return func(n)


r = func(1)
print(r)

结果:
1
2
3
end

 案例3:实现 1*2*3*4*5*6

>>> def fact(n):
...     if n == 1:
...         return 1
...     return n*fact(n-1)
...
>>>
>>> res = fact(3)
>>> print(res)
6

 

posted @ 2016-05-21 19:29  每天进步一点点!!!  阅读(1518)  评论(0编辑  收藏  举报