高级编程(1)
推导式
1、最简单的推导式
案例:创建列表[0.5,1,1.5,2,2.5,3,3.5,4]
实现方法1:不使用推导式
li=[]
for i in range(1,9):
li.append(i/2)
print(li)
实现方法2:使用推导式,一行命令即实现
print([i/2 for i in range(1,9)])
2、带条件的推导式
案例:取出列表[1, 2, 3, -4, 5, -6, 7, -8, 9]中负数的所有元素,并对取出的元素作平方运算
实现方法1:不使用推导式
li1=[1,2,3,-4,5,-6,7,-8,9]
li2=[]
for i in li1:
if i<0:
li2.append(i**2)
print(li2)
# 实现方法2:使用推导式,一行命令即实现
print([i**2 for i in li1 if i<0])
3. 推导式三目运算
案例:30以内所有能被3整除的数的变为平方,否则乘以2
如果使用for循环实现,中间还要加上IF语句才能实现,需要较多代码,但用推导式一行即实现
print([i^2 if i % 3 == 0 else i*2 for i in list(range(31))])
#4. 推导式嵌套
案例:在实现两字符串上各取出一个字符,并对这两个字符合并成一个元素,求出合并后的所有可能元素。
实现方法1:不使用推导式
li3=[]
for i in '123':
for j in 'abc':
li3.append(i+j)
print(li3)
实现方法2:使用推导式,一行命令即实现
print([i+j for i in '123' for j in 'abc'])
迭代器:
迭代器指的是迭代取值的工具,迭代是指一个重复的过程,每一次重复都是基于上次结果而来来迭代提供了一种通用的不依赖索引的迭代取值方式
我们从列表中取出各元素值,我们常通过列表的下标来取,或者通过for循环来取。for循环就是典型的迭代。
可迭代对象(iterable)
可以用for循环遍历的对象都是可迭代对象
1、str, list, tuple, dict, set 等都是可迭代对象
2、generator(生成器和yield的生成器函数)也是可迭代对象
判断是否可迭代对象
1、查看类中是否含有__iter__()方法来判断其是否是一个可迭代对象
2、使用 isinstance(obj, iterable) 判断对象是否可迭代对象
form collections import iterable # 内置模块,不需要PIP安装
例如:print(isinstance("abc",iterable)) # 结果True
例如:print(isinstance(123,iterable)) # 结果False
迭代器特性:
1、有内置的__iter__()方法的对象,执行迭代器的__iter__()方法得到的依然是迭代器本身
2、有内置的__next__()方法的对象,执行该方法可以不依赖索引取值
from collections import iterator
例如:print( isinstance('abc', iterator) ) #False ,列表是可迭代对象,但不是迭代器
iter()
将可迭代对象转为迭代器
li = [1, 2, 3, 4]
lis1 = li.__iter__()
lis2 = iter(li)
print( type(li) ) # <class 'list'> 列表
print( type(lis1) ) # <class 'list_interator'> 列表迭代器了
print( type(lis2) ) # <class 'list_interator'> 列表迭代器了
如果是迭代器对象,如何取值
1、迭代器不能通过下标取值
2、用__next__()依次取值,超出长度时报错
print( lis1.next() ) # 取出1
print( lis1.next() ) # 取出2
print( lis1.next() ) #取出3
print( lis1.next() ) # 取出4
print( lis1.next() ) #报错:stopIteration
3、也可通过next()方法取值,效果与__next__()效果一样,通常使用此方法
4、for循环取值
for i in lis1: print(i) # 从头遍历对象所有元素,结束时也不会报错
5、迭代器取值只能顺延调用,不能逆序或随机取值
可迭代对象与迭代器区别
1、可用于for循环的都是可迭代类型
2、作用于next()都是迭代器类型
3、list、dict、str等都是可迭代的但不是迭代器,因为next()函数无法调用它位,可通过iter()函数将它位转为迭代器
4、for循环本质就是通过不断调用next()函数实现的
迭代器的作用
列表是把所有元素都创建了(消耗内存),而迭代器则是使用时才创建(节省内存)
生成器
在Python中,一边循环一边计算的机制称为生成器:generator
为什么有生成器呢
例如:[0,1,2,3,4,5,6,7,8,9,10…n]
这是一个无限大的列表内存消耗极大,如一次要用到这么多元素没话说,如一次只需要使用一部分那就浪费了内存
生成器就是在循环的过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,从而节省大量的空间
如何创建生成器
生成器表达式
生成器表达式来源于 迭代 和 列表解析 的组合,生成器和列表解析类似,但是它使用()而不是[]。
g = ( i for i in range(5)) # 这个看上去非常像推导式,只是用()而不是[]
print( type(g) )
print( g[0] ) # 报错,说明生成器不能用下标取值
print( next(g) )
print( next(g) ) # next()超出长度会报错 StopIteration
for i in g:
print(i)
if i > 3 :
break
生成器函数
需求:生成一个自定义长度的列表
实现方法1:不采用生成器函数实现
def yield_test(number):
n = 0
li =[]
while n<number:
li.append(n)
n += 1
print(li)
yield_test(20000)
直接生成所有的列表元素会很耗内存的
实现方法2:在函数中加入yield,该函数就变成了生成器
def yield_test(number):
n = 0
# li =[]
while n<number:
# li.append(n)
yield n
n += 1
# print(li)
res = yield_test(20000)
print(res) # 这是一个生成器对象,现要访问这个生成器对象时,可用next()方法取数,也可用循环去做
注意:yield返回一个值,并且记住这个返回值的位置,下次遇到next()调用时,代码从yield的下一条语句开始执行。
与return的差别是,return也是返回一个值,但是直接结束函数
# 案例:斐波那契数列:除了第一个与第二个数以外,任何一个数都可以由前两个相加得到
def createnums():
print('---start-----')
a, b = 0, 1
for i in range(5):
print('--1--')
yield b
print('--2--')
a, b = b, a + b
print('---end------')
g = createnums();
print(next(g)) # 打印'--1--', 1 yeild将b给返回,返回给next(g)
print(next(g)) # 遇到第二个next(g),会接着上一次yield下面的代码继续执行
print(next(g))
print(next(g))
print(next(g))
print(next(g))
return与yield对比:
1、return: 函数的返回值,当函数代码执行到return时,就退出了函数,也就是说,return下面的代码都不会再执行。
2、yield: 是将函数变为生成器关键字,将值返回到next(g),只不过再遇到下一个next(g)的时候,会接着上一次执行的代码继续执行。
send()
send() 和 next() 一样,都能让生成器继续往下走一步(遇到yield返回),但send()能传一个值,这个值作为yield表达式整体的结果
案例:
def yield_test():
a1 = yield "hello"
yield a1
g = yield_test()
print(next(g)) # 结果hello
print(g.send('world')) # 结果world
代码解析:
1、赋值符是从右到左执行,所以执行第一个yield时,并没有执行 a1= 这边的操作
2、执行send()时,执行a1=操作,而此时传来了'world'值,所以a1='world'了,
再执行yield a1这行,故此时输出"world"了
** 非空的值不能作为启动生成器的对象, send(None) 相当于 next()
迭代器与生成器
1、生成吕能做到迭代器能做的所有事
2、因为生成器自动创建了iter() 和next()方法,生成器显得简洁,而且高效
面向对象
类的构成
类由3个部分构成:
1、类的名称:类名
2、类的属性:一组数据
3、类的方法:允许对类进行操作的方法
类的定义
python使用class关键字来定义类,其基本结构如下:
class MyClass: # 类的命名规则一般采用大驼峰规则
pass
print(MyClass)
运行结果 》》》
<class '__main__.MyClass'>
创建对象
python中,可以根据已经定义的类去创建出一个个对象
obj_name = MyClass() # 将类赋值对一个变量,实际就是创建了对象
mc = MyClass() # 创建对象也称呼为类的实例化
print(mc, type(mc))
运行结果 》》》
<__main__.MyClass object at 0x000001DAC2C357B8> <class '__main__.MyClass'>
检测对象是不是此类的对象
使用isinstance检测一个对象是不是这个类的对象,在以后我们可能会写很多的类,也会创建很多对象,可能自己都不知道哪个对象是哪个类的,所以检测显得尤为重要。是则返回True,不是则返回Flase
# 接上述实例
r = isinstance(mc, MyClass)
print(r)
运行结果 》》》
True
类的使用
python中万物皆对象,所以类也是一个对象喔!!
class MyClass():
pass
print(id(MyClass), type(MyClass))
运行结果 》》》
1571347124712 <class 'type'>
可以发现我们创建的类MyClass是type来管理的,且它也是一个对象
使用类创建方法
class Person():
name = '张三' # 数据 (属性)
def like(w): # 能做什么事情 行为 (方法)
print('python')
p1 = Person()
p2 = Person()
p1.name = '张三2' # 这是给实例对象添加属性的方式
print(p1.name)
print(p2.name)
p1.like() # 方法的使用
运行结果 》》》
李明
张三
直接看这个可能不太好理解,让我们看一个简单的。
a = 'python1'
print(a.split('1'))
运行结果 》》》
['python', '']
这里我们就用到了str的类,给a赋值的时候等于创建了一个对象(实例),
然后用split方法对实例进行操作,我们自己创建的方法就跟这个差不多。
例如我们上面创建了一个like的方法,然后我们就可以使用这个方法。