【Python】sys,os,subprocess,exec,eval



2018年06月05日    Author:Guofei

文章归类: 0xb0_Python语法    文章编号: 1204

版权声明:本文作者是郭飞。转载随意,但需要标明原文链接,并通知本人
原文链接:https://www.guofei.site/2018/06/05/sysos.html


sys

sys.argv # 是一个由str组成的list,包含所有的命令行参数.
# 例如 python abc.py a c,那么 sys.argv= ['abc.py', 'a', 'c']

sys.stdout, sys.stdin sys.stderr # 分别表示标准输入输出,错误输出的文件对象.
sys.stdin.readline()  # 从标准输入读一行
sys.stdout.write("a") # 屏幕输出a

sys.exit(exit_code) # 退出程序
sys.modules # 是一个dictionary,表示系统中所有可用的module
sys.version # python 版本
sys.platform # 操作系统环境.
# Linux (2.x and 3.x): 'linux2'; Windows: 'win32'; Windows/Cygwin 'cygwin'; Mac OS X : 'darwin'; OS/2: 'os2'; OS/2 EMX: 'os2emx'; RiscOS: 'riscos'; AtheOS: 'atheos'

import sys
sys.path # 是一个list,指明所有查找module,package的路径.
sys.path.append('E:\\MyPython') # 把目录添加到path,这样就可以 import 了

观察引用计数的小程序

import sys

a='abc'
print(id(a))
print(sys.getrefcount(a))
b='abc'
id(b)
print(sys.getrefcount(a))

OS

增删改

os.chdir(path) # 把path设定为当前目录,例如os.chdir('d:\\outlook') 注意windows下用到转义
os.getcwd() # 获得当前工作目录
os.listdir(path) # 返回指定目录下所有文件和目录名

os.mkdir(path) # 新建目录,父目录必须存在的,否则报错。目录存在时也报错
os.makedirs(path) # 新建目录(递归创建,所以没有父目录也可以)。目录存在时报错

os.rmdir(path) # 删除目录。前提是目录为空,否则报错
os.remove(path) # 删除文件

os.rename(oldname,newname) #更改文件名。因为参数可以带路径,所以也可以用来移动到其它文件夹

特殊常量

os.curdir  # 当前目录 '.'
os.pardir  # 上一级目录 '..'
os.sep  # 路径分隔符 win下是'\\' Linux 下为'/'
os.linesep  # 终止符 win下是'\r\n',Linux 下为 '\n'
os.name  # 当前操作系统 ('posix','nt','mac','os2','ce','java')

os.path

可以用来编写平台无关的程序


os.path.isfile(path) # 如果 path 是文件且存在,返回 True
os.path.isdir(path) # 如果 path 是路径且存在,返回 True
os.path.exists(path) # 判断路径是否存在
os.path.islink(path) # 是否是符号链接(快捷方式)
os.path.ismount(path) # 是否是挂载点

os.path.dirname(path) # 返回path中的路径部分
os.path.basename(path) # 返回path中的文件名部分
os.path.split(path) # 返回一个tuple,分离目录名和文件名
os.path.join(path,name) # 把path和name合成
os.path.splitext(path) # 返回一个tuple,分别是含目录的文件名和扩展名


os.path.getsize(path) # 返回文件大小


a = os.path.getatime('E:\\pathname\\filename.txt')  # 浮点数时间, 最新访问时间
b = os.path.getctime('E:\\pathname\\filename.txt')  # 浮点数时间, 创建时间
c = os.path.getmtime('E:\\pathname\\filename.txt')  # 浮点数时间, 修改时间
import time
time.gmtime(a) # 转化为格林威治时间
time.localtime(a)  # 转化为当地时间


# 用os.path
os.path.abspath("1.txt") == os.path.join(os.getcwd(), "1.txt")
os.path.split(os.getcwd()) # 用于分开一个目录名称中的目录部分和文件名称部分。
os.path.join(os.getcwd(), os.pardir, 'a', 'a.doc') # 全成路径名称.
os.pardir 表示当前平台下上一级目录的字符 ..
os.path.getctime("/root/1.txt")  返回1.txt的ctime(创建时间)时间戳
os.path.exists(os.getcwd()) 判断文件是否存在
os.path.expanduser('~/dir') ~扩展成用户根目录
os.path.expandvars('$PATH') 扩展环境变量PATH
os.path.isfile(os.getcwd()) 判断是否是文件名1是0否
os.path.isdir('c:\Python26\temp') 判断是否是目录,1是0否
os.path.islink('/home/111.sql') 是否是符号连接 windows下不可用
os.path.ismout(os.getcwd()) 是否是文件系统安装点 windows下不可用
os.path.samefile(os.getcwd(), '/home/huaying') 看看两个文件名是不是指的是同一个文件


