Python 函数

定义函数

(需要在使用前定义,最好函数名以小写字母开头)

位置传参
def 函数名(参数1[,参数2,...]):
    '函数文档,不会打印出来,只有用:函数名.__doc__和help(函数名)才会打印出这引号里的话,只能写在函数下面第一行'
    """
    多行函数文档
    上面那个只能单行时使用,这个也必须写在函数定义下面第一行,这里写在了下面第二行,其实是不对的
    """
    功能语句...
    [return 参数]
关键字传参
def 函数名(参数1=默认值[,参数2=默认值,...]):
    '给定默认参数(引用函数时如果没传参就用默认)'
...
*传参
def 函数名(*参数名):
    '给定收集多个非关键字参数(当不知道会传多少个参数进来时,该方法可以传很多参数),其将被转化成一个元组'
...

举例:

>>> def abc(a, *b):
    print(a)
    print('参数长度:',len(b))
    print('第二个参数:',b[1])  #b是一个元组

>>> abc(1,'sad',3,4,435,23)
1
参数长度: 5
第二个参数: 3

注:
*传参来说,如果想要定义个确定的参数时,引用时就得用关键字传参,例如:def abc(*a,abc) ,那么传参时得这样:abc(1,2,'sa',abc='关键字传参')

**传参
def 函数名(**参数名):
    '给定收集多个关键字参数(当不知道会传多少个关键字参数进来时,该方法可以传很多参数),其将被转化成一个字典'
...

举例:

>>> def two(a=1,**b):
    print(b)  #b是一个字典

>>> two(a=1,b=2,c=3,d=4,e=5,f=6)
{'e': 5, 'd': 4, 'c': 3, 'b': 2, 'f': 6}
>>> di = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}
>>> two(**di)
{'b': 2, 'e': 5, 'c': 3, 'f': 6, 'd': 4}
# 可以看出有两种方式传参,一个是各种:键=值,另一种是:**字典

注:
在python3.8中,新增了传参限制的语法,如符号/前仅允许位置传参,符号*后仅允许关键字传参,举例:

def test(a, /, b, *, c):
  pass

test(1, 2, c=3)
# a必须为位置传参,b随意,c必须为关键字传参
lambda函数

(也称为匿名函数,不需要取名,不需要提前定义,现定义现用方式)
格式:a = lambda 参数1[,参数2,...]: 功能语句(例如:参数1+参数2),意思就是传入前面的参数,并返回冒号后面的内容,举例:

>>> a = lambda x,y: x+y
>>> a(1,2)
3  #传入1和2,返回1+2
内嵌函数

(函数内部可以再定义函数,但是只有他的外面一层函数能调用他),举例:

def 函数名1(参数):
    功能语句...
    def 函数名2(参数):
        功能语句...
    函数名2(实参)    #这里调用内嵌函数

引用函数

1.按顺序传参:函数名(实参1[,实参2])
2.关键字传参:函数名(形参=实参[,形参=实参])
注:
对于传参时,要注意函数中设置了默认值的参数,其在调用前就已经分配了一块地址,给其传参时,将会再开辟一个另外的地址存放,如果没传参时,就是直接用原来那个地址的参数来使用,举例:

def abc(a, lt=[]):
    lt.append(a)
    print(lt)

abc(1)      #[1],此时用的是默认的lt,假设地址是1
abc(2, [])  #[2] ,此时用的是自己传的lt,开设了另一个地址存放,假设是2
abc(3)      #[1, 3],此时用的还是默认的lt,也就是地址为1的那个lt,所以是在第一次调用以后的基础上继续调用

递归函数

1.设置递归深度:

import sys
sys.setrecursionlimit(深度)

防止递归无限循环下去(Python默认最多递归1000次)
注:
递归虽然能使代码更加简洁,但效率相对来说可能没有迭代高

内置函数

可以通过dir(__builtins__)查看所有的内置函数

list()

把一个数据变成列表,括号里得是元组、字符串或列表等(迭代器),举例:

#字符串
>>> str1='a b c'
>>> list(str1)
['a', ' ', 'b', ' ', 'c']
#元组
>>> tuple1=(1,2,'a')
>>> list(tuple1)
[1, 2, 'a'] 

注:
千万别给变量取名叫list、tuple、str等,不然这个函数就会被同名的局部变量覆盖而无法使用,可以看下面:

