博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python 脚本自动交互_适用于艺术家的Python技巧:如何向任何Python脚本添加交互性...
阅读量:2524 次
发布时间:2019-05-11

本文共 15261 字,大约阅读时间需要 50 分钟。

python 脚本自动交互

继续学习有关艺术家的Python技巧系列:

脚本是自动化创意工作中繁琐部分的好方法,并使您可以将大部分精力集中在有趣和有趣的部分上。 但是,有时会出现一次快速的一次性脚本被足够频繁地使用以使其成为实用程序的情况。 发生这种情况时,脚本仅仅随您吐出而无需与您进行任何交互就可以独立运行就足够了。 该脚本将需要接受输入参数,询问您有意义的问题,然后对它们采取行动。

让我们从本系列的上一篇文章, 获取脚本。 列出目录中所有损坏的图像文件是一件方便的小事。 很好,但是不必将该脚本复制到要测试不良图像的每个目录中,肯定会更方便。 另外,如果您的脚本可以为您找到损坏的图像后将其删除,那就更好了。 当然,删除文件总是让人有些恐惧。 您要确保只删除不良的,因此从脚本中进行一些提示和确认会很好,所以让我们这样做。

接下来是上一篇文章结尾处存在的脚本:

from      
os
import listdir
from PIL
import Image
for filename
in listdir
(
'./'
) :
   
if filename.
endswith
(
'.png'
) :
       
try :
            img
= Image.
open
(
'./' +filename
)
# open the image file
            img.
verify
(
)
# verify that it is, in fact an image
       
except
(
IOError
,
SyntaxError
)
as e:
           
print
(
'Bad file:'
, filename
)
# print out the names of corrupt files

接受命令行参数

添加便利性的第一个有用的方面是让您的脚本可以在您选择的任意目录中运行。 您可以让脚本提示您输入目录名称,但是我更希望在实际运行脚本时将其作为输入参数。 无论哪种方式都有道理,但对我而言,主要是关于懒惰。 如果在运行脚本时指定目录路径:

python remove-corrupt-pngs. py /path/to/directory

我可以利用外壳程序的内置制表符完成功能,并因此减少键入(通过按键盘上的较少按钮来键入相同的数字)。

要从命令行获取输入(或参数),最简单的方法是使用另一个Python的默认模块: sys 。 具体来说,您对sys.argv感兴趣,它是在启动脚本的同时输入的单词列表(以空格分隔)。 该列表是Python脚本中经常使用的基本数据结构。 可以将它们视为一系列以相同名称分组的变量。

接下来是一个简短的小测试示例。 创建一个名为list_test.py的新Python脚本,并使用以下代码填充它:

import      
sys
print
(
'Length of list:'
,
len
(
sys .
argv
)
)
print
(
sys .
arv
)

保存脚本。 现在,当您从命令行( python list_test.py )运行它时,脚本的输出应如下所示:

Length of      
list :
1
[
'list_test.py'
]

启动脚本时,尝试在命令行上添加一个或两个参数(例如python list_test.py blahblah blah )。 该脚本将输出如下内容:

