Python 调用系统命令的模块 Subprocess

有些时候需要调用系统内部的一些命令,或者给某个应用命令传不定参数时可以使用该模块。

初识 Subprocess 模块

Subprocess 模块提供了多个方法来运行额外的进程。在 Python2.7 的时候使用的方法主要有 call(),check_call(), check_output(),到了 Python3.5 的时候加入了一个更高级的方法 run(),该方法可以运行一个额外的进程同时它还能收集到运行之后的结果。Popen 类最为一个低级 API,它主要用于构建其他 API,在更复杂的流程交互中非常有用。Popen 的构造函数接受参数来设置新进程,以便父进程可以通过管道与它通信。它替换了其他模块和函数的所有功能,甚至更多。Subprocess 子进程模块旨在替换 os.system(), os.spawnv()等函数,os 和 popen2 模块中 popen()的变体,以及 commands()模块

注意:在 Unix 和 Windows 系统上工作的应用编程接口大致相同,但是底层的实现是不同的,因为操作系统中的过程模型不同。这里显示的所有示例都是在 Mac 操作系统上测试的。在非 Unix 操作系统上的行为可能会有所不同。例如 unix 系统查看文件列表使用 ls,windows 只能使用 dir.

Run 方法使用

运行外部命令

要实现和 os.system()命令相同的方式,运行外部命令而不与之交互时候,我们可以使用 run()函数。前面提到了这是一个高级函数

先看一下其语法结构。

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None)

运行被 arg 描述的指令。等待指令完成,然后返回一个 CompletedProcess 示例。run 方法的参数和 Popen 的构造函数一样,接受的大多数参数都被传递给该接口。(timeout, input, check 和 capture_output 除外)。

import subprocess
completed = subprocess.run(['ls', '-1'])
print('returncode:', completed.returncode)

输出内容:

subprocess_demo.py
returncode: 0

第一个参数传入的就是我们要运行的命令,其格式推荐使用列表字符串的形式,将命令进行分割。这避免了转义引号或 shell 可能解释的其他特殊字符的需要。

如果将 shell 参数设置为 true 值将导致子进程生成一个中间 shell 进程,然后运行该命令。默认情况下是直接运行命令。

import subprocess

completed = subprocess.run('echo $HOME', shell=True)
print('returncode:', completed.returncode)

输出

/Users/chenxiangan
returncode: 0

使用中间 shell 意味着在运行命令之前要处理命令字符串中的变量、glob 模式和其他特殊的 shell 特性。

错误处理

CompletedProcess 的 returncode 属性是程序的退出代码。 调用者负责解释它以检测错误。 如果 run()的 check 参数为 True,则检查退出代码,如果它指示发生错误,则引发 CalledProcessError 异常。

#公众号:python 学习开发
#author:陈祥安
import subprocess try:
subprocess.run(['false'], check=True)
except subprocess.CalledProcessError as err:
print('ERROR:', err)

运行结果

ERROR: Command '['false']' returned non-zero exit status 1.

false 命令总是以非零状态代码退出,run()将其解释为错误。

将 run()函数的 check 属性设置为 True,等同于使用 check_call()方法。

获取结果

由于 run()启动的进程的标准输入和输出通道绑定到父输入和输出。 这意味着调用程序无法捕获命令的输出。 可以通过调整 stdout 和 stderr 参数来捕获输出的值。

#公众号:python 学习开发
#author:陈祥安
import subprocess completed = subprocess.run(
['ls', '-1'],
stdout=subprocess.PIPE,
)
print('returncode:', completed.returncode)
print(f"结果的字节长度 {len(completed.stdout)}:\n{ completed.stdout.decode('utf-8')}")

输出

returncode: 0
结果的字节长度 24:
subprocess_demo.py

ls -1 命令成功运行,捕获并返回输出结果。

下一个示例在子 shell 中运行一系列命令。 在命令退出并显示错误代码之前,消息将发送到标准输出和标准错误。

#公众号:python 学习开发

import subprocess

