推导式

介绍:在Python中有一种特有的语法,就是推导式(又称为解析式)。推导式是可以从一个数据序列构建另一个新的数据序列的结构体。
分类:列表(list)推导式、字典(dict)推导式、集合(set)推导式

列表推导式

基本语法:[out_express for out_express in input_list]
在未学习列表推导式的时候,实现对1-20之间每个数除以2的结果形成的新列表

  1. list1 = []
  2. for i in range(1, 21):
  3. list1.append(i / 2)
  4. print(list1)

使用列表推导式后的代码如下:

  1. s = [i / 2 for i in range(1, 21)]
  2. 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]

  1. lst = [6, 2, 6, 7, -15, 8, -17, -10, -15, -4]
  2. new_lst = [i**2 for i in lst if i < 0]
  3. print(new_lst)

嵌套循环推导式的语法为:[i for row inmatrix for i in row]
例如实现生成列表[‘1a’, ‘1b’, ‘1c’, ‘2a’, ‘2b’, ‘2c’, ‘3a’, ‘3b’, ‘3c’]

  1. lst = [i+j for i in '123' for j in 'abc']
  2. print(lst)

字典推导式

基本语法:{out_exp_key:out_exp_value for out_exp in input_list}
例如实现以下列表中的元素与索引,即key-value的形式,li = [“age”,”name”,”gender”]为key

  1. li = ["age", "name", "gender"]
  2. dic = {i: li.index(i) for i in li}
  3. print(dic) # {'age': 0, 'name': 1, 'gender': 2}

集合推导式

基本语法:{out_exp_res for out_exp in input_set}
例如实现生成6个1-100间的元素,并进行去重

  1. import random
  2. s = {random.randint(1,100) for i in range(1, 7)}
  3. print(s)

注意:没有元组推导式 ,而(i for i in range(10)) 返回的是 generator object

迭代器

迭代器指的是迭代取值的工具,迭代器是一个重复的过程,每一次的重复都是基于上一次结果而来,迭代器提供了一种通用的不依赖索引的迭代取值方式。

可迭代对象

可以使用for循环遍历的都是可迭代对象

  • str、list、tuple、dict、set
  • generator,包括生成器和yield的生成器函数

    判断是否迭代

    此方法来验证是否是一个可迭代的对象

  • 是否有内置的iter方法

  • isinstance(obj,Iterable),用法与type()类似

    1. from collections import Iterable
    2. print(isinstance('abc',Iterable)) # True
    3. print(isinstance([1,2,3,4],Iterable)) # True
    4. print(isinstance(123,Iterable)) # False

    迭代器对象

  • 有内置的iter()方法的对象

  • 有内置的next()方法的对象,此方法可以不依赖索引值

注意:可迭代对象不一定是迭代器

  1. li = [1,2,3,4]
  2. print(isinstance(li,Iterator)) # False

iter()

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。那么我们可以用iter()方法将可迭代对象转为迭代器。

  1. li = [1, 2, 3, 4]
  2. lis = iter(li) # 也可以写成 lis = li.__iter__()
  3. print(type(lis)) # <class 'list_iterator'>

注意:

  • 迭代器不可以通过下标取值,而是使用next(){常用}next();此外超出长度会报错
  • next()只能顺延使用,不能逆序使用

    1. li = [1, 2, 3, 4]
    2. lis = iter(li)
    3. prin(lis[1])
    4. # 报错 TypeError: 'list_iterator' object is not subscriptable 迭代器不可通过下标来取值
    5. print(next(lis)) # 也可以写成print(lis.__next__()) 取1
    6. print(next(lis)) # 2
    7. print(next(lis)) # 3
    8. print(next(lis)) # 4
    9. print(next(lis)) # 超出长度,报错 StopIteration

    可迭代对象与迭代器区别

  • 可用于for循环的都是可迭代类型

  • 作用于next()都是迭代器类型
  • list、dict、str等都是可迭代对象但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转为迭代器
  • python中的for循环本质就是通过不断调用next()函数实现的

    生成器

    在python中,一边循环一边计算的机制称为生成器。
    生成器就是在循环的过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,从而节省大量的空间。

    生成器表达式

    生成器表达式来源于列表解析迭代的组合,生成器与列表解析类似,区别是使用()而不是[]。
    1. f = (x for x in range(5))
    2. print(f) # generator object
    3. print(next(f)) # 0
    4. print(next(f)) # 1
    5. print(next(f)) # 2
    6. print(next(f)) # 3
    7. print(next(f)) # 4
    8. print(next(f)) # 超出长度,报错 StopIteration 生成器也是可迭代对象

    生成器函数

    当函数中含有yield关键字时,这个函数是一个generator。调用函数就是意味着创建了一个对象,它的工作原理就是通过重复调用next()next()方法,直到捕捉一个异常。