Length of      
list :
3
[
'list_test.py, ' blahblah
', ' blah
']

首先要注意的是如何找到列表的长度,就像在列表上使用len()函数一样简单。 接下来要注意的是列表本身的符号。 本系列的第一篇文章( 对此进行了一些介绍,但是为了快速上手,列表用方括号( [] )包围,并且每个列表项之间都用一个逗号分隔。逗号。 对于sys.argv列表,脚本名称始终是该列表中的第一项。 此后的每个单词都是列表中的后续项。 您可以通过在列表名称后面的方括号内指定索引(整数)来单独访问列表中的每个项目(例如sys.argv [0] )。

关于该索引的简短论述

现在快速进行题外话并谈论索引是值得的。 大多数人(以及一些奇怪的语言,我正在研究Lua和MATLAB)从1开始计数,而Python和大多数现代编程语言则没有。 他们的计数从零开始。 因此,即使脚本名称是sys.argv列表中的第一项,也可以使用sys.argv [0]对其进行访问。 如果使用sys.argv [1] ,则将获得列表中的第二项(在上一个示例中,该为blahblah )。

现在回到脚本

既然您知道如何检查列表的长度并访问列表中的单个元素,那么可以使损坏的图像查找脚本更加智能。 首先,假设脚本名称之后的第一个参数是您要检查的图像目录的路径。 将路径分配给它自己的变量是明智的。 我称它为imgdir 。 要将路径参数分配给imgdir变量,可以只使用imgdir = sys.argv [1]

但是有一个陷阱:如果在启动脚本时忘记指定目录名怎么办? 如果您的脚本对此进行检查,那就太好了。 幸运的是,您可以检查sys.argv列表的长度。 如果sys.argv列表不是2,则说明未指定路径。 代码块如下所示:

if      
len
(
sys .
argv
)
==
2 :
    imgdir
=
sys .
argv
[
1
]
else :
   
print
(
'You need to include a path to the directory you want to check.'
)
    exit
(
2
)

小段文字检查sys.argv列表中是否有两项,并将第二次(索引1)分配给imgdir变量。 否则,它会显示一条错误消息并退出( exit(2) )。 另外,如果目录路径中包含空格,也可以退出,但是您没有正确地将其用引号引起来。 (文件名中的空格可能会使编写脚本时感到痛苦。请避免在文件命名约定中犯下此类暴行。)

将这段代码插入到脚本顶部。 然后,您需要使脚本利用该imgdir目录,这非常简单,因为它主要是与imgdir交换'./'问题 。 之后,您的脚本应如下所示:

import      
sys
from
os
import listdir
from PIL
import Image
if
len
(
sys .
argv
)
==
2 :
    imgdir
=
sys .
argv
[
1
]
else :
   
print
(
'You need to include a path to the directory you want to check.'
)
    exit
(
2
)
for filename
in listdir
( imgdir
) :
   
if filename.
endswith
(
'.png'
) :
       
try :
            img
= Image.
open
( imgdir+
'/' +filename
)
# open the image file
            img.
verify
(
)
# verify that it is, in fact an image
       
except
(
IOError
,
SyntaxError
)
as e:
           
print
(
'Bad file:'
, filename
)
# print out the names of corrupt files

现在,您可以在任何地方运行脚本,并检查计算机可以访问的任何目录; 不再需要到处复制相同的脚本。

提示用户输入

要让您的脚本为您删除那些不良文件,实际上很容易。 您只需要使用os模块中内置的remove()函数。 但是,暂时不要这样做。

删除文件时总是要格外小心。 当他们走了,他们走了。 因此,您应该让脚本删除文件,然后先确切地告诉您要删除的文件,然后再询问您是否要进行确认,因此您首先要将该部分添加到脚本中。

在Python脚本中提示输入的最简单方法是使用raw_input()函数。 从表面上看,它看起来很像print()函数。 您在括号之间放置一个字符串,Python将其吐出到屏幕上。 但是,不同之处在于raw_input()随后将等待您键入内容并按Enter。 您键入的任何内容都存储在变量中。 然后,您的脚本可以读取该变量的内容并决定如何从该处执行操作。

对于此特定脚本,您希望它询问是否应删除特定文件。 该行的代码可能如下所示:

delete_files = raw_input ( 'Would you like to remove this bad image? (y/N)' )

用户输入的任何内容都将作为字符串存储在delete_files变量中。 对于删除文件,我要处理的方式是使用“ no”作为默认响应。 仅当用户键入“是”的某些变体时,脚本才会继续删除任何内容。 这段代码看起来像这样:

if delete_files      
in
[
'Y'
,
'y'
,
'Yes'
,
'yes'
,
'YES'
] :
   
print
(
'Removing bad image.'
)
   
# code for deleting image goes here (we'll get to it, promise)
else :
   
print
(
'Leaving bad image in place.'
)

到目前为止,将所有部分放在一起,您的脚本应如下所示:

import      
sys
from
os
import listdir
from PIL
import Image
if
len
(
sys .
argv
)
==
2 :
    imgdir
=
sys .
argv
[
1
]
else :
   
print
(
'You need to include a path to the directory you want to check.'
)
    exit
(
2
)
for filename
in listdir
( imgdir
) :
   
if filename.
endswith
(
'.png'
) :
       
try :
            img
= Image.
open
( imgdir+
'/' +filename
)
# open the image file
            img.
verify
(
)
# verify that it is, in fact an image
       
except
(
IOError
,
SyntaxError
)
as e:
           
print
(
'Bad file:'
, filename
)
# print out the names of corrupt files
           
            delete_files
=
raw_input
(
'Would you like to remove this bad image? (y/N)'
)
           
           
if delete_files
in
[
'Y'
,
'y'
,
'Yes'
,
'yes'
,
'YES'
] :
               
print
(
'Removing bad image.'
)
               
# code for deleting image goes here (we'll get to it, promise)
           
else :
               
print
(
'Leaving bad image in place.'
)

但是,您对此设置有一个问题。 如果您的脚本发现大量损坏的图像该怎么办? 必须确认分别删除每个人将是非常繁琐和烦人的。 让脚本告诉您所有不良图像,并要求您一次性删除它们会更好。

尽管这是一个好主意,但您将需要重新考虑脚本中的一些逻辑。 别担心,从代码方面来说,这不是一件大事。 只是一个小的“编排”调整。 到目前为止,您的脚本一直在处理错误文件,并在找到它们时立即打印它们的名称。 但是,如果您的脚本要同时处理所有错误文件,那么您将需要某种机制来存储每个错误文件的名称。 您将需要另一个列表。

您的脚本将首先在列表中存储错误文件的名称,而不是在找到文件后立即尝试删除该文件,您可以将其命名为badfiles 。 您可以在Python中创建一个空列表,如下所示:

badfiles = [ ]

您只使用一个等号和一对方括号,就可以了。 但是您可能会发现自己在问:“为什么我需要一个空白列表?我认为这应该是损坏的图像的列表,而不是没有的列表。”

好问题。 简短的答案是,如果列表不首先存在,则无法将其添加到列表中。 如果您不是从空篮子开始的话,收集野餐食物就很难。 在空列表到位后,您需要一种将每个错误文件的名称添加到列表中的机制。 幸运的是,Python的内置列表具有很好的处理方式。 每个列表都有一个append()函数,您可以使用该函数将项目添加到列表中。 它的用法如下所示:

badfile. append ( 'corrupt.png' )

假设错误图片的名称为“ corrupt.png”。 当然,您不需要键入实际的文件名; 您已经有一个变量了。 在脚本中,找到坏文件时不会打印坏文件的名称,而是将该文件的名称附加到列表中。 然后,脚本完成检查目录中的不良图像后,便可以将要显示的文件列表打印到屏幕上, 然后询问是否要删除它们。

当您这样做时,您的脚本开始看起来像这样:

import      
sys
from
os
import listdir
from PIL
import Image
if
len
(
sys .
argv
)
==
2 :
    imgdir
=
sys .
argv
[
1
]
else :
   
print
(
'You need to include a path to the directory you want to check.'
)
    exit
(
2
)
badfiles
=
[
]
# Empty list to store names of corrupt images
for filename
in listdir
( imgdir
) :
   
if filename.
endswith
(
'.png'
) :
       
try :
            img
= Image.
open
( imgdir+
'/' +filename
)
# open the image file
            img.
verify
(
)
# verify that it is, in fact an image
       
except
(
IOError
,
SyntaxError
)
as e:
            badfiles.
append
( filename
)
# Add bad file name to list
print
(
'List of bad images:'
)
for filename
in badfiles:
   
print
( imgdir+
'/' +filename
)
# Print each corrupted file's name with full path
print
(
'There are,'
len
( badfiles
)
,
'bad images that need to be deleted and replaced.'
delete_files
=
raw_input
(
'Would you like to remove these bad images? (y/N)'
)
if delete_files
in
[
'Y'
,
'y'
,
'Yes'
,
'yes'
,
'YES'
] :
   
print
(
'Removing bad images.'
)
   
# code for deleting image goes here (we'll get to it, promise)
else :
   
print
(
'Leaving bad images in place.'
)

删除文件

至此,您的脚本正在愉快地创建损坏图像的列表,并在检查完整个目录后将该列表打印到屏幕上。 现在让我们讨论一下实际上删除那些文件。 正如我在上一节中提到的,删除就像在os模块中使用remove()函数一样简单。 当然,您需要使脚本知道该功能。 请记住,现在您的脚本还不了解整个os模块。 您只需在脚本顶部导入listdir

您可以在脚本顶部从os import remove打耳光并完成此操作,但我们还是要懒惰。 您已经从os导入了一个函数,因此您也可以尝试将该行重用于remove()函数,实际上可以。 您要从模块导入的每个函数只需在该行中列出,并用逗号分隔。 您的导入行应如下所示:

​from os import listdir , remove

现在您的脚本知道了如何删除文件。 万岁少打字!

至于实际使用remove()函数,这很容易。 您只需将其提供给您要删除的文件的完整路径,该文件就不会再冒烟了。 您只需要对badfiles列表中的每个文件执行此操作 。 该过程的代码仅使用另一个for循环:

for filename      
in badfiles:
    remove
( imgdir+
'/' +filename
)

将其插入您已经编写的代码中(关于承诺删除文件的注释在此处),完成的脚本应如下所示:

import      
sys
from
os
import listdir
, remove
from PIL
import Image
if
len
(
sys .
argv
)
==
2 :
    imgdir
=
sys .
argv
[
1
]
else :
   
print
(
'You need to include a path to the directory you want to check.'
)
    exit
(
2
)
badfiles
=
[
]
# Empty list to store names of corrupt images
for filename
in listdir
( imgdir
) :
   
if filename.
endswith
(
'.png'
) :
       
try :
            img
= Image.
open
( imgdir+
'/' +filename
)
# open the image file
            img.
verify
(
)
# verify that it is, in fact an image
       
except
(
IOError
,
SyntaxError
)
as e:
            badfiles.
append
( filename
)
# Add bad file name to list
print
(
'List of bad images:'
)
for filename
in badfiles:
   
print
( imgdir+
'/' +filename
)
# Print each corrupted file's name with full path
print
(
'There are,'
len
( badfiles
)
,
'bad images that need to be deleted and replaced.'
delete_files
=
raw_input
(
'Would you like to remove these bad images? (y/N)'
)
if delete_files
in
[
'Y'
,
'y'
,
'Yes'
,
'yes'
,
'YES'
] :
   
print
(
'Removing bad images.'
)
   
for filename
in badfiles:
        remove
( imgdir+
'/' +filename
)
# Permanently delete files
else :
   
print
(
'Leaving bad images in place.'
)

现在,您有了一个可以在任何地方运行的脚本,因为它需要用户在命令行中输入。 更重要的是,您的脚本会在执行危险操作(例如删除文件)之前先请求权限。 此外,现在您知道了如何从命令行获取参数并将一些简单的用户交互添加到脚本中。

您可以使用本文介绍的技术将交互性添加到您编写的任何Python脚本中,这意味着您不必在工作目录中浮动随机脚本。 您可以将脚本全部保存在一个位置,然后从那里使用它们。 更少的步骤,更轻松的维护,并且您仍在自动化繁琐的工作,因此您可以专注于自己的创作工作-什么是不爱的?

翻译自:

python 脚本自动交互

转载地址:http://azdzd.baihongyu.com/

你可能感兴趣的文章
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_07 缓冲流_4_缓冲流的效率测试_复制文件...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_06 Properties集合_3_Properties集合中的方法load...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_07 缓冲流_5_BufferedWriter_字符缓冲输出流...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_07 缓冲流_6_BufferedReader_字符缓冲输入流...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_07 缓冲流_7_练习_对文本的内容进行排序...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_08 转换流_1_字符编码和字符集...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_08 转换流_2_编码引出的问题_FileReader读取GBK格式文件...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_08 转换流_3_转换流的原理...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_08 转换流_4_OutputStreamWriter介绍&代码实现...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_08 转换流_5_InputStreamReader介绍&代码实现...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_08 转换流_6_练习_转换文件编码...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_1_序列化和反序列化的概述...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_5_InvalidClassException异常_原理...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_2_对象的序列化流_ObjectOutputStream...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_10 打印流_1_打印流_概述和使用...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_4_transient关键字_瞬态关键字...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_07-网络编程_第1节 网络通信概述_1_软件结构...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_6_练习_序列化集合...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_3_对象的反序列化流_ObjectInputStream...
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_07-网络编程_第1节 网络通信概述_2_网络通信协议...
查看>>