Python笔记【九】

本文为博主原创,未经授权,严禁使用转载。
本文链接:https://blog.csdn.net/zyooooxie/article/details/113391645

继续学习Python,继续更新。

个人博客:https://blog.csdn.net/zyooooxie

getattr()【2】

之前分享过一期 getattr(), https://blog.csdn.net/zyooooxie/article/details/108998778,讲得 主要是对属性的操作。

后来 了解到 反射: 主要根据字符串去寻找类的属性值,主要用于用户交互,触发类内函数运行;根据字符串动态的判断、调用、添加/修改、删除类或类的实例化对象中的方法或属性。

getattr(object, name[, default ]) 如果给定的name是object的方法,则返回的是函数对象;调用的话就是 后面加括号,getattr(object, ‘name’)();

"""
@blog: https://blog.csdn.net/zyooooxie
"""

class TestGetattr(object):
    ABCDEF = 987654

    def __init__(self, test_str: str):
        self.test = test_str

    def test_a(self):
        print(self.test)

    @classmethod
    def test_b(cls):
        print(cls.ABCDEF)


def main():
    t = TestGetattr('zyooooxie')
    print(getattr(t, 'test_a', '这个其实是有的'))
    getattr(t, 'test_a')()
    print()

    print(getattr(t, 'test_b', '这个其实是有的'))
    getattr(t, 'test_b')()
    print()

    print(getattr(TestGetattr, 'test_b', '这个其实是有的'))
    getattr(TestGetattr, 'test_b')()

    # 如果给定的方法func()是实例函数,则不能写getattr(A, 'func')(),因为fun()是实例函数的话,是不能用A类对象来调用的,应该写成getattr(A(), 'func')();
    # print(getattr(TestGetattr, 'test_a', '这个不行的'))            # TypeError: test_a() missing 1 required positional argument: 'self'


换个实际的例子:

https://blog.csdn.net/zyooooxie/article/details/113541873 是 之前做的 请求方法,我现在把代码重新优化下

"""
@blog: https://blog.csdn.net/zyooooxie
"""

# request_type只分为【3个post+1个get】json、form、file、get

class SessionSendReq(object):

    def __init__(self, session):
        # session 实际是一个请求会话
        self.session = session

    def get(self, test_url, params_data, test_header):
        res = self.session.get(test_url, params=params_data, headers=test_header)
        return res

    def form(self, test_url, new_data, test_header):
        res = self.session.post(test_url, data=new_data, headers=test_header)
        return res

    def json(self, test_url, new_json, test_header):
        res = self.session.post(test_url, json=new_json, headers=test_header)
        return res

    def _file(self, test_url, file_name, new_data, test_header, file_parameter=None):
        f = open(file_name, 'rb')

        if file_parameter is None:
            file_dict = {'file': f}
        else:
            file_dict = {file_parameter: f}

        res = self.session.post(test_url, params=new_data, files=file_dict, headers=test_header)
        f.close()
        return res


	def req(self, test_url: str, request_type: str, test_data: dict, header: dict, file=None, file_parameter=None):
	    request_type = request_type.lower()
	
	    if file is None:
	
	        if hasattr(SessionSendReq, request_type):
	            getattr(self, request_type)(test_url, test_data, test_header=header)
	        else:
	            raise Exception('请求方法 不合法:{}, {}'.format(request_type, file))
	
	    else:
	        assert request_type == 'file'
	        return self._file(test_url, new_data=test_data, file_name=file, file_parameter=file_parameter,
	                          test_header=header)


if __name__ == '__main__':
    SessionSendReq('session123456').req(test_url='https://blog.csdn.net/zyooooxie/', request_type='json',
                                        test_data={'name': 'zyooooxie'}, header={'blog': 'csdn'})

    SessionSendReq('session123456').req(test_url='https://blog.csdn.net/zyooooxie/', request_type='file',
                                        test_data={'name': 'zyooooxie'}, header={'blog': 'csdn'}, file='common_fun.py')