例1:实现自定义长度的列表

  1. # 不使用生成器函数
  2. def yield_test(number):
  3. n = 0
  4. li = []
  5. while n < number:
  6. li.append(n)
  7. n += 1
  8. print(li)
  9. yield_test(10)
  10. # 使用生成器函数
  11. def yield_test(number):
  12. n = 0
  13. while n < number:
  14. yield n # 在函数中加入yield,该函数就变为生成器函数
  15. n += 1
  16. res = yield_test(10)
  17. print(next(res))
  18. print(res.__next__())

例2:定义斐波那契数列的函数,特征:除了第一个和第二个数之外,任何一个数都可以由前两个数相加而成。

  1. def CreateNums():
  2. print('-----func start-----')
  3. a, b = 0, 1
  4. for i in range(5):
  5. print('---1---')
  6. yield b
  7. print('---2---')
  8. a, b = b, a + b
  9. print('---3---')
  10. return('-----func end-----')
  11. g = CreateNums()
  12. print(next(g)) # 打印---1--- 1,yield将b返回,并返回到next(g)
  13. 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

  1. <a name="Au4Wx"></a>
  2. ## 生成器与迭代器
  3. - 生成器能做到迭代器能做的所有事
  4. - 而且因为生成器自动创建了iter()和next()方法,生成器显得简洁,而且高效。
  5. <a name="tFFPQ"></a>
  6. # 面向对象编程
  7. <a name="sSzMO"></a>
  8. ## 面向对象编程介绍
  9. 面向对象编程:Object Oriented Programming,简称OOP,是一种程序设计思想。<br />所谓面向对象的语言,就是语言中所有的操作者都是通过对象来进行的
  10. <a name="TEh9p"></a>
  11. ## 面向过程与面向对象的区别
  12. - 面向过程
  13. - 面向过程指的是将程序分成一个个步骤,并按照每个步骤来完成程序
  14. - 这种方式往往只适用一个功能,复用性较低
  15. - 关注的是每一个过程、细节,而不是对象
  16. - 面向对象
  17. - 面向对象编程,关注的是对象,而不注重过程
  18. - 减少重复代码的重写过程
  19. <a name="W6iBJ"></a>
  20. ## 面向对象的概念与术语
  21. - **类(Class)**: 用来描述具有相同属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。其中的对象被称作类的实例。
  22. - **对象**:也称实例。通过类定义的初始化方法,赋予具体的值,成为一个"有血有肉的实体"。
  23. - **实例化**:创建类的实例的过程或操作。
  24. - **实例变量**:定义在实例中的变量,只作用于当前实例。
  25. - **类变量**:类变量是所有实例公有的变量。类变量定义在类中,但在方法体之外。
  26. - **数据成员**:类变量、实例变量、方法、类方法、静态方法和属性等的统称。
  27. - **方法**:类中定义的函数。
  28. - **静态方法**:不需要实例化就可以由类执行的方法
  29. - **类方法**:类方法是将类本身作为对象进行操作的方法。
  30. - **方法重写**:如果从父类继承的方法不能满足子类的需求,可以对父类的方法进行改写,这个过程也称override。
  31. - **封装**:将内部实现包裹起来,对外透明,提供api接口进行调用的机制
  32. - **继承**:即一个派生类(derived class)继承父类(base class)的变量和方法。
  33. - **多态**:根据对象类型的不同以不同的方式进行处理。
  34. <a name="5592560e"></a>
  35. # 类与对象
  36. <a name="AGASJ"></a>
  37. ## 类和对象
  38. 类是用来描述具有相同属性和方法的对象的集合。<br />对象是指某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的。
  39. 类的构成:
  40. - 类的名称:类名
  41. - 类的属性:一组数据
  42. - 类的方法:允许对类进行操作的方法
  43. python中常用class来表示类,它的语法为
  44. ```python
  45. class 类名:
  46. 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()

注意:

  1. init()方法可以返回值,但必须是None;
  2. init()方法中声明的属性,可以在类的外部通过对象来访问;
  3. 要定义的方法中定义对象的属性,需要注意先调用指定该方法,才会将属性封装到对象中,即可访问。

    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']
  1. 求(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'}