标签归档:linux

如何在已经创建的virtualenv中设置pythonpath?

问题:如何在已经创建的virtualenv中设置pythonpath?

我要编辑什么文件?我创建了一个虚拟环境。

What file do I edit, and how? I created a virtual environment.


回答 0

编辑#2

正确的答案是@arogachev的答案。


如果要更改PYTHONPATHvirtualenv中使用的名称,可以将以下行添加到virtualenv的bin/activate文件中:

export PYTHONPATH="/the/path/you/want"

这样,PYTHONPATH每次使用此virtualenv时都会设置新的。

编辑:( 回答@RamRachum的评论)

要将其恢复到的原始值deactivate,您可以添加

export OLD_PYTHONPATH="$PYTHONPATH"

在前面提到的行之前,然后将以下行添加到bin/postdeactivate脚本中。

export PYTHONPATH="$OLD_PYTHONPATH"

EDIT #2

The right answer is @arogachev’s one.


If you want to change the PYTHONPATH used in a virtualenv, you can add the following line to your virtualenv’s bin/activate file:

export PYTHONPATH="/the/path/you/want"

This way, the new PYTHONPATH will be set each time you use this virtualenv.

EDIT: (to answer @RamRachum’s comment)

To have it restored to its original value on deactivate, you could add

export OLD_PYTHONPATH="$PYTHONPATH"

before the previously mentioned line, and add the following line to your bin/postdeactivate script.

export PYTHONPATH="$OLD_PYTHONPATH"

回答 1

@ s29的评论应该是一个答案:

向虚拟环境添加目录的一种方法是安装virtualenvwrapper(这对很多事情都有用),然后执行

mkvirtualenv myenv
workon myenv
add2virtualenv . #for current directory
add2virtualenv ~/my/path

如果要删除这些路径,请编辑文件 myenvhomedir/lib/python2.7/site-packages/_virtualenv_path_extensions.pth

有关virtualenvwrapper的文档可以在http://virtualenvwrapper.readthedocs.org/en/latest/中找到。

有关此功能的特定文档,请访问 http://virtualenvwrapper.readthedocs.org/en/latest/command_ref.html?highlight=add2virtualenv

The comment by @s29 should be an answer:

One way to add a directory to the virtual environment is to install virtualenvwrapper (which is useful for many things) and then do

mkvirtualenv myenv
workon myenv
add2virtualenv . #for current directory
add2virtualenv ~/my/path

If you want to remove these path edit the file myenvhomedir/lib/python2.7/site-packages/_virtualenv_path_extensions.pth

Documentation on virtualenvwrapper can be found at http://virtualenvwrapper.readthedocs.org/en/latest/

Specific documentation on this feature can be found at http://virtualenvwrapper.readthedocs.org/en/latest/command_ref.html?highlight=add2virtualenv


回答 2

您可以创建一个.pth包含要搜索的目录的文件,并将其放置在site-packages目录中。例如:

cd $(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
echo /some/library/path > some-library.pth

效果与添加/some/library/path到相同sys.path,并且保持在virtualenv设置本地。

You can create a .pth file that contains the directory to search for, and place it in the site-packages directory. E.g.:

cd $(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
echo /some/library/path > some-library.pth

The effect is the same as adding /some/library/path to sys.path, and remain local to the virtualenv setup.


回答 3

  1. 初始化您的virtualenv
cd venv

source bin/activate
  1. 只需通过输入以下命令来设置或更改python路径:
export PYTHONPATH='/home/django/srmvenv/lib/python3.4'
  1. 用于检查python路径,请在python中输入:
   python

      \>\> import sys

      \>\> sys.path
  1. Initialize your virtualenv
cd venv

source bin/activate
  1. Just set or change your python path by entering command following:
export PYTHONPATH='/home/django/srmvenv/lib/python3.4'
  1. for checking python path enter in python:
   python

      \>\> import sys

      \>\> sys.path


回答 4

我修改了激活脚本以获取文件.virtualenvrc(如果文件存在于当前目录中)并PYTHONPATH在激活/停用时保存/恢复。

您可以在activate此处找到修补的脚本。。它是由virtualenv 1.11.6创建的激活脚本的直接替代。

然后我向我添加了类似的内容.virtualenvrc

export PYTHONPATH="${PYTHONPATH:+$PYTHONPATH:}/some/library/path"

I modified my activate script to source the file .virtualenvrc, if it exists in the current directory, and to save/restore PYTHONPATH on activate/deactivate.

You can find the patched activate script here.. It’s a drop-in replacement for the activate script created by virtualenv 1.11.6.

Then I added something like this to my .virtualenvrc:

export PYTHONPATH="${PYTHONPATH:+$PYTHONPATH:}/some/library/path"

回答 5

它已经在这里回答-> 我的虚拟环境(python)是否导致PYTHONPATH中断?

UNIX / Linux

将“ export PYTHONPATH = / usr / local / lib / python2.0”添加到〜/ .bashrc文件,并通过键入“ source〜/ .bashrc”或“。〜/ .bashrc”将其导出。

Windows XP

1)转到控制面板2)双击系统3)转到高级选项卡4)单击环境变量

在“系统变量”窗口中,检查是否有一个名为PYTHONPATH的变量。如果已经有了,请检查它是否指向正确的目录。如果还没有,请单击“新建”按钮并创建它。

密码

另外,您也可以在代码下方执行以下操作:-

import sys
sys.path.append("/home/me/mypy") 

It’s already answered here -> Is my virtual environment (python) causing my PYTHONPATH to break?

UNIX/LINUX

Add “export PYTHONPATH=/usr/local/lib/python2.0” this to ~/.bashrc file and source it by typing “source ~/.bashrc” OR “. ~/.bashrc”.

WINDOWS XP

1) Go to the Control panel 2) Double click System 3) Go to the Advanced tab 4) Click on Environment Variables

In the System Variables window, check if you have a variable named PYTHONPATH. If you have one already, check that it points to the right directories. If you don’t have one already, click the New button and create it.

PYTHON CODE

Alternatively, you can also do below your code:-

import sys
sys.path.append("/home/me/mypy") 

如何检查scikit学习安装了哪个版本的nltk?

问题:如何检查scikit学习安装了哪个版本的nltk?

在shell脚本中,我正在检查是否已安装此软件包,如果未安装,请先安装它。因此,使用shell脚本:

import nltk
echo nltk.__version__

但它会在以下位置停止shell脚本 import在行

在Linux终端中尝试以这种方式查看:

which nltk

没有任何东西以为已安装。

还有没有其他方法可以在shell脚本中验证此软件包的安装,如果未安装,请同时安装。

In shell script I am checking whether this packages are installed or not, if not installed then install it. So withing shell script:

import nltk
echo nltk.__version__

but it stops shell script at import line

in linux terminal tried to see in this manner:

which nltk

which gives nothing thought it is installed.

Is there any other way to verify this package installation in shell script, if not installed, also install it.


回答 0

import nltk 是Python语法,因此无法在Shell脚本中使用。

为了测试的版本nltkscikit_learn,你可以写一个Python脚本并运行它。这样的脚本可能看起来像

import nltk
import sklearn

print('The nltk version is {}.'.format(nltk.__version__))
print('The scikit-learn version is {}.'.format(sklearn.__version__))

# The nltk version is 3.0.0.
# The scikit-learn version is 0.15.2.

请注意,并非所有Python软件包都保证具有__version__属性,因此对于某些其他软件包可能会失败,但是对于nltk和scikit-learn至少它会起作用。

import nltk is Python syntax, and as such won’t work in a shell script.

To test the version of nltk and scikit_learn, you can write a Python script and run it. Such a script may look like

import nltk
import sklearn

print('The nltk version is {}.'.format(nltk.__version__))
print('The scikit-learn version is {}.'.format(sklearn.__version__))

# The nltk version is 3.0.0.
# The scikit-learn version is 0.15.2.

Note that not all Python packages are guaranteed to have a __version__ attribute, so for some others it may fail, but for nltk and scikit-learn at least it will work.


回答 1

试试这个:

$ python -c "import nltk; print nltk.__version__"

Try this:

$ python -c "import nltk; print nltk.__version__"

回答 2

在Windows®系统中,您可以尝试

pip3 list | findstr scikit

scikit-learn                  0.22.1

如果您在Anaconda上,请尝试

conda list scikit

scikit-learn              0.22.1           py37h6288b17_0

这可以用来找出您已安装的任何软件包的版本。例如

pip3 list | findstr numpy

numpy                         1.17.4
numpydoc                      0.9.2

或者,如果您想一次查找多个包裹

pip3 list | findstr "scikit numpy"

numpy                         1.17.4
numpydoc                      0.9.2
scikit-learn                  0.22.1

请注意,当搜索多个单词时,必须使用引号字符。

照顾自己。

In Windows® systems you can simply try

pip3 list | findstr scikit

scikit-learn                  0.22.1

If you are on Anaconda try

conda list scikit

scikit-learn              0.22.1           py37h6288b17_0

And this can be used to find out the version of any package you have installed. For example

pip3 list | findstr numpy

numpy                         1.17.4
numpydoc                      0.9.2

Or if you want to look for more than one package at a time

pip3 list | findstr "scikit numpy"

numpy                         1.17.4
numpydoc                      0.9.2
scikit-learn                  0.22.1

Note the quote characters are required when searching for more than one word.

Take care.


回答 3

要检查shell脚本中scikit-learn的版本,如果已安装pip,则可以尝试以下命令

pip freeze | grep scikit-learn
scikit-learn==0.17.1

希望能帮助到你!

For checking the version of scikit-learn in shell script, if you have pip installed, you can try this command

pip freeze | grep scikit-learn
scikit-learn==0.17.1

Hope it helps!


回答 4

您只需执行以下操作即可找到NLTK版本:

In [1]: import nltk

In [2]: nltk.__version__
Out[2]: '3.2.5'

对于scikit-learn,

In [3]: import sklearn

In [4]: sklearn.__version__
Out[4]: '0.19.0'

我在这里使用python3。

You can find NLTK version simply by doing:

In [1]: import nltk

In [2]: nltk.__version__
Out[2]: '3.2.5'

And similarly for scikit-learn,

In [3]: import sklearn

In [4]: sklearn.__version__
Out[4]: '0.19.0'

I’m using python3 here.


回答 5

您可以按照以下方式从python笔记本单元格中进行检查

!pip install --upgrade nltk     # needed if nltk is not already installed
import nltk      
print('The nltk version is {}.'.format(nltk.__version__))
print('The nltk version is '+ str(nltk.__version__))

#!pip install --upgrade sklearn      # needed if sklearn is not already installed
import sklearn
print('The scikit-learn version is {}.'.format(sklearn.__version__))
print('The scikit-learn version is '+ str(nltk.__version__))

you may check from a python notebook cell as follows

!pip install --upgrade nltk     # needed if nltk is not already installed
import nltk      
print('The nltk version is {}.'.format(nltk.__version__))
print('The nltk version is '+ str(nltk.__version__))

and

#!pip install --upgrade sklearn      # needed if sklearn is not already installed
import sklearn
print('The scikit-learn version is {}.'.format(sklearn.__version__))
print('The scikit-learn version is '+ str(nltk.__version__))

回答 6

在我的安装了python 2.7的ubuntu 14.04机器中,如果我去这里,

/usr/local/lib/python2.7/dist-packages/nltk/

有一个名为

VERSION

如果我这样做,cat VERSION它将打印3.1,这是已安装的NLTK版本。

In my machine which is ubuntu 14.04 with python 2.7 installed, if I go here,

/usr/local/lib/python2.7/dist-packages/nltk/

there is a file called

VERSION.

If I do a cat VERSION it prints 3.1, which is the NLTK version installed.