主要是将 excel读取的request_type字段值【4个:json、form、file、get】 和 SessionSendReq的请求方法get()、form()、json() 做了统一,_file()是特殊处理。

sorted()

https://docs.python.org/zh-cn/3.8/library/functions.html#sorted
https://docs.python.org/zh-cn/3.8/howto/sorting.html#sortinghowto

"""
@blog: https://blog.csdn.net/zyooooxie
"""

import random
from operator import itemgetter

gl_list = [(123, 'AA', {'zy': 2022}), (123, 'AB', {'ZY': 2023}), (234, 'AA', {'ZY': 2024}), (234, 'AB', {'zy': 2024}),
           (123, 'AC', {'zy': 2023}), (123, 'AB', {'ZY': 2022}), (234, 'AC', {'ZY': 2022}), (234, 'AA', {'zy': 2022})]

random.shuffle(gl_list)

print(gl_list)
print()


def test_sorted_0():
    # sorted(iterable, *, key=None, reverse=False)

    # sorted是 根据 iterable 中的项返回一个新的已排序list。具有两个可选参数,它们都必须指定为关键字参数;
    list_ = [e * 3 for e in range(17)]
    random.shuffle(list_)
    print(list_)

    # key 指定带有单个参数的函数,用于从 iterable 的每个元素中提取用于比较的键 (例如 key=str.lower)。默认值为 None (直接比较元素)
    a = sorted(list_, key=None, reverse=False)

    # reverse 为一个布尔值。 reverse = True 降序 , reverse = False 升序(默认)
    b = sorted(list_, reverse=True)

    # sorted 方法 不是在原来的基础上进行的操作。
    print(a, type(a))
    print(b, type(b))
    print(list_, '原本的')


def test_sorted_1():
    #  sorted() 可以接收任何的 iterable

    a = (1, 2, 4, 2, 3)
    print(sorted(a))

    d = {'zy': 123, 'ZY': 456, 'zY': 789}
    print(sorted(d))
    print(sorted(d.keys()))
    print(sorted(d.values(), reverse=True))

    b = 'https://blog.csdn.net/zyooooxie'
    print(sorted(b, key=str.lower))

    s = {123, 789, 456, 741, 852, 963}
    print(sorted(s))

    print()

    # The built-in sorted() function is guaranteed to be stable. A sort is stable if it guarantees not to change the relative order of elements that compare equal
    # 内置的 sorted() 确保是稳定的。 如果一个排序 确保不会改变 比较结果相等元素的相对顺序 就称其为稳定的。
    # 这意味着当多个记录具有相同的键值时,将保留其原始顺序。

    c = sorted(gl_list, key=lambda x: x[0])
    print('以[0]排序', c)

    # 根据多个参数排序 - 按 [0] 排序,然后按 [1] 排序
    c1 = sorted(gl_list, key=lambda x: (x[0], x[1]))
    print('多个参数排序[0]-[1]', c1)

    # 根据多个参数排序 - 按 [2]的 values 排序,然后按 [1] 排序    【降序】
    c2 = sorted(gl_list, key=lambda x: (list(x[2].values()), x[1]), reverse=True)
    print('多个参数排序[2]-[1] 降序', c2)


def test_sorted_2():
    print()

    abc_list = list()

    for e in gl_list:
        # ele = e[0], e[1]
        ele = list(e[2].values()), e[1]
        abc_list.append(ele)

    print(abc_list)
    print('多个参数排序[2]-[1] 降序', sorted(abc_list, reverse=True))

functools.cmp_to_key()

https://docs.python.org/zh-cn/3.8/library/functools.html#functools.cmp_to_key

"""
@blog: https://blog.csdn.net/zyooooxie
@qq: 153132336
@wechat: 153132336
"""

import random

from functools import cmp_to_key


# python标准模块functools中的cmp_to_key可以将一个cmp函数变成一个key函数,从而支持自定义排序

# 在一些接受key的函数中(例如sorted,min,max),key仅仅支持一个参数,就无法实现两个参数之间的对比。
# 采用cmp_to_key函数,可以接受两个参数,将两个参数做处理,转换成一个参数,就可以应用于key关键字之后。


