一、闭包函数

  • 函数对象:可以将定义的函数内的函数返回全局使用,从而打破函数的层级限制。

  • 名称空间与作用域:作用域关系在定义函数阶段时就已经固定死了,与调用位置无关,即在任意位置调用函数都需要跑到定义函数是找到作用域关系。

1、1什么是闭包

闭包:闭是封闭(函数内部的函数)。包是包含(该函数内部对外部作用域二非全局作用域的变量的引用)。闭包指的是:函数内部函数对外部作用域二非全局作用域的引用。

1、1、1 两种为函数传参的方式

1. 使用参数的形式

def func(x):
   print(x)
func(1)
func(1)
func(1)

结果:

1

1

1

2.包给函数

def outter(x):
   x = 1
   def inner():
       print(x)
    return inner
f = outter(1)
f()
f()
f()
#查看闭包元素
print(f"f.__closeure__[0].cell_comtents:{f.__closure__[0].cell_contents}")

运行结果:

1

1

1

f.__closeure__[0].cell_comtents:1

1.2闭包函数的应用

闭包的意义:返回的函数对象,不仅仅是一个个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。

应用领域:延迟计算(原来我们传参数,现在我们是包起来)、爬虫领域。

import requests


def get(url):
   response = requests.get(url)
   print(f"done: {url}")
   
get('https://www.baidu.com')
get('https://www.baidu.com')
get('https://www.baidu.com')


get('https://www.cnblogs.com/linhaifeng')
get('https://www.cnblogs.com/linhaifeng')
get('https://www.cnblogs.com/linhaifeng')
done: https://www.baidu.com
done: https://www.baidu.com
done: https://www.baidu.com
done: https://www.cnblogs.com/linhaifeng
done: https://www.cnblogs.com/linhaifeng
done: https://www.cnblogs.com/linhaifeng

上面的方式是极其复杂的,我们如果使用默认参数也只能解决一个网址,因此我们可以考虑使用闭包的方式。

import requests
def get_url(url):
   def func():
       res = requests.get(url)
       print(f'{url}')
   return func
baidu = get_url('https://www.baidu.com')
baidu()
baidu()
baidu()

运行结果:

https://www.baidu.com https://www.baidu.com https://www.baidu.com

二、装饰器

2、1无参装饰器

2、1、1 什么是装饰器

器:指的是工具,而程序中的函数就是具备某一功能的工具,所以装饰器指的是为被装饰对象添加额外功能。因此定义装饰器就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能。

需要注意的是:

  • 装饰器本身其实是可以任意可调用的对象

  • 被装饰的对象也可以是任意可调用的对象

2、1、2 为什么要用装饰器

如果我们已经上线了一个项目,我们需要修改某一个方法,但是我们不想修改方法的使用方法,这个时候可以使用装饰器。因为软件的维护应该遵循开放封闭原则,即软件一旦上线运行后,软件的维护对修改代码是封闭的,对扩展功能指的是开放的。

装饰器的实现必须遵守两大原则:

  1. 不修改被装饰对象的源代码

  2. 不修改被装饰对象的调用方式

装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。

2、1、3怎么使用装饰器

不用装饰器

  1. 改变源代码:

    imimport time


    def index():
       start = time.time()
       print('welcome to index')
       time.sleep(1)
       end = time.time()
       print(F"index run time is {start-end}")


    index()

    运行结果:

    welcome to index index run time is -1.0008180141448975

  2. 编写重复代码:

    import time


    def index():
       print('welcome to index')
       time.sleep(1)


    def f2():
       print('welcome to index')
       time.sleep(1)


    start = time.time()
    index()
    end = time.time()
    print(F"index run time is {start-end}")

    start = time.time()
    f2()
    end = time.time()
    print(F"f2 run time is {start-end}")

    运行结果:

    welcome to index index run time is -1.0046868324279785 welcome to index f2 run time is -1.000690221786499

