python3学习05---迭代器,函数

昨天玩了一会儿,文章忘更新了2333 补上

# 迭代器与生成器

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

list1=[1,2,3,4,5,6,7]
print(iter(list1)) # 得到一个迭代器对象 
it=iter(list1)
#可以遍历迭代器得到元素对象
for x in it:
    print(x,end=",")

#也可以用next函数获取
# print(next(it)) #有异常,print(next(it)) StopIteration
#因为it在上面已经被遍历完了
# 可以看出  当迭代器无法遍历后,后抛出StopIteration异常
print()
list2=[1,5,6,7,8,9,4]
it=iter(list2)
# 我们可以利用异常来结束迭代
while True:
    try:
        print(next(it),end=",")
    except StopIteration:
        print("遍历完成,结束循环")
        break;
# 1,5,6,7,8,9,4,遍历完成,结束循环
#这里用到了 try except 的异常处理  有点类似于try catch  finally 到时候到对应章节再学习

# 创建一个迭代器
#这里涉及到了面向对象的概念,有java基础的 基本不会陌生

#这里创建一个返回数字的迭代器,初始值为1,逐步加1
class MyNumbers:
    def __iter__(self):
        self.a=1
        return self
    def __next__(self):
     #增加迭代技术标识
        if self.a<=5:
            x=self.a
            self.a+=1
            return x
        else:
            raise StopIteration
mycalss=MyNumbers()
myiter=iter(mycalss)
print(next(myiter)) #1
print(next(myiter)) #2
print(next(myiter)) #3
print(next(myiter)) #4
print(next(myiter)) #5
# print(next(myiter)) #     raise StopIteration StopIteration


#生成器  yield

#用斐波拉切数列来理解yield
# 普通方法
def fab(max):
    n,a,b=0,0,1
    while n<max:
        print(b,end=",")
        a,b=b,a+b
        n=n+1
fab(5) #1,1,2,3,5,
'''
结果没有问题,但有经验的开发者会指出,直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。
要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List。以下是 fab 函数改写后的第二个版本
'''
# 用list代替代码中输出
print()
print(" list 版本")
def fab(max):
    n,a,b=0,0,1
    list=[]
    while n<max:
        list.append(b)
        a,b=b,a+b
        n=n+1
    return list
for n in fab(5):
    print(n,end=",")
#1,1,2,3,5,

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