>>> type(list)
<class 'type'>    # 原本获取的是一个内置函数类
>>> list = 1
>>> type(list)
<class 'int'>     # 获取的是局部变量1
tuple()

把一个数据变成元组,跟list用法差不多,参考上面

str()

把数据变成字符串,但只是在外面单纯用引号括起来,举例:

>>> tuple1=(1,2,3)
>>> str(tuple1)
'(1, 2, 3)'  #不是'123'

注:
如果想列表、元组之类的转字符串,用str()是没用的,但是可以用字符串下的join()方法,用空把他们连起来即可,举例:

>>> a = ['a', 'b', 'c']
>>> "".join(a)
'abc'
>>> a = [1,2,3]
>>> "".join(i for i in a)
TypeError: sequence item 0: expected str instance, int found

但是从第二个例子可以看出如果列表里元素不是字符串的话,就会报错,所以可以用链表推导式来全部转成str形式,然后再拼起来,举例:

>>> a = [1,2,3]
>>> "".join(str(i) for i in a)
'123'
len()

返回字符串长度,如果是列表和元组就是输出有几个

max()

返回参数或集合最大值,如果是一个字符串,则返回一个ASCII码值最大的,列表和元组的话必须里面全是一种变量类型;返回最小值用min(),这两个还可以结合字典查询最值对应的键,格式为:max(字典, key=字典.get)举例:

>>> d
{2: 2, 3: 6, 5: 1, 6: 1, 7: 1, 9: 1}
>>> max(d, key=d.get)
3

注:
在python中方法函数都是可传递的,因此上面key=d.get其实就是把字典d下的方法get传入,然后依次对每一个值用get方法,因此上面的代码也可以理解成:

max(d, key=lambda k: d.get(k))
# 依次传入所有的key,然后分别求出对应的value
sum()

计算参数和,针对列表和元组,且必须里面全是数字,sum后面还可以加个参数,表示计算的总和再加这个数,举例:

>>> list1=[1,2,3]
>>> sum(list1)
6
>>> sum(list1,2)
8    #总和再加上2,相当于:sum(list1) + 2

注:
python自带模块里没有求均值的(numpy模块下有),用自带的求均值可以:

>>> sum(list1)/len(list1)
2.0    #总和除以总数
sorted()

sort()方法差不多,可以对字符串、列表排序,对字符串排序后会变成一个列表,举例:

>>> str1='asb'
>>> sorted(str1)
['a', 'b', 's']
reversed()

reverse()一样可以对字符串、列表倒序,但生成的是个对象而不是列表,例如直接:

>>> str1='asb'
>>> reversed(str1)
<reversed object at 0x03D30590>

所以如果要生成个列表就:

>>> list(reversed(str1))
['b', 's', 'a']
enumerate()

可以生成一个元组,包含各个的下标个和对应的值,跟reversed一样需要转下类型,举例:

>>> str1='asb'
>>> list(enumerate(str1))
[(0, 'a'), (1, 's'), (2, 'b')]  #转列表
>>> dict(enumerate(str1))
{0: 'a', 1: 's', 2: 'b'}    #转字典

该方法常用于迭代数据同时希望能够获取下标的场景,举例:

>>> for index, each in enumerate(['a', 'b', 'c']):
    print(index, each)
0 a
1 b
2 c
zip()

把两个数据合起来生成一个一一映射的关系,映射长度取决于短的那个,举例:

>>> str1='asb'
>>> str2='csaf'
>>> list(zip(str1,str2))
[('a', 'c'), ('s', 's'), ('b', 'a')]
>>> dict(zip(str1,str2))
{'a': 'c', 'b': 'a', 's': 's'}

要注意的是对于转字典时,出现两个重复的键映射时,会被后一个映射的值给覆盖,例如:

>>> a = [1,3,4,5,2,5]
>>> b = ['a','fs','s','s','d','g']
>>> dict(zip(b,a))
{'g': 5, 'a': 1, 'd': 2, 's': 5, 'fs': 3}  #s出现2次,第一次是4,第二次是5,所以最后就为5

注:
zip不但可以将两个数据一一映射起来,还能进行反操作,即将一一映射的数据返回原来的样子,举例:

>>> x = list(zip([1,2,3], [4,5,6]))
>>> x
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(*x))
# 使用*号代表反操作
[(1, 2, 3), (4, 5, 6)]
type()

输出变量类型,举例:

>>> type('a')
<class 'str'>

注:
该函数还能够创建类对象,在元类编程里会介绍

isinstance(a,b)

确定变量类型,a是你输入的变量,b是你输入的类型,然后会对比两个类型是否一样,一样就返回True,不一样返回False,举例:

>>> a = 'a'
>>> isinstance(a, int)
False
>>> isinstance(a, str)
True
range([start,],stop[,step=1])

生成一个从start参数值到stop参数值结束的数字序列,比如:range(1,5)就是生成一个:1到4的序列(不包含5);如果只有stop,就会生成一个从0到stop-1的序列,比如:range(5)就生成:0,1,2,3,4;step表示每次加几,比如range(0,10,2),就是:0,2,4,6,8(每次递增2)。range经常和for结合使用,举例:

>>> for i in range(5) :
        print(i, end='-')

0-1-2-3-4-    #range()和for结合使用
filter(过滤函数,要过滤的内容)

将右边内容以左边函数方式计算,并将0或者False的过滤掉,举例:

>>> list(filter(lambda x: x % 2, range(10)))    #过滤1到10里的偶数(把右边的数全部除2,结果为0都会被过滤)
[1, 3, 5, 7, 9]

过滤函数就写None,默认过滤0和False,举例:

>>> list(filter(None,range(10)))
[1, 2, 3, 4, 5, 6, 7, 8, 9]    #把0过滤了
map(加工规则,要加工的内容)

把右边内容以左边规则加工,要注意的是右边加工的内容必须为可迭代的,举例:

>>> map(square, [1,2,3,4,5])   # 计算列表各个元素的平方
[1, 4, 9, 16, 25]
>>> list(map(lambda x: x*2 ,range(10)))    #把1到10都乘2
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

并且map函数还支持传入多个数据,举例:

>>> list(map(lambda x, y: x*y ,range(10), range(10, 20)))
# 同时传入两个迭代器进行乘积运算
[0, 11, 24, 39, 56, 75, 96, 119, 144, 171]
eval(expression[, globals[, locals]])

将字符串表达式转成他本应该是的类型,然后执行该表达式,并返回值,举例:

>>> eval('2')
2    #自动转int型
>>> eval('2+2')
4    #自动转为int型计算并返回

也可以用来实现简单数据类型的深拷贝,原理类似JS中先转JSON再解析从而实现深拷贝,举例:

>>> a = [1,2,[1,2,3]]
>>> b = eval(str(a))
# 先转字符串在eval,实现a的深拷贝
>>> b
[1, 2, [1, 2, 3]]
>>> a[2].pop()
3
>>> b
# 可以看到b没有随之改变
[1, 2, [1, 2, 3]]

但这种方式只支持内容都是基本数据类型的情况,对于内容当中存在类、函数等情况时,就会报错

abs()

计算绝对值

exec()

动态执行python代码,里面放的是字符串,但是会被解析成python代码运行,举例:

>>> exec("print('aaa')")
aaa    #执行了里面的语句

这个当需要动态生成变量时就挺好用,举例:

>>> for each in range(10):
        exec("x" + str(each) + "= each")    #动态生成x0到x9变量,并赋值0到9
        print("x" + str(each) + ":",eval("x" + str(each)))  #使用eval将x0到x9从字符串变回原来的变量

x0: 0
x1: 1
x2: 2
x3: 3
x4: 4
x5: 5
x6: 6
x7: 7
x8: 8
x9: 9
>>> x0
0

这里再用exec()来实现一个最基本的交互界面:

while 1:
    try:
        cmd = input(">>")
        exec(cmd)
    except Exception as e:
        print(e)
round()

四舍五入数字,举例:

>>> round(3.5)
4

其还有第二个参数,代表四舍五入到第几位,比如四舍五入到小数点前两位,则:

>>> round(3.567,2)
3.57
__import__("package.module")

动态导入某个包的某个模块(当然直接导入模块也是可以的),例如:b = __import__("lib.ast"),但要注意的是此时虽然导入了lib.ast并传给了b,但是b此时并不是lib.ast,b相当于是lib,所以要用ast还得从b里面调用,假如ast下有个类A,A下有属性m,举例:

b = __import__("Lib.ast")
Y = b.ast.A()       #此时b只是Lib,所以要用b.ast
print(Y.m)

注:
  使用importlib模块下的import_module("module", "package")也能实现同样的功能,而且和上面不同的是得到的不是包而是模块,举例:

import importlib
a = importlib.import_module("ast", "Lib")
X = a.A()
print(X.m)
chr()/ord()

ASCII转字符串/字符串转ASCII,举例:

>>> ord('a')
97
>>> chr(97)
'a'
format()

和字符串自带的format()方法功能差不多,只是使用方法上稍微不同,可以将字符按规定格式输出,例如左右居中的对其输出、保留精度输出、进制转换输出等,例如:

>>> format("aaa", ">10")  # 长度10位,向右居中
'       aaa'

将上面的换成字符串下的format()方法时,需要在括号中加入:代表调用格式,举例:

>>> "{:>10}".format("aaa")  # 和上面等效
'       aaa'

更多使用参考:
https://www.cnblogs.com/mys6/p/10561416.html

any()

对于列表、数组这样的数据,里面内容只要任一不为False则返回True,否则返回False,举例:

>>> any([1,0])
True
>>> any([0,0])
False
all()

对于列表、数组这样的数据,里面内容只要全不为False则返回True,否则返回False,举例:

>>> all([1,0])
False
>>> all([1,1])
True
id()

获取内存地址

setattr/getattr

添加/获取类属性,举例:

>>> class A:
    pass
# 定义一个类
>>> a = A()
>>> setattr(a, "x", 1)
# 设置定义对象a的属性x
>>> a.x
1
>>> getattr(a, "x")
# 可以看出getattr和直接获取是一样的
1
>>> getattr(a, "y", 0)
# 获取a对象的y属性,不存在则返回默认值0
0
>>> setattr(A, "y", 1)
# 给类A设置属性y
>>> getattr(a, "y", 0)
1
dir()

查看某个内容的所有属性和方法等,如果不传值的话,则输出当前内存中的所有变量,举例:

>>> dir()
# 查看刚开启的shell里所有的变量
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
>>> a = 1
>>> dir()
# 上面定义了变量a,可以发现多了a
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a']
>>> dir(a)
# 查看a的所有属性和方法
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
repr()

将内容变成供解释器读取的字符串,举例:

>>> a = {'x':1, 'y':[1,2,3]}
>>> repr(a)
# 变成对应的字符串
"{'x': 1, 'y': [1, 2, 3]}"

该方法的场景可以用来捕捉异常错误时看到更详细的内容,举例:

>>> try:
    raise Exception("error")
except Exception as e:
    print(e)
# 一般打印的只有错误信息
error
>>> try:
    raise Exception("error")
except Exception as e:
    print(repr(e))
# 可以看到错误所属的类
Exception('error',)
callable

判断传入的对象是否可调用,举例:

>>> callable(1)
False
>>> callable(lambda x: x+1)
True
>>> class A:
    pass
>>> callable(A)
True
更多内置函数参考

https://www.cnblogs.com/linux-chenyang/p/6473820.html

函数、方法类

函数类

python中一切都是对象,包括函数、方法等,例如函数对象,我们可以查看其类:

def x(): 
    print(1)

print(type(x))

# <class 'function'>

而定义函数,实质就是通过函数类实例化一个函数对象,其中需要传入code对象,代表函数执行的代码,以及传入一个全局字典,记录需要使用到的全局属性举例:

def x(): 
    print(1)
    y()

def y():
    print(2)

fun_class = type(x)
z = fun_class(x.__code__, {"print": print, "y": y})
# 定义一个函数z,传入x的__code__属性和函数映射
z()
print(z.__globals__)
print(y.__code__)
print(y.__globals__)
# 默认定义函数时将全局字典传入,相当于function_class(code, globals())

# 1
# 2
# {'print': <built-in function print>, 'y': <function y at 0x000001C0A6438598>}
# <code object y at 0x000001C0A61C2DB0, file "...xxx.py", line xxx>
# {'__name__': '__main__', ..., 'x': <function x at 0x000001C0A4563EA0>, 'y': <function y at 0x000001C0A6438598>}

一个函数的调用主要就是通过去指定属性__code__里查找代码对象内容以及需要调用的函数等,所以我们也可以通过修改这些属性来改变函数的执行的内容,举例:

def x(): 
    print(1)

def y():
    print(2)

z = x
x.__code__ = y.__code__
# 将x指向的函数的执行代码改成y指向的函数代码,此时由于z和x指向的函数相同,所以z和x都是输出2
# 如果执行的是:x = y,则代表将x指向y,此时z还是指向原来的函数,所以z输出1
z() # 2
方法类

方法类实际上在内部定义了一个__func__属性用于指向执行的函数对象,以及一个__self__属性指向绑定的对象,举例:

class A:
    def aaa(self):
        pass

a = A()
print(type(A().aaa.__func__), type(A().aaa.__self__))

# <class 'function'> <class '__main__.A'>
参数机制

对于python中的函数和方法,设置的参数默认值都会被存放在当前类的__defaults____kwdefaults__属性里,举例:

class A:
    def __init__(self, x, y=None, li=[]):
        self.xxx = x
        self.yyy = y
        self.li = li

    def test(self, m=1, *args, n=100, **kwargs):
        pass

print(A.__init__.__defaults__, A.__init__.__kwdefaults__)
print(A.test.__defaults__, A.test.__kwdefaults__)

# (None, []) None
# (1,) {'n': 100}

可以看出如果没有设置*传参,那么全部参数都存放在__defaults__当中,而*之后的参数则全部存放在__kwdefaults__

注:
如果设置的参数默认值是可变对象,就有可能会被复用,例如参数默认值是列表导致的问题:

def test(x, li=[]):
    li.append(x)
    print(li)

test(1)
test(2, [])
test(3)
print(test.__defaults__)

# [1]
# [2]
# [1, 3]
# ([1, 3],)

可以看到因为第一次和第三次调用test函数时没有传入列表,因此test函数使用了__defaults__属性里的列表进行操作,结果导致第一次和第三次使用的是一个列表,而第二次使用的是另一个列表,因此参数的默认值尽量不要使用可变对象

code对象

参考:
https://www.cnblogs.com/wutaotaosin/articles/12525937.html
https://blog.csdn.net/qq_29695701/article/details/94194146

栈帧

栈帧是python用来管理函数的对象,每当创建一个函数,就会创建一个栈帧对象来记录当前函数的相关信息,如:函数名、当前执行到的行数、上一级函数等

获取栈帧

几种获取方式:

  • 通过inspect模块的currentframe()函数获取,举例:
import inspect

def test():
    # 获取当前函数栈帧
    frame = inspect.currentframe()
    # 获取函数名
    print(frame.f_code.co_name)
    # 获取执行的行数
    print(frame.f_lineno)

test()

# test
# 9

注:
该函数内部是通过sys下的_getframe()函数获取的,源码如下:

def currentframe():
    """Return the frame of the caller or None if this is not possible."""
    return sys._getframe(1) if hasattr(sys, "_getframe") else None
  • 通过捕获异常,此时sys.exc_info()里会接收异常的三个对象,然后通过sys.exc_info()[2].tb_frame获取栈帧,举例:
import sys

def test():
    try:
        raise
    except:
        # 获取栈帧
        frame = sys.exc_info()[2].tb_frame
        print(frame.f_code.co_name)
        print(frame.f_lineno)

test()

# test
# 10
栈帧示例-封装函数获取当前代码行数

在封装的方法里获取栈帧的上一级栈帧,然后返回栈帧对应的行数,举例:

import sys

def get_row():
    try:
        raise
    except:
        frame = sys.exc_info()[2].tb_frame
        return frame.f_back.f_lineno

if __name__ == '__main__':
    print(get_row())

# 12

inspect.currentframe()或者sys._getframe(1)也都是可以的,这里的示例通过异常来获取是参考了logging模块的实现方式

栈帧示例-print封装(自动输出文件、行数、时间)
import sys
import os
from datetime import datetime