linux tee不能与python一起使用?

问题:linux tee不能与python一起使用?

我制作了一个python脚本,该脚本使用无限循环与Web服务器通信。我想将每个通讯数据记录到一个文件中,并同时从终端监视它们。所以我像这样使用tee命令。

python client.py | tee logfile

但是,我没有从终端或日志文件中得到任何东西。python脚本运行正常。这是怎么回事 我错过了什么吗?

一些建议,将不胜感激。先感谢您。

I made a python script which communicates with a web server using an infinite loop. I want to log every communication data to a file and also monitor them from terminal at same time. so I used tee command like this.

python client.py | tee logfile

however, I got nothing from terminal nor logfile. the python script is working fine. what is happening here? am I missing something?

some advice would be appreciated. thank you in advance.


回答 0

来自man python

   -u     Force stdin, stdout and stderr to  be  totally  unbuffered.   On  systems
          where it matters, also put stdin, stdout and stderr in binary mode.  Note
          that there is internal buffering in xreadlines(), readlines()  and  file-
          object  iterators  ("for  line  in sys.stdin") which is not influenced by
          this option.  To work around this, you will want to use  "sys.stdin.read‐
          line()" inside a "while 1:" loop.

因此,您可以做的是:

/usr/bin/python -u client.py >> logfile 2>&1

或使用tee

python -u client.py | tee logfile

From man python:

   -u     Force stdin, stdout and stderr to  be  totally  unbuffered.   On  systems
          where it matters, also put stdin, stdout and stderr in binary mode.  Note
          that there is internal buffering in xreadlines(), readlines()  and  file-
          object  iterators  ("for  line  in sys.stdin") which is not influenced by
          this option.  To work around this, you will want to use  "sys.stdin.read‐
          line()" inside a "while 1:" loop.

So what you can do is:

/usr/bin/python -u client.py >> logfile 2>&1

Or using tee:

python -u client.py | tee logfile

python-dev安装错误:ImportError:没有名为apt_pkg的模块

问题:python-dev安装错误:ImportError:没有名为apt_pkg的模块

我是Debian用户,我想安装python-dev,但是当我以root身份在shell中运行代码时:

# aptitude install python-dev

我收到以下错误:

Traceback (most recent call last):       
  File "/usr/bin/apt-listchanges", line 28, in <module>
    import apt_pkg
ImportError: No module named apt_pkg

似乎是什么问题,我该如何解决?

I am Debian user, and I want to install python-dev, but when I run the code in the shell as a root:

# aptitude install python-dev

I get the following error:

Traceback (most recent call last):       
  File "/usr/bin/apt-listchanges", line 28, in <module>
    import apt_pkg
ImportError: No module named apt_pkg

What seems to be the problem and how can I resolve it?


回答 0

确保您有一个有效的python-apt软件包。您可以尝试再次删除并安装该软件包以解决apt_pkg.so的问题。

apt-get install python-apt

Make sure you have a working python-apt package. You could try and remove and install that package again to fix the problem with apt_pkg.so not being located.

apt-get install python-apt

回答 1

我在做的时候遇到了这个问题sudo apt-get update。我的环境是debian8,python2.7 + 3.4(默认)+ 3.5。

以下代码将仅为apt_pkg....sopython 3.5重新创建文件

sudo apt-get install python3-apt --reinstall

以下代码解决了我的问题,

cd /usr/lib/python3/dist-packages
sudo ln -s apt_pkg.cpython-{35m,34m}-x86_64-linux-gnu.so

因此,很显然,python3-apt会检查最高的python版本,而不是当前使用的python版本。

I met this problem when doing sudo apt-get update. My env is debian8, with python2.7 + 3.4(default) + 3.5.

The following code will only re-create a apt_pkg....so file for python 3.5

sudo apt-get install python3-apt --reinstall

The following code solved my problem,

cd /usr/lib/python3/dist-packages
sudo ln -s apt_pkg.cpython-{35m,34m}-x86_64-linux-gnu.so

So, obviously, python3-apt checks the highest python version, instead of the current python version in use.


回答 2

通过以下方法解决:

/usr/lib/python3/dist-packages# cp apt_pkg.cpython-34m-i386-linux-gnu.so apt_pkg.so

要么:

/usr/lib/python3/dist-packages# cp apt_pkg.cpython-35m-x86_64-linux-gnu.so apt_pkg.so

基本上,如果您No such file or directory公正ls地尝试获得正确的名字。

Solve it by this:

/usr/lib/python3/dist-packages# cp apt_pkg.cpython-34m-i386-linux-gnu.so apt_pkg.so

Or:

/usr/lib/python3/dist-packages# cp apt_pkg.cpython-35m-x86_64-linux-gnu.so apt_pkg.so

Basically, if you get a No such file or directory just ls to try to get the right name.


回答 3

在我尝试从Deadsnakes存储库中安装Python3.7之后,在Ubuntu 18.04.2上发生了这种情况。

解决方法是这个

1) cd /usr/lib/python3/dist-packages/

2) sudo ln -s apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.so

This happened to me on Ubuntu 18.04.2 after I tried to install Python3.7 from the deadsnakes repo.

Solution was this

1) cd /usr/lib/python3/dist-packages/

2) sudo ln -s apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.so


回答 4

当同时安装了新版本的python和旧版本时,通常会发生此错误。

  • Ubuntu 18.04.1随附python版本3.6.6
  • 已安装ppa:deadsnakes / python3.7.1或替代版本
  • 运行使用apt_pkg模块的命令,并显示诸如以下错误:

        from CommandNotFound.db.db import SqliteDatabase
    File "/usr/lib/python3/dist-packages/CommandNotFound/db/db.py", line 5, in <module>
        import apt_pkg
    

当我们安装带有apt的非发行版python3版本时,会将共享模块目录设置为python3的共享目录,通常是/usr/lib/python3

在大多数情况下,这是可以的,但是在某些情况下,不同版本的python会比其他python版本依赖不同的库或共享对象/库,因此正如其他答案所指出的那样,我们需要将.SO链接到正确的python版本。因此,如果我们在64位系统上安装了python3.6,则apt_pkg .SO链接为

sudo ln -s apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.so

但是问题在于,当我们安装较新的python版本时,链接将更新为指向最新的python版本,这将导致找不到apt_pkg模块的错误。通过检查发行版附带的python版本,您可以创建上述链接。或者,我们使用一种方法来为命令提供选择python版本以链接.SO的选择,例如;

sudo ln -s apt_pkg.cpython-{36m,35m,34m}-x86_64-linux-gnu.so apt_pkg.so

因为python会创建到最新安装的python版本的链接,所以我们给命令提供了从3个python版本中进行选择的选项,它将选择给定的最高版本。

This error will often occur when a newer version of python has been installed alongside an older version e.g;

  • Ubuntu 18.04.1 ships with python version 3.6.6
  • Installed ppa:deadsnakes/python3.7.1 or alternative
  • Run a command that uses the apt_pkg module and get an error such as;

        from CommandNotFound.db.db import SqliteDatabase
    File "/usr/lib/python3/dist-packages/CommandNotFound/db/db.py", line 5, in <module>
        import apt_pkg
    

When we install a non-distro python3 version with apt it will set a shared module directory to be that of python3 most usually it will be /usr/lib/python3.

Most of the time this will be ok, but under some circumstances the different versions of python rely on different libraries or shared objects/libraries than the other python version does, so as other answers have pointed out we need to link the .SO to the correct python version. So if we have python3.6 installed on a 64bit system then the apt_pkg .SO link would be

sudo ln -s apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.so

But the problem lies in the fact that when we install a newer python version the link will update to point to the newest python version, which leads to the error of apt_pkg module not being found. By checking which version of python ships with your distro you can create the link as shown above. Or we use a method to offer the command a choice of python versions to link the .SO such as;

sudo ln -s apt_pkg.cpython-{36m,35m,34m}-x86_64-linux-gnu.so apt_pkg.so

Because python will create this link to the newest installed python version we give the command the option to choose from 3 python versions, of which it will choose the highest version given.


回答 5

@ user8178061的解决方案效果很好,但是我对python3.7Ubuntu的版本做了一些修改

我更换了apt_pkg.cpython-3m-i386-linux-gnu.soapt_pkg.cpython-36m-x86_64-linux-gnu.so

这里执行两个命令:

cd /usr/lib/python3/dist-packages

sudo cp apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.so

The solution of @user8178061 worked well but I did it with some modifications for my version wich is python3.7 with Ubuntu

I replaced the apt_pkg.cpython-3m-i386-linux-gnu.so with apt_pkg.cpython-36m-x86_64-linux-gnu.so

Here the two commands to execute:

cd /usr/lib/python3/dist-packages

sudo cp apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.so


回答 6

在ubuntu18.04上更新python3.7之后,这对我有用

cd /usr/lib/python3/dist-packages
sudo cp apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.so

This worked for me on after updating python3.7 on ubuntu18.04

cd /usr/lib/python3/dist-packages
sudo cp apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.so

回答 7

由于某种原因apt_pkg.so,python3 dist-packages目录中缺少我的安装。(apt_pkg.cpython-33m-x86_64-linux-gnu.so在那里?!),但是,我不得不作出一个符号链接apt_pkg.so -> apt_pkg.cpython-33m-x86_64-linux-gnu.so/usr/lib/python3/dist-packages

我不确定我的升级是否中断,或者为什么会这样。尝试升级后发生(精确-> raring->定量升级)

For some reason my install was missing apt_pkg.so in the python3 dist-packages dir. (apt_pkg.cpython-33m-x86_64-linux-gnu.so was there?!) but and I had to make a symlink apt_pkg.so -> apt_pkg.cpython-33m-x86_64-linux-gnu.so in /usr/lib/python3/dist-packages

I’m not sure whether my upgrade was broken or why this was the case. It occured after trying to upgrade (precise->raring->quantal upgrade)


回答 8

  1. 检查您的默认Python 3版本:
python --version
Python 3.7.5
  1. cd进入/usr/lib/python3/dist-packages并检查apt_pkg.*文件。您会发现默认Python版本没有:
ll apt_pkg.*
apt_pkg.cpython-36m-x86_64-linux-gnu.so
  1. 创建符号链接:
sudo ln -s apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.cpython-37m-x86_64- linux-gnu.so 
  1. Check your default Python 3 version:
python --version
Python 3.7.5
  1. cd into /usr/lib/python3/dist-packages and check the apt_pkg.* files. You will find that there is none for your default Python version:
ll apt_pkg.*
apt_pkg.cpython-36m-x86_64-linux-gnu.so
  1. Create the symlink:
sudo ln -s apt_pkg.cpython-36m-x86_64-linux-gnu.so apt_pkg.cpython-37m-x86_64- linux-gnu.so 

回答 9

不得已的方法是,sudo cp /usr/lib/python3/dist-packages/apt_pkg.cpython-35m-x86_64-linux-gnu.so /usr/lib/python3/dist-packages/apt_pkg.cpython-36m-x86_64-linux-gnu.so 如果该ln命令对您来说太多了,或者由于某种原因魔术无法正常工作。

cpmv如果您仅致力于使用一个Python版本,则也可以使用上述方法。

A last resort is sudo cp /usr/lib/python3/dist-packages/apt_pkg.cpython-35m-x86_64-linux-gnu.so /usr/lib/python3/dist-packages/apt_pkg.cpython-36m-x86_64-linux-gnu.so if the ln command is too much for you or somehow magically doesn’t work.

cp above can also be mv if you are only dedicated to using one Python version.


回答 10

如果您使用的是python 3.7,请通过更新Alternatives将其降级为python 3.6,这对我有用

sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1