# functools.cmp_to_key(func)
# 将(旧式的) 比较函数转换为新式的key function . 在类似于sorted() ,min() ,max() ,heapq.nlargest() ,heapq.nsmallest() ,itertools.groupby() 等函数的key 参数中使用


# 比较函数意为一个可调用对象,该对象接受两个参数并比较它们,结果为小于则返回一个负数,相等则返回零,大于则返回一个正数。
# 该函数 想要 接受的参数按原顺序,则返回一个负数。若两参数相等则返回零,想要改变顺序则返回一个正数


def cmp_func_0(val1, val2):
    # 降序-首位
    if val1[0] < val2[0]:  # val1的首位 小于 val2的首位时,要换位置
        return 1
    elif val1[0] > val2[0]:  # val1的首位 大于 val2的首位时,不变位置
        return -1

    # 升序-第二位
    elif val1[1] > val2[1]:  # 首位元素相等时,val1的第2位 大于 val2的第2位 时,要换位置
        return 1

    else:  # 首位元素相等时,val1的第2位 小于等于 val2的第2位 时,不动
        return -1


def test_0():
    list_ = [(e * 3, e + 11) for e in range(5)]
    list_1 = [(e * 3, e - 11) for e in range(5)]
    list_.extend(list_1)

    random.shuffle(list_)

    list_.extend(list_[5:])
    print(list_)

    # 按 首位 降序排序,再按 第二位 升序排序
    list_2 = sorted(list_, key=cmp_to_key(cmp_func_0))
    print(list_2)


def cmp_func_1(val1: int, val2: int):
    """
    升序排序:
    当前面的参数 小于后面的参数 保持不变,返回-8888,
    当前面的的参数 大于后面的参数 交换顺序,返回8888
    :param val1:
    :param val2:
    :return:
    """
    if val1 < val2:
        return -8888

    else:
        return 8888


def test_1():
    list_ = [e * 3 for e in range(10)]
    random.shuffle(list_)
    print(list_)

    # 升序
    list_2 = sorted(list_, key=cmp_to_key(cmp_func_1))
    print(list_2)

    list_2 = sorted(list_, key=cmp_to_key(lambda x, y: x - y))
    print(list_2)
    

闭包

"""
@blog: https://blog.csdn.net/zyooooxie
"""

from typing import Union
from typing import Callable


# 关于 return fun 和 return fun() 的区别
def fun_x(x: int):
    def fun_y(y: int):
        return x * y

    print(fun_y, 'fun_x() 打印的')
    return fun_y  # 返回的是一个function对象


def fun_x1(x: int):
    # 若fun_y1的参数都是位置参数,不使用默认参数,就报错了
    def fun_y1(y=8):
        return x * y

    print(fun_y1(), 'fun_x1() 打印的')
    return fun_y1()  # 返回的是 执行结果(函数返回值)


def FUN_X(x: Union[Callable, int]):
    print(x, '传入的参数', type(x))

    if isinstance(x, Callable):
        print(x('zyooooxie'), 'FUN_X() 打印的')
    return type(x)


if __name__ == '__main__':
    pass
    a = fun_x(66)
    print(a, 'https://blog.csdn.net/zyooooxie')

    a1 = fun_x1(55)
    print(a1, 'https://blog.csdn.net/zyooooxie')

    A = FUN_X(99)
    print(A, 'https://blog.csdn.net/zyooooxie')

    # 实际传的是 一个function对象
    A = FUN_X(fun_x)
    print(A, 'https://blog.csdn.net/zyooooxie')
    
"""
@blog: https://blog.csdn.net/zyooooxie
"""

# 一、什么是闭包?
# 在一个函数内部嵌套定义了另一个函数,其中 内部函数使用了外部函数作用域的变量(自由变量),并且外部函数的返回值是内部函数的引用,
# 当外部函数结束时,外部函数的变量会被绑定到内部函数,由此就构成了闭包。