利用 iterable 我们可以把 fab 函数改写为一个支持 iterable 的 class,
利用迭代器,可以减少内存消耗
'''
print()
print("class 版本")
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
for n in fab(5):
    print(n,end=",")

'''
用了clss版本的,虽然减少了内存占用 但是明显编码复杂度提示了
所以用到了yield
'''
print()
print("yield 版本")
def fab(max):
    n,a,b=0,0,1
    while n<max:
        yield b
        a,b=b,a+b
        n=n+1
for n in fab(5):
    print(n,end=",")
'''
简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,
Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!
在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,
下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield
'''

# 函数
'''
函数的规则
1.函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
2.任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
3.函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
4.函数内容以冒号 : 起始,并且缩进。
5.return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。
'''

#和java中的方法差不多 ,但没有那么严格的限制
#没有明确的返回值类型,参数列表中的参数类型也没有定死,也没有访问修饰符
#有点类似于 js

#定义几个简单的函数

#无参数 无返回值的
def hello():
    print("hello world")
hello() # hello world


#有参数,无返回值的
def getSum(a,b):
    print(a+b)

getSum(10,15) #25

#无参数 有返回值的
def getConfig():
    return "config.xml"
a=getConfig();
print(a) #config.xml

#有参数 有返回值的
def getMax(list):
    return max(list)

list=[1,2,3,4,5,6,7,8]
print(getMax(list)) # 8


#参数传递
'''
python中的参数传递
不可变类型:字符串strings,元组tuples,数字numbers ,传递的只是a的值,没有影响a本事,如果在函数内修改了a的值,则是生成了一个新的a对象
可变类型:列表list,字典dict,set集合 是将真正的a传递过去,修改后外部的a也会受影响
'''

# 传递不可变对象
def change(a):
    print("进入方法,改变a的值前",id(a)) #查看a的地址 3058149517616
    a=10
    print("改变a的值后",id(a)) #查看a的地址 3058149517904
a=1
print("调用方法前",id(a)) #查看a的地址 3058149517616
change(a)
print("方法结束",id(a)) # 3058149517616
print(a) # 1
# 可以看见在调用函数前后,形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,形参指向的是不同的 id。

#传递可变对象
def changeList(list):
    print("进入方法,改变list的值之前:",id(list)) #进入方法,改变list的值之前: 2731559237120
    list.append([8,8,4,8])
    print("修改list的值后:",id(list)) #修改方法结束: 2731559237120
    return
list=[1,2,3,4]
print("进入方法前:",id(list)) # 进入方法前: 2731559237120
changeList(list)
print("修改方法结束:",id(list)) #修改方法结束: 2731559237120
print(list) #[1, 2, 3, 4, [8, 8, 4, 8]]
#可见原参数也被修改了


# 参数类型
'''
必须参数  必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
关键字参数 关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
默认参数 调用函数时,如果没有传递参数,则会使用默认参数。
不定长参数 你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述 2 种参数不同,声明时不会命名。
'''

#必要参数
def printme(str):
    print(str)
    return
# printme() # TypeError: printme() missing 1 required positional argument: 'str'必须要穿参数 不然报错
printme(123) # 123

#关键字参数 传入关键字参数会根据参数名匹配,可以不保持顺序一致
def printme(str):
    print(str)
    return
printme(str="你好") # 你好


#默认参数
def printName(name="zxy"):
    print(name)
printName(); # zxy
printName("send name") # send name


# 不定长参数

# 加了 * 的参数会以元组的形式导入,存放所有未命名的变量参数
def printInfo(arg1,*args):
    print(arg1,args)
printInfo(10) # 10 ()
printInfo(10,20,40,50) # 10 (20, 40, 50)

#发现,如果没有传入不定长参数的时候 会输出一个()空元祖,可以加一些处理防止这种情况
def printInfo(*args):
    for x in args:
        print(x,end=",")
printInfo() # 什么都没有输出 而且不会报错
printInfo(10,2,0,3,5) # 10,2,0,3,5,

# 带两个 **号的不定长参数   加了两个星号 ** 的参数会以字典的形式导入
print()
def printInfo(**kwargs):
    print(kwargs)
# printInfo(1,2,3) #TypeError: printInfo() takes 0 positional arguments but 3 were given
printInfo(a=1,b=2,c=3,d=4)
#{'a': 1, 'b': 2, 'c': 3, 'd': 4}
#注意两个**的参数要用这种传递方式 指定键(等号前)和值(等号后)

#声明函数时,参数中星号 * 可以单独出现 但*号后的参数必须以关键字传入
def printMe(a,b,* args,c):
    print(a,b,args,c)
# printMe(1,2,3) # TypeError: printMe() missing 1 required keyword-only argument: 'c'
printMe(1,2,c=3) # 1 2 () 3


#匿名函数
'''
python 使用 lambda 来创建匿名函数。
所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。
lambda 只是一个表达式,函数体比 def 简单很多。
lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
'''
# 我想以java中 lambda中来理解 但好像又不太像
# 一般是简化代码 封装有限的逻辑代码进去
sum=lambda arg1,arg2:arg1+arg2
print(sum(1,2)) # 3

# return 语句 其实java写多了这个就很熟悉了 要注意的点是 python不是null 而是None

# python 3.8 出现了强制位置参数 /
#   / 用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。

def f(a,b,c,/,d,*,e,f):
    print("test")
f(10,20,30,20,e=40,f=50) # test
# f(e=40,f=50,a=30,c=60,b=50,d=100) # TypeError: f() got some positional-only arguments passed as keyword arguments: 'a, b, c'

#递归函数
def f(a):
    if a==1:
       return 1
    else:
        return a+f(a-1)

print(f(5))
# python3 中的数据结构

# 将列表当做栈来使用
'''
栈结构  后进先出
'''
stack=[1,2,3,4]
#压栈
stack.append(5)
stack.append(6)
print(stack) # [1, 2, 3, 4, 5, 6]
#弹栈
print(stack.pop()) # 6
print(stack.pop()) # 5
print(stack) # [1, 2, 3, 4]

#将列表当做队列使用
'''
队列结构 先进先出
这边需要引入deque
'''
from collections import deque
queue=deque([1,2,3,4])
# 入队
queue.append(5)
queue.append(6)
print(queue) # deque([1, 2, 3, 4, 5, 6])
#出队 因为先进先出 所以从左边开始移出元素
print(queue.popleft()) # 1
print(queue.popleft()) # 2
print(queue) # deque([3, 4, 5, 6])

#列表推导式
vec=[3,4,6]
print([3*x for x in vec]) # [9, 12, 18]
print([x for x in vec if x>3]) # [4, 6]

#实例应用 去除空格
text_list=['   zxy   ',' 888 ',' hi ,this is a table    ']
a=[ x.strip() for x in text_list]
print(a) # ['zxy', '888', 'hi ,this is a table']

# 遍历技巧

#字典 可以利用items获取键和值
dict={
     'name':'zxy','age':18}
for k,v in dict.items():
    print(k,v)
#name zxy
#age 18

# 同时遍历多个序列 zip
for q,a in zip([1,2,3,4],[8,9,10,'j','q','k']):
    print(f"我出了{q},他出了{a}")

    # 我出了1, 他出了8
    # 我出了2, 他出了9
    # 我出了3, 他出了10
    # 我出了4, 他出了j


# 反向遍历 reversed
for i in reversed(range(1,10,2)):
    print(i,end=",")
# 9,7,5,3,1,

#排序函数  使用 sorted() 函数返回一个已排序的序列,并不修改原值
for i in sorted([8,9,10,1,6,7]):
    print(i,end=",")
print() # 1,5,8,8,9,10,67,
a=[8,9,10,1,5,67,8]
for i in sorted(a):
    print(i,end=",")
print()
print("a:",a) #a: [8, 9, 10, 1, 5, 67, 8]

你可能感兴趣的:(学习记录,python)