• 内置函数,匿名函数,正则表达式,常用模块


    匿名函数:

    1.函数没有名字

    2.函数体自带return,所以不能在lambda中用return

    lambda x,y,z=1:x+y+z  等同于 def func(x,y,z=1):return x+y+z

    print(func) 和print(lambda x,y,z=1:x+y+z) 一样都是打印的内存地址

    匿名函数的应用场景:

    应用于一次性的场景,临时使用

    内置函数:

    print(abs(-1))  # 取绝对值
    # 1
    print(all([1,2,'a',None]))  # all()相当于对可迭代对象进行for循环,取出一个值判断它的bool值,如果一个为假,则为假,直到全为真,表达式的结果才为真
    # False
    print(all([]))
    # True
    print(any([1,2,'a',None]))  # 与all()相反,any()只要可迭代对象有一个为真,则表达式的结果为真
    # True
    print(any([]))
    # False

    bool值为假的情况,None,空,0,False
    print(any(['  ',None,False]))  # '  ' 不为空
    # Ture
    print(any(['',None,False]))   # '' 为空
    # False
    print(bin(10))  # 十进制转二进制
    print(oct(10))  # 十进制转八进制
    print(hex(10)) # 十进制转十六进制 
    bytes()
    # python3 字符串本身就是以unicode形式存储的
    unicode---->encode---->bytes
    即可得到bytes类型
    
    print('hello'.encode('utf-8'))
    # b'hello'
    print(bytes('hello',encoding='utf-8'))
    # b'hello'
    callable   # 检查是否可被调用的,就是名称加括号后能否被执行
    print(callable(bytes))  
    # True
    print(callable(abs))
    # True
    print(chr(65))
    # A
    print(ord('#'))
    # 35
    #工厂函数
    x = 1 # x = int(1)
    x = int(2)
    
    complex
    float
    str
    list
    tuple
    dict
    set
    frozenset  # s1 = frozenset({1,2,3,4})  # print(type(s1))
    # dir   查看可以调用的属性
    import sys
    print(dir(sys))
    print(divmod(10,3))
    # (3,1)      (商,余数)
    #enumerate
    l=['a','b','c']
    res=enumerate(l)   # enumerate是迭代器
    print(res)      # <enumerate object at 0x000001DAA438>  打印的是enumerte的对象
    for i in res:
        print(i)
    
    #
    (0,'a')
    (1,'b')
    (2,'c')
    #enumerate就是给每个元素前面加一个索引
    #globals,locals  查看全局作用域(内置和全局)(通过字典形式展示出来)和局部作用域
    #hash 校验字符串
    print(hash('abcdefg123'))
    print(hash('abcdefg123'))
    # 6142847409289919031
    # 6142847409289919031
    #id      是python解释器实现的功能,只是反映了变量在内存的地址,但并不是真实的内存地址
    x=1
    print(id(x)) 
    #isinstance
    x=1
    print(type(x) is int)
    print(isinstance(x,int))  # x是int的一个实例
    print(pow(3,2))    # 3**2
    # 9
    print(pow(3,2,2))  # 3**2%2
    # 1
    #reversed
    l=[1,'a',2,'c']
    print(list(reversed(l)))
    # ['c',2,'a',1]
    #slice切片
    l=[1,2,3,4,5,6]
    print(l[0:4:2])   # 已经写死
    #[1,3]
    
    s=slice(0,4,2)    # 可以应用于很多列表
    print(l[s])
    #[1,3]
    #sorted  排序
    l=[1,10,4,3,-1]
    print(sorted(l))
    # [-1,1,3,4,10]
    print(sorted(l,reverse=True))
    # [10,4,3,1,-1]
    #sum
    print(sum(i for i in range(10)))
    # 45
    #vars
    import m1    # m1.py
    print(vars(m1) == m1.__dict__)
    #zip
    s='hello'
    l=[1,2,3,4,5]
    res=zip(s,l)   # zip对象,res是迭代器
    print(list(res))
    # [('h',1),('e',2),('l',3),('l',4),('o',5)]
    #__import__  根据字符串导入模块
    sys=__import__('sys')
    print(sys)
    -----------------------------------------
    import sys   # sys 这里并不是字符串,是一个名字
    1.执行模块里面的内容
    2.产生名称空间
    3.在当前位置拿到名字sys
    
    现在有一个需求是根据用户输入的字符串来导入模块
    m_name = input('module>>: ')
    if m_name == 'sys':
        m=__import__(m_name)
        print(m)   # 得到内置模块
        print(m.path)

    内置函数的补充

    salaries={
    'tom':3000,
    'jerry':10000000,
    'peter':10000,
    'brian':2000
    }
    #取出工资最高的人名
    print(list(zip(salaries.values(),salaries,keys())))
    #[(1000, 'tom'),(10000000, 'jerry'),(10000, 'peter'),(2000, 'brian')]
    print(max(zip(salaries.values(),salaries,keys())))
    #(10000000, 'jerry')
    print(max(zip(salaries.values(),salaries,keys()))[1])

    # 简便方法
    print(max(salaries,key=lambda name:salaries[name])) # max for循环salaries,得到名字,传给lambda的name,然后根据name得到薪资,这个薪资就当作max的key
    # jerry

    def get_value(name):   # 通过key获取value    
    return salaries[name]

    print(max(salaries,key=get_value)) #key指定的是函数的内存地址
    # jerry
    此方法,函数一直占据内存空间,使用lambda会更好
    salaries={
    'tom':3000,
    'jerry':10000000,
    'peter':10000,
    'brian':2000
    }

    def get_value(name):   # 通过key获取value    
    return salaries[name]
    print(sorted(salaries,key=get_value,reverse=True))
    #map
    names=['tom','jerry','peter','brian','json']
    
    res=map(lambda x:x+'_hello',names)
    # map for循环names,取出一个值赋给前面的lambda
    print(list(res))
    print(list(res))
    print(list(res))
    #
    ['tom_hello','jerry_hello','peter_hello','brian_hello','json_hello'] [] # res是一个迭代器,只能由前往后走,第一次运行就已经走完了,后面没有值了 []

    res=map(lambda x:x if x == 'tom' else x+'hello',names)
    print(list(res))
    # ['tom','jerry_hello','peter_hello','brian_hello','json_hello']
    #reduce
    from functools import reduce
    
    print(reduce(lambda x,y:x+y,range(101)))   # 没有指定初始值,reduce会先for循环,得到的第一个值作为初始值,再for循环得到下一个值,传给前面的函数
    #5050
    print(reduce(lambda x,y:x+y,range(101),100))   #指定初始值为100,把初始值作为第一个值,还有for循环得到一个值,这两个值传给前面的函数(0和100))
    #5150
    #filter
    names=['tom_hello','jerry_hello','peter_hello','json_hello','brian']
    filter(lambda print(list(name:name.endswith('hello'),names)))
    #['tom_hello','jerry_hello','peter_hello','json_hello']

    eval

    cmd='print(x)'
    
    x=1
    
    # eval可以自己指定名称空间,名称空间有两种,一个全局一个局部,全都是字典形式
    
    #eval(cmd,{},{})  
    #第一个{}是全局作用域,第二个{}是局部作用域,找的时候先从局部作用域中找,
    找不到再去第一个{}全局作用域查找
    
    eval(cmd,{},{'x':1000})  
    # 1000
    eval(cmd,{'x':0},{'x':1000}) 
    # 1000   先从局部找,所以还是1000
    eval(cmd,{'x':0},{'y':1000})
    # 0   找全局名称空间中的变量

    re模块

    import re
    #w 匹配字母数字下划线
    print(re.findall('w','hello_ | tom 123'))
    # ['h', 'e', 'l', 'l', 'o', '_', 't', 'o', 'm', '1', '2', '3']
    
    #W 非字母数字下划线
    print(re.findall('W','hello_ | tom 123'))
    #[' ', '|', ' ', ' ']
    
    #s 匹配任意空白字符,等价于[	
    
    ] #
    回到行首
    print(re.findall('s','hello_ | tom 123 
     	'))
    #[' ', ' ', ' ', ' ', '
    ', ' ', '	']
    
    #S匹配任意非空字符
    print(re.findall('S','hello_ | tom 123 
     	'))
    # ['h', 'e', 'l', 'l', 'o', '_', '|', 't', 'o', 'm', '1', '2', '3']
    
    #d 匹配任意数字,等价于[0-9]
    print(re.findall('d','hello_ | tom 123 
     	'))
    #['1', '2', '3']
    
    #D 匹配任意非数字
    print(re.findall('D','hello_ | tom 123 
     	'))
    # ['h', 'e', 'l', 'l', 'o', '_', ' ', '|', ' ', 't', 'o', 'm', ' ', ' ', '
    ', ' ', '	']
    
    #^匹配字符串开头
    print(re.findall('^he','hello_ | hello h tom 123 
     	'))
    #['he']
    
    #$ 匹配字符串结尾
    print(re.findall('123$','hello_ | hello h tom 123 
     	123'))
    #['123']
    # . 匹配任意一个字符,除了
    
    print(re.findall('a.c','a a1c a*c a2c abc a c aaaaaac aacc'))
    #['a1c', 'a*c', 'a2c', 'abc', 'a c', 'aac', 'aac']
    
    print(re.findall('a.c','a a1c a*c a2c abc a
    c'))
    # ['a1c', 'a*c', 'a2c', 'abc']
    
    print(re.findall('a.c','a a1c a*c a2c abc a
    c',re.DOTALL))
    print(re.findall('a.c','a a1c a*c a2c abc a
    c',re.S))
    # ['a1c', 'a*c', 'a2c', 'abc','a
    c']
    # ['a1c', 'a*c', 'a2c', 'abc','a
    c']
    # []内部可以有多个字符,但是本身只能匹配多个字符中的一个
    print(re.findall('a[1 23]c','a a1c a*c a2c a c a
    c',re.S))
    #['a1c', 'a2c', 'a c']
    
    print(re.findall('a[a-z]c','aac abc aAc a12c a1c a*c a2c a c a
    c',re.S))
    #['aac','abc']
    
    print(re.findall('a[a-zA-Z]c','aac abc aAc a12c a1c a*c a2c a c a
    c',re.S))
    #['aac','abc','aAc']
    
    print(re.findall('a[+/*-]c','a-c a+c a/c aac abc aAc a12c a1c a*c a2c a c a
    c',re.S))
    #['a-c','a+c','a/c','a*c']
    #  转义
    print(re.findall(r'a\c','ac abc'))
    #['a\c']
    # ? 左边那一个字符有0个或1个
    print(re.findall(r'ab?','a ab abb abbb abbbbb bbbbb'))
    #['a', 'ab', 'ab', 'ab', 'ab']
    
    print(re.findall('ab?','aab a ab'))
    #['a','ab','a','ab']
    
    print(re.findall('ab?','aab a ab'))
    #['a', 'ab', 'a', 'ab']
    # * 左边那一个字符有0个或无穷个
    print(re.findall('ab*','a ab abb abbb abbbb bbbbbb'))
    # ['a', 'ab', 'abb', 'abbb', 'abbbb']
    # +左边那个字符有1个或无穷个
    print(re.findall('ab+','a ab abb abbb abbbb bbbbbb'))
    # ['ab', 'abb', 'abbb', 'abbbb']
    #{n,m} 左边的字符有n到m次
    print(re.findall('ab{3}','a ab abb abbb abbbb bbbbbb'))
    # ['abbb', 'abbb']
    
    print(re.findall('ab{2,3}','a ab abb abbb abbbb bbbbbb'))
    # ['abb', 'abbb', 'abbb']
    
    print(re.findall('ab{0,}','a ab abb abbb abbbb bbbbbb')) ==>'ab*'
    #  ['a', 'ab', 'abb', 'abbb', 'abbbb']
    
    print(re.findall('ab{1,}','a ab abb abbb abbbb bbbbbb'))  ==>'ab+'
    #  ['ab', 'abb', 'abbb', 'abbbb']
    # .* 匹配所有字符  贪婪匹配
    
    print(re.findall('a.*c','a123c456c'))
    # ['a123c456c']
    
    # .*? 非贪婪匹配  --> 推荐使用
    print(re.findall('a.*?c','a1c23c456c'))
    #['a1c']
    # | 或
    print(re.findall('company|companies','Too many companies have gone bankrupt, and the next one is my company'))
    #['companies','company']
    #() 分组,只显示组里面的内容
    
    print(re.findall('ab','abababab123'))
    #['ab', 'ab', 'ab', 'ab']
    
    print(re.findall('ab+','abababab123'))
    # ['ab','ab','ab','ab']
    
    print(re.findall('ab+123','abababab123'))
    # ['ab123']
    
    print(re.findall('(ab)','abababab123'))
    # ['ab','ab','ab','ab']
    
    print(re.findall('(a)b','abababab123'))
    # ['a','a','a','a']
    
    print(re.findall('a(b)','abababab123'))
    # ['b','b','b','b']
    
    print(re.findall('(ab)+','abababab123'))
    # ['ab']      
    
    print(re.findall('(?:ab)+','abababab123'))
    # ['abababab']
    print(re.findall('(abc)+','abababab123'))
    # []      
    
    print(re.findall('(ab)+123','abababab123'))
    # ['ab']     最后 ab123中的ab
    
    print(re.findall('(?:ab)+123','abababab123'))
    # ['abababab123'] 
    print(re.findall('(ab)+(123)','abababab123'))
    # [('ab','123')]

    print(re.findall('compan(y|ies)','Too many companies have gone bankrupt, and the next one is my company'))
    
    
    

     # ['ies','y']

    
    
    print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))
    

     # ['companies','company']

    re的其他方法

    #re.search和re.findall的区别是,re.findall会一直找到结尾,re.search只要匹配到一次就不再继续往下寻找了
    
    print(re.search('ab','abababab123').group())
    # ab  是第一个ab
    
    print(re.search('ab','12asdsadsdf'))
    # None   None值的就不能有group()了
    print(re.search('ab','123ab456'))
    print(re.match('ab','123ab456'))
    
    #<_sre.SRE_Match object; span=(3, 5), match='ab'>
    #None
    
    match和search的区别是:match只有在开头能匹配到时才匹配
    search是一直寻找到第一次
    print(re.split('b','abcde'))
    # ['a','cde']
    
    print(re.split('[ab]','abcde'))
    # ['','','cde']
    print(re.sub('tom','hello','tom make love tom'))
    #hello make love hello
    
    print(re.sub('tom','hello','tom make love tom',1))    只替换一次
    #hello make love tom
    
    print(re.subn('tom','hello','tom make love tom tom'))
    #('hello make love hello hello', 3)
    
    print(re.sub('(w+)(W+)(w+)(W+)(w+)',r'52341','tom make love'))
    或
    print(re.sub('(w+)( .* )(w+)',r'321','tom make love'))
    #love make tom
    obj=re.compile('d{2}') 事先把正则表达式进行编译
    
    print(obj.search('abc123eeee').group())
    print(obj.findall('abc123eeee'))
    
    #12
    #['12']
    可以重复使用一个正则表达式

    sys模块

    打印进度条

    import sys
    import time
    for i in range(1,10):
        sys.stdout.write('
    %s' %('#'*i))
        sys.stdout.flush()
        time.sleep(0.3)
        
    等同于
    
    import sys,time
    
    for i in range(1,100):
        print('
    %s'%('#'*i),file=sys.stdout,flush=True,end='')
        time.sleep(0.5)

    print('[%-10s]'%'hello')   打印固定长度,但是已经写死了

    现在把滚动条长度设定为认为输入
    
    width=10
    print(('<%%-%ds>'%width)%('hello'))
    def progress(percent,width=50):
    if percent >= 100:
    #print(' [%s] 100%%' %(width*'#'))
    percent=100 show_str
    =('[%%-%ds]'%width)%(int(width*percent/100)*'#') print(' %s %d%s' %(show_str,percent),file=sys.stdout,flush=True,end='') total_size=102141 recv_size=0 while recv_size < total_size: time.sleep(0.01) # 模拟下载的网络延迟 recv_size+=1024 #后面网络部分可以改为len(conn.recv()) recv_per=int(100*recv_size/total_size) progress(recv_per)

    序列化

    把对象(变量)从内存中变成可存储或传输的过程称为序列化

    为什么要序列化
    1.持久保存状态
    2.跨平台数据交互

    import json
    
    dic={'name':'tom','age':18}
    # print(json.dumps(dic))  # {"name":"tom","age":18}
    
    
    序列化
    with open('a.json','w') as f:
        f.write(json.dumps(dic))
    反序列化
    with open('a.json','r') as f:
        data=f.read()
        dic=json.loads(data)
        print(dic['name'])

    更简单的方法

    序列化:把一个类型按照json的格式转成json认识的字符串
    dic={'name':'tom','age':18}
    json.dump(dic,open('b.json','w'))
    
    反序列化:把json格式的字符串按照json格式转成一个类型
    print(json.load(open('b.json','r'))['name'])

    pickle序列化

    import pickle
    dic={'name':'tom','age':18}
    
    # print(pickle.dumps(dic))   # 与json得到的结果不同,pickle得到的是pickle格式的bytes
    
    with open('d.pkl','wb') as f:
        f.write(pickle.dumps(dic))
    with open('d.pkl','rb') as f:
        dic=pickle.loads(f.read())
        print(dic['name'])
    dic={'name':'tom','age':18}
    pickle.dump(dic,open('e.pkl','wb'))
    
    =======================================
    print(pickle.load(open('e.pkl','rb'))['name'])
    def func():
        print('from func')
        
    import pickle
    print(pickle.dumps(func))
    或
    pickle.dump(open(func,'func.pkl','wb'))
    
    ==========================================
    pickle的反序列化
    
    import pickle
    
    print(pickle.load('func.pkl','rb'))
    #报错
    #func在序列化结束的时候,内存地址已经被清掉了,反序列化的时候
    #需要在内存中找一个func的内存地址,但无法找到
    ==================================
    
    import pickle
    
    def func():
        print('反序列化的文件')
    
    print(pickle.load('func.pkl','rb'))
    #此时的fun指向的函数内存地址已经发生改变
    
    #凡是涉及到内存地址的序列化,反序列化的时候一定要基于内存中事先要存在这个内存地址

    os模块

    os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
    os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
    os.curdir  返回当前目录: ('.')
    os.pardir  获取当前目录的父目录字符串名:('..')
    os.makedirs('dirname1/dirname2')    可生成多层递归目录
    os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
    os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
    os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
    os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
    os.remove()  删除一个文件
    os.rename("oldname","newname")  重命名文件/目录
    os.stat('path/filename')  获取文件/目录信息
    os.sep    输出操作系统特定的路径分隔符,win下为"\",Linux下为"/"
    os.linesep    输出当前平台使用的行终止符,win下为"	
    ",Linux下为"
    "
    os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
    os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
    os.system("bash command")  运行shell命令,直接显示
    os.environ  获取系统环境变量
    os.path.abspath(path)  返回path规范化的绝对路径
    os.path.split(path)  将path分割成目录和文件名二元组返回
    os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
    os.path.basename(path)  返回path最后的文件名。如何path以/或结尾,那么就会返回空值。即os.path.split(path)的第二个元素
    os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
    os.path.isabs(path)  如果path是绝对路径,返回True
    os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
    os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
    os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
    os.path.getatime(path)  返回path所指向的文件或者目录的最后存取时间
    os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
    os.path.getsize(path) 返回path的大小
    View Code
    在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
    >>> os.path.normcase('c:/windows\system32\')   
    'c:\windows\system32\'   
       
    
    规范化路径,如..和/
    >>> os.path.normpath('c://windows\System32\../Temp/')   
    'c:\windows\Temp'   
    
    >>> a='/Users/jieli/test1/\a1/\\aa.py/../..'
    >>> print(os.path.normpath(a))
    /Users/jieli/test1
    View Code
    import os
    
    print(os.listdir('.'))  # 列出当前目录下的文件
    
    res=os.system('dir .')  #显示当前路径下的所有文件
    print('=====>',res)   #拿不到命令的执行结果
    
    print(os.path.dirname(r'C:acda.txt'))  #  C:acd
    print(os.path.basename(r'C:acda.txt')) # a.txt
    print(os.path.split(r'C:acda.txt'))  #('C:\a\b\c\d','a.txt')
    print(os.path.join('C:\','a','b','c','d.txt')) # C:acd.txt
    print(os.path.join('C:\','a','b','D:\','c','d.txt')) # D:cd.txt  
    a='/Users/jieli/test1/\a1/\\aa.py/../..'
    print(os.path.normpath(a))   # Usersjieli	est1

    Django处理路径的方式

    print(os.path.dirname(os.path.dirname(os.path.abspath(__fiel__))))

    Openstack处理路径的方式

    BASE_DIR=os.path.normpath(os.path.join(
    os.path.abspath(__fiel__),
    '..',
    '..'
    )
    )
    print(BASE_DIR)

    以上两种处理路径的方式用哪种都可以

    time模块

    import time
    
    # 3种形式的时间
    #1.时间戳,计算机使用  
    print(time.time())  #1970年到现在的秒数
    
    #2.格式化的时间
    print(time.strftime('%Y-%m-%d %X'))  #年-月-日 时-分-秒
    
    #3.元组形式
    print(time.localtime())
    print(time.localtime().tm_mon)
    print(time.gmtime())   # UTC 时间

    print(time.localtime(123123123))
    print(time.gmtime(123123123))
    print(time.mktime(time.localtime()))
    print(time.strftime('%Y',time.gmtime()))
    
    '2017-03-01'
    print(time.strptime('2017-03-01','%Y-%m-%d'))

    print(time.ctime())
    print(time.ctime(123123123))
    print(time.asctime())
    print(time.asctime(time.gmtime()))

    random模块

    import random
     
    print(random.random())#(0,1)----float    大于0且小于1之间的小数
     
    print(random.randint(1,3))  #[1,3]    大于等于1且小于等于3之间的整数
     
    print(random.randrange(1,3)) #[1,3)    大于等于1且小于3之间的整数
     
    print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5]
     
    print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合
     
    print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716 
     
     
    item=[1,3,5,7,9]
    random.shuffle(item) #打乱item的顺序,相当于"洗牌"
    print(item)

    生成随机验证码

    def make_code(n):
        res = ''
        for i in range(n):
            s1=str(random.randint(0,9))
            s2=chr(random.ranint(65,90))
            res+=random.choice([s1,s2])
        return res
    print(make_code(10))

    shelve 模块

    可以做序列化,不能跨平台,支持python所有的数据类型

    import shelve
    
    f=shelve.open(r'sheve.shl')
    
    f['tom']={'age':18,'password':'123'}
    f['jerry']={'age':20,'password':'123'}
    f.close()
    
    -------------------------------
    import shelve
    
    obj=shelve(r'sheve.shl')
    print(obj['tom'])
    print(obj['jerry'])
    
    for i in obj:
        print(i,obj[i])
    
    obj.close()
  • 相关阅读:
    windows 下搭建安装 sass
    mac 下搭建安装 sass
    解决 document.getElementsByClassName 在 IE8 下的兼容下的问题
    placeholder颜色
    文本两端对齐
    css3之border-color
    pip 安装自己开发模块 边调试边修改
    Go语言格式化字符
    遍历修改django bootstrap form 为 django bootstrap3
    git 合并两个仓库
  • 原文地址:https://www.cnblogs.com/Ryans-World/p/7294123.html
Copyright © 2020-2023  润新知