try:
completed = subprocess.run(
'echo to stdout; echo to stderr 1>&2; exit 1',
check=True,
shell=True,
stdout=subprocess.PIPE,
)
except subprocess.CalledProcessError as err:
print('ERROR:', err)
else:
print('returncode:', completed.returncode)
print(f"stdout 中的字节长度 {len(completed.stdout)} : {completed.stdout.decode('utf-8')!r}")

输出结果

to stderr
ERROR: Command 'echo to stdout; echo to stderr 1>&2; exit 1' returned non-zero exit status 1.

发送到标准错误的消息被打印到控制台,但是发送到标准输出的消息是隐藏的。

为了防止通过 run()运行的命令的错误消息被写入控制台, 需要将 stderr 参数设置为 subprocess.PIPE。修改后代码如下

#公众号:python 学习开发

import subprocess

try:
completed = subprocess.run(
'echo to stdout; echo to stderr 1>&2; exit 1',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
except subprocess.CalledProcessError as err:
print('ERROR:', err)
else:
print('returncode:', completed.returncode)
print(f"stderr 字节长度{len(completed.stdout)}: {completed.stdout.decode('utf-8')!r}")
print(f"stderr 字节长度{len(completed.stderr)}: {completed.stderr.decode('utf-8')!r}")

输出结果

returncode: 1
stderr 字节长度 10: 'to stdout\n'
stderr 字节长度 10: 'to stderr\n'

本示例未设置 check=True,因此会捕获并打印命令的输出。若要在使用 check_output()时捕获错误消息,请将 stderr 设置为 STDOUT,消息将与命令的其余输出合并。

禁止输出

对于不应该显示或捕获输出的情况,使用 DEVNULL 来抑制输出流,这个例子同时抑制了标准输出和错误流。

# 公众号:python 学习开发

import subprocess

try:
completed = subprocess.run(
'echo to stdout; echo to stderr 1>&2; exit 1',
shell=True,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
except subprocess.CalledProcessError as err:
print('ERROR:', err)
else:
print('returncode:', completed.returncode)
print(f'stdout is {completed.stdout!r}')
print(f'stderr is {completed.stderr!r}')

输出

returncode: 1
stdout is None
stderr is None

名称 DEVNULL 来自于 Unix 特殊设备文件/DEVE/null,该文件在打开读取时以文件结尾响应,并在写入时接收但忽略任何数量的输入。

Popen 方法的使用

函数 run()、call()、check_call()和 check_output()是 Popen 类的包装器。直接使用 Popen 可以更好地控制命令的运行方式以及输入和输出流的处理方式。例如,通过传递 stdin、stdout 和 stderr 的不同参数,可以模拟 os.popen()。

Popen 的语法结构如下:

class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=None, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None, text=None)¶

args 应当是一个程序的参数列表或者一个简单的字符串。默认情况下,如果 args 是一个序列,将运行的程序是此序列的第一项。如果 args 是一个字符串,解释是平台相关的,如下所述。除非另有说明,推荐将 args 作为序列传递。

参数 shell (默认为 False)指定是否使用 shell 执行程序。如果 shell 为 True,更推荐将 args 作为字符串传递而非序列。

在 POSIX,当 shell=True, shell 默认为 /bin/sh。如果 args 是一个字符串,此字符串指定将通过 shell 执行的命令。这意味着字符串的格式必须和在命令提示符中所输入的完全相同。这包括,例如,引号和反斜杠转义包含空格的文件名。如果 args 是一个序列,第一项指定了命令,另外的项目将作为传递给 shell (而非命令) 的参数对待。也就是说, Popen 等同于:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

在 Windows,使用 shell=True,环境变量 COMSPEC 指定了默认 shell。在 Windows 你唯一需要指定 shell=True 的情况是你想要执行内置在 shell 中的命令(例如 dir 或者 copy)。在运行一个批处理文件或者基于控制台的可执行文件时,不需要 shell=True。

与进程的单向通信

要运行进程并读取其所有输出,需要将 stdout 值设置为 PIPE 并调用。

import subprocess

print('read:')
proc = subprocess.Popen(
['echo', '"to stdout"'],
stdout=subprocess.PIPE,
)
stdout_value = proc.communicate()[0].decode('utf-8')
print('stdout:', repr(stdout_value))

输出

read:
stdout: '"to stdout"\n'

如果要设置管道允许调用程序将数据写入管道,需要将 stdin 设置为 pipe。

import subprocess

print('write:')
proc = subprocess.Popen(
['cat', '-'],
stdin=subprocess.PIPE,
)
proc.communicate('stdin: to stdin\n'.encode('utf-8'))

输出

write:
stdin: to stdin

要一次将数据发送到进程的标准输入通道,可以使用返回对象的 communication()方法。 它与使用'w'模式的 popen()类似.

与进程的双向通信

要同时设置 Popen 实例进行读写,请结合使用以前的技术。

import subprocess

print('popen2:')

proc = subprocess.Popen(
['ls', '-l'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)
msg = 'through stdin to stdout'.encode('utf-8')
stdout_value = proc.communicate(msg)[0].decode('utf-8')
print('pass through:', repr(stdout_value))

输出

popen2:
pass through: 'total 8\n-rw-r--r-- 1 chenxiangan staff 316 Jul 9 11:20 subprocess_demo.py\n'

使用 communicate() 而非 .stdin.write, .stdout.read 或者 .stderr.read 来避免由于任意其他 OS 管道缓冲区被子进程填满阻塞而导致的死锁。

错误捕获

Popen 还可以像使用 popen3()一样,同时监视 stdout 和 stderr 流。

import subprocess

print('popen3:')
proc = subprocess.Popen(
'ls -l; echo "to stderr" 1>&2',
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
msg = 'through stdin to stdout'.encode('utf-8')
stdout_value, stderr_value = proc.communicate(msg)
print('pass through:', repr(stdout_value.decode('utf-8')))
print('stderr :', repr(stderr_value.decode('utf-8')))

输出

popen3:
pass through: 'total 8\n-rw-r--r-- 1 chenxiangan staff 447 Jul 9 11:22 subprocess_os_system.py\n'
stderr : 'to stderr\n'

从 stderr 读取的工作与 stdout 相同。 通过传入 PIPE 告诉 Popen 连接到通道,并且 communication()方法在返回结果之前可以从中读取所有数据。

结合常规输出和错误输出

要将进程的错误输出定向到其标准输出通道,可以使用 STDOUT 代替 stderr 而不是 PIPE。

# 公众号:python 学习开发

import subprocess

print('popen4:')
proc = subprocess.Popen(
'ls -l; echo "to stderr" 1>&2',
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
msg = 'through stdin to stdout\n'.encode('utf-8')
stdout_value, stderr_value = proc.communicate(msg)
print('combined output:', repr(stdout_value.decode('utf-8')))
print('stderr value :', repr(stderr_value))

输出

popen4:
combined output: 'total 8\n-rw-r--r-- 1 chenxiangan staff 441 Jul 9 11:25 subprocess_os_system.py\nto stderr\n'
stderr value : None

以这种方式组合输出类似于 popen4()的工作方式。

管道之间的连接

通过创建单独的 Popen 实例并将它们的输入和输出链接在一起,可以类似于 Unix shell 的工作方式将多个命令连接到管道中。

# 公众号:python 学习开发

import subprocess

cat = subprocess.Popen(
['cat', 'subprocess_demo.py'],
stdout=subprocess.PIPE, # 提供输出的方式
) grep = subprocess.Popen(
['grep', '公众号'],
stdin=cat.stdout, # cat 的输出最为输入
stdout=subprocess.PIPE,
) cut = subprocess.Popen(
['awk', '-F', ':', '{print $2}'],
stdin=grep.stdout,
stdout=subprocess.PIPE,
) end_of_pipe = cut.stdout print(end_of_pipe.readline().decode('utf-8'))

输出

python 学习开发

上面的内容就等价于下面的命令

cat subprocess_demo.py |grep "公众号" |awk -F ':' '{print $2}'

与另一个命令交互

前面的所有示例都假定了有限的交互量。方法读取所有输出并等待子进程退出后返回。在程序运行时,还可以增量地对 Popen 实例使用的各个管道句柄进行读写。一个简单的 echo 程序演示了这种技术,该程序从标准输入读取数据并将其写入标准输出。

在下一个示例中,脚本 repeat.py 用作子进程。它从 stdin 读取值并将值写入 stdout,每次一行,直到没有更多输入为止。它还在启动和停止时向 stderr 写入一条消息,显示子进程的生存期。

# 文件:repeater.py
# 公众号:python 学习开发
import sys sys.stderr.write('repeater.py: starting\n')
sys.stderr.flush() while True:
next_line = sys.stdin.readline()
sys.stderr.flush()
if not next_line:
break
sys.stdout.write(next_line)
sys.stdout.flush() sys.stderr.write('repeater.py: exiting\n')
sys.stderr.flush()

下一个交互示例以不同的方式使用 Popen 实例拥有的 stdin 和 stdout 文件句柄.

在第一个例子中,将 0-4 依次被写入进程的 stdin,并且在每次写入之后读回下一行输出。 在第二个示例中,写入这五个数字,但是使用 communic()一次读取所有输出。

import io
import subprocess print('One line at a time:')
proc = subprocess.Popen(
'python3 repeater.py',
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)
stdin = io.TextIOWrapper(
proc.stdin,
encoding='utf-8',
line_buffering=True, # send data on newline
)
stdout = io.TextIOWrapper(
proc.stdout,
encoding='utf-8',
)
for i in range(5):
line = '{}\n'.format(i)
stdin.write(line)
output = stdout.readline()
print(output.rstrip())
remainder = proc.communicate()[0].decode('utf-8')
print(remainder) print()
print('All output at once:')
proc = subprocess.Popen(
'python3 repeater.py',
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
)
stdin = io.TextIOWrapper(
proc.stdin,
encoding='utf-8',
)
for i in range(5):
line = f'{i}\n'
stdin.write(line)
stdin.flush() output = proc.communicate()[0].decode('utf-8')
print(output)

“repeater.py:exiting”出现在每个循环位置的不同点。


One line at a time:
repeater.py: starting
0
1
2
3
4
repeater.py: exiting All output at once:
repeater.py: starting
repeater.py: exiting
0
1
2
3
4

信号之间的进程

正在 os 模块中的进程管理示例包括使用 os.fork()和 os.kill()在进程之间发送信号的演示。

由于每个 Popen 实例都提供了一个带有子进程的进程 id 的 pid 属性,所以可以对子进程执行类似的操作。下一个例子结合了两个脚本。这个子进程为 USR 信号设置一个信号处理器。

#signal_child.py
import os
import signal
import time
import sys pid = os.getpid()
received = False def signal_usr1(signum, frame):
"Callback invoked when a signal is received"
global received
received = True
print(f'CHILD {pid:>6}: Received USR1')
sys.stdout.flush() print(f'CHILD {pid:>6}: Setting up signal handler')
sys.stdout.flush()
signal.signal(signal.SIGUSR1, signal_usr1)
print(f'CHILD {pid:>6}: Pausing to wait for signal')
sys.stdout.flush()
time.sleep(3) if not received:
print(f'CHILD {pid:>6}: Never received signal')

然后再写一个文件,此脚本作为父进程运行。 它启动 signal_child.py,然后发送 USR1 信号。

import os
import signal
import subprocess
import time
import sys proc = subprocess.Popen(['python3', 'signal_child.py'])
print('PARENT : Pausing before sending signal...')
sys.stdout.flush()
time.sleep(1)
print('PARENT : Signaling child')
sys.stdout.flush()
os.kill(proc.pid, signal.SIGUSR1)

运行之后

PARENT      : Pausing before sending signal...
CHILD 46573: Setting up signal handler
CHILD 46573: Pausing to wait for signal
PARENT : Signaling child
CHILD 46573: Received USR1

进程组

如果子进程是由 Popen 创建的进程产生的,那些子进程将不会收到发送给父进程的任何信号。 当 Popen 使用 shell 参数时,很难通过发送 SIGINT 或 SIGTERM 来使 shell 中启动的命令终止。

若要在不知道进程 id 的情况下向后代发送信号,请使用进程组将子进程关联起来,以便将它们一起发送信号。使用 os.setpgrp()创建进程组,将进程组 id 设置为当前进程的进程 id。

import os
import signal
import subprocess
import tempfile
import time
import sys script = '''#!/bin/sh
echo "Shell script in process $$"
set -x
python3 signal_child.py
'''
script_file = tempfile.NamedTemporaryFile('wt')
script_file.write(script)
script_file.flush() proc = subprocess.Popen(['sh', script_file.name])
print('PARENT : Pausing before signaling {}...'.format(
proc.pid))
sys.stdout.flush()
time.sleep(1)
print('PARENT : Signaling child {}'.format(proc.pid))
sys.stdout.flush()
os.kill(proc.pid, signal.SIGUSR1)
time.sleep(3)

输出

PARENT      : Pausing before signaling 46600...
Shell script in process 46600
+ python3 signal_child.py
CHILD 46601: Setting up signal handler
CHILD 46601: Pausing to wait for signal
PARENT : Signaling child 46600
CHILD 46601: Never received signal

用于发送信号的 pid 与等待信号的 shell 脚本的子脚本的 pid 不匹配,因为在本例中有三个独立的进程在交互

1.程序子进程向父 shell.py 发送信号

2.shell 进程运行主 python 程序创建的脚本

3.signal_child.py 进程。

如果想在不知道其进程 ID 的情况下向后代发送信号,可以使用进程组来关联子进程,以便它们可以一起发出信号。可以使用 os.setpgrp()创建进程组,然后将进程组 id 设置为当前进程的进程 id。这样所有子进程都从父进程继承它们的进程组,因为它只能在 Popen 及其后代创建的 shell 中设置,所以不应该在创建 Popen 的同一进程中调用 os.setpgrp()。更改之后的代码如下:

import os
import signal
import subprocess
import tempfile
import time
import sys def show_setting_prgrp():
print('Calling os.setpgrp() from {}'.format(os.getpid()))
os.setpgrp()
print('Process group is now {}'.format(os.getpgrp()))
sys.stdout.flush() script = '''#!/bin/sh
echo "Shell script in process $$"
set -x
python3 signal_child.py
'''
script_file = tempfile.NamedTemporaryFile('wt')
script_file.write(script)
script_file.flush() proc = subprocess.Popen(
['sh', script_file.name],
preexec_fn=show_setting_prgrp,
)
print('PARENT : Pausing before signaling {}...'.format(
proc.pid))
sys.stdout.flush()
time.sleep(1)
print('PARENT : Signaling process group {}'.format(
proc.pid))
sys.stdout.flush()
os.killpg(proc.pid, signal.SIGUSR1)
time.sleep(3)

输出结果

+ python3 signal_child.py
Calling os.setpgrp() from 46618
Process group is now 46618
PARENT : Pausing before signaling 46618...
Shell script in process 46618
CHILD 46619: Setting up signal handler
CHILD 46619: Pausing to wait for signal
PARENT : Signaling process group 46618
CHILD 46619: Received USR1

事件发生的顺序如下:

1.父程序实例化 Popen。

2.Popen 实例派生了一个新的进程。

3.新进程运行 os.setpgrp()。

4.新进程会运行 exec()启动 shell。

5.shell 会运行 shell 脚本

6.shell 脚本再次 fork,该进程执行 Python。

7.python 运行脚本 signal_child.py

8.父程序使用 shell 的 pid 向进程组发出信号。

9.shell 和 Python 进程接收信号

10.运行 signal child.py 的 Python 进程调用信号处理程序。

参考资料

https://docs.python.org/3.7/library/subprocess.html

Python 调用系统命令的模块 Subprocess的更多相关文章

  1. python调用系统命令 shell命令

    使用python调用系统命令,基本有3种选择: 1. 使用os模块的system方法 import os os.system('ls') 2. 使用os模块的popen方法 import os os. ...

  2. python调用系统命令popen、system

    python调用Shell脚本,有两种方法:os.system(cmd)或os.popen(cmd),前者返回值是脚本的退出状态码,后者的返回值是脚本执行过程中的输出内容.所以说一般我们认为popen ...

  3. python 调用系统命令

    Python执行系统命令一般的用到了四种方法, 第一种是 os.system(),  这个方法比较常用, 使用也简单, 会自动的生成一个进程,在进程完成后会自动退出, 需要注意的是 os.system ...

  4. Python调用C可执行程序(subprocess) 分类: python 服务器搭建 C/C++ shell 2015-04-13 21:03 87人阅读 评论(0) 收藏

    从Python 2.4开始,Python引入subprocess模块来管理子进程,以取代一些旧模块的方法:如 os.system.os.spawn.os.popen.popen2.commands. ...

  5. python调用系统命令的方法

    1.os模块 (1)system()方法 这个方法是直接调用标准C的system() 函数,在一个子终端运行系统命令 (2)poen()方法 这个方法执行命令后通过一个管道文件将结果返回 3.subp ...

  6. Python执行系统命令:使用subprocess的Popen函数

    使用subprocess的Popen函数执行系统命令 参考: http://blog.sina.com.cn/s/blog_8f01450601017dlr.html http://blog.csdn ...

  7. python调用接口——requests模块

    前提:安装pip install requests 导入import requests 1.get请求   result=requests.get(url,d).json()  或  .text 2. ...

  8. Python全栈之路----常用模块----subprocess模块

    我们经常需要通过Python去执行一条系统命令或脚本,系统的shell命令是独立于你的python进程之外的,每执行一条命令,就是发起一个新进程,通过python调用系统命令或脚本的模块在python ...

  9. 使用python执行系统命令——subprocess

     背景:subprocess是python官方推荐调用系统命令的模块 import subprocess subprocess最主要的两个方法/类: # 参数说明:stdin和stdout相当于一个管 ...

随机推荐

  1. regarding-hsts-in-netscaler

    regarding-hsts-in-netscaler 参考: Strict Transport Security (STS or HSTS) with Citrix NetScaler and Ac ...

  2. [NOIP2018模拟赛10.18]自闭报告

    闲扯 这一天,菜鸡RyeCatcher又想起来了被毒瘤题支配的恐惧 今天比较好玩,还是ljy提醒才发现文件夹里有题面...不知道外面的人什么时候才发现 看完了题面,又回到了雅礼啥题也不会写的感觉 T1 ...

  3. vue跳转本页面报错

    一个按钮绑定一个方法,方法是跳转到某个路由地址,当已经点击触发方法到该路由下的时候,再进行点击该按钮控制台就会报错,不会影响项目运行 解决方法: if(this.$route.path == '/bi ...

  4. js检测是不是数字

    function isValueNumber(value) { var reg = (/(^-?[0-9]+\.{1}\d+$)|(^-?[1-9][0-9]*$)|(^-?0{1}$)/); var ...

  5. Java 之 IDEA 的 Debug 追踪

    使用 IDEA 的断点调试功能,查看程序的运行过程. 1.在有效代码行,点击行号右边的空白区域,设置断点,程序执行到断点将停止,我们可以手动来运行程序 2.点击 Debug 运行模式 3.程序停止在断 ...

  6. Join 和 App

    在关系型数据库系统中,为了满足第三范式(3NF),需要将满足“传递依赖”的表分离成单独的表,通过Join 子句将相关表进行连接,Join子句共有三种类型:外连接,内连接,交叉连接:外连接分为:left ...

  7. kbmMW 5.10.10 SmartBinding问题修正

    千呼万唤始出来,最新的kbmMW 5.10.01终于发布了,详情可以看xalion发的更新日志. 我期待的Smartbinding for Listview终于来了,在这一版本中,对SmartBind ...

  8. Image Processing and Analysis_8_Edge Detection:Learning to Detect Natural Image Boundaries Using Local Brightness, Color, and Texture Cues ——2004

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...

  9. 向量的一种特殊乘法 element wise multiplication

    向量的一种特殊乘法 element wise multiplication 物体反射颜色的计算采用这样的模型: vec3 reflectionColor = objColor * lightColor ...

  10. Struts2 Action类的创建以及参数传递以及接收

    一.Struts中Action得创建方式 1,直接创建一个简单的Action类 添加Struts.xml,配置转发方法返回转发的页面. 2,实现一个Action类 Strust.xml配置对应的Url ...