# 二、构成闭包的条件?
# 1. 必须有一个内嵌函数
# 2. 内嵌函数必须引用外部函数中的变量
# 3. 外部函数的返回值必须是内嵌函数


# 普通函数
def abc():
    print('这是一个普通函数')


abc()


# 嵌套函数
def ABC():
    str_0 = '这是一个'

    def print_():
        str_1 = '普通嵌套函数'
        print(str_0, str_1)

    print_()
    print(str_0)


ABC()


# 函数f中嵌套了函数g,并返回函数g
def f(x1, x2, x3):
    def g(y):
        print(x1 + y + x3, '这是g()里面的')
        return x2

    return g


# 闭包中外部函数返回的是一个函数对象。一般情况下,返回的函数会赋值给一个变量,这个变量可以在后面被继续执行调用。

# 将执行函数时返回的闭包 赋值给变量a
a = f(1, 11, 111)

# 调用 存储在变量a中的 闭包函数
print(a(55), 'https://blog.csdn.net/zyooooxie')

# 无需将闭包存储进临时变量,也可以直接一次性调用闭包函数
print(f(1, 11, 111)(55))


print('----------')

# 上面的f()的参数x1, x2, x3可以被g()访问,在f()返回g函数后,f()就退出了,随之消失的是变量名x1, x2, x3(注意是变量名称x1,变量的值在这里还不一定会消失)。
# 当将闭包赋值给a后,原来x1指向的数据对象(即数值1)仍被a指向的闭包函数引用着,所以x1对应的值1在x1消失后仍保存在内存中,
# 只有当名为a的闭包被消除后,原来x1指向的数值1才会消失。

a = f(1, 11, 111)  # a,将一直引用数值对象 1, 11, 111
print(a(3), '返回11')  # 调用闭包函数a,将返回 11 (g()返回的),其中1, 11, 111 是被a引用着的对象,即使a(3)执行完了也不放开
print(a(5), '返回11')  # 再次调用函数a,将返回 11,其中1, 11, 111 和上面一条语句的 是同一个数据对象

print('----------')

# 闭包的__closure__ 属性,记录着自由变量的地址。
# __closure__ 属性的类型是一个元组,这表明闭包可以支持多个自由变量的形式。这些元素是cell对象,有个cell_contents属性,保存着真正的值。

# 当闭包被调用时,系统就会根据该地址找到对应的自由变量,完成整体的函数调用。

print(f(5, 55, 555).__closure__)
print(f(5, 55, 555).__closure__[0].cell_contents)
print(f(5, 55, 555).__closure__[-1].cell_contents)

print('----------')

# 闭包特性1:变量x对应的数据对象对每个闭包来说都是相互独立的

# 例如:下面得到两个闭包,这两个闭包中持有的自由变量虽然都引用相等的数值1,但两个数值是不同数据对象,这两个闭包也是相互独立的:
a1 = f1(1)
b1 = f1(1)
print(a1, id(a1))
print(b1, id(b1))

print(a1(654), b1(654))

print('----------')


# 在闭包中,外函数结束调用后,内函数仍然可以使用外函数的变量,并且可以保存变量的状态,
# 如果要改变闭包的环境变量,就要使用关键字nonlocal。

def func3(x):
    x += 1  # x是局部变量
    print("func3() x的值为", x)

    def func4():
        nonlocal x
        x += 111
        print("func4() x的值为", x)

    return func4


# 闭包特性2:闭包函数可以一直访问x对应的数据对象,即使名称x已经消失

m = func3(2)  # 要想使变量被连续修改,需要使用同一个函数对象
# 调用内函数
m()
m()
m()

# 可以发现x的值发生了变化,内函数修改了环境变量,并保持变量的状态。


print('----------')

# 小结:一般情况下,函数结束后,函数内的变量会消失。如果想要在函数结束后,变量仍然可以使用,就要使用闭包。
# 在函数内部里面还有函数,外函数结束后,返回一个函数对象,内函数“继承”外函数的变量,能够使用并修改这些环境变量。这是因为这些环境变量以元组的形式保存在内存中了。构成闭包后,内函数可以找到这些变量。

