个人学习python的笔记!基于 python3 ! 相关文档可以参考: https://docs.python.org/zh-cn/3/library/index.html , 本地可以执行python3 -m pydoc -p 1234
打开文档,python作为世界上最好的语言和万能的胶水语言,只能说太过于完美了!
基本语法 1. 简单控制语句 字符串推荐用 ''
单引号引用
1 2 3 4 5 6 7 8 9 10 11 12 list : List [int ] = [1 , 2 , 3 ]for elem in list : if elem > 1 : print (f'data {elem} > 1' ) else : print (f'data {elem} < 1' ) ''' data 1 < 1 data 2 > 1 data 3 > 1 '''
2. 异常 1 2 3 4 5 6 7 8 9 x = -1 try : if x < 0 : raise Exception("Sorry, no numbers below zero" ) except Exception as err: print ("find err: %s" % err) ''' find err: Sorry, no numbers below zero '''
3. 推导式(YYDS) 推导式好处: 效率更高,有点像Java的stream-api,羡慕的要死
1 2 3 4 list = [-1 ,-2 ,-3 ,4 ,5 ,6 ]print ([elem if elem>0 else -elem for elem in list if elem %2 ==0 ])
1. 列表推导式 一共两种形式:(参考: https://zhuanlan.zhihu.com/p/139621170 ) , 它主要是输出是列表(list
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import re""" 获取所有的数字 """ list = ["1" , "2" , "3" , "4" , "5" , "a" , "b" , "c" ]print ([elem for elem in list if re.match("\\d" , elem)])''' ['1', '2', '3', '4', '5'] ''' """ 获取所有的字母 """ print ([elem for elem in list if re.match("[a-z]" , elem)])''' ['a', 'b', 'c'] ''' """ 如果元素是数字则存储,否则则upper """ print ([elem if re.match("\\d" , elem) else elem.upper() for elem in list ])''' ['1', '2', '3', '4', '5', 'A', 'B', 'C'] '''
最佳实践: 参考(https://github.com/httpie/httpie/blob/master/httpie/core.py#L235 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 def decode_raw_args ( args: List [Union [str , bytes ]], stdin_encoding: str ) -> List [str ]: """ Convert all bytes args to str by decoding them using stdin encoding. """ return [ arg.decode(stdin_encoding) if type (arg) is bytes else arg for arg in args ] def decode_raw_args_parse ( args: List [Union [str , bytes ]], stdin_encoding: str ) -> List [str ]: """ Convert all bytes args to str by decoding them using stdin encoding. 不使用推导式 """ result: List [str ] = [] for arg in args: if type (arg) is bytes : result.append(arg.decode(stdin_encoding)) else : result.append(arg) return result print (decode_raw_args(args=[b'111' , b'222' ], stdin_encoding="utf-8" ))print (decode_raw_args(args=["111" , "222" ], stdin_encoding="" ))''' ['111', '222'] ['111', '222'] ''' print (decode_raw_args_parse(args=[b'111' , b'222' ], stdin_encoding="utf-8" ))print (decode_raw_args_parse(args=["111" , "222" ], stdin_encoding="" ))''' ['111', '222'] ['111', '222'] '''
2. 字典推导式 { key_expr: value_expr for value in collection if condition }
,输出是 dict
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 """ { key_expr: value_expr for value in collection if condition } 反转key value,且获取 value 为在set {'a', 'b', 'c'}中的元素 """ dict_old = {'a' : 'A' , 'b' : 'B' , 'c' : 'C' , 'd' : 'D' } print ({dict_old[value]: value for value in dict_old if value in {'a' , 'b' , 'c' }})''' {'A': 'a', 'B': 'b', 'C': 'c'} ''' print ({key: value for value, key in dict_old.items() if value in {'a' , 'b' , 'c' }})''' {'A': 'a', 'B': 'b', 'C': 'c'} '''
3. 集合推导式 表达式:
{ expr for value in collection if condition }
{exp1 if condition else exp2 for x in data}
输出是 set
其实就是上面列表推导式 []
换成 {}
,输出由 list
变成了 set
4. for 循环 迭代器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import osfrom collections.abc import Iterablewith open ("text.log" , "wt" ) as file: file.truncate() file.writelines("line 1" + os.linesep) file.writelines("line 2" + os.linesep) file.writelines("line 3" + os.linesep) pass with open ("text.log" , "rt" ) as file: for line in file: print ("type: {type}, isinstance: {isinstance}, line: {line}" .format (type =type (file), isinstance =isinstance (file, Iterable), line=line)) pass ''' type: <class '_io.TextIOWrapper'>, isinstance: True, line: line 1 type: <class '_io.TextIOWrapper'>, isinstance: True, line: line 2 type: <class '_io.TextIOWrapper'>, isinstance: True, line: line 3 '''
这里面 _io.TextIOWrapper
实现了 __next__()
方法
比如我们自己实现一个可迭代的对象
下面可以看到我使用了类型申明 List[str]
其实这个python运行时并不会检测,需要工具进行检测!
变量默认都是 Any
类型 ,具体可以看 https://docs.python.org/zh-cn/3/library/typing.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 from typing import List class Items (object ): def __init__ (self, list : List [str ] ): self.list = list self.index = 0 def __next__ (self, *args, **kwargs ): """ next,没有抛出StopIteration """ if self.index >= len (self.list ): raise StopIteration result = self.list [self.index] self.index = self.index + 1 return result def __iter__ (self, *args, **kwargs ): """ 返回一个迭代器 """ return self data = Items(["1" , "2" , "3" ]) for x in data: print (x) ''' 1 2 3 '''
5. 包管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from ..a import foo from .a import foo_a import sys from copy import deepcopy from pygments.formatters.terminal import TerminalFormatter import demo.utils.adef c_foo (): demo.utils.a.foo_a() TerminalFormatter() deepcopy() print (sys.api_version) def b_foo (): foo()
基本数据类型 1. 定义方式 mylist: list[str] = ["apple", "banana", "cherry"]
mylist=["apple", "banana", "cherry"]
Text Type: str
Numeric Types: int
, float
, complex
Sequence Types: list
, tuple
, range
Mapping Type: dict
Set Types: set
, frozenset
Boolean Type: bool
Binary Types: bytes
, bytearray
, memoryview
2. 数字基本类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 x = 1 y = 1.1 z = 1j a = complex (1 , 2 ) print (type (x))print (type (y))print (type (z))print (z.imag, z.real)print (type (a))print (a.imag, a.real)''' <class 'int'> <class 'float'> <class 'complex'> 1.0 0.0 <class 'complex'> 2.0 1.0 '''
3. 字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 str = "hello" print (str )print (str [0 :])print (str [:5 ])print (str [:-1 ])print (str [0 :5 ])print (str [0 :5 :1 ])print (str [0 :5 :2 ])''' hello hello hello hell hello hello hlo ''' print ("My name is {} and age is {}" .format ("tom" , 18 ))''' My name is tom and age is 18 ''' quantity = 3 itemno = 567 price = 49.95 myorder = "I want to pay {2} dollars for {0} pieces of item {1}." print (myorder.format (quantity, itemno, price))''' I want to pay 49.95 dollars for 3 pieces of item 567. ''' str = "hello world! " print (str .upper())print (str .lower())print (str .strip())print (str + " ..." )''' HELLO WORLD! hello world! hello world! hello world! ... ''' myorder = "I have a {carname}, it is a {model}." print (myorder.format (carname="Ford" , model="Mustang" ))''' I have a Ford, it is a Mustang. '''
4. lambda 其实就是一个func
1 2 3 4 5 6 7 8 def add (num ): return lambda x: x + num print (add(10 )(10 ))''' 20 '''
lanbda 例子2
1 2 3 4 5 6 7 8 9 10 11 12 import jsonclass Obj : def __init__ (self ): self.name = "tom" self.age = 1 print (json.dumps(Obj(), default=lambda obj: obj.__dict__))''' {"name": "tom", "age": 1} '''
集合 list
, tuple
, range
, dict
, set
, frozenset
list , 例如: mylist = ["apple", "banana", "cherry"]
tuple 是特殊的数组,就是不能改变, 例如 mytuple = ("apple", "banana", "cherry")
range 可以理解是个迭代器, 例如: dict 就是个map, 例如: thisdict = {"brand": "Ford", "model": "Mustang", "year": 1964}
set 就是个去重复的list , 例如: myset = {"apple", "banana", "cherry"}
1. list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 mylist = ["apple" , "banana" , "cherry" ] print (mylist[0 ])print (mylist[2 ])print (mylist[-1 ])print (mylist[0 :3 :2 ])''' apple cherry cherry ['apple', 'cherry'] ''' mylist.append("orange" ) print (mylist)''' ['apple', 'banana', 'cherry', 'orange'] ''' mylist.insert(0 , "mango" ) print (mylist)''' ['mango', 'apple', 'banana', 'cherry', 'orange'] ''' for x in mylist: print (x) ''' apple banana cherry orange ''' for index in range (len (mylist)): print ("index: %d" % index) ''' index: 0 index: 1 index: 2 index: 3 index: 4 ''' if "apple" in mylist: print ("success!" ) ''' success! ''' new_list = [elem.upper() for elem in mylist if "a" in elem] print (new_list)''' ['MANGO', 'APPLE', 'BANANA', 'ORANGE'] ''' newList = [] for elem in mylist: if 'a' in elem: newList.append(elem.upper()) print (newList)''' ['MANGO', 'APPLE', 'BANANA', 'ORANGE'] '''
2. map 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 thisdict = {"brand" : "Ford" , "model" : "Mustang" , "year" : 1964 } for key, value in thisdict.items(): print ("key: {}, value: {}" .format (key, value)) ''' key: brand, value: Ford key: model, value: Mustang key: year, value: 1964 ''' for key in thisdict: print ("key: {}, value: {}" .format (key, thisdict[key])) ''' key: brand, value: Ford key: model, value: Mustang key: year, value: 1964 '''
3. range 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 for x in range (6 ): print ("x is %d" % x) ''' x is 0 x is 1 x is 2 x is 3 x is 4 x is 5 ''' for x in range (2 , 6 ): print ("x is %d" % x) ''' x is 2 x is 3 x is 4 x is 5 ''' for x in range (1 , 6 , 2 ): print ("x is %d" % x) ''' x is 1 x is 3 x is 5 '''
函数 1. 定义一个函数 1 2 3 4 5 def func_1 (): pass func_1()
2. 参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 def func_1 (name, age=1 , *args, **kwargs ): print ("name: %s" % name) print ("age: %d" % age) print ("len(args): {}, type: {}" .format (len (args), type (args))) for value in args: print ("args value: {}" .format (value)) print ("len(kwargs): {}, type: {}" .format (len (kwargs), type (kwargs))) for key, value in kwargs.items(): print ("kwargs key: {}, value: {}" .format (key, value)) func_1(name="tom" , age=10 , args="1" , kwargs="2" ) ''' name: tom age: 10 len(args): 0 len(kwargs): 0, type: <class 'tuple'> len(kwargs): 2, type: <class 'dict'> kwargs key: args, value: 1 kwargs key: kwargs, value: 2 ''' func_1("tom" , 10 , "1" , "2" , args="1" , kwargs="2" ) ''' name: tom age: 10 len(args): 2, type: <class 'tuple'> args value: 1 args value: 2 len(kwargs): 2, type: <class 'dict'> kwargs key: args, value: 1 kwargs key: kwargs, value: 2 '''
3. 类型 申明输入输出类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from typing import List , Union def decode_raw_args ( args: List [Union [str , bytes ]], stdin_encoding: str ) -> List [str ]: """ Convert all bytes args to str by decoding them using stdin encoding. """ return [ arg.decode(stdin_encoding) if type (arg) is bytes else arg for arg in args ]
类 1. 定义类和方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Person (object ): gender = "none" def __init__ (self, name, age ): self.name = name self.age = age def my_name (self ): return self.name p = Person(name="tome" , age=1 ) print (p.my_name())
2. 类型的继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import json class Person(object): # gender none, male or female gender = "none" # 构造器 def __init__(self, name, age): self.name = name self.age = age def my_name(self): return self.name p = Person(name="tome" , age=1 ) print(p.my_name()) class Mail(Person): def __init__(self, name, age): super(Mail, self).__init__(name, age) self.gender = "mail" def my_name(self): return self.name + "_mail" p = Mail(name="tome" , age=1 ) print(json.dumps(p, default=lambda obj: obj.__dict__)) print(p.my_name())
3. 类 __new__
函数 主要是__init__
执行前会调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import jsonclass Person (object ): def __new__ (cls, *args, **kwargs ): instance = object .__new__(cls) instance.job = "it" return instance def __init__ (self, name, age ): self.name = name self.age = age def to_json (self ): return json.dumps(self, default=lambda obj: obj.__dict__) p = Person(name="tome" , age=1 ) print (p.to_json())
其他用法技巧 1. 类型断言 1 2 3 4 5 6 if type (1 ) is int : print ("args is int" ) ... ''' args is int '''
2. 测试 可以参考文件: https://segmentfault.com/q/1010000010389542 , 属于doctest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 def humanize_bytes (n, precision=2 ): """Return a humanized string representation of a number of bytes. >>> humanize_bytes(1) '1 B' >>> humanize_bytes(1024, precision=1) '1.0 kB' >>> humanize_bytes(1024 * 123, precision=1) '123.0 kB' >>> humanize_bytes(1024 * 12342, precision=1) '12.1 MB' >>> humanize_bytes(1024 * 12342, precision=2) '12.05 MB' >>> humanize_bytes(1024 * 1234, precision=2) '1.21 MB' >>> humanize_bytes(1024 * 1234 * 1111, precision=2) '1.31 GB' >>> humanize_bytes(1024 * 1234 * 1111, precision=1) '1.3 GB' """ abbrevs = [ (1 << 50 , 'PB' ), (1 << 40 , 'TB' ), (1 << 30 , 'GB' ), (1 << 20 , 'MB' ), (1 << 10 , 'kB' ), (1 , 'B' ) ] if n == 1 : return '1 B' for factor, suffix in abbrevs: if n >= factor: break return f'{n / factor:.{precision} f} {suffix} '
3. yield 其实类似于程序的断电,比如程序运行到那里其实是返回一个生成器,然后当你下一步是才会执行,比较节省内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from typing import List def new (size: int = 1024 * 1024 ): yield new_data(size) def new_data (size: int ) -> List [int ]: return [0 ] * size data = new() print (type (data))print (len (next (data))) ''' <class 'generator'> 1048576 '''
常用的工具包 base64 1 2 3 4 5 6 7 echo "aGVsbG8gcHl0aG9uCg==" | python -c "import sys,base64; print(sys.stdin.read())" -> echo "aGVsbG8gcHl0aG9uCg==" | python -c "import sys,base64; print(base64.b64decode(sys.stdin.read()))" -> stdout: b'hello python\n'
文件操作 r
, w
, x
,a
四种类型(a: append, w=truncate+create, x=truncate+create if not exit)b
,t
文件类型第一列可以和第二列文件类型组合,第一列不允许并存
1 2 3 4 5 6 7 8 9 10 11 import oswith open ("file.log" , "w" ) as file: for x in range (0 , 100 ): file.write("hello world" +os.linesep) with open ("file.log" ,"r" ) as file: for line in file.readlines(): print (line)
json 1 2 3 4 import jsonprint (json.dumps({"k1" : "v1" , "k2" : [1 , 2 , 3 ]}))print (json.loads('{"k1": "v1", "k2": [1, 2, 3]}' ))
如果是class,需要继承 JSONEncoder和JSONDecoder实现子类
,或者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import json, datetimeclass Demo (object ): def __init__ (self, name: str , age: int , birthday: datetime.date ): self.name = name self.agw = age self.birthday = birthday def to_json (self, _ ): return {"name" : self.name, "age" : self.agw, "birthday" : self.birthday.strftime("%Y-%m-%d" )} data = Demo("tom" , 18 , datetime.date(2001 , 1 , 1 )) print (json.dumps(data, default=data.to_json))
typing (类型限制) 官方文档: https://docs.python.org/zh-cn/3/library/typing.html
可以参考这篇文章: https://sikasjc.github.io/2018/07/14/type-hint-in-python/
对于喜欢静态类型的语言,我觉得是非常nice的
1 2 3 4 5 6 7 8 from typing import Dict , List def test (data: Dict [str , str ] ) -> List [str ]: return [x for x in data] print (test({"k1" : "v1" , "k2" : "v2" }))
可变参数 (args&kwargs) 可以使用 *args
(arguments) 和 **kwargs
(keyword arguments) 来定义可变参数
注意:可变参数解绑需要使用 *
或者 **
解出来,不然的话就有问题了,所以在参数转发中称为万能转发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class People : def __init__ (self, name='' , age=0 , **kwargs ) -> None : self.name = name self.age = age self.hobby = '' if 'hobby' not in kwargs else kwargs['hobby' ] def __str__ (self ) -> str : return f'name: {self.name} , age: {self.age} , hobby: {self.hobby} ' def NewPeople (*args, **kwargs ): print (f'NewPeople args: {args} , kwargs:{kwargs} ' ) return People(*args, **kwargs) print (People('tom' , 18 , hobby='swimming' ))print (People(name='tom' , age=18 , hobby='swimming' ))print (NewPeople('tom' , 18 , hobby='swimming' ))print (NewPeople(name='tom' , age=18 , hobby='swimming' ))
输出
1 2 3 4 5 6 name: tom, age: 18, hobby: swimming name: tom, age: 18, hobby: swimming NewPeople args: ('tom', 18), kwargs:{'hobby': 'swimming'} name: tom, age: 18, hobby: swimming NewPeople args: (), kwargs:{'name': 'tom', 'age': 18, 'hobby': 'swimming'} name: tom, age: 18, hobby: swimming
subprocess (执行命令) 使用python执行命令是非常常见的事情,这里我们使用python去处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import osimport subprocessdef c_system (): status = os.system("ls -al /data" ) if status != 0 : raise Exception(f"exit: {status} " ) def test_popen (): a = os.popen("ls -al /data" ) print (a.read()) def test_subprocess (): cmd = subprocess.run( ["ls" , "-l" , "/" ], capture_output=True ) print (str (cmd.stdout, 'utf-8' )) print (str (cmd.stderr, 'utf-8' )) print (cmd.returncode) test_subprocess()
argparse 工具 python实际上自带了参数解析器,说实话非常的nice,实际上完全够用了,但是写法不太优雅,有兴趣的同学可以看 https://github.com/pallets/click/ 这个库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import argparseimport sysif __name__ == '__main__' : parser = argparse.ArgumentParser(description='The test command' ) """ 子命令 """ subparsers = parser.add_subparsers(help ='sub-command help' ) run_parser = subparsers.add_parser('run' , description='run cpp files' ) run_parser.add_argument('--cpp' , dest='cpp' , required=True , type =str , help ='the cpp file' ) """ 参数 """ parser.add_argument('-c' , '--config' , dest='config' , metavar='config' , type =str , required=False , help ='The config file' ) parser.add_argument('-v' , '--version' , dest='version' , action='store_true' ) parser.add_argument('--num' , dest='num' , action='append' , type =str ) parser.add_argument('--int' , dest='int' , nargs='+' , type =int ) """ 参数组 """ run_parser = parser.add_argument_group( 'test' , description='build && run cpp file' ) run_parser = run_parser.add_mutually_exclusive_group(required=True ) run_parser.add_argument('--foo' , help ='foo help' ) run_parser.add_argument('--bar' , help ='bar help' ) run_parser.add_argument('--cpp' , '-cpp' , dest='cpp' , type =str , help ='the cpp file' ) args = parser.parse_args() print (args) if args.version: print ("version: 1.0.0" ) exit(0 )
如何使用了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ➜ vscode git:(master) ✗ python parse_args.py --help usage: parse_args.py [-h] [-c config] [-v] [--num NUM] [--int INT [INT ...]] [--foo FOO | --bar BAR] {run,build} ... The test command positional arguments: {run,build} sub-command help optional arguments: -h, --help show this help message and exit -c config, --config config The config file -v, --version --num NUM --int INT [INT ...] group params: test group params --foo FOO foo help --bar BAR bar help ➜ vscode git:(master) ✗ python parse_args.py run --cpp main.cpp test.cpp Namespace(config=None, version=False, num=None, int=None, foo=None, bar=None, cpp=['main.cpp', 'test.cpp']) ➜ vscode git:(master) ✗ python parse_args.py --version --int 1 2 3 --num 2 --num 3 Namespace(config=None, version=True, num=['2', '3'], int=[1, 2, 3], foo=None, bar=None) version: 1.0.0
包装器(decorator) decorator 体现了aop的思想,非常的方便,简直是yyds!
打印日志 bytedance/byteapi/utils.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import timeimport loggingdef print_run_time_simple (func ): def wrapper (*args, **kwargs ): start = time.time() ret = func(*args, **kwargs) run_time = time.time() - start if run_time > 0.5 : logging.info(f'当前函数 {func.__name__} 耗时: {run_time:.2 f} s' ) return ret return wrapper
1 2 3 4 5 6 7 8 from bytedance.byteapi import utilsimport logging@utils.print_run_time_simple def test_print (): logging.info("hello world" )
1 2 3 4 5 6 7 8 9 10 11 (venv) ➜ pytest tests/test_utils.py ========================================================== test session starts ========================================================== platform darwin -- Python 3.9.18, pytest-4.6.11, py-1.11.0, pluggy-0.13.1 rootdir: /Users/bytedance/python, inifile: pytest.ini collected 1 item tests/test_utils.py::test_print ------------------------------------------------------------- live log call ------------------------------------------------------------- 2023-12-04 23:41:24 test_utils.py:8 [INFO]: hello world 2023-12-04 23:41:24 utils.py:10 [INFO]: 当前函数 test_print 耗时: 0.00s PASSED [100%]
decorator 写法,可以传递参数 bytedance/byteapi/utils.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import timeimport loggingdef print_run_time (cost ): def decorator (func ): def wrapper (*args, **kwargs ): start = time.time() ret = func(*args, **kwargs) run_time = time.time() - start if run_time > cost: logging.info(f'当前函数 {func.__name__} 耗时: {run_time:.2 f} s' ) return ret return wrapper return decorator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from bytedance.byteapi import utilsimport loggingimport time@utils.print_run_time(cost=1.5 ) def test_sleep_1s (): logging.info(f"start sleep: 1s" ) time.sleep(1 ) logging.info(f"end sleep: 1s" ) @utils.print_run_time(cost=1.5 ) def test_sleep_2s (): logging.info(f"start sleep: 2s" ) time.sleep(2 ) logging.info(f"end sleep: 2s" )
输出,我们发现sleep2s的函数执行的时候命中了耗时打印日志 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 (venv) ➜ pytest tests/test_utils.py::test_sleep_2s tests/test_utils.py::test_sleep_1s ========================================================== test session starts ========================================================== platform darwin -- Python 3.9.18, pytest-4.6.11, py-1.11.0, pluggy-0.13.1 rootdir: /Users/bytedance/python, inifile: pytest.ini collected 2 items tests/test_utils.py::test_sleep_2s ------------------------------------------------------------- live log call ------------------------------------------------------------- 2023-12-04 23:49:42 test_utils.py:23 [INFO]: start sleep: 2s 2023-12-04 23:49:44 test_utils.py:25 [INFO]: end sleep: 2s 2023-12-04 23:49:44 utils.py:23 [INFO]: 当前函数 test_sleep_2s 耗时: 2.01s PASSED [ 50%] tests/test_utils.py::test_sleep_1s ------------------------------------------------------------- live log call ------------------------------------------------------------- 2023-12-04 23:49:44 test_utils.py:15 [INFO]: start sleep: 1s 2023-12-04 23:49:45 test_utils.py:17 [INFO]: end sleep: 1s PASSED [100%]
__name__
变量如果在一个包下有多个立即执行代码,切记一定要用这个判断下
1 2 if __name__ == "__main__" : main()