zoukankan      html  css  js  c++  java
  • python拓展知识

    类方法self的作用

    未绑定的类方法:没有self,通过类来引用方法返回一个未绑定方法对象。要调用它,你必须显示地提供一个实例作为第一个参数。

    绑定的实例方法:有self,通过实例访问方法返回一个绑定的方法对象。Python自动地给方法绑定一个实例,所以我们调用它时不用再传一个实例参数。

    class Test(object):
    
        def func(self, message):
            print message
    
    
    obj = Test()
    x = obj.func
    # x 是一个绑定的方法对象, 不需要传递一个实例参数
    x('hi')
    
    # fn 是一个未绑定的方法对象, 需要传递一个实例参数
    fn = Test.func
    fn(obj, 'hi')
    
    # fn('hi') # 错误的调用

    type关键字

    既可以查看一个对象的类型 ,也可以创建类对象

    查看对象类型

    a = 1
    type(a)
    # <type 'int'>
    
    b = 'hello'
    type(b)
    # <type 'str'>

    创建类对象

    # 需要给一个参数来绑定类
    def fn(self):
        print 'hello world'
    
    Hello = type('Hello', (object,), dict(hello=fn))
    
    h = Hello()
    h.hello()

    locals() 和 globals() 的区别

    locals()返回局部所有类型的变量的字典, globals()返回当前位置的全部全局变量的字典

    def test(arg):
        z = 1
        print locals()
    
    test(4)
    # {'z': 1, 'arg': 4}
    print globals()
    # {'__builtins__': <module '__builtin__' (built-in)>, '__file__': '...', '__package__': None, 'test': <function test at 0x10ea970c8>, '__name__': '__main__', '__doc__': None}

    字符串title函数

    将字符串的每个单词的首字母大写,下划线连接的单词首字母也要大写

    str = 'my_str'
    print str.title()
    # My_Str

    字符串的rpartition函数

    以某个分隔符将字符串分成两段,取最后一个匹配的位置的分隔符分隔,返回一个三元组(head, sep, tail)

    print 'django.core.app'.rpartition('.')
    # ('django.core', '.', 'app')

    python特殊函数__call__

    所有的函数都是可调用对象,一个类实例也可以变成一个可调用对象,只需实现一个特殊方法__call__()

    class Person(object):
        def __init__(self, name, gender):
            self.name = name
            self.gender = gender
    
        def __call__(self, job):
            print 'My name is %s' % self.name
            print 'My gender is %s' % self.gender
            print 'My job is %s' % job
    
    p = Person('Bob', 'male')
    p('student')

    python strip(), lstrip(), rstrip()函数

    strip(): 返回字符串的副本,并删除前导和后缀字符

    lstrip(): 返回字符串的副本,删除前导字符

    rstrip(): 返回字符串的副本,删除后缀字符

    str = ' hello '
    print len(str)  # 5
    print len(str.strip())  # 7
    
    str = 'rhellor'
    print str.strip('r')  # hello
    print str.lstrip('r')  # hellor
    print str.rstrip('r')  # rhello

    random.shuffle()

    random.shuffle 将列表随机排序

    import random
    
    li = [1, 2, 3, 4, 5]
    random.shuffle(li)
    
    for i in li:
        print i

     os.path模块

    os.path.basename(path):获取对应路径下的文件名

    os.path.abspath(path):返回path规范化的绝对路径

    os.path.split(path): 将path分割成目录和文件名二元组返回

    os.path.dirname(path): 返回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.splitext(path): 分离文件名与扩展名;默认返回(fname,fextension)元组,可做分片操作

    os.path.getatime(path): 返回path所指向的文件或者目录的最后存取时间

    os.path.getmtime(path): 返回path所指向的文件或者目录的最后修改时间

    os.path.join(path1[, path2[, path3..]]):

    os.path.join 可以传入多个参数

    • 会从第一个以”/”开头的参数开始拼接,之前的参数全部丢弃;
    • 以上一种情况为先。在上一种情况确保情况下,若出现”./”开头的参数,会从”./”开头的参数的上一个参数开始拼接。
    import os
    
    print "1:", os.path.join('aaaa', '/bbbb', 'ccccc.txt')
    # 1: /bbbb/ccccc.txt
    
    print "2:", os.path.join('/aaaa', '/bbbb', '/ccccc.txt')
    # 2: /ccccc.txt
    
    print "3:", os.path.join('aaaa', './bbb', 'ccccc.txt')
    # 3: aaaa/./bbb/ccccc.txt

     os.stat()

    方法用于在给定的路径上执行一个系统 stat 的调用

    import os
    print os.stat("/root/python/zip.py")
    # (33188, 2033080, 26626L, 1, 0, 0, 864, 1297653596, 1275528102, 1292892895)
    print os.stat("/root/python/zip.py").st_mode   #权限模式
    # 33188
    print os.stat("/root/python/zip.py").st_ino   #inode number
    # 2033080
    print os.stat("/root/python/zip.py").st_dev    #device
    # 26626
    print os.stat("/root/python/zip.py").st_nlink  #number of hard links
    # 1
    print os.stat("/root/python/zip.py").st_uid    #所有用户的user id
    # 0
    print os.stat("/root/python/zip.py").st_gid    #所有用户的group id
    # 0
    print os.stat("/root/python/zip.py").st_size  #文件的大小,以位为单位
    # 864
    print os.stat("/root/python/zip.py").st_atime  #文件最后访问时间
    # 1297653596
    print os.stat("/root/python/zip.py").st_mtime  #文件最后修改时间
    # 1275528102
    print os.stat("/root/python/zip.py").st_ctime  #文件创建时间
    # 1292892895

    socket.getaddrinfo()

    函数原型:socket.getaddrinfo(host, port[, family[, socktype[, proto[, flags]]]])

    返回值:[(family, socktype, proto, canonname, sockaddr)]有元组组成的列表,元组里面包含5个元素,其中sockaddr是(host, port)

    • family:表示socket使用的协议簇,常用的协议簇包括AF_UNIX(本机通信) 、AF_INET(TCP/IP协议簇中的IPv4协议)、AF_INET6(TCP/IP协议簇中的IPv4协议)。python的socket包中AF_UNIX=1, AF_INET=2, AF_INET6=10
    • sockettype:表示socket的类型,常见的socket类型包括SOCK_STREAM(TCP流)、SOCK_DGRAM(UDP数据报)、SOCK_RAW(原始套接字),SOCK_STREAM=1,  SOCK_DGRAM=2, SOCK_RAW=3
    • proto:套接口所用的协议,若不指定,可用0,常用的协议有IPPROTO_TCP(6)和IPPTOTO_UDP(17),他们分别对应TCP传输协议、UDP传输协议
    import socket
    print socket.getaddrinfo('www.baidu.com', 80)
    # [(2, 2, 17, '', ('180.97.33.108', 80)), (2, 1, 6, '', ('180.97.33.108', 80)), (2, 2, 17, '', ('180.97.33.107', 80)), (2, 1, 6, '', ('180.97.33.107', 80))]

    struct模块pack和unpack

    pack(fmt, v1, v2….):按照给定格式将数据封装成字符串(实际类似于c结构体的字节流)

    unpack(fmt, string ):按照给定格式解析字节流,返回解析出的tuple

    calcsize(fmt):计算给定的格式占用多少字节的内存

    参考博客: https://blog.csdn.net/w83761456/article/details/21171085

    # coding: utf-8
    import struct
    
    a = 'hello'
    b = 'world!'
    c = 2
    d = 45.123
    
    bytes = struct.pack('5s6sif', a, b, c, d)
    print bytes
    # helloworld!�}4B
    
    a, b, c, d = struct.unpack('5s6sif', bytes)
    print a, b, c, d
    # hello world! 2 45.1230010986

    metaclass

    允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。多喜欢自定义__new__方法

    class Trick(FlyToSky):

      pass

    当我们在创建上面的类的时候,python做了如下的操作:

    Trick中有__metaclass__这个属性吗?如果有,那么Python会在内存中通过__metaclass__创建一个名字为Trick的类对象,也就是Trick这个东西。如果Python没有找到__metaclass__,它会继续在自己的父类FlyToSky中寻找__metaclass__属性,并且尝试以__metaclass__指定的方法创建一个Trick类对象。如果Python在任何一个父类中都找不到__metaclass__,它也不会就此放弃,而是去模块中搜寻是否有__metaclass__的指定。如果还是找不到,那就是使用默认的type来创建Trick。

    那么问题来了,我们要在__metaclass__中放置什么呢?答案是可以创建一个类的东西,type,或者任何用到type或子类化type的东西都行。

    参考博客:  https://www.cnblogs.com/piperck/p/5840443.html

    class UpperAttrMetaClass(type):
        def __new__(mcs, class_name, class_parents, class_attr):
            attrs = ((name, value) for name, value in class_attr.items() if not name.startswith('__'))
            uppercase_attrs = dict((name.upper(), value) for name, value in attrs)
            return super(UpperAttrMetaClass, mcs).__new__(mcs, class_name, class_parents, uppercase_attrs)
    
    
    class Trick(object):
        __metaclass__ = UpperAttrMetaClass
        bar = 12
        money = 'unlimited'
    
    print Trick.BAR
    print Trick.MONEY

    设置守护进程 setDaemon(flag)

    当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,主线程会创建多个子线程,在python中,默认情况下(其实就是setDaemon(False)),主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束,当我们使用setDaemon(True)方法,设置子线程为守护线程时,主线程一旦执行结束,则全部线程全部被终止执行,可能出现的情况就是,子线程的任务还没有完全执行结束,就被迫停止。

    线程join方法

    join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程再终止。

    join有一个timeout参数:

    • 设置守护线程,主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序。所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和。简单的来说,就是给每个子线程一个timeout的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。
    • 没有设置守护线程,主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,但是并没有杀死子线程,子线程依然可以继续执行,直到子线程全部结束,程序退出。

    参考博客:https://www.cnblogs.com/cnkai/p/7504980.html

    functools.wraps

    在使用装饰器时难免会损失一些东西,使用functools.wraps可以将原函数对象的指定属性复制给包装函数对象, 默认有 __module__、__name__、__doc__,或者通过参数选择。

    from functools import wraps
    
    def logged(func):
        @wraps(func)
        def with_logging(*args, **kwargs):
            print func.__name__ + " was called"
            return func(*args, **kwargs)
    
        return with_logging
    
    @logged
    def f(x):
        """does some math"""
        return x + x * x
    
    print f.__name__
    # 不加wraps: with_logging
    # 加wraps: f
    print f.__doc__
    # 不加wraps: None
    # 加wraps: does some math

    孤儿进程和僵尸进程

    什么是孤儿进程?

    一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

    什么是僵尸进程?

    首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打开的文件等,但内核为每一个终止子进程保存了一定量的信息。这些信息至少包括进程ID,进程的终止状态,以及该进程使用的CPU时间,所以当终止子进程的父进程调用wait或waitpid时就可以得到这些信息。

    而僵尸进程就是指:一个进程执行了exit系统调用退出,而其父进程并没有为它收尸(调用wait或waitpid来获得它的结束状态)的进程。

    任何一个子进程(init除外)在exit后并非马上就消失,而是留下一个称为僵尸进程的数据结构,等待父进程处理。这是每个子进程都必需经历的阶段。另外子进程退出的时候会向其父进程发送一个SIGCHLD信号。

    如何避免僵尸进程?

    • 通过signal(SIGCHLD, SIG_IGN)通知内核对子进程的结束不关心,由内核回收。如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN);表示父进程忽略SIGCHLD信号,该信号是子进程退出的时候向父进程发送的。
    • 父进程调用wait/waitpid等函数等待子进程结束,如果尚无子进程退出wait会导致父进程阻塞。waitpid可以通过传递WNOHANG使父进程不阻塞立即返回。
    • 如果父进程很忙可以用signal注册信号处理函数,在信号处理函数调用wait/waitpid等待子进程退出。
    • 通过两次调用fork。父进程首先调用fork创建一个子进程然后waitpid等待子进程退出,子进程再fork一个孙进程后退出。这样子进程退出后会被父进程等待回收,而对于孙子进程其父进程已经退出所以孙进程成为一个孤儿进程,孤儿进程由init进程接管,孙进程结束后,init会等待回收。

    参考博客:https://www.cnblogs.com/Anker/p/3271773.html

    selectpollepoll三者的区别

    为何使用select 单进程实现并发?

    因为一个进程实现多并发比多线程是实现多并发的效率还要高,因为启动多线程会有很多的开销,而且CPU要不断的检查每个线程的状态,确定哪个线程是否可以执行。

    那么单进程是如何实现多并发的呢?

    之前的socket一个进程只能接收一个连接,当接收新的连接的时候产生阻塞,因为这个socket进程要先和客户端进行通信,二者是彼此互相等待的【客户端发一条消息,服务端收到,客户端等着返回....服务端等着接收.........】一直在阻塞着,这个时候如果再来一个连接,要等之前的那个连接断了,这个才可以连进来。也就是说用基本的socket实现多进程是阻塞的。为了解决这个问题采用每来一个连接产生一个线程,是不阻塞了,但是当线程数量过多的时候,对于cpu来说开销和压力是比较大的。

    客户端发起一个连接,会在服务端注册一个文件句柄,服务端会不断轮询这些文件句柄的列表,主进程和客户端建立连接而没有启动线程,这个时候主进程和客户端进行交互,其他的客户端是无法连接主进程的,为了实现主进程既能和已连接的客户端收发消息,又能和新的客户端建立连接,就把轮询变的非常快(死循环)去刷客户端连接进来的文件句柄的列表,只要客户端发消息了,服务端读取了消息之后,有另一个列表去接收给客户端返回的消息,也不断的去刷这个列表,刷出来后返回给客户端,这样和客户端的这次通信就完成了,但是跟客户端的连接还没有断,但是就进入了下一次的轮询。

    三者区别

    select:单进程实现并发

    poll: 它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。

    epoll: 直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法, epoll可以同时支持水平触发和边缘触发, epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表 就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了 这些文件描述符在系统调用时复制的开销, 另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描 述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调 机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。

    水平触发和边缘触发

    水平触发:select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll() 的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发。

    边缘触发:只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发。

    参考博客:https://www.cnblogs.com/qianyuliang/p/6551553.html

    atexit模块

    atexit只定义了一个register函数用于注册程序退出时的回调函数,我们可以在这个回调函数中做一些资源清理的操作

    import atexit
    
    def exit0(*args, **kwarg):
        print 'exit0'
        for arg in args:
            print arg
    
        for item in kwarg.items():
            print item
    
    def exit1():
        print 'exit1'
    
    atexit.register(exit0, *[1, 2, 3], **{"a": 1, "b": 2, })
    atexit.register(exit1)
    
    @atexit.register
    def exit2():
        print 'exit2'
    
    # 回调函数执行的顺序与它们被注册的顺序刚才相反
    # exit2
    # exit1
    # exit0
    # 1
    # 2
    # 3
    # ('a', 1)
    # ('b', 2)

    shutil模块

    高级的 文件、文件夹、压缩包处理模块

    常用函数

    copyfileobj(文件1,文件2):将文件1的数据覆盖copy给文件2

    copyfile(文件1,文件2):不用打开文件,直接用文件名进行覆盖copy

    copymode(文件1,文件2):之拷贝权限,内容组,用户,均不变

    copystat(文件1,文件):只拷贝了权限

    copy(文件1,文件2):拷贝文件和权限都进行copy

    copy2(文件1,文件2):拷贝了文件和状态信息

    copytree(源目录,目标目录):可以递归copy多个目录到指定目录下

    rmtree(目标目录):可以递归删除目录下的目录及文件

    move(源文件,指定路径):递归移动一个文件

    make_archive():可以压缩,打包文件

    psutil模块

    psutil是一个跨平台库(http://pythonhosted.org/psutil/)能够轻松实现获取系统运行的进程和系统利用率(包括CPU、内存、磁盘、网络等)信息。它主要用来做系统监控,性能分析,进程管理。它实现了同等命令行工具提供的功能,如ps、top、lsof、netstat、ifconfig、who、df、kill、free、nice、ionice、iostat、iotop、uptime、pidof、tty、taskset、pmap等。目前支持32位和64位的Linux、Windows、OS X、FreeBSD和Sun Solaris等操作系统

    参考博客:https://www.cnblogs.com/saneri/p/7528283.html

    inspect模块

    主要用处

    • 对是否是模块、框架、函数进行类型检查
    • 获取源码
    • 获取类或者函数的参数信息
    • 解析堆栈

    常用函数

    getargspec(func):返回一个命名元组ArgSpect(args, varargs, keywords, defaults),args是函数位置参数名列表,varargs是*参数名,keywords是**参数名,defaults是默认参数值的元组。

    getmembers(object[, predicate]):返回一个包含对象的所有成员的(name, value)列表。返回的内容比对象的__dict__包含的内容多,源码是通过dir()实现的。predicate是一个可选的函数参数,被此函数判断为True的成员才被返回。

    getmodule(object):返回定义对象的模块

    getsource(object):返回对象的源代码

    getsourcelines(object):返回一个元组,元组第一项为对象源代码行的列表,第二项是第一行源代码的行号

    stack():第一列是对象名,第二列是当前脚本文件名,第三列是行数,第四列是函数名,第五列是具体执行的程序。第一行是当前函数,第二行是父级函数,以此往上推

    threading.local()

    这个方法的特点用来保存一个全局变量,但是这个全局变量只有在当前线程才能访问,localVal.val = name这条语句可以储存一个变量到当前线程,如果在另外一个线程里面再次对localVal.val进行赋值,那么会在另外一个线程单独创建内存空间来存储,也就是说在不同的线程里面赋值 不会覆盖之前的值,因为每个线程里面都有一个单独的空间来保存这个数据,而且这个数据是隔离的,其他线程无法访问

    import threading
    # 创建全局ThreadLocal对象:
    localVal = threading.local()
    localVal.val = "Main-Thread"
    
    
    def process_student():
        print '%s (in %s)' % (localVal.val, threading.current_thread().name)
    
    
    def process_thread(name):
        #赋值
        localVal.val = name
        process_student()
        
    
    t1 = threading.Thread(target=process_thread, args=('One',), name='Thread-A')
    t2 = threading.Thread(target=process_thread, args=('Two',), name='Thread-B')
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print localVal.val
    
    # One (in Thread-A)
    # Two (in Thread-B)
    # Main-Thread

    logging模块

    logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比print,具备如下优点:

    • 可以通过设置不同的日志等级,在release版本中只输出重要信息,而不必显示大量的调试信息
    • print将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging则可以由开发者决定将信息输出到什么地方,以及怎么输出
    # 基本使用
    import logging
    logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    logger = logging.getLogger(__name__)
    
    logger.info("Start print log")
    logger.debug("Do something")
    logger.warning("Something maybe fail.")
    logger.info("Finish")

    参考博客:https://www.cnblogs.com/liujiacai/p/7804848.html

    日志高级版zipkin

    参考博客:https://blog.csdn.net/liumiaocn/article/details/80657943

  • 相关阅读:
    解决ArrayList线程不安全
    TraceView工具的使用
    Service
    Android之移动热修复
    06 swap命令,进程管理,rmp命令与yum命令,源码安装python
    04 linux用户群组和权限
    03 linux命令的操作
    Unity 5.x 导入教学Demo
    Creo二次开发—内存处理
    求一个数的二进制数中所含1的个数的代码实现
  • 原文地址:https://www.cnblogs.com/wust-ouyangli/p/10025170.html
Copyright © 2011-2022 走看看