os.environ # 一个dictionary 包含环境变量的映射关系
# os.environ["HOME"] 得到环境变量HOME的值
# os.environ["USER"] 得到用户名
# os.environ["LOGNAME"] 得到用户名



os.getegid() # 得到有效组id  os.getgid() 得到组id
os.getuid() # 得到用户id  os.geteuid() 得到有效用户id
os.setegid os.setegid() os.seteuid() os.setuid()
os.getgruops() # 得到用户组名称列表
os.getlogin() # 得到用户登录名称
os.getenv # 得到环境变量
os.putenv # 设置环境变量
os.umask # 设置umask
os.system(cmd) 利用系统调用运行cmd命令
操作举例

用Python来模拟shell

#!/usr/bin/python
import os, sys
cmd = sys.stdin.readline()
while cmd:
    os.system(cmd)
    cmd = sys.stdin.readline()

os.walk(path)

for root,dirs,files in os.walk("D:\py\d1218"):
    pass


path_walker=os.walk("D:\py\d1218", topdown=True) # 返回一个generator
# (1)参数top表示需要遍历的顶级目录的路径。
# (2)参数topdown的默认值是“True”表示首先返回顶级目录下的文件,然后再遍历子目录中的文件。当topdown的值为"False"时,表示先遍历子目录中的文件,然后再返回顶级目录下的文件。
# (3)参数onerror默认值为"None",表示忽略文件遍历时的错误。如果不为空,则提供一个自定义函数提示错误信息后继续遍历或抛出异常中止遍历。

for top, dirs, nondirs in path_walker:
    pass
# top是一个str,是当前遍历的目录(绝对目录)
# dirs是一个list,是当前遍历的目录下面的目录
# nondirs是一个list,是当前遍历的目录下面的文件名

运行CMD命令

import os
# os.system("ipconfig")
p=os.popen('ipconfig')
print(p.read())
tar = tarfile.open('rt-polaritydata.tar.gz', "r:gz")
tar.extractall(path='temp')
tar.close()

subprocess

os.system 在使用上有一定的局限性,可以用 subprocess 来代替

1. subprocess.call

返回args执行完毕后的 return code

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False) # 返回int
# 参数args描述了子进程中需要执行的命令
# cmd = ['ls', '-l']
# cmd = ['exit 1']
# ret = subprocess.call(cmd)
# shell=True时,可以把文本分解成多条命令执行。不安全,所以尽量使shell=False。PS:windows下,False似乎会出错

stdout和stderr

注意不要为stdout和stderr参数赋值subprocess.PIPE,如果子进程输出量较多会造成死锁,这两个参数可以赋值为subprocess.STDOUT打印到屏幕或者赋值为一个文件对象将输出写入文件

//test.py
import subprocess as sp
sp.call('python run.py', shell = True, stdin=open('fake_input', 'r'), stdout=open('result', 'w'))
//run.py
i = int(raw_input("Input a number:"))
print("You input number:", i)

CalledProcessError的使用

import subprocess
try:
    res = subprocess.check_call(['ls', '('])
    print('res:', res)
except subprocess.CalledProcessError as exc:
    print('returncode:', exc.returncode)
    print('cmd:', exc.cmd)
    print('output:', exc.output)

2. subprocess.check_call

  • 如果args执行之后的 return code 为0,那么 check_all 返回0;
  • 如果 returncode 不为 0,那么没有返回值,而是raise出来一个 <CalledProcessError>
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False) # 返回int

例子:

cmd1 = ['exit 1'] # 将会报错
ret = subprocess.check_call(cmd2, shell=True)

3. subprocess.check_output

  • 把命令的输出作为字符串返回,
  • 如果 returncode 不为 0, 那么将raise一个 <CalledProcessError>
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False) # 返回str,内容是命令所输出的字符串

4. subprocess.Popen