使用装饰器

  1. 第一种传参方式:改变调用方式

    import time
    def index():
       print('welcome to index')
       time.sleep(1)
    def time_cout(func):
       start = time.time()
       func()
       end = time.time()
       print(f"{func} time is {start-end}")
    time_cout(index)

    运行结果:

    welcome to index <function index at 0x0000000002061E18> time is -1.0

  2. 第二种传参方式:包给函数-外包

    import time
    def index():
       print('welcome to index')
       time.sleep(1)
    def time_cout(func):
       def wra():
           start = time.time()
           func()
           end = time.time()
           print(f"{func} time is {start-end}")
       return wra
    index = time_cout(index)
    index()

运行结果: ​ welcome to index ​ <function index at 0x00000000003C1E18> time is -1.0

2、1、4 完善装饰器

上数的装饰器,最后的调用index()的时候,其实是在调用warpper(),因此如果原始的Index()有返回值的时候,warpper()函数的返回值应该和人index()的返回值相同,也就是说,我们需要同步原始的index()和warpper()d方法的返回值。

import time
def index():
   print('welcome to index')
   time.sleep(1)
   return 123
def time_cout(func):
   def wra():
       start = time.time()
       res = func()
       end = time.time()
       print(f"{func} time is {start-end}")
       return  res
   return wra
index = time_cout(index)
res = index()
print(f'res:{res}')

运行结果:

welcome to index <function index at 0x102977620> time is -1.0050289630889893 res: 123

但是如果原始的index()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有wrapper=index(),所以给wrapper()方法传参即可。

def home(name):
   print(f"welcome {name} to home page")
   time.sleep(1)
   return name
def time_cout(func):
   def wra(*args, **kwargs):
       start = time.time()
       res = func(*args, **kwargs)
       end = time.time()
       print(f"{func} time is {start-end}")
       return  res
   return wra
index = time_cout(home)
res = home('han')
print(f'res:{res}')

运行结果:

welcome han to home page res:han

2、1、5 装饰器语法糖

在被装饰函数正上方,并且是单独一行写上@装饰器名

import time

def time_cout(func):
   def wra(*args, **kwargs):
       start = time.time()
       res = func(*args, **kwargs)
       end = time.time()
       print(f"{func} time is {start-end}")
       return  res
   return wra
@time_cout # home = time_count(home)
def index():
   print('welcome to index')
   time.sleep(1)
   return 123
@time_cout #index = time_cout(index)
def home(name):
   print(f"welcome {name} to home page")
   time.sleep(1)
   return name
res = home('egon')
print(f"res:{res}")

运行结果:

welcome egon to home page <function home at 0x0000000001E7A950> time is -1.0 res:egon

2、1、6 装饰器模板

def deco(func):
   def wrapper(*args, **kwargs):
       res = func(*args, **kwargs)
       return res
   return wrapper

 

2、2 有参装饰器

无参装饰器只套了两层,本节讲的是一个套三层的装饰器-- 有参装饰器,但现在我们先实现一个用户登录注册的装饰器。

import time
currennt_user = {'username':None}

def login(func):
   # func是最原始的index
   def warpper(*args, **kwargs):
       if currennt_user['username']:
           res = func(*args, **kwargs)
           return res
       user = input('username:').strip()
       pwd = input('password:').strip()

       if user == 'nick' and pwd == '123':
           print('login successful')
           currennt_user['user'] = user
           res = func(*args, *kwargs)

           return res
       else:
           print('user or password error')
   return  warpper
@login
def home(name):
   print(f"welcome {name} to home page")
   time.sleep(1)
   return  123
@login
def index():
   print('welcome to index')
   time.sleep(1)
   return 123
res = index()

运行结果:

username:nick password:123 login successful welcome to index

对于上面的登录注册,我们把用户登录成功的信息写入内存中。但是在工业上,用户信息可以存在文本中、mysql中、mongodb当中,但是我们只让用户信息来自于file的用户可以认证。因此我们可以改写上述的装饰器。

import time
currennt_user = {'username':None}

