Python函数高级

一、闭包函数

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

def outter(x):
    x = 1

    def inner():
        print(x)

    return inner


f = outter(2)
f()  # 1
f()  # 1
f()  # 1
# 查看闭包的元素
print(f.__closure__[0].cell_contents)  # 1

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

1、应用领域:

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

import requests


def outter(url):
    def get():
        response = requests.get(url)
        print(f"done: {url}")

    return get


baidu = outter('https://www.baidu.com')
python = outter('https://www.python.org')

baidu()
baidu()

python()
python()

二、装饰器

装饰器指的是为被装饰器对象添加额外功能。因此定义装饰器就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能。装饰器的实现必须遵循两大原则:

  1. 不修改被装饰对象的源代码
  2. 不修改被装饰对象的调用方式

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

不改变函数体代码,并且不改变函数调用方式,它本质就是一个函数。

def f1(x):
    def f2():
        print(x)  # 10
    return f2

f2 = f1()
f2()  # f2()

1、无参装饰器

1、装饰器模板

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

2、举例:

import time


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


def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print(f"{func} time is {start - end}")  #  time is -1.0038220882415771

    return wrapper


index = time_count(index)  # index为被装饰函数index的内存地址,即index = wrapper
index()  # wrapper()

3、被装饰函数有返回值:

如果原始的被装饰函数index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和wrapper()方法的返回值。

import time


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


def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        res1 = func()
        end = time.time()
        print(f"{func} time is {start - end}")  #  time is -1.0050289630889893
        return res1

    return wrapper


index = time_count(index)
res = index()
print(f"res: {res}")  #
res: 123

4、被装饰函数需要传参:

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

import time


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


def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)
    return name


def time_count(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f"{func} time is {start-end}") #  time is -1.0039079189300537
        return res

    return wrapper


home = time_count(home)

res = home('egon')
print(f"res: {res}") #res: egon

5、装饰器语法糖:

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

import time


def time_count(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f"{func} time is {start-end}") # time is -1.0005171298980713
        return res

    return wrapper


@time_count  # home = time_count(home)
def home(name):
    print(f"welcome {name} to home page") #welcome egon to home page
    time.sleep(1)
    return name


@time_count  # index = time_count(index)
def index():
    print('welcome to index')
    time.sleep(1)
    return 123


res = home('egon')
print(f"res: {res}") #res: egon


2、 有参装饰器

1、注意无参装饰器只套两层。

import time

current_user = {'username': None}


def login(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):
        if current_user['username']:
            res1 = func(*args, **kwargs)
            return res1

        user = input('username: ').strip()
        pwd = input('password: ').strip()

        if user == 'nick' and pwd == '123':
            print('login successful')
            current_user['username'] = user
            res1 = func(*args, **kwargs)
            return res1
        else:
            print('user or password error')

    return wrapper


@login
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)


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


res = index()

username: nick
password: 123
login successful
welcome to index

2、我们首先看看三层闭包怎么运用。

def f1(y):
    
    def f2():
        x = 1

        def f3():
            print(f"x: {x}")  # x: 1
            print(f"y: {y}")  # x: 1

        return f3

    return f2


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

3、应用:有参三层装饰器:

import time

current_user = {'username': None}


def auth(engine='file'):

    def login(func):

        def wrapper(*args, **kwargs):

            if current_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')
                    current_user['username'] = user
                    res = func(*args, **kwargs)

                    return res
                else:
                    print('user or password error')
            elif engine == 'mysql':
                print('base of mysql, please base of file')

        return wrapper

    return login


@auth(engine='mysql')
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)


@auth(engine='file')
def index():
    print('welcome to index')
    time.sleep(1)


res = index()

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

三、迭代器

1、可迭代的对象

Python内置str、list、tuple、dict、set、file都是可迭代对象

内置有__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()

2、迭代器对象:

执行可迭代对象的__iter__方法,拿到的返回值就是迭代器对象。只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的,只能使用迭代器对象。

  1. 内置__next__方法,执行该方法会拿到迭代器对象中的一个值
  2. 内置有__iter__方法,执行该方法会拿到迭代器本身
  3. 文件本身就是迭代器对象。
s = 'hello'
iter_s = s.__iter__()

while True:
    try:
        print(iter_s.__next__())
    except StopIteration:
        break

3、for迭代器循环

for循环称为迭代器循环,in后必须是可迭代的对象。

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


print(range(10))  # range(0, 10)
for i in range(10):
    print(i)

四、三元表达式

语法:条件成立时的返回值 if 条件 else 条件不成立时的返回值

x = 10
y = 20

print(x if x > y else y)  # 20

五、列表推导式

语法:

[expression for item1 in iterable1 if condition1
            for item2 in iterable2 if condition2
             ...
            for itemN in iterableN if conditionN
]

举例:

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


name_list = ['nick', 'sean', 'jason', 'tank']
for n in [name if name == 'nick' else name + '_a' for name in name_list] :
    print(n)  # 'nick', 'sean_a', 'jason_a', 'tank_a'

六、字典生成式

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}

zip()方法

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

res = zip(keys, values)
print(res)  # 

info_dict = {k: v for k, v in res}
print(info_dict)  # {'name': 'nick', 'age': 19, 'gender': 'male'}

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