Popen对象创建后,主程序不会自动等待子进程完成。我们必须调用对象的wait()方法,父进程才会等待 (也就是阻塞block)

subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0) # 返回一个对象,可以对这个对象继续操作
# args 字符串或列表
# bufsize 0:无缓冲。正整数:缓冲大小。负:系统默认缓冲(一般是全缓冲)
# shell Unix下,相当于args前面添加了'/bin/sh' '-c'  windows下,相当于添加'cmd.exe /c'
# env 设置环境变量
# universal_newlines 各种换行符统一处理成'\n'

Popen中封装的其他函数:

  1. Popen.poll():检查子进程的状态,查看子进程是否结束
  2. Popen.wait():等待子进程的结束
  3. Popen.communicate(input=None):与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。
  4. Popen.send_signal(signal):向子进程发送信号
  5. Popen.terminate():停止(stop)子进程。在windows平台下,该方法将调用Windows API TerminateProcess()来结束子进程
  6. Popen.kill():杀死子进程
  7. Popen.stdin:如果在创建Popen对象是,参数stdin被设置为PIPE,Popen.stdin将返回一个文件对象用于策子进程发送指令;否则返回None
  8. Popen.stdout:如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令;否则返回None
  9. Popen.stderr:如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令;否则返回None
  10. Popen.pid:获取子进程的进程ID
  11. Popen.returncode:获取进程的返回值。如果进程还没有结束,返回None

psutil:看资源利用率

import psutil
import os

info = psutil.virtual_memory()
print('内存使用:',psutil.Process(os.getpid()).memory_info().rss/1024/2014, 'M')
print('总内存:',info.total/1024/2014, 'M')
print('内存占比:',info.percent)
print('cpu个数:',psutil.cpu_count())


psutil.cpu_stats()
psutil.cpu_count()
psutil.disk_partitions()

psutil.boot_time()

# 线程
psutil.pids()
psutil.pid_exists(pid=15144)

# 硬盘
hdd = psutil.disk_usage("/")

eval 和 exec

区别

  • eval
    • 是内置函数,而非语句,它计算表达式并返回它的值
    • ???不能执行多行
  • exec
    • 编译并计算,它总是返回 None
  • complie
    • 它不执行,也不评估语句,而是返回可执行的代码对象
    • evalexec 的底层。
# exec 可以跑多行,可以执行 if,def 这类的语句
exec('if True: a=3\nprint(a)')

# eval
x = eval('abs({})'.format(-10))

# complie
codes=
compile(source, filename, mode[, flags[, dont_inherit]])
# source -- 字符串或者AST(Abstract Syntax Trees)对象。
# filename -- 代码文件名称,如果不是从文件读取代码则传递一些可辨认的值。
# mode -- 指定编译代码的种类。可以指定为 exec, eval, single。
# flags -- 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。。
# flags和dont_inherit是用来控制编译源码时的标志
c = compile("for i in range(0,10): print(i)", '', 'exec') # exec(c)
c = compile("3 * 4 + 5", '', 'eval') # eval(c)
c = compile("print(1);print(2)", '', 'single') # 只会执行第一句 exec(c)

exec

exec,有一些地方要注意(感觉是 exec 本身不完善)

  • exec 生产的变量是存在 locals() 里面的
  • 前提是 locals() 里面没这个变量,否则无法写入

直接跑没问题

exec('a=3')
print(a)

在函数中的正确写法

# 正确写法
def func():
    # 前提是前后代码中都没有使用 a,否则读写 locals 都会有问题
    exec('a=3')
    b = locals()['a']
    print(b)


func()

错误写法

# 报错,因为编译时就找不到a
def func():
    exec('a=3')
    print(a)


func()

# 虽然没报错,但是结果是错的
def func():
    a = 1
    exec('a=3')
    print(a)


func()
# 输出 1,因为编译时被优化了

其它

查看单个变量的内存

sys.getsizeof(a)/1024/1024 # 除完以后单位是 M
# len(variable.encode('utf-8')) # 这个是看字符串所占用的 Byte 数
whos


globals() # 命名空间
locals() # 命名空间
# 在函数外部时,globals() 和 locals() 一样

参考文献

https://blog.csdn.net/yuchen1986/article/details/22059873
https://www.cnblogs.com/zhoug2020/p/5079407.html


您的支持将鼓励我继续创作!