推导式
介绍:在Python中有一种特有的语法,就是推导式(又称为解析式)。推导式是可以从一个数据序列构建另一个新的数据序列的结构体。
分类:列表(list)推导式、字典(dict)推导式、集合(set)推导式
列表推导式
基本语法:[out_express for out_express in input_list]
在未学习列表推导式的时候,实现对1-20之间每个数除以2的结果形成的新列表
list1 = []
for i in range(1, 21):
list1.append(i / 2)
print(list1)
使用列表推导式后的代码如下:
s = [i / 2 for i in range(1, 21)]
print(s)
可见,当使用列表推导式后,大大简化了代码。
当列表推导式还需要满足某条件下才输出表达式时,可以通过以下语法规范实现:[out_express for out_express in input_list if out_express_condition]
例如将列表将li列表中小于0的元素开方并且保存到新列表中。li = [6, 2, 6, 7, -15, 8, -17, -10, -15, -4]
lst = [6, 2, 6, 7, -15, 8, -17, -10, -15, -4]
new_lst = [i**2 for i in lst if i < 0]
print(new_lst)
嵌套循环推导式的语法为:[i for row inmatrix for i in row]
例如实现生成列表[‘1a’, ‘1b’, ‘1c’, ‘2a’, ‘2b’, ‘2c’, ‘3a’, ‘3b’, ‘3c’]
lst = [i+j for i in '123' for j in 'abc']
print(lst)
字典推导式
基本语法:{out_exp_key:out_exp_value for out_exp in input_list}
例如实现以下列表中的元素与索引,即key-value的形式,li = [“age”,”name”,”gender”]为key
li = ["age", "name", "gender"]
dic = {i: li.index(i) for i in li}
print(dic) # {'age': 0, 'name': 1, 'gender': 2}
集合推导式
基本语法:{out_exp_res for out_exp in input_set}
例如实现生成6个1-100间的元素,并进行去重
import random
s = {random.randint(1,100) for i in range(1, 7)}
print(s)
注意:没有元组推导式 ,而(i for i in range(10)) 返回的是 generator object
迭代器
迭代器指的是迭代取值的工具,迭代器是一个重复的过程,每一次的重复都是基于上一次结果而来,迭代器提供了一种通用的不依赖索引的迭代取值方式。
可迭代对象
可以使用for循环遍历的都是可迭代对象
- str、list、tuple、dict、set
-
判断是否迭代
此方法来验证是否是一个可迭代的对象
是否有内置的iter方法
isinstance(obj,Iterable),用法与type()类似
from collections import Iterable
print(isinstance('abc',Iterable)) # True
print(isinstance([1,2,3,4],Iterable)) # True
print(isinstance(123,Iterable)) # False
迭代器对象
有内置的iter()方法的对象
- 有内置的next()方法的对象,此方法可以不依赖索引值
注意:可迭代对象不一定是迭代器
li = [1,2,3,4]
print(isinstance(li,Iterator)) # False
iter()
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。那么我们可以用iter()方法将可迭代对象转为迭代器。
li = [1, 2, 3, 4]
lis = iter(li) # 也可以写成 lis = li.__iter__()
print(type(lis)) # <class 'list_iterator'>
注意:
- 迭代器不可以通过下标取值,而是使用next(){常用}或next();此外超出长度会报错
next()只能顺延使用,不能逆序使用
li = [1, 2, 3, 4]
lis = iter(li)
prin(lis[1])
# 报错 TypeError: 'list_iterator' object is not subscriptable 迭代器不可通过下标来取值
print(next(lis)) # 也可以写成print(lis.__next__()) 取1
print(next(lis)) # 2
print(next(lis)) # 3
print(next(lis)) # 4
print(next(lis)) # 超出长度,报错 StopIteration
可迭代对象与迭代器区别
可用于for循环的都是可迭代类型
- 作用于next()都是迭代器类型
- list、dict、str等都是可迭代对象但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转为迭代器
- python中的for循环本质就是通过不断调用next()函数实现的
生成器
在python中,一边循环一边计算的机制称为生成器。
生成器就是在循环的过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,从而节省大量的空间。生成器表达式
生成器表达式来源于列表解析和迭代的组合,生成器与列表解析类似,区别是使用()而不是[]。f = (x for x in range(5))
print(f) # generator object
print(next(f)) # 0
print(next(f)) # 1
print(next(f)) # 2
print(next(f)) # 3
print(next(f)) # 4
print(next(f)) # 超出长度,报错 StopIteration 生成器也是可迭代对象
生成器函数
当函数中含有yield关键字时,这个函数是一个generator。调用函数就是意味着创建了一个对象,它的工作原理就是通过重复调用next()或next()方法,直到捕捉一个异常。
例1:实现自定义长度的列表
# 不使用生成器函数
def yield_test(number):
n = 0
li = []
while n < number:
li.append(n)
n += 1
print(li)
yield_test(10)
# 使用生成器函数
def yield_test(number):
n = 0
while n < number:
yield n # 在函数中加入yield,该函数就变为生成器函数
n += 1
res = yield_test(10)
print(next(res))
print(res.__next__())
例2:定义斐波那契数列的函数,特征:除了第一个和第二个数之外,任何一个数都可以由前两个数相加而成。
def CreateNums():
print('-----func start-----')
a, b = 0, 1
for i in range(5):
print('---1---')
yield b
print('---2---')
a, b = b, a + b
print('---3---')
return('-----func end-----')
g = CreateNums()
print(next(g)) # 打印---1--- 1,yield将b返回,并返回到next(g)
print(next(g)) # 遇到第二个next(g),会接着上一次的yield下面的代码继续执行
return与yield
- return:函数的返回值,当函数执行到return时,就退出了函数,即return下面的代码都不执行
- yield:将函数变为生成器关键字,将值返回到next(g),只不过下一次再遇到next(g)的时候,会接着上一次执行的代码继续执行。
send()
send() 和 next() 一样,都能让生成器继续向前走一步(遇到 yield 返回),但 send() 能传一个值,这个值作为 yield 表达式整体的结果。 ```python def test():1.赋值运算符从右往左
a1 = ‘hello’ # 2. a1 = ‘world’ yield a1 # 3. 将a1返回到send处
res = test() print(next(res)) print(res.send(‘world’))
print(res.send(‘world’)) # 注意:当yield已经返回完,那么再使用next()或者send()会报错
print(res.send(‘world’)) # 非空值不能作为生成器启动对象 print(res.send(None’)) # 相当于执行了next
<a name="Au4Wx"></a>
## 生成器与迭代器
- 生成器能做到迭代器能做的所有事
- 而且因为生成器自动创建了iter()和next()方法,生成器显得简洁,而且高效。
<a name="tFFPQ"></a>
# 面向对象编程
<a name="sSzMO"></a>
## 面向对象编程介绍
面向对象编程:Object Oriented Programming,简称OOP,是一种程序设计思想。<br />所谓面向对象的语言,就是语言中所有的操作者都是通过对象来进行的
<a name="TEh9p"></a>
## 面向过程与面向对象的区别
- 面向过程
- 面向过程指的是将程序分成一个个步骤,并按照每个步骤来完成程序
- 这种方式往往只适用一个功能,复用性较低
- 关注的是每一个过程、细节,而不是对象
- 面向对象
- 面向对象编程,关注的是对象,而不注重过程
- 减少重复代码的重写过程
<a name="W6iBJ"></a>
## 面向对象的概念与术语
- **类(Class)**: 用来描述具有相同属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。其中的对象被称作类的实例。
- **对象**:也称实例。通过类定义的初始化方法,赋予具体的值,成为一个"有血有肉的实体"。
- **实例化**:创建类的实例的过程或操作。
- **实例变量**:定义在实例中的变量,只作用于当前实例。
- **类变量**:类变量是所有实例公有的变量。类变量定义在类中,但在方法体之外。
- **数据成员**:类变量、实例变量、方法、类方法、静态方法和属性等的统称。
- **方法**:类中定义的函数。
- **静态方法**:不需要实例化就可以由类执行的方法
- **类方法**:类方法是将类本身作为对象进行操作的方法。
- **方法重写**:如果从父类继承的方法不能满足子类的需求,可以对父类的方法进行改写,这个过程也称override。
- **封装**:将内部实现包裹起来,对外透明,提供api接口进行调用的机制
- **继承**:即一个派生类(derived class)继承父类(base class)的变量和方法。
- **多态**:根据对象类型的不同以不同的方式进行处理。
<a name="5592560e"></a>
# 类与对象
<a name="AGASJ"></a>
## 类和对象
类是用来描述具有相同属性和方法的对象的集合。<br />对象是指某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的。
类的构成:
- 类的名称:类名
- 类的属性:一组数据
- 类的方法:允许对类进行操作的方法
python中常用class来表示类,它的语法为
```python
class 类名:
pass
注意:类名通常采用驼峰命名法
例如:创建一个类为逻辑 对象为千尼,在类中定义方法输出:千尼好腻害
class Logic:
def test(self):
print('千尼好腻害')
qianni = Logic() # 创建对象,并将对象赋值给qianni,即创建了qianni这个对象
qianni.test() # 调用类中的方法 对象.方法名()
self参数
self本身是形参,self指的就是对象本身
class LogicStudent:
def test_one(self):
print(self)
N_stu = LogicStudent()
print(N_stu) # <__main__.LogicStudent object at 0x0000026950878400>
N_stu.test_one() # <__main__.LogicStudent object at 0x0000026950878400>
# 这里提现了N_stu和self是同一个对象
class People:
def test_infor(self):
print(self.name,self.age)
x_stu = People()
x_stu.name = '小胖'
x_stu.age = 20
x_stu.test_infor()
f_stu = People()
f_stu.name = '海绵宝宝'
f_stu.age = 221
f_stu.test_infor()
"""
第三行中打印结果是 小胖 20 海绵宝宝 21,当self改成x_stu则是 小胖 20,改成f_stu是 海绵宝宝 221
不允许改成不同的对象如 x_stu.name,f_stu.age
"""
- self在定义时需要定义,但是在调⽤时会⾃动传⼊
- self的名字并不是规定死的,但是最好还是按照约定是⽤self
- self总是指调⽤时的类的实例
init()方法
init()方法称初始化方法,也称构造方法。在创建对象后会自动执行该方法,为对象的属性设置初始值。
演示其执行的过程: ```python class Student: def init(self):print('--1--')
s = Student() print(‘—2—‘)
上述打印的顺序分别是1 2<br />将涉及小胖 20的程序进行优化,得:
```python
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def infor(self):
print(self.name, self.age)
s = People('小胖', 19)
s.infor()
f = People('发糕', 33)
f.infor()
注意:
- init()方法可以返回值,但必须是None;
- init()方法中声明的属性,可以在类的外部通过对象来访问;
要定义的方法中定义对象的属性,需要注意先调用指定该方法,才会将属性封装到对象中,即可访问。
str()方法
str()方法在开发中能够打印自定义的内容,将自定义内容通过return返回(返回值必须是字符串)。 ```python class People: def init(self, name, age):
self.name = name self.age = age
def str(self):
return self.name # 注意返回的必须是字符串
res = People(‘小胖’,19) print(res) # 小胖
<a name="wRJSL"></a>
# 练习
1. 过滤掉该列表names = ["jerry","hansen","Amy","Wendy","Tom","Bob"]长度小于或等于3的字符串列表,并将剩下的转换成大写字母。
```python
names = ["jerry","hansen","Amy","Wendy","Tom","Bob"]
lst = [s.upper() for s in names if len(s) > 3]
print(lst) # ['JERRY', 'HANSEN', 'WENDY']
- 求(x,y),其中x是0-5之间的偶数,y是0-5之间的奇数组成的元组列表。效果如下:[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
```python
方法一
tu = {(x, y) for x in range(0, 5, 2) for y in range(1, 5, 2)} print(tu)
方法二
tu = {(x, y) for x in range(5) if x % 2 == 0 for y in range(1, 5, 2) if y % 2 == 1} print(tu)
3. [ 'Bob', 'JOHN', 'alice', 'bob', 'ALICE', 'James', 'Bob','JAMES','jAMeS' ] 该列表很紊乱,实现去重,以及将名字格式统一成首字母大写(str.capitalize())
```python
names_02 = ['Bob', 'JOHN', 'alice', 'bob', 'ALICE', 'James', 'Bob', 'JAMES', 'jAMeS']
print({name.capitalize() for name in names_02}) # {'James', 'John', 'Alice', 'Bob'}