try 语句、finally 子句

https://docs.python.org/zh-cn/3.8/reference/compound_stmts.html#finally

异常处理是通过 try … except 语句来指定的。 该语句的 finally 子句可被用来指定清理代码,它并不处理异常,而是无论之前的代码是否发生异常都会被执行。


# 异常处理是通过 try ... except 语句来指定的。 该语句的 finally 子句可被用来指定清理代码,它并不处理异常,而是无论之前的代码是否发生异常都会被执行。
def test_try_finally(int_=0):
    try:
        a = 1 / int_

    except ZeroDivisionError:
        a = 0

    finally:
        print(a)
        print('finally')


# 如果存在 finally,它将指定一个‘清理’处理程序。
# try子句执行 (包括任何except和else子句),如果在这些子句中发生任何未处理的异常,该异常会被临时保存,finally子句先被执行。如果存在被保存的异常,它会在finally子句的末尾被重新引发。

# 如果 finally 子句执行了 return, break 或 continue 语句,则被保存的异常会被丢弃:

def test_try_finally_return_0(int_=0):
    try:
        a = 1 / int_

    # 没有except和else子句

    finally:

        print('finally')
        return '被保存的异常会被丢弃'

        # print('try的异常 被重新引发')


def test_try_finally_return_1(int_=0):
    try:
        a1 = 1 / int_
    except ZeroDivisionError:
        print('不行,我再试试')
        a2 = 1 / int_

    finally:
        print('finally')
        return '被保存的异常会被丢弃'
        # print('except的异常 被重新引发,此时有2个异常')


def test_try_finally_return_2(int_=1):
    print('这儿 int_的值是{}'.format(int_))
    try:
        a = 1 / int_
    except:
        pass
    else:
        a = 1 / 0

    finally:
        print('finally')

        return '被保存的异常会被丢弃'
        # print('else的异常 被重新引发,此时有1个异常')


def test_try_finally_continue_break_0(int_=0):
    for i in range(5):
        if i >= 3:
            try:
                a = 1 / int_
            # 没有except和else子句

            finally:
                print('finally')

                print('try的异常 被保存的异常会被丢弃')
                # continue
                break


def test_try_finally_continue_break_1(int_=0):
    for i in range(5):
        if i >= 3:
            try:
                a = 1 / int_
            except ZeroDivisionError:

                print('不行,我再试试')
                a2 = 1 / int_

            finally:
                print('finally')

                print('except的异常 被保存的异常会被丢弃')
                # continue
                break


def test_try_finally_continue_break_2(int_=1):
    print('这儿 int_的值是{}'.format(int_))

    for i in range(5):
        if i >= 3:
            try:
                a = 1 / int_
            except:
                pass
            else:
                a = 1 / 0

            finally:
                print('finally')

                # print('else的异常 被保存的异常会被丢弃')
                # continue
                # break


#  如果 finally 子句引发了另一个异常,被保存的异常会被设为新异常的上下文。
def test_try_finally_Error(int_=0):
    try:
        a = 1 / int_
    except ZeroDivisionError:
        pass

    finally:
        # 报错了直接抛了异常
        print(a)  # UnboundLocalError: local variable 'a' referenced before assignment

        return '报错了直接抛了异常,没走到这一步'


# 当 return, break 或 continue 语句 在一个 try...finally 语句的 try 子语句体中被执行时,finally 子语句也会‘在离开时’被执行。

def test_try_finally_break():

    try:
        for i in range(1, 10):
            print(i)

            a = 1 / i

            if a == 0.25:

                break

    finally:
        print(a, 'finally打印的')


def test_try_finally_continue():

    try:
        for i in range(1, 10):
            print(i)

            a = 1 / i
            if a <= 0.25:
                continue

            print(a, 'continue没执行')

    finally:
        print(a, 'finally打印的')


def test_try_return_0(int_=1):
    print('这儿 int_的值是{}'.format(int_))

    try:
        a = 1 / int_
        print(a, 'try打印的')

        return a

    finally:
        a = 65  # 虽然这儿重新赋值,实际返回的是 try的
        print(a, 'finally打印的')