class LogPrint:
    """日志输出封装类
    """
    def __init__(self):
        self._config()
    
    def _config(self):
        """基本配置
        """
        # 日志文件目录
        self.log_dir = "./"
        # print函数可接收的参数
        self.output_options = ["sep", "end", "file", "flush"]
        # 日志文件可接收的参数
        self.log_options = ["encoding"]

    def _get_frame(self):
        """获取栈帧"""
        try:
            return sys._getframe(5)
        except:
            return sys.exc_info()[2].tb_frame.f_back.f_back.f_back.f_back.f_back

    def _get_cur_row(self):
        """获取日志行数
        """
        return self._get_frame().f_lineno

    def _get_file_name(self):
        """获取文件名
        """
        return self._get_frame().f_code.co_filename

    def _get_head(self):
        """输出语句头
        """
        return f"[{self._get_file_name()}-{self._get_cur_row()}]: "

    def _get_tail(self, time_f):
        """输出语句尾,包括打印输出和日志输出的(日志输出一定会加上时间)
        @param:
            - time_f 是否加上输出时间
        """
        tail = ""
        tail_l = f" ({datetime.now()})"
        if time_f:
            tail = tail_l
        return tail, tail_l

    def _format_output(self, s, head, tail):
        """格式化输出内容
        """
        return head + " ".join(s) + tail

    def _get_output(self, *s, time_f=True):
        """获取输出内容,包括打印输出和日志输出的
        """
        head = self._get_head()
        tail, tail_l = self._get_tail(time_f)
        s_p = self._format_output(s, head, tail)
        s_l = self._format_output(s, head, tail_l)
        return s_p, s_l

    def printf(self, *s, time_f=True, log=False, split=True, **config):
        """输出文件名,行数,时间
        @param:
            s: 输出字符串
            split: 行分隔符
            time_f: 是否输出时间
            log: 是否保存进日志
            config: print相关配置参数
        """
        s_p, s_l = self._get_output(*s, time_f=time_f)
        self._print_deco(s_p, split=split, **config)
        if log:
            self._write_to_log(s_l, **config)

    def printl(self, *s, time_f=True, **config):
        """输出文件名,行数,时间到日志
        @param:
            同printf
        """
        s_p, s_l = self._get_output(*s, time_f=time_f)
        self._write_to_log(s_l, **config)

    def _has_log_dir(self):
        """日志文件夹是否存在
        """
        return hasattr(self, "log_dir") and os.path.isdir(self.log_dir)

    def _get_log_file(self):
        """获取日志文件名
        """
        now = datetime.now()
        year, month, day = now.year, now.month, now.day
        return f"{year}-{month}.log"
        # return f"{year}-{month}-{day}.log"

    def _write_to_log(self, s, **config):
        """写入到日志方法
        """
        if not self._has_log_dir():
            return
        config = self._get_log_config(config)
        encoding = config["encoding"] if "encoding" in config else "utf-8"
        log_file = self._get_log_file()
        with open(f"{self.log_dir}/{log_file}", "a", encoding=encoding) as lf:
            lf.write(f"{s}\n")

    def _print_split(self, config):
        """输出行分隔符
        """
        if config.get("split"):
            print("=" * 100)

    def _get_config(self, type, config):
        """获取指定配置
        """
        option_config = {}
        self.options = getattr(self, f"{type}_options") or {}
        for k in config:
            if k in self.options:
                option_config[k] = config[k]
        return option_config

    def _get_log_config(self, config):
        """获取日志输出参数配置
        """
        return self._get_config("log", config)

    def _get_output_config(self, config):
        """获取print参数配置
        """
        return self._get_config("output", config)

    def _print_deco(self, *s, **config):
        """输出装饰器,扩展相关功能
        """
        self._print_split(config)
        print(*s, **self._get_output_config(config))
        self._print_split(config)

# 暴露输出方法
# =======================================
# 输出内容
printf = LogPrint().printf
# 输出到日志
printl = LogPrint().printl

if __name__ == '__main__':
    printf("aaa", split=False, log=True)
    printl("bbb")
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 再也不会爱 只会喜欢 一辈子虽然那么长 我没有精力和爱的能力第二个 一生只爱一个人 我相信有人跟我一样
    微胖柳儿阅读 230评论 0 0
  • 顿时便是两器相击,发出叮叮金属相撞之声,那领头的人身后几人,或许是因为对手是女性的原因,动作却是快了不少,这使易青...
    唐醋鲤鱼阅读 270评论 0 1
  • 虽然这样不好意思开口,但是我还是得坦诚的面对自己。我并非是一个作家,这一篇文章的核心内容是我在《得到》APP中的一...
    风落天阅读 467评论 0 0