info_dict = {'name': 'nick', 'age': 19, 'gender': 'male'}
print(info_dict.keys())  # dict_keys(['name', 'age', 'gender'])
print(info_dict.values())  # dict_values(['nick', 19, 'male'])

res = zip(info_dict.keys(), info_dict.values())
print(res)  # 

info_dict = {k: v for k, v in res}
print(info_dict)  # {'name': 'nick', 'age': 19, 'gender': 'male'}

七、生成器

1、yield

生成器的本质就是迭代器

def func():
    print(1)
    yield   # 在函数中但凡出现yield关键字,再调用函数,就不会继续执行函数体代码,而是会返回一个值。
    print(2)


g = func()
print(g)  # 
  1. 提供一种自定义迭代器的方式
  2. yield可以暂停住函数,并提供当前的返回值

yield和return:

  1. 相同点:两者都是在函数内部使用,都可以返回值,并且返回值没有类型和个数的限制
  2. 不同点:return只能返回一次之;yield可以返回多次值

2、自定义range()方法

def my_range(start, stop, step=1):
    while start < stop:
        yield start
        start += 1


g = my_range(0, 3)
print(f"list(g): {list(g)}")

复杂版本:

def range(*args, **kwargs):
    if not kwargs:
        if len(args) == 1:
            count = 0
            while count < args[0]:
                yield count
                count += 1
        if len(args) == 2:
            start, stop = args
            while start < stop:
                yield start
                start += 1
        if len(args) == 3:
            start, stop, step = args
            while start < stop:
                yield start
                start += step

    else:
        step = 1

        if len(args) == 1:
            start = args[0]
        if len(args) == 2:
            start, stop = args

        for k, v in kwargs.items():
            if k not in ['start', 'step', 'stop']:
                raise ('参数名错误')

            if k == 'start':
                start = v
            elif k == 'stop':
                stop = v
            elif k == 'step':
                step = v

        while start < stop:
            yield start
            start += step


for i in range(3):
    print(i)  # 0,1,2

for i in range(99, 101):
    print(i)  # 99,100

for i in range(1, 10, 3):
    print(i)  # 1,4,7

for i in range(1, step=2, stop=5):
    print(i)  # 1,3

for i in range(1, 10, step=2):
    print(i)  # 1,3,5,7,9

3、生成器表达式

把列表推导式的[]换成()就是生成器表达式 。

优点:省内存,一次只产生一个值在内存中

t = (i for i in range(10))
print(t)  #  at 0x00000000026907B0>
print(next(t))  # 0
print(next(t))  # 1

举例:

with open('32.txt', 'r', encoding='utf8') as f:
    nums = [len(line) for line in f]  # 列表推导式相当于直接给你一筐蛋

print(max(nums))  # 2


with open('32.txt', 'r', encoding='utf8') as f:
    nums = (len(line) for line in f)  # 生成器表达式相当于给你一只老母鸡。

print(max(nums))  # ValueError: I/O operation on closed file.

八、函数递归

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

age(1)=26,age(n)=age(n-1)+2 ,求age(5)的值:

'''
...
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)}")

递归的本质就是干重复的活。

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


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


tell(lis)

二分法的思想实现查找数字。

from random import randint

nums = [randint(1, 100) for i in range(100)]
nums = sorted(nums)


def search(search_num, nums):
    print(nums)
    mid_index = len(nums) // 2
    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)

九、匿名函数:lamdbda 参数 : 逻辑代码

匿名函数,他没有绑定名字,使用一次即被收回,加括号既可以运行。

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

与内置函数联用

匿名函数通常与max()、sorted()、filter()、sorted()方法联用。

1.max()

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

  1. 首先将可迭代对象变成迭代器对象
  2. res=next(迭代器对象),将res当做参数传给key指定的函数,然后将该函数的返回值当做判断依据
salary_dict = {
    'nick': 3000,
    'jason': 100000,
    'tank': 5000,
    'sean': 2000
}

print(max(salary_dict))  # tank


def func(k):
    return salary_dict[k]


print(max(salary_dict, key=func))  # jason
print(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(lis)  # [1, 3, 2, 5, 8, 6]
print(sorted(lis, reverse=True))  # [8, 6, 5, 3, 2, 1]

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

print(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(list(res))  # ['jason sb', 'tank sb', 'sean sb']

4.filter()

如果我们想筛选除名字中含有'sb'的名字,我们可以使用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(list(filter_res))  # ['jason sb', 'tank sb', 'sean sb']

十、内置函数

Python函数高级_第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

7.abs():求绝对值。

  
  
  
  
print(abs(-13))  # 13

8.all():可迭代对象内元素全为真,则返回真。

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

9.any():可迭代对象中有一元素为真,则为真。

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

10.bin()/oct()/hex():二进制、八进制、十六进制转换。

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

11.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']

12.frozenset():不可变集合。

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

13.globals()/loacals():查看全局名字;查看局部名字。

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


func()  # {'a': 1}

14.pow():

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

15.round():

  
  
  
  
print(round(3.5)) #4

16.slice():

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

17.sum():

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

18.__import__():通过字符串导入模块。

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

19. 面向对象知识点

  1. classmethod
  2. staticmethod
  3. property
  4. delattr
  5. hasattr
  6. getattr
  7. setattr
  8. isinstance()
  9. issubclass()
  10. object()
  11. super()

你可能感兴趣的:(Python函数高级)