def login(func):
   # func是最原始的index
   def warpper(*args, **kwargs):
       if currennt_user['username']:
           res = func(*args, **kwargs)
           return res
       user = input('username:').strip()
       pwd = input('password:').strip()
       engine = 'file'

       if engine == 'file':
           print('base of file')

           if user == 'nick' and pwd == '123':
               print('login successful')
               currennt_user['user'] = user
               res = func(*args, *kwargs)

               return res
           else:
               print('user or password error')
       elif engine == 'mysql':
           print('base of mysql')
       elif engine == 'mongodb':
           print('base of mongodb')
       else:
           print('default')

   return  warpper
@login
def home(name):
   print(f"welcome {name} to home page")
   time.sleep(1)
   return  123
@login
def index():
   print('welcome to index')
   time.sleep(1)
   return 123
res = index()

运行结果:

username:nick password:123 base of file login successful welcome to index

2、2、1三层闭包

  1. 三层闭包的运行

    def f1(y):
      def f2():
          x = 1
          def f3():
              print(f'x:{x}')
              print(f'y:{y}')
          return f3
      return f2

    f2 = f1(2)
    f3 = f2()
    f3()

    运行结果:

    x:1

    y:2

  2. 现在需求改下,我们需要判断用户动态的获取用户密码的方式,如果是file类型的,我们则让用户进行认证。因此我们可以使用有参装饰器。

     import time
    currennt_user = {'username':None}
    def auth(engine = 'file'):
       def login(func):
           # func是最原始的index
           def warpper(*args, **kwargs):
               if currennt_user['username']:
                   res = func(*args, **kwargs)
                   return res
               user = input('username:').strip()
               pwd = input('password:').strip()


               if engine == 'file':
                   print('base of file')

                   if user == 'nick' and pwd == '123':
                       print('login successful')
                       currennt_user['user'] = user
                       res = func(*args, *kwargs)

                       return res
                   else:
                       print('user or password error')
               elif engine == 'mysql':
                   print('base of mysql')
               elif engine == 'mongodb':
                   print('base of mongodb')
               else:
                   print('default')

           return  warpper
       return login
    @auth(engine='mysql')
    def home(name):
       print(f"welcome {name} to home page")
       time.sleep(1)
       return  123
    @auth(engine='file')
    def index():
       print('welcome to index')
       time.sleep(1)
       return 123
    res = index()

运行结果: username:nick password:123 base of file login successful welcome to index

3、1 装饰器模板

3、1、1双层装饰器

def outter(func):
   def wrapper(*args, **kwargs):  # wrapper是未来要运行的函数
       # 加功能
       res = func(*args, **kwargs)  # func是被装饰的函数
       return res

   return wrapper


@outter
def shopping():
   print('shopping')

 

3、1、2 三层装饰器(给双层装饰器加参数的)

def sanceng(engine):
   def outter(func):
       def wrapper(*args, **kwargs):  # wrapper是未来要运行的函数
           # 加功能
           print(engine)
           res = func(*args, **kwargs)  # func是被装饰的函数
           return res

       return wrapper

   return outter


@sanceng('file')
def shopping():
   print('shopping')

 

三、迭代器

迭代器:迭代的工具。迭代是更新换代,如爷爷生爸爸,爸爸生儿子。迭代也可以说成是重复,但每一次的重复都是基于上一次的结果来的。如计算机中的迭代开发,就是基于软件的上一个版本更新的。

下面的代码就不是迭代而是重复:

while True:
   print('*'*10)

3、1可迭代对象

python中一切皆对象,如

x = 1
name = 'nick'
lis = [1, 2]
tup = (1, 2)
dic = {'name': 'nick'}
s1 = {'a', 'b'}


def func():
   pass