sudo update-alternatives --config python3

if you’re using python 3.7 downgrade it to python 3.6 by updating Alternatives, This worked for me

sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1

sudo update-alternatives --config python3

回答 11

如果您使用的是Python 3.5,请降级为3.4。这是最安全的举动。

在下面,/usr/lib/python3/dist-packages您将看到*34m*不能使用哪个python 3.5。zhazha回答了它的符号链接。

If you’re using python 3.5, downgrade to 3.4. That’s the safest move to do.

Under /usr/lib/python3/dist-packages you’ll see *34m* which python 3.5 can’t use. zhazha answer symlink to it.


回答 12

除了为其建立符号链接外apt_pkg.so,您可能还希望以与之apt_inst.so相同的方式进行apt_pkg.so

ln -s apt_inst.cpython-35m-x86_64-linux-gnu.so apt_inst.so 

In addition to making a symbolic link for apt_pkg.so, you may want to make apt_inst.so in the same manner of apt_pkg.so.

ln -s apt_inst.cpython-35m-x86_64-linux-gnu.so apt_inst.so 

回答 13

我看到每个人都在说如何通过奇怪的复制等方式修复它,但是没人真正说出为什么会出现此问题。

因此,让我解释一下,对于像我这样的人,不想仅仅因为SO上的某人告诉了他们而弄乱系统文件。


问题是:

  • 许多系统脚本都将python3 shebang硬编码到其中。您可以自己检查:
~$ grep -R "\#\!/usr/bin/python3" /usr/lib/*

/usr/lib/cnf-update-db:#!/usr/bin/python3
/usr/lib/command-not-found:#!/usr/bin/python3
/usr/lib/cups/filter/pstotiff:#!/usr/bin/python3
/usr/lib/cups/filter/rastertosag-gdi:#!/usr/bin/python3 -u
grep: /usr/lib/cups/backend/cups-brf: Permission denied
/usr/lib/cups/backend/hpfax:#!/usr/bin/python3
/usr/lib/language-selector/ls-dbus-backend:#!/usr/bin/python3
/usr/lib/python3/dist-packages/language_support_pkgs.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/softwareproperties/MirrorTest.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/installdriver.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/openprinting.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/xmldriverprefs.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/smburi.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/ppds.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/debug.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/DistUpgrade/dist-upgrade.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/CommandNotFound/db/db.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/Quirks/quirkreader.py:#!/usr/bin/python3
grep: /usr/lib/ssl/private: Permission denied
/usr/lib/system-service/system-service-d:#!/usr/bin/python3
/usr/lib/ubuntu-release-upgrader/check-new-release-gtk:#!/usr/bin/python3
/usr/lib/ubuntu-release-upgrader/do-partial-upgrade:#!/usr/bin/python3
/usr/lib/ubuntu-release-upgrader/check-new-release:#!/usr/bin/python3
/usr/lib/update-notifier/package-data-downloader:#!/usr/bin/python3
/usr/lib/update-notifier/backend_helper.py:#!/usr/bin/python3
/usr/lib/update-notifier/apt_check.py:#!/usr/bin/python3
/usr/lib/update-notifier/apt-check:#!/usr/bin/python3

  • python apt package python-apt/python3-apt是系统软件包,因此它是默认系统python

因此,这些脚本将始终获得当前链接到的版本python3,但是由于apt软件包不存在而失败。


常规解决方案:永远不要更改默认python3链接。曾经 这也适用于python链接-如果应用程序是使用Python2编写的,但其中的某些旧语法元素在Python3中不起作用,则该应用程序将无法工作。

[我的终端打破了这种方式,因为我使用了终结者,终结者显然是用Python2.7编写的,与Python3不兼容。]


这里介绍的解决方案建议复制/链接apt软件包文件或更改python3链接。

让我们分析一下:

  1. 复制/链接apt包

应该不是问题,因为从Python3.4开始,所有python脚本也都可以在较新的版本上运行。

至今。但是,如果您将系统保留足够长的时间,将来可能会中断。

  1. python3回链接

这是一个很好的解决方案,因为我们可以回到“从不更改链接”


“但是我喜欢只打python!” – 我也喜欢这个!这就是我首先解决这个问题的方法!

  1. 通常,应该避免手动更改系统链接-update-alternatives而是使用它来链接不同的版本。这适用于具有多个版本的任何应用。这仍然会破坏那些系统脚本(因为它确实会更改链接),但是您可以轻松地来回切换,而不必担心将链接和目标按正确的顺序放置或输入错误。

  2. 考虑为链接或别名使用python/以外的其他名称python3

  3. 或将自己的python/python3链接添加到PATH(就像虚拟环境一样),而无需更改系统链接。

I see everyone saying how to fix it with strange copying etc, but no one really said why the problem occurs.

So let me explain, for those of you who like me don’t want to mess with system files only because someone on SO told them so.


The problem is that:

  • many system scripts have python3 shebang hardcoded into them. You can check it yourself:
~$ grep -R "\#\!/usr/bin/python3" /usr/lib/*

/usr/lib/cnf-update-db:#!/usr/bin/python3
/usr/lib/command-not-found:#!/usr/bin/python3
/usr/lib/cups/filter/pstotiff:#!/usr/bin/python3
/usr/lib/cups/filter/rastertosag-gdi:#!/usr/bin/python3 -u
grep: /usr/lib/cups/backend/cups-brf: Permission denied
/usr/lib/cups/backend/hpfax:#!/usr/bin/python3
/usr/lib/language-selector/ls-dbus-backend:#!/usr/bin/python3
/usr/lib/python3/dist-packages/language_support_pkgs.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/softwareproperties/MirrorTest.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/installdriver.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/openprinting.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/xmldriverprefs.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/smburi.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/ppds.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/cupshelpers/debug.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/DistUpgrade/dist-upgrade.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/CommandNotFound/db/creator.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/CommandNotFound/db/db.py:#!/usr/bin/python3
/usr/lib/python3/dist-packages/Quirks/quirkreader.py:#!/usr/bin/python3
grep: /usr/lib/ssl/private: Permission denied
/usr/lib/system-service/system-service-d:#!/usr/bin/python3
/usr/lib/ubuntu-release-upgrader/check-new-release-gtk:#!/usr/bin/python3
/usr/lib/ubuntu-release-upgrader/do-partial-upgrade:#!/usr/bin/python3
/usr/lib/ubuntu-release-upgrader/check-new-release:#!/usr/bin/python3
/usr/lib/update-notifier/package-data-downloader:#!/usr/bin/python3
/usr/lib/update-notifier/backend_helper.py:#!/usr/bin/python3
/usr/lib/update-notifier/apt_check.py:#!/usr/bin/python3
/usr/lib/update-notifier/apt-check:#!/usr/bin/python3

  • python apt package python-apt/python3-apt is a system package, so it’s for default system python

Thus, the scripts will always get the version currently linked to python3, but fail because the apt package is not present.


General solution: NEVER change default python3 link. Ever. This also applies to python link – if an app was written in Python2 with some old syntax elements that don’t work in Python3, the app will not work.

[My terminal broke that way because I use Terminator, which is apparently written in Python2.7 not compatible with Python3.]


Solutions presented here either suggest copying/linking the apt package files or changing python3 link.

Let’s analyse both:

  1. Copying/linking the apt package

This shouldn’t be a problem because from around Python3.4 all python scripts work on newer versions as well.

So far. But it may break in the future – if you keep your system long enough.

  1. Changing python3 link back

This is a great solution because we can get back to “never ever changing the link”


“But I like having to type just python!” – I like it too! That’s how I got to this problem in the first place!

  1. In general, you should avoid manually changing system links – use update-alternatives instead to link different versions. This applies to any app with many versions. This will still break those system scripts (because it does change the link), but you can switch back and forth easily, without worrying whether you put link and dest in the right order or made a typo.

  2. Consider using other name than python/python3 for your link or alias.

  3. Or add your own python/python3 link to PATH (just like virtual environments do), without changing system links.


回答 14

Windows 10 WSL v1(Ubuntu 16.04.6 LTS)

这个reddit答案(稍加修改对我有用

sudo ln -sfn /usr/lib/python3/dist-packages/apt_pkg.cpython-35m-x86_64-linux-gnu.so apt_pkg.so

Windows 10 WSL v1 (Ubuntu 16.04.6 LTS)

This reddit answer (slightly modified worked for me)

sudo ln -sfn /usr/lib/python3/dist-packages/apt_pkg.cpython-35m-x86_64-linux-gnu.so apt_pkg.so


回答 15

请查看以下文档。肯定会解决问题。 http://www.programmersought.com/article/55001874709/

Please review the following documentation. It will definitely solve the problem. http://www.programmersought.com/article/55001874709/


回答 16

没有一个答案对我有用(我正在使用Ubuntu 16.04和Python 3.6)。因此,我终于解决了以下问题:

1-连接到服务器的FTP

2-转到文件夹“ / usr / lib / python3 / dist-packages /”

3-复制文件“ apt_pkg.cpython-3 5 m-x86_64-linux-gnu.so”

4-将此重复文件重命名为“ apt_pkg.cpython-3 6 m-x86_64-linux-gnu.so”

而已!

None of the answers worked for me (I am using Ubuntu 16.04 and Python 3.6). So I finally solved the issue as following:

1- connect to the FTP of the server

2- go to the folder “/usr/lib/python3/dist-packages/”

3- duplicate the file “apt_pkg.cpython-35m-x86_64-linux-gnu.so”

4- rename this duplicated file to “apt_pkg.cpython-36m-x86_64-linux-gnu.so”

That’s it!


回答 17

我在Ubuntu 16.04上,并已升级到Python 3.7。这是我尝试添加PPA时遇到的错误

    sudo add-apt-repository ppa:ubuntu-toolchain-r/test                                           
Traceback (most recent call last):
  File "/usr/bin/add-apt-repository", line 11, in <module>
    from softwareproperties.SoftwareProperties import SoftwareProperties, shortcut_handler
  File "/usr/lib/python3/dist-packages/softwareproperties/SoftwareProperties.py", line 27, in <module>
    import apt_pkg
ModuleNotFoundError: No module named 'apt_pkg'

我可以通过创建以下符号链接来与我的初始python 3.4 apt_pkg.cpython-34m-x86_64-linux-gnu.so建立符号链接来解决此错误

sudo ln -s apt_pkg.cpython-34m-x86_64-linux-gnu.so apt_pkg.so

I’m on Ubuntu 16.04, and upgraded to Python 3.7. Here is the error that I had when trying to add a PPA

    sudo add-apt-repository ppa:ubuntu-toolchain-r/test                                           
Traceback (most recent call last):
  File "/usr/bin/add-apt-repository", line 11, in <module>
    from softwareproperties.SoftwareProperties import SoftwareProperties, shortcut_handler
  File "/usr/lib/python3/dist-packages/softwareproperties/SoftwareProperties.py", line 27, in <module>
    import apt_pkg
ModuleNotFoundError: No module named 'apt_pkg'

I was able to fix this error by making symbolic link with my initial python 3.4 apt_pkg.cpython-34m-x86_64-linux-gnu.so by creating the following symbolic link

sudo ln -s apt_pkg.cpython-34m-x86_64-linux-gnu.so apt_pkg.so

回答 18

请尝试通过设置区域设置变量来解决此问题:

export LC_ALL="en_US.UTF-8"

export LC_CTYPE="en_US.UTF-8"

Please try to fix this by setting the locale variables:

export LC_ALL="en_US.UTF-8"

export LC_CTYPE="en_US.UTF-8"

回答 19

以防万一,这终于解决了这个问题,这显然是python版本冲突所致,方法是重定向链接python3,然后将其重定向到正确的python版本:

sudo rm /usr/bin/python3
sudo ln -s /usr/bin/python3.4

您可能需要输入正确的python版本,找到以下版本:

python3 -V

Just in case it helps another, I finally solved this problem, that was apparently caused by python version conflicts, by redirecting the link python3, then redirecting it to the right python version:

sudo rm /usr/bin/python3
sudo ln -s /usr/bin/python3.4

You may need to enter the correct python version, found with:

python3 -V

为什么打印到标准输出这么慢?可以加快速度吗?

问题:为什么打印到标准输出这么慢?可以加快速度吗?

我一直对使用print语句简单地输出到终端需要多长时间感到惊讶/沮丧。在经历了最近令人痛苦的缓慢日志记录之后,我决定进行调查,并惊讶地发现几乎所有的时间都在等待终端处理结果。

可以以某种方式加快对stdout的写入速度吗?

我编写了一个脚本(print_timer.py此问题底部的’ ‘)来比较将100k行写入stdout,文件以及将stdout重定向到时的时序/dev/null。计时结果如下:

$ python print_timer.py
this is a test
this is a test
<snipped 99997 lines>
this is a test
-----
timing summary (100k lines each)
-----
print                         :11.950 s
write to file (+ fsync)       : 0.122 s
print with stdout = /dev/null : 0.050 s

哇。为了确保python在幕后不做任何事情,例如认识到我将stdout重新分配给/ dev / null之类的东西,我在脚本之外进行了重定向…

$ python print_timer.py > /dev/null
-----
timing summary (100k lines each)
-----
print                         : 0.053 s
write to file (+fsync)        : 0.108 s
print with stdout = /dev/null : 0.045 s

因此,这不是python技巧,而仅仅是终端。我一直都知道将输出转储到/ dev / null会加快速度,但是从来没有想到它是如此重要!

令我惊讶的是tty这么慢。写入物理磁盘比写入“屏幕”(大概是全RAM操作)要快得多,并且实际上与使用/ dev / null转储到垃圾中一样快?

此链接讨论了终端如何阻止I / O,以便它可以“解析[输入],更新其帧缓冲区,与X服务器通信以滚动窗口等等” ……但是我不知道完全了解它。可能要花这么长时间?

我期望没有出路(缺少更快的tty实现?),但是无论如何我都会问。


更新:阅读了一些评论后,我想知道屏幕尺寸实际上对打印时间有多大影响,这确实有一定意义。上面最慢的数字是我的Gnome终端被炸毁为1920×1200。如果我减小很小,我得到…

-----
timing summary (100k lines each)
-----
print                         : 2.920 s
write to file (+fsync)        : 0.121 s
print with stdout = /dev/null : 0.048 s

那当然更好(〜4倍),但不会改变我的问题。这只会增加我的问题,因为我不明白为什么终端屏幕渲染会减慢应用程序向stdout的写入速度。为什么我的程序需要等待屏幕渲染继续?

是否所有创建的终端/ tty应用程序都不相等?我还没有实验。在我看来,终端确实应该能够缓冲所有传入的数据,不可见地进行解析/渲染,并且仅以合理的帧速率渲染在当前屏幕配置中可见的最新块。因此,如果我可以在约0.1秒内将+ fsync写入磁盘,则终端应该能够以该顺序完成相同的操作(在执行此操作时可能需要进行一些屏幕更新)。

我仍然希望可以从应用程序端更改tty设置,以使程序员更好地实现此行为。如果严格来说这是终端应用程序问题,那么这可能甚至不属于StackOverflow吗?

我想念什么?


这是用于生成计时的python程序:

import time, sys, tty
import os

lineCount = 100000
line = "this is a test"
summary = ""

cmd = "print"
startTime_s = time.time()
for x in range(lineCount):
    print line
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

#Add a newline to match line outputs above...
line += "\n"

cmd = "write to file (+fsync)"
fp = file("out.txt", "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
os.fsync(fp.fileno())
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

cmd = "print with stdout = /dev/null"
sys.stdout = file(os.devnull, "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

print >> sys.stderr, "-----"
print >> sys.stderr, "timing summary (100k lines each)"
print >> sys.stderr, "-----"
print >> sys.stderr, summary

I’ve always been amazed/frustrated with how long it takes to simply output to the terminal with a print statement. After some recent painfully slow logging I decided to look into it and was quite surprised to find that almost all the time spent is waiting for the terminal to process the results.

Can writing to stdout be sped up somehow?

I wrote a script (‘print_timer.py‘ at the bottom of this question) to compare timing when writing 100k lines to stdout, to file, and with stdout redirected to /dev/null. Here is the timing result:

$ python print_timer.py
this is a test
this is a test
<snipped 99997 lines>
this is a test
-----
timing summary (100k lines each)
-----
print                         :11.950 s
write to file (+ fsync)       : 0.122 s
print with stdout = /dev/null : 0.050 s

Wow. To make sure python isn’t doing something behind the scenes like recognizing that I reassigned stdout to /dev/null or something, I did the redirection outside the script…

$ python print_timer.py > /dev/null
-----
timing summary (100k lines each)
-----
print                         : 0.053 s
write to file (+fsync)        : 0.108 s
print with stdout = /dev/null : 0.045 s

So it isn’t a python trick, it is just the terminal. I always knew dumping output to /dev/null sped things up, but never figured it was that significant!

It amazes me how slow the tty is. How can it be that writing to physical disk is WAY faster than writing to the “screen” (presumably an all-RAM op), and is effectively as fast as simply dumping to the garbage with /dev/null?

This link talks about how the terminal will block I/O so it can “parse [the input], update its frame buffer, communicate with the X server in order to scroll the window and so on”… but I don’t fully get it. What can be taking so long?

I expect there is no way out (short of a faster tty implementation?) but figure I’d ask anyway.


UPDATE: after reading some comments I wondered how much impact my screen size actually has on the print time, and it does have some significance. The really slow numbers above are with my Gnome terminal blown up to 1920×1200. If I reduce it very small I get…

-----
timing summary (100k lines each)
-----
print                         : 2.920 s
write to file (+fsync)        : 0.121 s
print with stdout = /dev/null : 0.048 s

That is certainly better (~4x), but doesn’t change my question. It only adds to my question as I don’t understand why the terminal screen rendering should slow down an application writing to stdout. Why does my program need to wait for screen rendering to continue?

Are all terminal/tty apps not created equal? I have yet to experiment. It really seems to me like a terminal should be able to buffer all incoming data, parse/render it invisibly, and only render the most recent chunk that is visible in the current screen configuration at a sensible frame rate. So if I can write+fsync to disk in ~0.1 seconds, a terminal should be able to complete the same operation in something of that order (with maybe a few screen updates while it did it).

I’m still kind of hoping there is a tty setting that can be changed from the application side to make this behaviour better for programmer. If this is strictly a terminal application issue, then this maybe doesn’t even belong on StackOverflow?

What am I missing?


Here is the python program used to generate the timing:

import time, sys, tty
import os

lineCount = 100000
line = "this is a test"
summary = ""

cmd = "print"
startTime_s = time.time()
for x in range(lineCount):
    print line
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

#Add a newline to match line outputs above...
line += "\n"

cmd = "write to file (+fsync)"
fp = file("out.txt", "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
os.fsync(fp.fileno())
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

cmd = "print with stdout = /dev/null"
sys.stdout = file(os.devnull, "w")
startTime_s = time.time()
for x in range(lineCount):
    fp.write(line)
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)

print >> sys.stderr, "-----"
print >> sys.stderr, "timing summary (100k lines each)"
print >> sys.stderr, "-----"
print >> sys.stderr, summary

回答 0

写入物理磁盘比写入“屏幕”(大概是全RAM操作)要快得多,并且实际上与使用/ dev / null转储到垃圾中一样快?

恭喜,您刚刚发现了I / O缓冲的重要性。:-)

磁盘似乎速度更快,因为它具有很高的缓冲能力:write()在将任何内容实际写入物理磁盘之前,所有Python的调用都将返回。(操作系统稍后执行此操作,将成千上万的单个写入合并为一个大而有效的块。)

另一方面,终端几乎不执行缓冲或不进行缓冲:每个人print/ write(line)等待完整的写入(即显示到输出设备)完成。

为了使比较合理,必须使文件测试使用与终端相同的输出缓冲,可以通过将示例修改为以下操作来做到这一点:

fp = file("out.txt", "w", 1)   # line-buffered, like stdout
[...]
for x in range(lineCount):
    fp.write(line)
    os.fsync(fp.fileno())      # wait for the write to actually complete

我在我的机器上运行了文件写入测试,并通过缓冲在100,000行中也进行了0.05s的测试。

但是,通过上述修改以无缓冲方式写入数据,只需要40秒就可以将1,000行写入磁盘。我放弃了等待100,000行的写操作,但是从以前的内容推论得出,这将花费一个多小时

这使航站楼的11秒成为现实,不是吗?

因此,要回答您最初的问题,考虑到所有因素,实际上写信到终端的速度非常快,并且没有太多的空间可以使它更快(但是各个终端的工作量有所不同;请参阅Russ对此的评论)回答)。

(您可以像使用磁盘I / O一样添加更多的写缓冲,但是直到刷新缓冲区之后,您才能看到向终端写入的内容。这是一个折衷方案:交互性与大容量效率。)

How can it be that writing to physical disk is WAY faster than writing to the “screen” (presumably an all-RAM op), and is effectively as fast as simply dumping to the garbage with /dev/null?

Congratulations, you have just discovered the importance of I/O buffering. :-)

The disk appears to be faster, because it is highly buffered: all Python’s write() calls are returning before anything is actually written to physical disk. (The OS does this later, combining many thousands of individual writes into a big, efficient chunks.)

The terminal, on the other hand, does little or no buffering: each individual print / write(line) waits for the full write (i.e. display to output device) to complete.

To make the comparison fair, you must make the file test use the same output buffering as the terminal, which you can do by modifying your example to:

fp = file("out.txt", "w", 1)   # line-buffered, like stdout
[...]
for x in range(lineCount):
    fp.write(line)
    os.fsync(fp.fileno())      # wait for the write to actually complete

I ran your file writing test on my machine, and with buffering, it also 0.05s here for 100,000 lines.

However, with the above modifications to write unbuffered, it takes 40 seconds to write only 1,000 lines to disk. I gave up waiting for 100,000 lines to write, but extrapolating from the previous, it would take over an hour.

That puts the terminal’s 11 seconds into perspective, doesn’t it?

So to answer your original question, writing to a terminal is actually blazingly fast, all things considered, and there’s not a lot of room to make it much faster (but individual terminals do vary in how much work they do; see Russ’s comment to this answer).

(You could add more write buffering, like with disk I/O, but then you wouldn’t see what was written to your terminal until after the buffer gets flushed. It’s a trade-off: interactivity versus bulk efficiency.)


回答 1

感谢所有的评论!我最终在您的帮助下自行回答。不过,回答您自己的问题感觉很脏。

问题1:为什么打印到标准输出速度慢?

答:打印到标准输出并不是天生就慢。您正在使用的终端很慢。它与应用程序端的I / O缓冲(例如python文件缓冲)几乎为零。见下文。

问题2:可以加快速度吗?

答:是的,可以,但是似乎不是从程序方面(将“打印”到stdout的那一侧)进行。为了加快速度,请使用更快的其他终端仿真器。

说明…

我尝试了一个自描述为“轻量级”的终端程序,wterm并获得了明显更好的结果。下面是在wterm同一系统上以1920×1200 运行时,我的测试脚本的输出(位于问题的底部),该系统使用gnome-terminal的基本打印选项花费了12s:

-----
时序摘要(每条10万行)
-----
打印:0.261 s
写入文件(+ fsync):0.110 s
用stdout = / dev / null打印:0.050 s

0.26s比12s好得多!我不知道是否wterm更聪明地按照我的建议进行渲染(以合理的帧频渲染“可见”尾巴),或者是否“做得比”少gnome-terminal。为了我的问题,我得到了答案。 gnome-terminal是慢的。

所以-如果您运行的脚本长时间运行,感觉很慢,并且会向stdout喷出大量文本,请尝试其他终端,看看它是否更好!

请注意,我几乎是wterm从ubuntu / debian存储库中随机提取的。 该链接可能是同一终端,但是我不确定。我没有测试任何其他终端模拟器。


更新:因为必须要抓痒,所以我用相同的脚本和全屏(1920×1200)测试了一堆其他终端模拟器。我的手动收集的统计信息在这里:

wterm 0.3秒
间隔0.3秒
接收0.3秒
mrxvt 0.4s
konsole 0.6秒
药师0.7s
接线柱7s
xterm 9s
gnome终端12s
xfce4端子12s
巴拉终端18s
xvt 48s

记录的时间是手动收集的,但是它们是相当一致的。我记录了最好的(ish)值。YMMV,显然。

另外,它是对其中可用的各种终端仿真器的一次有趣的浏览!我很惊讶我的第一个“替代”测试竟然是同类中最好的。

Thanks for all the comments! I’ve ended up answering it myself with your help. It feels dirty answering your own question, though.

Question 1: Why is printing to stdout slow?

Answer: Printing to stdout is not inherently slow. It is the terminal you work with that is slow. And it has pretty much zero to do with I/O buffering on the application side (eg: python file buffering). See below.

Question 2: Can it be sped up?

Answer: Yes it can, but seemingly not from the program side (the side doing the ‘printing’ to stdout). To speed it up, use a faster different terminal emulator.

Explanation…

I tried a self-described ‘lightweight’ terminal program called wterm and got significantly better results. Below is the output of my test script (at the bottom of the question) when running in wterm at 1920×1200 in on the same system where the basic print option took 12s using gnome-terminal:

-----
timing summary (100k lines each)
-----
print                         : 0.261 s
write to file (+fsync)        : 0.110 s
print with stdout = /dev/null : 0.050 s

0.26s is MUCH better than 12s! I don’t know whether wterm is more intelligent about how it renders to screen along the lines of how I was suggesting (render the ‘visible’ tail at a reasonable frame rate), or whether it just “does less” than gnome-terminal. For the purposes of my question I’ve got the answer, though. gnome-terminal is slow.

So – If you have a long running script that you feel is slow and it spews massive amounts of text to stdout… try a different terminal and see if it is any better!

Note that I pretty much randomly pulled wterm from the ubuntu/debian repositories. This link might be the same terminal, but I’m not sure. I did not test any other terminal emulators.


Update: Because I had to scratch the itch, I tested a whole pile of other terminal emulators with the same script and full screen (1920×1200). My manually collected stats are here:

wterm           0.3s
aterm           0.3s
rxvt            0.3s
mrxvt           0.4s
konsole         0.6s
yakuake         0.7s
lxterminal        7s
xterm             9s
gnome-terminal   12s
xfce4-terminal   12s
vala-terminal    18s
xvt              48s

The recorded times are manually collected, but they were pretty consistent. I recorded the best(ish) value. YMMV, obviously.

As a bonus, it was an interesting tour of some of the various terminal emulators available out there! I’m amazed my first ‘alternate’ test turned out to be the best of the bunch.


回答 2

重定向可能什么也不做,因为程序可以确定其输出FD是否指向tty。

指向终端时,stdout可能是行缓冲的(与C的stdout流行为相同)。

作为一项有趣的实验,请尝试将输出传递到cat


我已经尝试了自己有趣的实验,这是结果。

$ python test.py 2>foo
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 6.040 s
write to file                 : 0.122 s
print with stdout = /dev/null : 0.121 s

$ python test.py 2>foo |cat
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 1.024 s
write to file                 : 0.131 s
print with stdout = /dev/null : 0.122 s

Your redirection probably does nothing as programs can determine whether their output FD points to a tty.

It’s likely that stdout is line buffered when pointing to a terminal (the same as C’s stdout stream behaviour).

As an amusing experiment, try piping the output to cat.


I’ve tried my own amusing experiment, and here are the results.

$ python test.py 2>foo
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 6.040 s
write to file                 : 0.122 s
print with stdout = /dev/null : 0.121 s

$ python test.py 2>foo |cat
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 1.024 s
write to file                 : 0.131 s
print with stdout = /dev/null : 0.122 s

回答 3

我无法谈论技术细节,因为我不知道这些细节,但这并不令我感到惊讶:该终端并非为打印此类数据而设计的。的确,您甚至提供了指向您每次打印某些内容时必须要做的GUI负载的链接!请注意,如果pythonw改为使用调用脚本,则不会花费15秒。这完全是一个GUI问题。重定向stdout到文件以避免这种情况:

import contextlib, io
@contextlib.contextmanager
def redirect_stdout(stream):
    import sys
    sys.stdout = stream
    yield
    sys.stdout = sys.__stdout__

output = io.StringIO
with redirect_stdout(output):
    ...

I can’t talk about the technical details because I don’t know them, but this doesn’t surprise me: the terminal was not designed for printing lots of data like this. Indeed, you even provide a link to a load of GUI stuff that it has to do every time you want to print something! Notice that if you call the script with pythonw instead, it does not take 15 seconds; this is entirely a GUI issue. Redirect stdout to a file to avoid this:

import contextlib, io
@contextlib.contextmanager
def redirect_stdout(stream):
    import sys
    sys.stdout = stream
    yield
    sys.stdout = sys.__stdout__

output = io.StringIO
with redirect_stdout(output):
    ...

回答 4

打印到终端将很慢。不幸的是,如果没有编写新的终端实现,我真的看不到您如何显着加快这一步。

Printing to the terminal is going to be slow. Unfortunately short of writing a new terminal implementation I can’t really see how you’d speed this up significantly.


回答 5

除了输出可能默认为行缓冲模式外,输出到终端还导致您的数据以最大的吞吐量流入终端和串行线,或者是伪终端和单独的处理显示的进程事件循环,从某种字体渲染字符,移动显示位以实现滚动显示。后一种情况可能分布在多个进程(例如telnet服务器/客户端,终端应用程序,X11显示服务器)上,因此也存在上下文切换和延迟问题。

In addition to the output probably defaulting to a line-buffered mode, output to a terminal is also causing your data to flow into a terminal and serial line with a maximum throughput, or a pseudo-terminal and a separate process that is handling a display event loop, rendering characters from some font, moving display bits to implement a scrolling display. The latter scenario is probably spread over multiple processes (e.g. telnet server/client, terminal app, X11 display server) so there are context switching and latency issues too.


在Linux中安装Pillow(Python模块)期间失败

问题:在Linux中安装Pillow(Python模块)期间失败

我正在尝试使用pip安装Pillow(Python模块),但是会引发以下错误:

ValueError: jpeg is required unless explicitly disabled using --disable-jpeg, aborting

因此,正如错误所述,我尝试了:

pip install pillow --global-option="--disable-jpeg"

但是它失败了:

error: option --disable-jpeg not recognized

有什么提示如何处理吗?

I’m trying to install Pillow (Python module) using pip, but it throws this error:

ValueError: jpeg is required unless explicitly disabled using --disable-jpeg, aborting

So as the error says, I tried:

pip install pillow --global-option="--disable-jpeg"

But it fails with:

error: option --disable-jpeg not recognized

Any hints how to deal with it?


回答 0

有报道枕头的错误在这里,这表明libjpegzlib现在需要的枕头3.0.0。

Linux上Pillow 的安装说明提供了有关如何安装这些软件包的建议。请注意,并非以下所有软件包都可能在您的计算机上丢失(注释表明libjpeg8-dev实际上仅缺少这些软件包)。

点/ PyPi(枕头> 3.4.2)

最新版本枕头的可PyPI上的轮子 – Python的新标准包装机制。这些预构建的软件包包括所有必要的二进制依赖关系,以允许Pillow运行,如果要使用PyPi安装Pillow,则应使用这些预构建包。

要使用轮子,您需要具有的版本pip>=1.4。如果您使用的是早期版本(pip --version),请使用以下方法升级pip:

pip install --upgrade pip 

一旦pip升级,pip install将在默认情况下,如果他们都可以使用特定于平台的轮文件。使用以下命令将Pillow升级到PyPi上可用的最新版本:

pip install --upgrade pillow

Ubuntu 12.04 LTS或Raspian Wheezy 7.0

sudo apt-get install libtiff4-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev python-tk

Ubuntu 14.04

sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk

Ubuntu 18.04

sudo apt install libjpeg8-dev zlib1g-dev

软呢帽20

的Fedora 20当量的libjpeg8-devlibjpeg-devel

sudo yum install libtiff-devel libjpeg-devel libzip-devel freetype-devel lcms2-devel libwebp-devel tcl-devel tk-devel

Mac OS X(通过Homebrew)

在带有Homebrew的 Mac OS X上,可以使用以下方法解决此问题:

brew install libjpeg zlib

您可能还需要使用以下命令强制链接zlib:

brew link zlib --force

20194月更新:在Mojave中,以上操作不起作用,您需要运行此错误报告(取自Pillow上的此错误报告)

sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /

2016年7月更新:zlib主存储库中不再有可用的公式(Homebrew将提示您安装lzlib哪个是其他库,将无法解决此问题)。

还有就是在可用公式受骗者库。您可以点击此存储库,然后按常规安装:

brew tap homebrew/dupes
brew install zlib

或者,您也可以改为zlib通过安装xcode,如下所示:

xcode-select --install

感谢凤凰城,Panos Angelopoulou,nelsonvarela,benjaminz和Kal在评论中

这些安装后,枕头的点子安装应该可以正常工作。

There is a bug reported for Pillow here, which indicates that libjpeg and zlib are now required as of Pillow 3.0.0.

The installation instructions for Pillow on Linux give advice of how to install these packages. Note that not all of the following packages may be missing on your machine (comments suggest that only libjpeg8-dev is actually missing).

pip / PyPi (Pillow>3.4.2)

The latest releases of Pillow are available on PyPi as wheels — the new standard packaging mechanism for Python. These prebuilt packages include all neccessary binary dependencies to allow Pillow to run and should be used if you want to install Pillow using PyPi

To use wheels, you need to have a version of pip>=1.4. If you are using an earlier version (pip --version) upgrade pip using the following:

pip install --upgrade pip 

Once pip is upgraded, pip install will use platform-specific wheel files by default if they are available. Use the following command to upgrade Pillow to the latest version available on PyPi:

pip install --upgrade pillow

Ubuntu 12.04 LTS or Raspian Wheezy 7.0

sudo apt-get install libtiff4-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev python-tk

Ubuntu 14.04

sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk

Ubuntu 18.04

sudo apt install libjpeg8-dev zlib1g-dev

Fedora 20

The Fedora 20 equivalent of libjpeg8-dev is libjpeg-devel.

sudo yum install libtiff-devel libjpeg-devel libzip-devel freetype-devel lcms2-devel libwebp-devel tcl-devel tk-devel

Mac OS X (via Homebrew)

On Mac OS X with Homebrew this can be fixed using:

brew install libjpeg zlib

You may also need to force-link zlib using the following:

brew link zlib --force

Update April 2019: In Mojave the above will not work and you need to run the following as taken from this bug report on Pillow

sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /

Update July 2016: There is no longer a formula for zlib available in the main repository (Homebrew will prompt you to install lzlib which is a different library and will not solve this problem).

There is a formula available in the dupes repository. You can either tap this repository, and install as normal:

brew tap homebrew/dupes
brew install zlib

Or you can install zlib via xcode instead, as follows:

xcode-select --install

Thanks to phoenix, Panos Angelopoulou, nelsonvarela, benjaminz and Kal in the comments

After these are installed the pip installation of Pillow should work normally.


回答 1

在Raspberry pi II上,我遇到了同样的问题。尝试以下方法后,我解决了问题。解决方案是:

sudo apt-get update
sudo apt-get install libjpeg-dev

On Raspberry pi II, I had the same problem. After trying the following, I solved the problem. The solution is:

sudo apt-get update
sudo apt-get install libjpeg-dev

回答 2

谢谢@mfitzp。就我而言(CentOS),这些库在yum存储库中不可用,但实际上解决方案甚至更容易。我做了什么:

sudo yum install python-devel
sudo yum install zlib-devel
sudo yum install libjpeg-turbo-devel

至此,枕头的安装成功完成。

Thank you @mfitzp. In my case (CentOS) these libs are not available in the yum repo, but actually the solution was even easier. What I did:

sudo yum install python-devel
sudo yum install zlib-devel
sudo yum install libjpeg-turbo-devel

And now pillow’s installation finishes successfully.


回答 3

最快的解决方法是提高点子。确实为我工作:

pip install --upgrade pip

The quickest fix is upgrate the pip. Did worked for me:

pip install --upgrade pip

回答 4

这对我有用。

   `sudo apt-get install libjpeg-dev`

This worked for me.

   `sudo apt-get install libjpeg-dev`

回答 5

brew install zlib

在OS X上不再工作,而是提示安装lzlib。安装没有帮助。

相反,您需要安装XCode命令行工具,并且应该安装 zlib

xcode-select --install
brew install zlib

on OS X doesn’t work anymore and instead prompts to install lzlib. Installing that doesn’t help.

Instead you install XCode Command line tools and that should install zlib

xcode-select --install

回答 6

这对我来说解决了jpeg和zlib错误:

C:\Windows\system32>pip3 install pillow --global-option="build_e
xt" --global-option="--disable-zlib" --global-option="--disable-jpeg"

This worked for me to solve jpeg and zlib error :

C:\Windows\system32>pip3 install pillow --global-option="build_e
xt" --global-option="--disable-zlib" --global-option="--disable-jpeg"

回答 7

ValueError: zlib is required unless explicitly disabled using --disable-zlib将点子从7.x升级到8.y可以解决问题。

所以我会先尝试更新工具。

可以使用以下方法完成:

pip install --upgrade pip

I had the ValueError: zlib is required unless explicitly disabled using --disable-zlib but upgrading pip from 7.x to 8.y resolved the problem.

So I would try to update tools before anything else.

That can be done using:

pip install --upgrade pip

回答 8

如果您不想安装libjpeg,也可以选择:

CFLAGS="--disable-jpeg" pip install pillow

来自https://pillow.readthedocs.io/zh/3.0.0/installation.html#external-libraries

The alternative, if you don’t want to install libjpeg:

CFLAGS="--disable-jpeg" pip install pillow

From https://pillow.readthedocs.io/en/3.0.0/installation.html#external-libraries


回答 9

尝试

pip install pillow

如果不起作用,请尝试清除

cache by pip install --upgrade pip

然后再次运行

pip install pillow

Try

pip install pillow

If it doesn’t work, try clearing the

cache by pip install --upgrade pip

Then again run

pip install pillow

回答 10

在debian / ubuntu上,您只需要:libjpeg62-turbo-dev

所以一个简单sudo apt install libjpeg62-turbo-dev 而又pip install pillow

On debian / ubuntu you only need: libjpeg62-turbo-dev

So a simple sudo apt install libjpeg62-turbo-dev and a pip install pillow


为什么要使用Python的os模块方法而不是直接执行shell命令?

问题:为什么要使用Python的os模块方法而不是直接执行shell命令?

我试图了解使用Python的库函数执行特定于操作系统的任务(例如创建文件/目录,更改文件属性等)的动机是什么,而不是仅通过os.system()or 来执行这些命令subprocess.call()

例如,为什么我要使用os.chmod而不是做os.system("chmod...")

我知道,尽可能多地使用Python的可用库方法,而不是直接执行Shell命令,更像是“ Pythonic”。但是,从功能角度来看,这样做还有其他动机吗?

我只在这里谈论执行简单的单行shell命令。当我们需要对任务的执行进行更多控制时,我知道subprocess例如使用模块更有意义。

I am trying to understand what is the motivation behind using Python’s library functions for executing OS-specific tasks such as creating files/directories, changing file attributes, etc. instead of just executing those commands via os.system() or subprocess.call()?

For example, why would I want to use os.chmod instead of doing os.system("chmod...")?

I understand that it is more “pythonic” to use Python’s available library methods as much as possible instead of just executing shell commands directly. But, is there any other motivation behind doing this from a functionality point of view?

I am only talking about executing simple one-line shell commands here. When we need more control over the execution of the task, I understand that using subprocess module makes more sense, for example.


回答 0

  1. 速度更快os.systemsubprocess.call创建了新的流程,而这对于这种简单的操作是不必要的。事实上,os.systemsubprocess.callshell参数通常至少创建两个新的流程:第一个是罩,而第二个是命令,你正在运行(如果它不是内置像贝壳test)。

  2. 有些命令在单独的过程没有用。例如,如果运行os.spawn("cd dir/"),它将更改子进程的当前工作目录,但不会更改Python进程的当前工作目录。您需要使用os.chdir它。

  3. 您不必担心shell 解释的特殊字符os.chmod(path, mode)不管文件名是什么都可以使用,而os.spawn("chmod 777 " + path)如果文件名是则将失败; rm -rf ~。(请注意,如果subprocess.call不带shell参数使用,可以解决此问题。)

  4. 您不必担心以破折号开头的文件名os.chmod("--quiet", mode)将更改名为的文件的权限--quiet,但os.spawn("chmod 777 --quiet")会失败,因为--quiet会解释为参数。即使这样,也是如此subprocess.call(["chmod", "777", "--quiet"])

  5. 您可以减少跨平台和跨外壳的问题,因为Python的标准库应该可以为您解决这些问题。您的系统有chmod命令吗?安装好了吗?它支持您期望它支持的参数吗?该os模块将尝试尽可能地跨平台,并在不可能的情况下进行记录。

  6. 如果您正在运行的命令具有您所关心的输出,则需要对其进行解析,这比听起来要棘手,因为您可能会忘记了极端情况(其中包含空格,制表符和换行符的文件名),即使您不在乎可移植性。

  1. It’s faster, os.system and subprocess.call create new processes which is unnecessary for something this simple. In fact, os.system and subprocess.call with the shell argument usually create at least two new processes: the first one being the shell, and the second one being the command that you’re running (if it’s not a shell built-in like test).

  2. Some commands are useless in a separate process. For example, if you run os.spawn("cd dir/"), it will change the current working directory of the child process, but not of the Python process. You need to use os.chdir for that.

  3. You don’t have to worry about special characters interpreted by the shell. os.chmod(path, mode) will work no matter what the filename is, whereas os.spawn("chmod 777 " + path) will fail horribly if the filename is something like ; rm -rf ~. (Note that you can work around this if you use subprocess.call without the shell argument.)

  4. You don’t have to worry about filenames that begin with a dash. os.chmod("--quiet", mode) will change the permissions of the file named --quiet, but os.spawn("chmod 777 --quiet") will fail, as --quiet is interpreted as an argument. This is true even for subprocess.call(["chmod", "777", "--quiet"]).

  5. You have fewer cross-platform and cross-shell concerns, as Python’s standard library is supposed to deal with that for you. Does your system have chmod command? Is it installed? Does it support the parameters that you expect it to support? The os module will try to be as cross-platform as possible and documents when that it’s not possible.

  6. If the command you’re running has output that you care about, you need to parse it, which is trickier than it sounds, as you may forget about corner-cases (filenames with spaces, tabs and newlines in them), even when you don’t care about portability.


回答 1

更安全。这里给你一个想法是一个示例脚本

import os
file = raw_input("Please enter a file: ")
os.system("chmod 777 " + file)

如果来自用户的输入是test; rm -rf ~,则将删除主目录。

这就是为什么使用内置函数更安全的原因。

因此,为什么还要使用子流程而不是系统。

It is safer. To give you an idea here is an example script

import os
file = raw_input("Please enter a file: ")
os.system("chmod 777 " + file)

If the input from the user was test; rm -rf ~ this would then delete the home directory.

This is why it is safer to use the built in function.

Hence why you should use subprocess instead of system too.


回答 2

在执行命令时,有四种很强的情况os比起使用os.systemsubprocess模块,更喜欢在模块中使用Python更具体的方法:

  • 冗余 -产生另一个进程是多余的,浪费时间和资源。
  • 可移植性os模块中的许多方法可在多个平台上使用,而许多shell命令是特定于OS的。
  • 了解结果 -生成执行任意命令的进程会迫使您从输出中解析结果,并了解命令是否以及为什么做错了什么。
  • 安全 -进程可以执行它给出的任何命令。这是一个较弱的设计,可以通过使用os模块中的特定方法来避免。

冗余(请参阅冗余代码):

实际上,您在执行最终系统调用的过程chmod中正在执行一个冗余的“中间人”(在您的示例中)。这个中间人是一个新的进程或子外壳。

来自os.system

在子shell中执行命令(字符串)…

并且subprocess仅仅是产生新流程的模块。

您可以执行所需的操作而无需产生这些过程。

可移植性(请参阅源代码可移植性):

os模块的目的是提供通用的操作系统服务,其描述始于:

该模块提供了使用依赖于操作系统的功能的便携式方法。

您可以os.listdir在Windows和Unix上使用。尝试将os.system/ subprocess用于此功能将迫使您维护两个调用(ls/ dir),并检查您所使用的操作系统。这不是便携式的,以后引起更大的挫败感(请参阅处理输出)。

了解命令的结果:

假设您要列出目录中的文件。

如果使用os.system("ls")/ subprocess.call(['ls']),则只能返回该进程的输出,这基本上是一个带有文件名的大字符串。

如何从两个文件中分辨出文件名中带有空格的文件?

如果您无权列出文件怎么办?

您应该如何将数据映射到python对象?

这些只是我的头上问题,尽管有解决这些问题的方法-为什么要再次解决为您解决的问题?

这是通过重复已经存在且可供您免费使用的实现来遵循“ 不要重复自己”原理(通常称为“ DRY”)的示例。

安全:

os.system并且subprocess功能强大。当您需要这种功能时,这很好,但是当您不需要这种功能时,这是危险的。使用时os.listdir,您知道它只能执行其他操作,然后列出文件或引发错误。当您使用os.systemsubprocess实现相同的行为时,您可能最终会做一些原本不想做的事情。

注射安全性(请参见外壳注射示例

如果将来自用户的输入用作新命令,则基本上已经给了他一个外壳。这就像SQL注入为用户在DB中提供外壳程序一样。

一个示例将是以下形式的命令:

# ... read some user input
os.system(user_input + " some continutation")

这可以很容易利用来运行任何使用输入任意代码:NASTY COMMAND;#创建最终的:

os.system("NASTY COMMAND; # some continuation")

有许多这样的命令会使您的系统处于危险之中。

There are four strong cases for preferring Python’s more-specific methods in the os module over using os.system or the subprocess module when executing a command:

  • Redundancy – spawning another process is redundant and wastes time and resources.
  • Portability – Many of the methods in the os module are available in multiple platforms while many shell commands are os-specific.
  • Understanding the results – Spawning a process to execute arbitrary commands forces you to parse the results from the output and understand if and why a command has done something wrong.
  • Safety – A process can potentially execute any command it’s given. This is a weak design and it can be avoided by using specific methods in the os module.

Redundancy (see redundant code):

You’re actually executing a redundant “middle-man” on your way to the eventual system calls (chmod in your example). This middle man is a new process or sub-shell.

From os.system:

Execute the command (a string) in a subshell …

And subprocess is just a module to spawn new processes.

You can do what you need without spawning these processes.

Portability (see source code portability):

The os module’s aim is to provide generic operating-system services and it’s description starts with:

This module provides a portable way of using operating system dependent functionality.

You can use os.listdir on both windows and unix. Trying to use os.system / subprocess for this functionality will force you to maintain two calls (for ls / dir) and check what operating system you’re on. This is not as portable and will cause even more frustration later on (see Handling Output).

Understanding the command’s results:

Suppose you want to list the files in a directory.

If you’re using os.system("ls") / subprocess.call(['ls']), you can only get the process’s output back, which is basically a big string with the file names.

How can you tell a file with a space in it’s name from two files?

What if you have no permission to list the files?

How should you map the data to python objects?

These are only off the top of my head, and while there are solutions to these problems – why solve again a problem that was solved for you?

This is an example of following the Don’t Repeat Yourself principle (Often reffered to as “DRY”) by not repeating an implementation that already exists and is freely available for you.

Safety:

os.system and subprocess are powerful. It’s good when you need this power, but it’s dangerous when you don’t. When you use os.listdir, you know it can not do anything else other then list files or raise an error. When you use os.system or subprocess to achieve the same behaviour you can potentially end up doing something you did not mean to do.

Injection Safety (see shell injection examples):

If you use input from the user as a new command you’ve basically given him a shell. This is much like SQL injection providing a shell in the DB for the user.

An example would be a command of the form:

# ... read some user input
os.system(user_input + " some continutation")

This can be easily exploited to run any arbitrary code using the input: NASTY COMMAND;# to create the eventual:

os.system("NASTY COMMAND; # some continuation")

There are many such commands that can put your system at risk.


回答 3

出于简单的原因-当您调用shell函数时,它将创建一个子shell,该子shell在命令存在后会被破坏,因此,如果您在shell中更改目录,则不会影响您在Python中的环境。

此外,创建子外壳非常耗时,因此直接使用OS命令将影响您的性能。

编辑

我正在运行一些计时测试:

In [379]: %timeit os.chmod('Documents/recipes.txt', 0755)
10000 loops, best of 3: 215 us per loop

In [380]: %timeit os.system('chmod 0755 Documents/recipes.txt')
100 loops, best of 3: 2.47 ms per loop

In [382]: %timeit call(['chmod', '0755', 'Documents/recipes.txt'])
100 loops, best of 3: 2.93 ms per loop

内部功能运行速度提高10倍以上

编辑2

在某些情况下,调用外部可执行文件可能比Python软件包产生更好的结果-我刚刚记得我的一位同事发送的一封邮件,其中说通过子进程调用的gzip的性能比他使用的Python软件包的性能高得多。但是当我们谈论模拟标准OS命令的标准OS软件包时肯定不会

For a simple reason – when you call a shell function, it creates a sub-shell which is destroyed after your command exists, so if you change directory in a shell – it does not affect your environment in Python.

Besides, creating sub-shell is time consuming, so using OS commands directly will impact your performance

EDIT

I had some timing tests running:

In [379]: %timeit os.chmod('Documents/recipes.txt', 0755)
10000 loops, best of 3: 215 us per loop

In [380]: %timeit os.system('chmod 0755 Documents/recipes.txt')
100 loops, best of 3: 2.47 ms per loop

In [382]: %timeit call(['chmod', '0755', 'Documents/recipes.txt'])
100 loops, best of 3: 2.93 ms per loop

Internal function runs more than 10 time faster

EDIT2

There may be cases when invoking external executable may yield better results than Python packages – I just remembered a mail sent by a colleague of mine that performance of gzip called through subprocess was much higher than the performance of a Python package he used. But certainly not when we are talking about standard OS packages emulating standard OS commands


回答 4

Shell调用是特定于OS的,而在大多数情况下不是Python os模块的功能。并且避免产生子流程。

Shell call are OS specific whereas Python os module functions are not, in most of the case. And it avoid spawning a subprocess.


回答 5

效率更高。“ shell”只是另一个OS二进制文件,其中包含许多系统调用。为什么只为单个系统调用而产生创建整个Shell进程的开销?

当您使用os.system的不是内置shell 时,情况甚至更糟。您启动一个Shell进程,然后启动一个可执行文件,然后该可执行文件(两个进程分开)进行系统调用。至少subprocess可以消除对shell中介过程的需求。

这不是特定于Python的。systemd出于相同的原因,它大大缩短了Linux启动时间:它使必要的系统调用本身而不是产生一千个shell。

It’s far more efficient. The “shell” is just another OS binary which contains a lot of system calls. Why incur the overhead of creating the whole shell process just for that single system call?

The situation is even worse when you use os.system for something that’s not a shell built-in. You start a shell process which in turn starts an executable which then (two processes away) makes the system call. At least subprocess would have removed the need for a shell intermediary process.

It’s not specific to Python, this. systemd is such an improvement to Linux startup times for the same reason: it makes the necessary system calls itself instead of spawning a thousand shells.


如何检查Python中的操作系统?

问题:如何检查Python中的操作系统?

我想检查操作系统(在运行脚本的计算机上)。

我知道我可以os.system('uname -o')在Linux 中使用,但是它在控制台中给了我一条消息,并且我想写一个变量。

如果脚本可以告诉您它是Mac,Windows还是Linux,那就可以了。我该如何检查?

I want to check the operating system (on the computer where the script runs).

I know I can use os.system('uname -o') in Linux, but it gives me a message in the console, and I want to write to a variable.

It will be okay if the script can tell if it is Mac, Windows or Linux. How can I check it?


回答 0

您可以使用sys.platform

from sys import platform
if platform == "linux" or platform == "linux2":
    # linux
elif platform == "darwin":
    # OS X
elif platform == "win32":
    # Windows...

sys.platform具有比更好的粒度sys.name

有关有效值,请参阅文档

另请参见“我正在运行什么操作系统?”的答案

You can use sys.platform:

from sys import platform
if platform == "linux" or platform == "linux2":
    # linux
elif platform == "darwin":
    # OS X
elif platform == "win32":
    # Windows...

sys.platform has finer granularity than sys.name.

For the valid values, consult the documentation.

See also the answer to “What OS am I running on?”


回答 1

如果您想更精确地了解使用“ Linux”,“ Windows”或“ Darwin”(Mac)的平台,则应使用:

>>> import platform
>>> platform.system()
'Linux'  # or 'Windows'/'Darwin'

platform.system函数在uname内部使用。

If you want to know on which platform you are on out of “Linux”, “Windows”, or “Darwin” (Mac), without more precision, you should use:

>>> import platform
>>> platform.system()
'Linux'  # or 'Windows'/'Darwin'

The platform.system function uses uname internally.


回答 2

通过检查,您可以大致了解所使用的操作系统sys.platform

获得这些信息后,您可以使用它来确定调用类似的东西os.uname()是否适合收集更具体的信息。您也可以在类似Unix的操作系统上使用Python系统信息,或者在Windows 上使用pywin32

如果您想进行更深入的检查而又不想关心操作系统,那么也可以使用psutil

You can get a pretty coarse idea of the OS you’re using by checking sys.platform.

Once you have that information you can use it to determine if calling something like os.uname() is appropriate to gather more specific information. You could also use something like Python System Information on unix-like OSes, or pywin32 for Windows.

There’s also psutil if you want to do more in-depth inspection without wanting to care about the OS.


回答 3

platform模块中提供了更多详细信息。

More detailed information are available in the platform module.


回答 4

您可以使用sys.platform


在Chrome中运行Selenium WebDriver python绑定

问题:在Chrome中运行Selenium WebDriver python绑定

使用Selenium时遇到问题。对于我的项目,我必须使用Chrome。但是,用Selenium启动该浏览器后,我无法连接到该浏览器。

由于某些原因,Selenium本身无法找到Chrome。当我尝试启动Chrome而没有添加路径时,会发生以下情况:

Traceback (most recent call last):
  File "./obp_pb_get_csv.py", line 73, in <module>
    browser = webdriver.Chrome() # Get local session of chrome
  File "/usr/lib64/python2.7/site-packages/selenium/webdriver/chrome/webdriver.py", line 46, in __init__
    self.service.start()
  File "/usr/lib64/python2.7/site-packages/selenium/webdriver/chrome/service.py", line 58, in start
    and read up at http://code.google.com/p/selenium/wiki/ChromeDriver")
selenium.common.exceptions.WebDriverException: Message: 'ChromeDriver executable needs to be available in the path.                 Please download from http://code.google.com/p/selenium/downloads/list                and read up at http://code.google.com/p/selenium/wiki/ChromeDriver'

为了解决此问题,我随后在启动Chrome的代码中包含了Chromium路径。但是,解释器无法找到要连接的套接字:

Traceback (most recent call last):
  File "./obp_pb_get_csv.py", line 73, in <module>
    browser = webdriver.Chrome('/usr/bin/chromium') # Get local session of chrome
  File "/usr/lib64/python2.7/site-packages/selenium/webdriver/chrome/webdriver.py", line 46, in __init__
    self.service.start()
  File "/usr/lib64/python2.7/site-packages/selenium/webdriver/chrome/service.py", line 64, in start
    raise WebDriverException("Can not connect to the ChromeDriver")
selenium.common.exceptions.WebDriverException: Message: 'Can not connect to the ChromeDriver'

我还尝试通过以下方式启动chrome解决问题:

铬--remote-shell-port = 9222

但是,这也不起作用。

PS。以下是有关我的系统的一些信息:

www-client:铬15.0.874.121  
dev-lang:python 2.7.2-r3 Selenium 2.11.1  
操作系统:GNU / Linux Gentoo Kernel 3.1.0-gentoo-r1

I ran into a problem while working with Selenium. For my project, I have to use Chrome. However, I can’t connect to that browser after launching it with Selenium.

For some reason, Selenium can’t find Chrome by itself. This is what happens when I try to launch Chrome without including a path:

Traceback (most recent call last):
  File "./obp_pb_get_csv.py", line 73, in <module>
    browser = webdriver.Chrome() # Get local session of chrome
  File "/usr/lib64/python2.7/site-packages/selenium/webdriver/chrome/webdriver.py", line 46, in __init__
    self.service.start()
  File "/usr/lib64/python2.7/site-packages/selenium/webdriver/chrome/service.py", line 58, in start
    and read up at http://code.google.com/p/selenium/wiki/ChromeDriver")
selenium.common.exceptions.WebDriverException: Message: 'ChromeDriver executable needs to be available in the path.                 Please download from http://code.google.com/p/selenium/downloads/list                and read up at http://code.google.com/p/selenium/wiki/ChromeDriver'

To solve this problem, I then included the Chromium path in the code that launches Chrome. However, the interpreter fails to find a socket to connect to:

Traceback (most recent call last):
  File "./obp_pb_get_csv.py", line 73, in <module>
    browser = webdriver.Chrome('/usr/bin/chromium') # Get local session of chrome
  File "/usr/lib64/python2.7/site-packages/selenium/webdriver/chrome/webdriver.py", line 46, in __init__
    self.service.start()
  File "/usr/lib64/python2.7/site-packages/selenium/webdriver/chrome/service.py", line 64, in start
    raise WebDriverException("Can not connect to the ChromeDriver")
selenium.common.exceptions.WebDriverException: Message: 'Can not connect to the ChromeDriver'

I also tried solving the problem by launching chrome with:

chromium --remote-shell-port=9222

However, this did not work either.

PS. Here’s some information about my system:

www-client: chromium 15.0.874.121  
dev-lang:   python 2.7.2-r3 Selenium 2.11.1  
OS:         GNU/Linux Gentoo Kernel 3.1.0-gentoo-r1

回答 0

您需要确保独立的ChromeDriver二进制文件(与Chrome浏览器二进制文件不同)位于您的路径中或在webdriver.chrome.driver环境变量中可用。

有关如何进行整理的完整信息,请参见http://code.google.com/p/selenium/wiki/ChromeDriver

编辑:

是的,似乎是从路径环境变量读取chromedriver二进制文件的Python绑定中的错误。似乎chromedriver不在您的路径中,您必须将其作为参数传递给构造函数。

import os
from selenium import webdriver

chromedriver = "/Users/adam/Downloads/chromedriver"
os.environ["webdriver.chrome.driver"] = chromedriver
driver = webdriver.Chrome(chromedriver)
driver.get("http://stackoverflow.com")
driver.quit()

You need to make sure the standalone ChromeDriver binary (which is different than the Chrome browser binary) is either in your path or available in the webdriver.chrome.driver environment variable.

see http://code.google.com/p/selenium/wiki/ChromeDriver for full information on how wire things up.

Edit:

Right, seems to be a bug in the Python bindings wrt reading the chromedriver binary from the path or the environment variable. Seems if chromedriver is not in your path you have to pass it in as an argument to the constructor.

import os
from selenium import webdriver

chromedriver = "/Users/adam/Downloads/chromedriver"
os.environ["webdriver.chrome.driver"] = chromedriver
driver = webdriver.Chrome(chromedriver)
driver.get("http://stackoverflow.com")
driver.quit()

回答 1

对于Linux

  1. 检查您是否安装了最新版本的Chrome浏览器-> chromium-browser -version
  2. 如果没有,请安装最新版本的chrome sudo apt-get install chromium-browser
  3. 此处获取适当版本的chrome驱动程序
  4. 解压缩chromedriver.zip
  5. 将文件移到/usr/bin目录sudo mv chromedriver /usr/bin
  6. 转到/usr/bin目录cd /usr/bin
  7. 现在,您需要运行类似sudo chmod a+x chromedriver将其标记为可执行文件的操作。
  8. 最后,您可以执行代码。

    from selenium import webdriver
    
    driver = webdriver.Chrome()
    driver.get("http://www.google.com")
    print driver.page_source.encode('utf-8')
    driver.quit()
    display.stop()

For Linux

  1. Check you have installed latest version of chrome brwoser-> chromium-browser -version
  2. If not, install latest version of chrome sudo apt-get install chromium-browser
  3. get appropriate version of chrome driver from here
  4. Unzip the chromedriver.zip
  5. Move the file to /usr/bin directory sudo mv chromedriver /usr/bin
  6. Goto /usr/bin directory cd /usr/bin
  7. Now, you would need to run something like sudo chmod a+x chromedriver to mark it executable.
  8. finally you can execute the code.

    from selenium import webdriver
    
    driver = webdriver.Chrome()
    driver.get("http://www.google.com")
    print driver.page_source.encode('utf-8')
    driver.quit()
    display.stop()
    

回答 2

仅Mac OSX

进行以下操作的更简单方法(假设您已经安装了自制软件,如果没有,应该先这样做,然后让自制软件使您的生活变得更好),只需运行以下命令:

brew install chromedriver

那应该将chromedriver放在您的路径中,并且您已经准备就绪。

Mac OSX only

An easier way to get going (assuming you already have homebrew installed, which you should, if not, go do that first and let homebrew make your life better) is to just run the following command:

brew install chromedriver

That should put the chromedriver in your path and you should be all set.


回答 3

对于窗户

从此直接链接 下载ChromeDriver 从此页面获取最新版本

将该chromedriver.exe文件粘贴到C:\Python27\Scripts文件夹中。

现在应该可以使用:

from selenium import webdriver
driver = webdriver.Chrome()

For windows

Download ChromeDriver from this direct link OR get the latest version from this page.

Paste the chromedriver.exe file in your C:\Python27\Scripts folder.

This should work now:

from selenium import webdriver
driver = webdriver.Chrome()

回答 4

对于窗户,请chromedriver.exe放在下面<Install Dir>/Python27/Scripts/

For windows, please have the chromedriver.exe placed under <Install Dir>/Python27/Scripts/


回答 5

有两种方法可以在Google Chrome浏览器中运行Selenium python测试。我正在考虑Windows(以Windows 10为例):

先决条件:从以下网址下载最新的Chrome驱动程序:https : //sites.google.com/a/chromium.org/chromedriver/downloads

方法1:

i)将下载的zip文件解压缩到您选择的目录/位置中
ii)如下所示在代码中设置可执行路径:

self.driver = webdriver.Chrome(executable_path='D:\Selenium_RiponAlWasim\Drivers\chromedriver_win32\chromedriver.exe')

方式2:

i)只需将chromedriver.exe粘贴在/ Python / Scripts /下(在我的情况下,文件夹为:C:\ Python36 \ Scripts)
ii)现在编写如下的简单代码:

self.driver = webdriver.Chrome()

There are 2 ways to run Selenium python tests in Google Chrome. I’m considering Windows (Windows 10 in my case):

Prerequisite: Download the latest Chrome Driver from: https://sites.google.com/a/chromium.org/chromedriver/downloads

Way 1:

i) Extract the downloaded zip file in a directory/location of your choice
ii) Set the executable path in your code as below:

self.driver = webdriver.Chrome(executable_path='D:\Selenium_RiponAlWasim\Drivers\chromedriver_win32\chromedriver.exe')

Way 2:

i) Simply paste the chromedriver.exe under /Python/Scripts/ (In my case the folder was: C:\Python36\Scripts)
ii) Now write the simple code as below:

self.driver = webdriver.Chrome()

回答 6

对于Windows的IDE:

如果您的路径不起作用,则可以尝试将其添加chromedriver.exe到您的项目中,就像在此项目结构中一样。

然后,您应该chromedriver.exe在主文件中加载。至于我,我装了driver.exedriver.py

def get_chrome_driver():
return webdriver.Chrome("..\\content\\engine\\chromedriver.exe",
                            chrome_options='--no-startup-window')

..表示driver.py's上层目录

. 表示目录 driver.py位于

希望这会有所帮助。

For Windows’ IDE:

If your path doesn’t work, you can try to add the chromedriver.exe to your project, like in this project structure.

Then you should load the chromedriver.exe in your main file. As for me, I loaded the driver.exe in driver.py.

def get_chrome_driver():
return webdriver.Chrome("..\\content\\engine\\chromedriver.exe",
                            chrome_options='--no-startup-window')

.. means driver.py's upper directory

. means the directory where the driver.py is located

Hope this will be helpful.


boto3客户端NoRegionError:仅在某些情况下必须指定区域错误

问题:boto3客户端NoRegionError:仅在某些情况下必须指定区域错误

我有一个boto3客户程序:

boto3.client('kms')

但是它发生在新机器上,它们动态地打开和关闭。

    if endpoint is None:
        if region_name is None:
            # Raise a more specific error message that will give
            # better guidance to the user what needs to happen.
            raise NoRegionError()

为什么会这样呢?为什么只有部分时间呢?

I have a boto3 client :

boto3.client('kms')

But it happens on new machines, They open and close dynamically.

    if endpoint is None:
        if region_name is None:
            # Raise a more specific error message that will give
            # better guidance to the user what needs to happen.
            raise NoRegionError()

Why is this happening? and why only part of the time?


回答 0

您必须以一种或另一种方式告诉boto3您希望在哪个区域kms创建客户端。可以使用region_name参数明确地完成此操作,如下所示:

kms = boto3.client('kms', region_name='us-west-2')

或者,您可以在~/.aws/config文件中拥有一个与个人资料相关联的默认区域,如下所示:

[default]
region=us-west-2

或者您可以使用如下环境变量:

export AWS_DEFAULT_REGION=us-west-2

但您确实需要告诉boto3使用哪个区域。

One way or another you must tell boto3 in which region you wish the kms client to be created. This could be done explicitly using the region_name parameter as in:

kms = boto3.client('kms', region_name='us-west-2')

or you can have a default region associated with your profile in your ~/.aws/config file as in:

[default]
region=us-west-2

or you can use an environment variable as in:

export AWS_DEFAULT_REGION=us-west-2

but you do need to tell boto3 which region to use.


回答 1

os.environ['AWS_DEFAULT_REGION'] = 'your_region_name'

就我而言,敏感性很重要。

os.environ['AWS_DEFAULT_REGION'] = 'your_region_name'

In my case sensitivity mattered.


回答 2

我相信默认情况下,boto会选择aws cli中设置的区域。您可以运行#aws configure命令,然后按Enter键(它显示您在aws cli中使用区域设置的凭据)两次以确认您的区域。

I believe, by default, boto picks the region which is set in aws cli. You can run command #aws configure and press enter (it shows what creds you have set in aws cli with region)twice to confirm your region.


回答 3

您还可以在脚本本身中设置环境变量,而不是传递region_name参数

os.environ['AWS_DEFAULT_REGION'] = 'your_region_name'

区分大小写可能很重要。

you can also set environment variables in the script itself, rather than passing region_name parameter

os.environ['AWS_DEFAULT_REGION'] = 'your_region_name'

case sensitivity may matter.


回答 4

对于Python 2,我发现,~/.aws/config如果在默认的其他配置文件中定义了区域,则boto3库不会从中获取区域。因此,您必须在会话创建中对其进行定义。

session = boto3.Session(
    profile_name='NotDefault',
    region_name='ap-southeast-2'
)

print(session.available_profiles)

client = session.client(
    'ec2'
)

我的~/.aws/config文件如下所示:

[default]
region=ap-southeast-2

[NotDefault]
region=ap-southeast-2

之所以这样做,是因为我将不同的配置文件用于对AWS,Personal和Work的不同登录。

For Python 2 I have found that the boto3 library does not source the region from the ~/.aws/config if the region is defined in a different profile to default. So you have to define it in the session creation.

session = boto3.Session(
    profile_name='NotDefault',
    region_name='ap-southeast-2'
)

print(session.available_profiles)

client = session.client(
    'ec2'
)

Where my ~/.aws/config file looks like this:

[default]
region=ap-southeast-2

[NotDefault]
region=ap-southeast-2

I do this because I use different profiles for different logins to AWS, Personal and Work.


回答 5

对于那些使用CloudFormation模板的人。您可以AWS_DEFAULT_REGION使用UserData和设置环境变量AWS::Region。例如,

MyInstance1:
    Type: AWS::EC2::Instance                
    Properties:                           
        ImageId: ami-04b9e92b5572fa0d1 #ubuntu
        InstanceType: t2.micro
        UserData: 
            Fn::Base64: !Sub |
                    #!/bin/bash -x

                    echo "export AWS_DEFAULT_REGION=${AWS::Region}" >> /etc/profile

For those using CloudFormation template. You can set AWS_DEFAULT_REGION environment variable using UserData and AWS::Region. For example,

MyInstance1:
    Type: AWS::EC2::Instance                
    Properties:                           
        ImageId: ami-04b9e92b5572fa0d1 #ubuntu
        InstanceType: t2.micro
        UserData: 
            Fn::Base64: !Sub |
                    #!/bin/bash -x

                    echo "export AWS_DEFAULT_REGION=${AWS::Region}" >> /etc/profile