# 函数的返回值是由最后被执行的 return 语句所决定的。 由于 finally 子句总是被执行,因此在 finally 子句中被执行的 return 语句总是最后被执行的。

def test_try_return_1(int_=1):
    print('这儿 int_的值是{}'.format(int_))

    try:
        a = 1 / int_
        print(a, 'try打印的')

        return a  # try里的 被忽略

    finally:
        a = 65  # 这儿重新赋值
        print(a, 'finally打印的')
        return a  # 返回的是 finally的


if __name__ == '__main__':
    pass

    # test_try_finally()
    # test_try_finally_continue_break_0()
    # test_try_finally_continue_break_1()
    # test_try_finally_continue_break_2()

    # abc = test_try_finally_return_0()
    # abc = test_try_finally_return_1()
    # abc = test_try_finally_return_2()

    # abc = test_try_return_0()
    # abc = test_try_return_1()

    # print(abc, '__main__')

    # test_try_finally_break()
    test_try_finally_continue()
    

之前 我写过 https://blog.csdn.net/zyooooxie/article/details/108316723 讲到fetch_sql(),后来又改了一版:若有传db、cur,直接使用,不主动 close;若没有传db、cur时,就主动去连接 db_name数据库,跑完整个方法后,会断开连接,因为实际有可能会报错,就用到了 try 语句、finally 子句;


def fetch_sql(sql: str, db_name: str, fetch_mode: str, db: Connection = None,
              cur: Cursor = None):
    """
    sql语句-fetchone()、fetchall()
    :param sql:
    :param db_name:
    :param fetch_mode:
    :param db:
    :param cur:
    :return:
    """

    if not bool(cur):
        db_use, cur_use = connect_db(db_name=db_name)

    else:
        db_use, cur_use = db, cur

    Log.debug(sql)

    if fetch_mode == 'fetchall':
        try_str = """cur_use.fetchall()"""

    elif fetch_mode == 'fetchone':
        try_str = """cur_use.fetchone()"""

    else:
        Log.error('fetch_mode: {}'.format(fetch_mode))
        raise Exception(fetch_mode)

    try:
        cur_use.execute(sql)
        data = eval(try_str, locals())

    except Exception as e:
        db_use.rollback()

        Log.debug(e.args)
        Log.info(traceback.format_exc())

        data = False

    else:

        fetch_sql_result_check(data)

    finally:

        if not bool(cur):
            close_db(db=db_use, cur=cur_use)

    return data
    

bool()

https://docs.python.org/zh-cn/3.8/library/functions.html?#bool

Python中的布尔类型只有两种值:True和False,非常方便用于if语句。

https://docs.python.org/zh-cn/3.8/library/stdtypes.html#truth-value-testing


# 说起for、while的判断条件,往往会直接写个 if 某元素;

# 下面基本完整地列出了会被视为假值的内置对象:
# 1.被定义为假值的常量: None 和 False。
# 2.任何数值类型的零: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
# 3.空的序列和多项集: '', (), [], {}, set(), range(0)

这儿是想 再说下 None 和 False,我上面 讲 try 语句、finally 子句,里面有个 fetch_sql_result_check() ;

这个方法中 result是执行sql后,fetch 拿到的结果,但实际我碰到的情形: sql执行 有问题,报错,被try捕捉后, data = False;sql执行 没问题,但是fetchone() 没数据时,data = None;

我是想要区分这2个情形的,若 直接写 if not result,总觉得不妥。


def fetch_sql_result_check(result):
    """
    SQL Fetch结果检查
    :param result:
    :return:
    """

    if result is False:
        raise Exception('sql执行的结果 -- Fetch Fail:{}'.format(result))

    elif not bool(result):
        Log.error('{}-Fetch Nothing'.format(result))

    else:
        Log.debug('Fetch Succeed')

本文链接:https://blog.csdn.net/zyooooxie/article/details/113391645

个人博客 https://blog.csdn.net/zyooooxie

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值