f = open('49w.txt', 'w', encoding='utf-8)

对于这一切对象中,但凡有__iter__方法的对象,都是可迭代对象。

# x = 1.__iter__  # SyntaxError: invalid syntax

# 以下都是可迭代的对象

name = 'nick'.__iter__
lis = [1, 2].__iter__
tup = (1, 2).__iter__
dic = {'name': 'nick'}.__iter__
s1 = {'a', 'b'}.__iter__
f = open('49w.txt', 'w', encoding='utf-8')
f.__iter__
f.close()

从上述可知可迭代对象:Python内置str、list、tuple、dict、set、file、都是可迭代对象。

特点:

  1. 内置__iter__方法的都叫可迭代的对象。

3、2迭代器对象

只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的。因此我们得找到一个方法能让其他的可迭代对象不依赖索引取值。

在找到该方法前,首先我们给出迭代器对象的概念:可迭代的对象执行__iter__方法得到的返回值。并且可迭代对象会有一个__next__方法。

# 不依赖索引的数据类型迭代取值
dic = {'a': 1, 'b': 2, 'c': 3}
iter_dic = dic.__iter__()
print(iter_dic.__next__())
print(iter_dic.__next__())
print(iter_dic.__next__())
# print(iter_dic.__next__()) # StopIteration:
a
b
c
# 依赖索引的数据类型迭代取值
lis = [1, 2, 3]
iter_lis = lis.__iter__()
print(iter_lis.__next__())
print(iter_lis.__next__())
print(iter_lis.__next__())
# print(iter_lis.__next__()) # StopIteration:
1
2
3

上述的方法是非常繁琐的,我们可以使用while循环精简下。其中使用的try...except...为异常处理模块,以后会详细讲解。

s = 'hello'
iter_s = s.__iter__()

while True:
  try:
      print(iter_s.__next__())
  except StopIteration:
      break
h
e
l
l
o

总结

特点:

  1. 内置__next__方法,执行该方法会拿到迭代器对象中的一个值

  2. 内置有__iter__方法,执行该方法会拿到迭代器本身

  3. 文件本身就是迭代器对象。

缺点:

  1. 取值麻烦,只能一个一个取,并且只能往后取,值取了就没了

  2. 无法使用len()方法获取长度

3、3 for循环原理

lis = [1, 2, 3]
for i in lis:
   print(i)
1
2
3

因为迭代器使用__iter__后还是迭代器本身,因此for循环不用考虑in后的对象是可迭代对象还是迭代器对象。

由于对可迭代对象使用__iter__方法后变成一个迭代器对象,这个迭代器对象只是占用了一小块内存空间,他只有使用__next__后才会吐出一个一个值。如lis = [1,2,3,4,5,...]相当于一个一个鸡蛋,而lis = [1,2,3,4,5,...].__iter__相当于一只老母鸡,如果你需要蛋,只需要__next__即可。

Python2中

print(range(10))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Python3中

print(range(10))  # range(0, 10)

四、三元表达式

**条件成立时的返回值if条件else条件不成立时的返回值

x = 10
y = 20
print(f'x if x > y else y:{x if X > y else y}')

运行结果:

x if x > y else y: 20

五、列表推导式

print(F"[i for i in range(10)]: {[i for i in range(10)]}")

# [i for i in range(10)]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

六、字典生成式

6、1 字典生成式

print({i: i**2 for i in range(10)})
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

6、2 zip()方法

keys = ['name', 'age', 'gender']
values = ['nick', 19, 'male']

res = zip(keys, values)
print(F"zip(keys,values): {zip(keys,values)}")

info_dict = {k: v for k, v in res}
print(f"info_dict: {info_dict}")
# 运行结果:
#zip(keys,values): <zip object at 0x11074c088>
#info_dict: {'name': 'nick', 'age': 19, 'sex': 'male'}

通过解压缩函数生成一个字典

info_dict = {'name': 'nick', 'age': 19, 'gender': 'male'}
print(f"info_dict.keys(): {info_dict.keys()}")
print(f"info_dict.values(): {info_dict.values()}")

res = zip(info_dict.keys(), info_dict.values())
print(F"zip(keys,values): {zip(info_dict.keys(),info_dict.values())}")

info_dict = {k: v for k, v in res}
print(f"info_dict: {info_dict}")
# 运行结果:

#info_dict.keys(): dict_keys(['name', 'age', 'gender'])
#info_dict.values(): dict_values(['nick', 19, 'male'])
#zip(keys,values): <zip object at 0x1105cefc8>
#info_dict: {'name': 'nick', 'age': 19, 'gender': 'male'}

七、生成器

7、1 yeild 关键字

yield的英文单词意思是生产,在函数中但凡出现yield关键字,再调用函数,就不会继续执行函数体代码,而是会返回一个值。

def func():
   print(1)
   yield
   print(2)
   yield


g = func()
print(g)

运行结果:

<generator object func at 0x10ddb6b48>

生成器的本质就是迭代器,同时也并不仅仅是迭代器,不过迭代器之外的用途实在是不多,所以我们可以大声地说:生成器提供了非常方便的自定义迭代器的途径。并且从Python 2.5+开始,[PEP 342:通过增强生成器实现协同程序]的实现为生成器加入了更多的特性,这意味着生成器还可以完成更多的工作。这部分我们会在稍后的部分介绍。

def func():
   print('from func 1')
   yield 'a'
   print('from func 2')
   yield 'b'


g = func()
print(F"g.__iter__ == g: {g.__iter__() == g}")

res1 = g.__next__()
print(f"res1: {res1}")

res2 = next(g)
print(f"res2: {res2}")

# next(g) # StopIteration

 

八、递归

8、1 什么是函数递归

函数的嵌套调用是:函数嵌套函数。函数的递归调用:它是一种特殊的嵌套调用,但是它在调用一个函数的过程中,又直接或间接地调用了它自身。

def foo():
   print('from foo')
   foo()

foo()  # 进入死循环

如果递归函数不断地调用函数自身,那么这个递归函数将会进入一个死循环,因此我们应该给递归函数一个明确的结束条件。

8.1.1 直接调用

直接调用指的是:直接在函数内部调用函数自身。

import sys

print(f"最大递归层数: {sys.getrecursionlimit()}")
# 最大递归层数: 3000
import sys

# 修改递归层数
sys.setrecursionlimit(10000)
def foo(n):
   print('from foo',n)
   foo(n+1)
foo(0)

8.1.2 间接调用

间接调用指的是:不在原函数体内调用函数自身,而是通过其他的方法间接调用函数自身。

def bar():
   print('from bar')
   foo()
   
def foo():
   print('from foo')
   bar()
   
bar()

递归必须要有两个明确的阶段:

  1. 递推:一层一层递归调用下去,进入下一层递归的问题规模都将会减小

  2. 回溯:递归必须要有一个明确的结束条件,在满足该条件开始一层一层回溯。

递归的精髓在于通过不断地重复逼近一个最终的结果。

53递归-代码.gif

'''
...
age(5) = age(4) + 2
age(4) = age(3) + 2
age(3) = age(2) + 2
age(2) = age(1) + 2
age(1) = 26


age(n) = age(n-1) +2
age(1) = 26 # n=1
'''


def age(n):
   if n == 1:
       return 26
   res = age(n-1) + 2
   return res


print(f"age(5): {age(5)}")
# age(5): 34

8、2 为什么要用递归

递归的本质就是干重复的活,但是仅仅是普通的重复,我们使用while循环就可以了。

lis = [1, [2, [3, [4, [5, [6, ]]]]]]


def tell(lis):
   for i in lis:
       if type(i) is list:
           tell(i)
       else:
           print(i)


# print(f"tell(lis): {tell(lis)}")
tell(lis)
#1
#2
#3
#4
#5
#6

8、3 如何用递归?

8.3.1 二分法的应用

有一个从小到大排列的整型数字列表,我们判断某一个数字是不是在这个列表里面。

动图二分法查找数字23:

53递归-二分23.gif

动图二分法查找数字1:

53递归-二分1.gif

nums = [1, 3, 7, 11, 22, 34, 55, 78, 111, 115]

for item in nums:
   if item == 10:
       print('find it')
       break
else:
   print('not exists')
# not exists

对于上述的列表我们可能可以通过一个for循环实现我们需要的功能,但是当我们的列表中的元素个数非常多时,我们还用这种方法,那是极其复杂的,因此我们可以考虑使用二分法的思想实现。

from random import randint
nums = [randint(1, 100) for i in range(100)]
nums = sorted(nums)
print(nums)
# [1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 10, 11, 11, 11, 11, 12, 13, 13, 15, 16, 16, 20, 21, 21, 23, 24, 26, 26, 27, 28, 28, 31, 33, 33, 34, 35, 38, 38, 39, 40, 42, 43, 45, 45, 46, 46, 47, 47, 51, 52, 52, 53, 53, 55, 55, 56, 56, 57, 57, 57, 58, 59, 61, 62, 64, 66, 66, 67, 68, 69, 69, 71, 72, 72, 74, 74, 75, 76, 78, 78, 79, 79, 79, 79, 80, 82, 85, 88, 89, 90, 90, 91, 91, 91, 94, 99, 99, 100]
def search(search_num, nums):
   mid_index = len(nums)//2
   print(nums)
   if not nums:
       print('not exists')
       return
   if search_num > nums[mid_index]:
       # in the right
       nums = nums[mid_index+1:]
       search(search_num, nums)
   elif search_num < nums[mid_index]:
       # in the left
       nums = nums[:mid_index]
       search(search_num, nums)
   else:
       print('find it')


search(7, nums)
#[1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 10, 11, 11, 11, 11, 12, 13, 13, 15, 16, 16, 20, 21, 21, 23, 24, 26, 26, 27, 28, 28, 31, 33, 33, 34, 35, 38, 38, 39, 40, 42, 43, 45, 45, 46, 46, 47, 47, 51, 52, 52, 53, 53, 55, 55, 56, 56, 57, 57, 57, 58, 59, 61, 62, 64, 66, 66, 67, 68, 69, 69, 71, 72, 72, 74, 74, 75, 76, 78, 78, 79, 79, 79, 79, 80, 82, 85, 88, 89, 90, 90, 91, 91, 91, 94, 99, 99, 100]
#[1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 10, 11, 11, 11, 11, 12, 13, 13, 15, 16, 16, 20, 21, 21, 23, 24, 26, 26, 27, 28, 28, 31, 33, 33, 34, 35, 38, 38, 39, 40, 42, 43, 45, 45, 46, 46, 47, 47]
#[1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 10, 11, 11, 11, 11, 12, 13, 13, 15, 16, 16, 20, 21]
#[1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7]
#[6, 6, 7, 7, 7]
#find it

 

九 、匿名函数

9、1 有名函数

我们之前定的函数都是有名函数,它是基于函数名使用。

def func():
   print('from func')


func()
func()
func()
print(func)
#from func
#from func
#from func
#<function func at 0x10518b268>

9、2 匿名函数

lambda x, y: x+y
<function __main__.<lambda>(x, y)>
res = (lambda x, y: x+y)(1, 2)
print(res)
# 3

9、3 与内置函数联用

54匿名函数-薪资.jpg?x-oss-process=style/watermark

salary_dict = {
   'nick': 3000,
   'jason': 100000,
   'tank': 5000,
   'sean': 2000
}

1.如果我们想从上述字典中取出薪资最高的人,我们可以使用max()方法,但是max()默认比较的是字典的key。

  1. 首先将可迭代对象变成迭代器对象

  2. res=next(迭代器对象),将res当做参数传给key指定的函数,然后将该函数的返回值当做判断依据

salary_dict = {
   'nick': 3000,
   'jason': 100000,
   'tank': 5000,
   'sean': 2000
}

print(f"max(salary_dict): {max(salary_dict)}")


def func(k):
   return salary_dict[k]


print(f"max(salary_dict, key=func()): {max(salary_dict, key=func)}")
# 'nick', v1 = func('nick')
# 'jason', v2 = func('jason')
# 'tank', v3 = func('tank')
# 'sean', v4 = func('sean')


print(
   f"max(salary_dict, key=lambda name: salary_dict[name]): {max(salary_dict, key=lambda name: salary_dict[name])}")
# max(salary_dict): tank
# max(salary_dict, key=func()): jason
# max(salary_dict, key=lambda name:
# salary_dict[name]): jason

2.如果我们想对上述字典中的人,按照薪资从大到小排序,可以使用sorted()方法。

sorted()工作原理:

  1. 首先将可迭代对象变成迭代器对象

  2. res=next(迭代器对象),将res当做参数传给第一个参数指定的函数,然后将该函数的返回值当做判断依据。

lis = [1, 3, 2, 5, 8, 6]
sorted(lis)
print(f"lis: {lis}")
print(f"sorted(lis,reverse=True): {sorted(lis,reverse=True)}")
# lis: [1, 3, 2, 5, 8, 6]
# sorted(lis,reverse=True): [8, 6, 5, 3, 2, 1]
salary_dict = {
   'nick': 3000,
   'jason': 100000,
   'tank': 5000,
   'sean': 2000
}

print(
   f"sorted(salary_dict, key=lambda name: salary_dict[name]): {sorted(salary_dict, key=lambda name: salary_dict[name])}")
# sorted(salary_dict, key=lambda name: salary_dict[name]): ['sean', 'nick', 'tank', 'jason']

3.如果我们想对一个列表中的某个人名做处理,可以使用map()方法。

map()工作原理:

  1. 首先将可迭代对象变成迭代器对象

  2. res=next(迭代器对象),将res当做参数传给第一个参数指定的函数,然后将该函数的返回值作为map()方法的结果之一。

name_list = ['jason', 'tank', 'sean']

res = map(lambda name: f"{name} sb", name_list)
print(f"list(res): {list(res)}")
# list(res): ['jason sb', 'tank sb', 'sean sb']

4.如果我们想筛选除名字中含有'sb'的名字,我们可以使用filter()方法。

filter()工作原理:

  1. 首先将可迭代对象变成迭代器对象

  2. res=next(迭代器对象),将res当做参数传给第一个参数指定的函数,然后filter会判断函数的返回值的真假,如果为真则留下。

name_list = ['nick', 'jason sb', 'tank sb', 'sean sb']

filter_res = filter(lambda name: name.endswith('sb'), name_list)
print(f"list(filter_res): {list(filter_res)}")
# list(filter_res): ['jason sb', 'tank sb', 'sean sb']

十、内置函数

10、1 掌握

1.bytes()

解码字符。

res = '你好'.encode('utf8')
print(res)
#b'\xe4\xbd\xa0\xe5\xa5\xbd'
res = bytes('你好', encoding='utf8')
print(res)
#b'\xe4\xbd\xa0\xe5\xa5\xbd'

2.chr()/ord()

chr()参考ASCII码表将数字转成对应字符;ord()将字符转换成对应的数字。

print(chr(65))
# A
print(ord('A'))
# 65

3.divmod()

分栏。

print(divmod(10, 3))
# (3, 1)

4.enumerate()

带有索引的迭代。

l = ['a', 'b', 'c']
for i in enumerate(l):
   print(i)
#(0, 'a')
#(1, 'b')
#(2, 'c')

5.eval()

把字符串翻译成数据类型。

lis = '[1,2,3]'
lis_eval = eval(lis)
print(lis_eval)
#[1, 2, 3]

6.hash()

是否可哈希。

print(hash(1))
# 1

10、2 了解

求绝对值。

print(abs(-13))  # 求绝对值
# 13

2.all()

可迭代对象内元素全为真,则返回真。

print(all([1, 2, 3, 0]))
print(all([]))
False
True

3.any()

可迭代对象中有一元素为真,则为真。

print(any([1, 2, 3, 0]))
print(any([]))
True
False

4.bin()/oct()/hex()

二进制、八进制、十六进制转换。

print(bin(17))
print(oct(17))
print(hex(17))
0b10001
0o21
0x11

5.dir()

列举出所有time的功能。

import time
print(dir(time))
#['_STRUCT_TM_ITEMS', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'altzone', 'asctime', 'clock', 'ctime', 'daylight', 'get_clock_info', 'gmtime', 'localtime', 'mktime', 'monotonic', 'perf_counter', 'process_time', 'sleep', 'strftime', 'strptime', 'struct_time', 'time', 'timezone', 'tzname', 'tzset']

6.frozenset()

不可变集合。

s = frozenset({1, 2, 3})
print(s)
# frozenset({1, 2, 3})

7.globals()/loacals()

查看全局名字;查看局部名字。

# print(globals())
def func():
   a = 1
#     print(globals())
   print(locals())


func()
# {'a': 1}

8.pow()

print(pow(3, 2, 3))  # (3**2)%3
# 0

9.round()

print(round(3.5))
# 4

10.slice()

lis = ['a', 'b', 'c']
s = slice(1, 4, 1)
print(lis[s])  # print(lis[1:4:1])
# ['b', 'c']

11.sum()

print(sum(range(100)))
# 4950

12.import()

通过字符串导入模块。

m = __import__('time')
print(m.time())
# 1556607502.334777

10、3 面向对象知识点

  1. classmethod

  2. staticmethod

  3. property

  4. delattr

  5. hasattr

  6. getattr

  7. setattr

  8. isinstance()

  9. issubclass()

  10. object()

  11. super()

十一、面向过程编程

面向过程编程是解决问题的一种思想,相当于武林门派,武林门派之间没有好坏之分,因此它与我们之后学习的面向对象编程其实没有好坏之分。

面向过程编程,核心是编程二字,过程指的是解决问题的步骤,即先干什么、后干什么、再干什么、然后干什么……

基于该思想编写程序就好比在设计一条流水线,面向对称编程其实是一种机械式的思维方式。

当我们写登录功能,我们首先需要输入账号、密码,然后认证两次密码是否相同,然后从数据库中读取密码验证用户密码输入是否正确,然后输入验证码……之后,我们就能够实现登录功能。这样把登录功能问题流程化,进而是解决问题的思路非常清晰。

56面向过程编程-流水线.jpg?x-oss-process=style/watermark

优点:复杂的问题流程化,进而简单化。

生产汽水瓶的流水线,没办法生产特斯拉。流水线下一个阶段的输入与上一个阶段的输出是有关联的。因此他的扩展性极差。

缺点:扩展性差。

11、1 注册功能

1.2 接受用户输入密码,进行合法性校验,拿到合法的密码**

def check_pwd():
  while True:
      pwd = input('password>>>').strip()
      if len(pwd) < 5:
          print('密码长度至少五位')
          continue
      re_pwd = input('re_password>>>').strip()
      if pwd == re_pwd:
          return pwd
      else:
          print('两次输入密码不一致')

1.3 将合法的用户名和密码写入文件

def insert(username, pwd, path='57.txt'):
   with open(path, 'a', encoding='utf8') as fa:
       fa.write(f'{username}:{pwd}\n')

 

1.4 注册

def register():
   username = check_username()
   pwd = check_pwd()
   insert(username, pwd)
   print(f'{username}注册成功')


register()
#username>>>nick
#password>>>12345
#re_password>>>12345
#nick注册成功

如果现在我们需要校验用户的年龄,因此我们需要增加一个check_age()方法,并且其他有牵连的地方都需要修改,因此它的扩展性极差。

1.5 封装文件读写功能

数据处理层

def select(username):
   with open('db.txt', 'r', encoding='utf8') as fr:
       for line in fr:
           info = line.strip('\n').split(':')
           if username == info[0]:
               return info


def tell_info():
   username = input('username>>>').strip()
   info = select(username)
   print(info)

用户功能层

def register():
   while True:
       username = input('username>>>').strip()
       # 检测用户是否重复,如果重复则重新输入
       res = select(username)
       if res:
           print('用户名已经存在')
       else:
           break

   while True:
       pwd = input('password>>>').strip()
       re_pwd = input('re_password>>>').strip()
       if pwd != re_pwd:
           print('两次输入密码不一致,请重新输入')
       else:
           break

把注册功能分开之后,功能与功能直接解耦合,复杂的问题流程化,更加清晰。

11、2 分层实现功能

  • 用户功能层:实现用户具体的功能。

  • 接口层:连接数据处理层和用户功能层。

  • 数据处理层:处理数据后把结果交给接口层。

分层实现功能的好处:当我们需要实现web端和app端的软件,我们只要把数据处理层和接口层写好,然后实现不同的用户功能层即可,web端使用web端的用户功能层,app端使用app端的用户功能层,但是接口层和数据处理层是通用的。

posted on 2019-09-18 20:58  hanyi12  阅读(463)  评论(0编辑  收藏  举报