标签归档:Python

Python3:ImportError:使用模块多处理中的值时,没有名为“ _ctypes”的模块

问题:Python3:ImportError:使用模块多处理中的值时,没有名为“ _ctypes”的模块

我正在使用Ubuntu,并已安装Python 2.7.5和3.4.0。在Python 2.7.5中,我能够成功分配变量x = Value('i', 2),但在3.4.0中却不能。我正进入(状态:

Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/usr/local/lib/python3.4/multiprocessing/context.py", line 132, in Value
      from .sharedctypes import Value
   File "/usr/local/lib/python3.4/multiprocessing/sharedctypes.py", line 10, in <
module>
   import ctypes
   File "/usr/local/lib/python3.4/ctypes/__init__.py", line 7, in <module>
      from _ctypes import Union, Structure, Array
ImportError: No module named '_ctypes'

我刚刚通过安装3.4.0的源代码更新到3.3.2。它安装在/usr/local/lib/python3.4中

我是否正确更新到Python 3.4?

我注意到一件事,Python 3.4安装在usr / local / lib中,而Python 3.3.2仍然安装在usr / lib中,因此它没有被覆盖。

I am using Ubuntu and have installed Python 2.7.5 and 3.4.0. In Python 2.7.5 I am able to successfully assign a variable x = Value('i', 2), but not in 3.4.0. I am getting:

Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/usr/local/lib/python3.4/multiprocessing/context.py", line 132, in Value
      from .sharedctypes import Value
   File "/usr/local/lib/python3.4/multiprocessing/sharedctypes.py", line 10, in <
module>
   import ctypes
   File "/usr/local/lib/python3.4/ctypes/__init__.py", line 7, in <module>
      from _ctypes import Union, Structure, Array
ImportError: No module named '_ctypes'

I just updated to 3.3.2 through installing the source of 3.4.0. It installed in /usr/local/lib/python3.4.

Did I update to Python 3.4 correctly?

One thing I noticed that Python 3.4 is installed in usr/local/lib, while Python 3.3.2 is still installed in usr/lib, so it was not overwritten.


回答 0

安装libffi-dev并重新安装python3.7对我来说解决了这个问题。

干净地构建py 3.7 libffi-dev 是必需的,否则以后的工作将失败

如果使用RHEL / Fedora:

yum install libffi-devel

要么

sudo dnf install libffi-devel

如果使用Debian / Ubuntu:

sudo apt-get install libffi-dev

Installing libffi-dev and re-installing python3.7 fixed the problem for me.

to cleanly build py 3.7 libffi-dev is required or else later stuff will fail

If using RHEL/Fedora:

yum install libffi-devel

or

sudo dnf install libffi-devel

If using Debian/Ubuntu:

sudo apt-get install libffi-dev

回答 1

在新的Debian映像上,克隆https://github.com/python/cpython并运行:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade
sudo apt-get install build-essential python-dev python-setuptools python-pip python-smbus
sudo apt-get install libncursesw5-dev libgdbm-dev libc6-dev
sudo apt-get install zlib1g-dev libsqlite3-dev tk-dev
sudo apt-get install libssl-dev openssl
sudo apt-get install libffi-dev

现在执行configure上面克隆的文件:

./configure
make # alternatively `make -j 4` will utilize 4 threads
sudo make altinstall

安装了3.7版并为我工作。

轻微更新

看来我说过我会用一些更多的解释来更新此答案,两年后,我没有太多补充。

  • 这篇SO帖子解释了为什么python-dev可能需要某些库。
  • 这篇SO文章解释了为什么可能在make命令中使用与altinstall相反的install参数。

除此之外,我猜测选择是通读cpython代码库以查找#include需要满足的指令,但是我通常要做的是继续尝试安装软件包,并继续通读安装所需软件包的输出,直到找到为止。成功。

让我想起了工程师,经理和程序员的故事,他们的汽车从山上滚下来

On a fresh Debian image, cloning https://github.com/python/cpython and running:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade
sudo apt-get install build-essential python-dev python-setuptools python-pip python-smbus
sudo apt-get install libncursesw5-dev libgdbm-dev libc6-dev
sudo apt-get install zlib1g-dev libsqlite3-dev tk-dev
sudo apt-get install libssl-dev openssl
sudo apt-get install libffi-dev

Now execute the configure file cloned above:

./configure
make # alternatively `make -j 4` will utilize 4 threads
sudo make altinstall

Got 3.7 installed and working for me.

SLIGHT UPDATE

Looks like I said I would update this answer with some more explanation and two years later I don’t have much to add.

  • this SO post explains why certain libraries like python-dev might be necessary.
  • this SO post explains why one might use the altinstall as opposed to install argument in the make command.

Aside from that I guess the choice would be to either read through the cpython codebase looking for #include directives that need to be met, but what I usually do is keep trying to install the package and just keep reading through the output installing the required packages until it succeeds.

Reminds me of the story of the Engineer, the Manager and the Programmer whose car rolls down a hill.


回答 2

如果您使用pyenv并在Debian / Raspbian / Ubuntu上收到错误“没有名为’_ctypes’的模块”(例如我是),则需要运行以下命令:

sudo apt-get install libffi-dev
pyenv uninstall 3.7.6
pyenv install 3.7.6

将您的python版本而不是3.7.6

If you use pyenv and get error “No module named ‘_ctypes'” (like i am) on Debian/Raspbian/Ubuntu you need to run this commands:

sudo apt-get install libffi-dev
pyenv uninstall 3.7.6
pyenv install 3.7.6

Put your version of python instead of 3.7.6


回答 3

在CentOS或任何Redhat Linux机器上安装Python 3.7的详细步骤:

  1. https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz下载Python
  2. 将内容提取到新文件夹中
  3. 在同一目录中打开终端
  4. 逐步运行以下代码:
sudo yum -y install gcc gcc-c++ 
sudo yum -y install zlib zlib-devel
sudo yum -y install libffi-devel 
./configure
make
make install

Detailed steps to install Python 3.7 in CentOS or any redhat linux machine:

  1. Download Python from https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xz
  2. Extract the content in new folder
  3. Open Terminal in the same directory
  4. Run below code step by step :
sudo yum -y install gcc gcc-c++ 
sudo yum -y install zlib zlib-devel
sudo yum -y install libffi-devel 
./configure
make
make install

回答 4

以为我会添加Centos安装:

sudo yum -y install gcc gcc-c++ 
sudo yum -y install zlib zlib-devel
sudo yum -y install libffi-devel 

检查python版本:

python3 -V

创建virtualenv:

virtualenv -p python3 venv

Thought I’d add the Centos installs:

sudo yum -y install gcc gcc-c++ 
sudo yum -y install zlib zlib-devel
sudo yum -y install libffi-devel 

Check python version:

python3 -V

Create virtualenv:

virtualenv -p python3 venv


回答 5

尝试使用下一个命令在Ubuntu 18.04中安装Python 3.7.3时遇到此错误。运行后安装成功(如建议在这里)。这个问题在那里解决了。$ pyenv install 3.7.3$ sudo apt-get update && sudo apt-get install libffi-dev

I run into this error when I tried to install Python 3.7.3 in Ubuntu 18.04 with next command: $ pyenv install 3.7.3. Installation succeeded after running $ sudo apt-get update && sudo apt-get install libffi-dev (as suggested here). The issue was solved there.


回答 6

没有解决方案。您必须再次重新编译python。一旦所有必需的软件包都已完全安装。

请遵循以下步骤:

  1. 安装所需的软件包
  2. ./configure --enable-optimizations

https://gist.github.com/jerblack/798718c1910ccdd4ede92481229043be

None of the solution worked. You have to recompile your python again; once all the required packages were completely installed.

Follow this:

  1. Install required packages
  2. Run ./configure --enable-optimizations

https://gist.github.com/jerblack/798718c1910ccdd4ede92481229043be


回答 7

请参阅此线程,以进行libffi的自定义安装,Python3.7很难找到libffi的库位置。另一种方法是CONFIGURE_LDFLAGS在Makefile中设置变量,例如CONFIGURE_LDFLAGS="-L/path/to/libffi-3.2.1/lib64"

Refer to this thread or this thread, for customized installation of libffi, it is difficult for Python3.7 to find the library location of libffi. An alternative method is to set the CONFIGURE_LDFLAGS variable in the Makefile, for example CONFIGURE_LDFLAGS="-L/path/to/libffi-3.2.1/lib64".


回答 8

我的解决方案:使用apt-get安装libffi-dev并没有帮助。但这有帮助:从源代码安装libffi,然后从源代码安装Python 3.8。

我的配置:Ubuntu 16.04 LTS Python 3.8.2

一步步:

从Visual Studio Code启动调试器并运行时,出现错误消息“ ModuleNotFoundError:没有名为’_ctypes’的模块” python3 -c "import sklearn; sklearn.show_versions()"

  • https://github.com/libffi/libffi/releases下载libffi v3.3
  • 安装libtool:sudo apt-get install libtool libffi中的README.md文件提到autoconf和automake也是必需的。它们已经安装在我的系统上。
  • 在没有文档的情况下配置libffi:

./configure --disable-docs

make check

sudo make install

之后,我的python安装程序可以找到_ctypes。

My solution: Installing libffi-dev with apt-get didn’t help. But this helped: Installing libffi from source and then installing Python 3.8 from source.

My configuration: Ubuntu 16.04 LTS Python 3.8.2

Step by step:

I got the error message “ModuleNotFoundError: No module named ‘_ctypes'” when starting the debugger from Visual Studio Code, and when running python3 -c "import sklearn; sklearn.show_versions()".

  • download libffi v3.3 from https://github.com/libffi/libffi/releases
  • install libtool: sudo apt-get install libtool The file README.md from libffi mentions that autoconf and automake are also necessary. They were already installed on my system.
  • configure libffi without docs:

./configure --disable-docs

make check

sudo make install

After that my python installation could find _ctypes.


回答 9

这为我在Debian解决了相同的错误:

sudo apt-get install libffi-dev

然后再次编译

参考:issue31652

This solved the same error for me on Debian:

sudo apt-get install libffi-dev

and compile again

Reference: issue31652


回答 10

如果您不介意使用Miniconda,则默认情况下会安装必需的外部库和_ctypes。它确实占用更多空间,并且可能需要使用中等版本的Python(例如,本文撰写时为3.7.6而不是3.8.2)。

If you don’t mind using Miniconda, the necessary external libraries and _ctypes are installed by default. It does take more space and may require using a moderately older version of Python (e.g. 3.7.6 instead of 3.8.2 as of this writing).


回答 11

您必须从包管理器中加载缺少的php3(Python3)模块。如果您有Ubuntu,我建议Synaptic Package Manager

sudo apt-get install synaptic

您可以在那里简单地搜索缺少的模块。搜索ctypes并安装所有软件包。然后转到您的Python目录并执行

./configure
make install.

这应该可以解决您的问题。

You have to load the missing php3 (Python3) modules from the package manager. If you have Ubuntu I recommend the Synaptic Package Manager:

sudo apt-get install synaptic

There you can simply search for the missing modules. search for ctypes and install all the packages. Then go to your Python dir and do

./configure
make install.

This should solve your problem.


回答 12

如果您正在做某事,这里没有人会听您说,因为“您做错了方法”,但是由于太精明的原因,您必须“做错了方法”(例如,在我的情况下,它很快会降级为犯规)关于Devops团队超重母亲的某人的话),您需要首先:

获取libffi并将其以常规方式安装到用户安装区域中。

git clone https://github.com/libffi/libffi.git
cd libffi
./configure --prefix=path/to/your/install/root
make
make install

然后返回您的Python 3源代码,并在python源代码目录的顶层setup.py中找到这部分代码。

        ffi_inc = [sysconfig.get_config_var("LIBFFI_INCLUDEDIR")]
        if not ffi_inc or ffi_inc[0] == '':
            ffi_inc = find_file('ffi.h', [], inc_dirs)
        if ffi_inc is not None:
            ffi_h = ffi_inc[0] + '/ffi.h'
            if not os.path.exists(ffi_h):
                ffi_inc = None
                print('Header file {} does not exist'.format(ffi_h))
        ffi_lib = None
        if ffi_inc is not None:
            for lib_name in ('ffi', 'ffi_pic'):
                if (self.compiler.find_library_file(lib_dirs, lib_name)):
                    ffi_lib = lib_name
                    break

        ffi_lib="ffi"  # --- AND INSERT THIS LINE HERE THAT DOES NOT APPEAR ---
        if ffi_inc and ffi_lib:
            ext.include_dirs.extend(ffi_inc)
            ext.libraries.append(ffi_lib)
            self.use_system_libffi = True

并添加我在上面用注释标记的行。为什么有必要,为什么没有办法在Linux平台上配置尊重’–without-system-ffi`的功能,也许我会找出为什么在接下来的几个小时内“不支持”的原因,但是一切都有从那以后一直工作。否则,祝您好运… YMMV。

它的作用:只是重写那里的逻辑,并使编译器链接命令添加“ -lffi”,这是它真正需要的全部。如果您是用户安装的库,则只要您PKG_CONFIG_PATH包含include ,它就可以很好地检测标题path/to/your/install/root/lib/pkgconfig

If you are doing something nobody here will listen you about because “you’re doing it the wrong way”, but you have to do it “the wrong way” for reasons too asinine (for instance, in my case it quickly degrades into foul words about somebody on devops team overweight mother), you need to first:

Get libffi and install it into your user install area the usual way.

git clone https://github.com/libffi/libffi.git
cd libffi
./configure --prefix=path/to/your/install/root
make
make install

Then go back to your Python 3 source and find this part of the code in setup.py at the top level of the python source directory

        ffi_inc = [sysconfig.get_config_var("LIBFFI_INCLUDEDIR")]
        if not ffi_inc or ffi_inc[0] == '':
            ffi_inc = find_file('ffi.h', [], inc_dirs)
        if ffi_inc is not None:
            ffi_h = ffi_inc[0] + '/ffi.h'
            if not os.path.exists(ffi_h):
                ffi_inc = None
                print('Header file {} does not exist'.format(ffi_h))
        ffi_lib = None
        if ffi_inc is not None:
            for lib_name in ('ffi', 'ffi_pic'):
                if (self.compiler.find_library_file(lib_dirs, lib_name)):
                    ffi_lib = lib_name
                    break

        ffi_lib="ffi"  # --- AND INSERT THIS LINE HERE THAT DOES NOT APPEAR ---
        if ffi_inc and ffi_lib:
            ext.include_dirs.extend(ffi_inc)
            ext.libraries.append(ffi_lib)
            self.use_system_libffi = True

and add the line I have marked above with the comment. Why it is necessary, and why there is no way to get configure to respect ‘–without-system-ffi` on Linux platforms, perhaps I will find out why that is “unsupported” in the next couple of hours, but everything has worked ever since. Otherwise, best of luck… YMMV.

WHAT IT DOES: just overrides the logic there and causes the compiler linking command to add “-lffi” which is all that it really needs. If you have the library user-installed, it is probably detecting the headers fine as long as your PKG_CONFIG_PATH includes path/to/your/install/root/lib/pkgconfig.


在namedtuple中输入提示

问题:在namedtuple中输入提示

考虑以下代码:

from collections import namedtuple
point = namedtuple("Point", ("x:int", "y:int"))

上面的代码只是演示我正在尝试实现的方法。我想namedtuple使用类型提示。

您知道如何以一种优雅的方式达到预期效果吗?

Consider following piece of code:

from collections import namedtuple
point = namedtuple("Point", ("x:int", "y:int"))

The Code above is just a way to demonstrate as to what I am trying to achieve. I would like to make namedtuple with type hints.

Do you know any elegant way how to achieve result as intended?


回答 0

从3.6开始,类型为命名元组的首选语法为

from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int = 1  # Set default value

Point(3)  # -> Point(x=3, y=1)

编辑 从Python 3.7开始,请考虑使用dataclasses(您的IDE可能尚不支持它们进行静态类型检查):

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int = 1  # Set default value

Point(3)  # -> Point(x=3, y=1)

The prefered Syntax for a typed named tuple since 3.6 is

from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int = 1  # Set default value

Point(3)  # -> Point(x=3, y=1)

Edit Starting Python 3.7, consider using dataclasses (your IDE may not yet support them for static type checking):

from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int = 1  # Set default value

Point(3)  # -> Point(x=3, y=1)

回答 1

您可以使用 typing.NamedTuple

来自文档

类型版本namedtuple

>>> import typing
>>> Point = typing.NamedTuple("Point", [('x', int), ('y', int)])

仅在Python 3.5及更高版本中存在

You can use typing.NamedTuple

From the docs

Typed version of namedtuple.

>>> import typing
>>> Point = typing.NamedTuple("Point", [('x', int), ('y', int)])

This is present only in Python 3.5 onwards


安装psycopg2时出错,找不到用于-lssl的库

问题:安装psycopg2时出错,找不到用于-lssl的库

我跑

sudo pip install psycopg2

我得到了一堆看起来像这样的输出:

cc -DNDEBUG -g -fwrapv -Os .....
.....
cc -DNDEBUG -g -fwrapv -Os .....
.....

最后,它说:

ld: library not found for -lssl

clang: error: linker command failed with exit code 1 (use -v to see invocation)

error: command 'cc' failed with exit status 1

----------------------------------------
Cleaning up...
Command /usr/bin/python -c "import setuptools, tokenize;__file__='/private/var/folders/bz/pvj1g9xj16d10pjjgbrfl3fw0000gn/T/pip_build_root/psycopg2/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /var/folders/bz/pvj1g9xj16d10pjjgbrfl3fw0000gn/T/pip-uE3thn-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /private/var/folders/bz/pvj1g9xj16d10pjjgbrfl3fw0000gn/T/pip_build_root/psycopg2
Storing debug log for failure in /Users/Tyler/Library/Logs/pip.log

最后,运行easy_install从源代码进行操作都给我相同的错误(关于-lssl找不到关于库的部分)。


运行brew安装(或升级)openssl将产生以下结果

$ brew upgrade openssl
Error: openssl-1.0.1h already installed

谁能帮我吗?

I run

sudo pip install psycopg2

and I get a bunch of output that looks like:

cc -DNDEBUG -g -fwrapv -Os .....
.....
cc -DNDEBUG -g -fwrapv -Os .....
.....

And at the end it says:

ld: library not found for -lssl

clang: error: linker command failed with exit code 1 (use -v to see invocation)

error: command 'cc' failed with exit status 1

----------------------------------------
Cleaning up...
Command /usr/bin/python -c "import setuptools, tokenize;__file__='/private/var/folders/bz/pvj1g9xj16d10pjjgbrfl3fw0000gn/T/pip_build_root/psycopg2/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /var/folders/bz/pvj1g9xj16d10pjjgbrfl3fw0000gn/T/pip-uE3thn-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /private/var/folders/bz/pvj1g9xj16d10pjjgbrfl3fw0000gn/T/pip_build_root/psycopg2
Storing debug log for failure in /Users/Tyler/Library/Logs/pip.log

Running easy_install or doing it from source both give me the same error at the end (the part about library not found for -lssl).


Running brew install (or upgrade) openssl yields the below

$ brew upgrade openssl
Error: openssl-1.0.1h already installed

Can anyone help me out?


回答 0

对于在macOS Sierra 10.12(或更高版本,最有可能)上寻求解决方案的用户:我通过安装命令行工具来解决此问题:

xcode-select --install

在那之后,pip install psycopg2应该工作。

如果没有,您也可以尝试链接到brew的openssl:

env LDFLAGS="-I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib" pip install psycopg2

通过brew安装openssl。请注意,brew link openssl --force不再起作用:

$ brew link openssl --force                                                                                 17.5s
Warning: Refusing to link: openssl
Linking keg-only openssl means you may end up linking against the insecure,
deprecated system OpenSSL while using the headers from Homebrew's openssl.
Instead, pass the full include/library paths to your compiler e.g.:
  -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib

正如@macho在下面指出的,如果这仍然不起作用,则可能需要使用--no-cachepip选项,例如

env LDFLAGS="-I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib" pip --no-cache install psycopg2

For anyone looking for a solution for this on macOS Sierra 10.12 (or later, most likely): I fixed this by installing the command line tools:

xcode-select --install

After that, pip install psycopg2 should work.

If it doesn’t, you could also try to link against brew’s openssl:

env LDFLAGS="-I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib" pip install psycopg2

with openssl installed via brew. Note that the brew link openssl --force does not work anymore:

$ brew link openssl --force                                                                                 17.5s
Warning: Refusing to link: openssl
Linking keg-only openssl means you may end up linking against the insecure,
deprecated system OpenSSL while using the headers from Homebrew's openssl.
Instead, pass the full include/library paths to your compiler e.g.:
  -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib

As @macho points out below if this still does not work, you might need to use the --no-cache option of pip, e.g.

env LDFLAGS="-I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib" pip --no-cache install psycopg2

回答 1

我从brew(brew install openssl)安装了OpenSSL

以下为我工作:

export LDFLAGS="-L/usr/local/opt/openssl/lib"
export CPPFLAGS="-I/usr/local/opt/openssl/include"
pip install psycopg2

I had OpenSSL installed from brew (brew install openssl)

The following worked for me:

export LDFLAGS="-L/usr/local/opt/openssl/lib"
export CPPFLAGS="-I/usr/local/opt/openssl/include"
pip install psycopg2

回答 2

运行时,brew link openssl我收到以下消息:

$ brew link openssl
Warning: Refusing to link: openssl
Linking keg-only openssl means you may end up linking against the insecure,
deprecated system OpenSSL while using the headers from Homebrew's openssl.
Instead, pass the full include/library paths to your compiler e.g.:
  -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib

遵循此建议,这是pip您需要使用的命令:

$ pip install -r requirements.txt --global-option=build_ext --global-option="-I/usr/local/opt/openssl/include" --global-option="-L/usr/local/opt/openssl/lib"

When running brew link openssl I get the following message:

$ brew link openssl
Warning: Refusing to link: openssl
Linking keg-only openssl means you may end up linking against the insecure,
deprecated system OpenSSL while using the headers from Homebrew's openssl.
Instead, pass the full include/library paths to your compiler e.g.:
  -I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib

Following this advice here’s the pip command you need to use:

$ pip install -r requirements.txt --global-option=build_ext --global-option="-I/usr/local/opt/openssl/include" --global-option="-L/usr/local/opt/openssl/lib"

回答 3

对我有用的是命令中提供的链接openssl的提示,

$ brew link openssl
Warning: Refusing to link macOS-provided software: openssl
If you need to have openssl first in your PATH run:
  echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.zshrc

For compilers to find openssl you may need to set:
  export LDFLAGS="-L/usr/local/opt/openssl/lib"
  export CPPFLAGS="-I/usr/local/opt/openssl/include"

$ export LDFLAGS="-L/usr/local/opt/openssl/lib"
$ export CPPFLAGS="-I/usr/local/opt/openssl/include"

$ pip install psycopg2
Collecting psycopg2
  Using cached https://files.pythonhosted.org/packages/23/7e/93c325482c328619870b6cd09370f6dbe1148283daca65115cd63642e60f/psycopg2-2.8.2.tar.gz
Installing collected packages: psycopg2
  Running setup.py install for psycopg2 ... done
Successfully installed psycopg2-2.8.2

What worked for me was the hint provided in the command to link openssl,

$ brew link openssl
Warning: Refusing to link macOS-provided software: openssl
If you need to have openssl first in your PATH run:
  echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.zshrc

For compilers to find openssl you may need to set:
  export LDFLAGS="-L/usr/local/opt/openssl/lib"
  export CPPFLAGS="-I/usr/local/opt/openssl/include"

$ export LDFLAGS="-L/usr/local/opt/openssl/lib"
$ export CPPFLAGS="-I/usr/local/opt/openssl/include"

$ pip install psycopg2
Collecting psycopg2
  Using cached https://files.pythonhosted.org/packages/23/7e/93c325482c328619870b6cd09370f6dbe1148283daca65115cd63642e60f/psycopg2-2.8.2.tar.gz
Installing collected packages: psycopg2
  Running setup.py install for psycopg2 ... done
Successfully installed psycopg2-2.8.2

回答 4

在莫哈韦沙漠,我将它们添加到.bash_profile

export PATH="/usr/local/opt/openssl/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/curl/lib -L/usr/local/opt/openssl/lib"
export CPPFLAGS="-I/usr/local/opt/curl/include -I/user/local/opt/openssl/include"

然后能够在python 3.7.4 virtualenv中安装psycopg 2.8.3。

重新安装xcode和命令行工具后。

以上所有答案都对您有所帮助!

On mojave I added these to the .bash_profile

export PATH="/usr/local/opt/openssl/bin:$PATH"
export LDFLAGS="-L/usr/local/opt/curl/lib -L/usr/local/opt/openssl/lib"
export CPPFLAGS="-I/usr/local/opt/curl/include -I/user/local/opt/openssl/include"

was then able to install psycopg 2.8.3 in a python 3.7.4 virtualenv.

This after reinstalling xcode and the command line tools.

All the answers above helped!


回答 5

使用MacOS Catalina 10.15.4,以下是对我有用的唯一命令:

env LDFLAGS="-I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib" pip install psycopg2

With MacOS Catalina 10.15.4, the following was the only command that worked for me:

env LDFLAGS="-I/usr/local/opt/openssl/include -L/usr/local/opt/openssl/lib" pip install psycopg2

回答 6

这是新的macOs版本的问题,其中pip无法安装cryptography。解决我的问题的是将env提供给install命令:

brew install openssl
env LDFLAGS="-L$(brew --prefix openssl)/lib" CFLAGS="-I$(brew --prefix openssl)/include" <YOUR COMMAND HERE>

您可以<YOUR COMMAND HERE>pip install cryptography或替换pip install <SOMETHING THAT REQUIRES cryptography>

归功于本文:修复macOS Sierra致命错误:找不到“ openssl / opensslv.h”或“ openssl / aes.h”文件

This’s the problem of new macOs version, where pip cannot install cryptography. What fixed my problem is to provide the env to the install command:

brew install openssl
env LDFLAGS="-L$(brew --prefix openssl)/lib" CFLAGS="-I$(brew --prefix openssl)/include" <YOUR COMMAND HERE>

You can replace <YOUR COMMAND HERE> with pip install cryptography, or pip install <SOMETHING THAT REQUIRES cryptography> for example.

Credit to this article: Fixing macOS Sierra fatal error: ‘openssl/opensslv.h’ or ‘openssl/aes.h’ file not found


回答 7

在使用Homebrew安装OpenSSL之后,以下两个命令使用Fish帮我解决了此问题。

set -gx LDFLAGS "-L/usr/local/opt/openssl/lib"
set -gx CPPFLAGS "-I/usr/local/opt/openssl/include"

使用brew info openssl之后,可以获取最新信息。

Using Fish, the following two commands solved this issue for me after installing OpenSSL with Homebrew.

set -gx LDFLAGS "-L/usr/local/opt/openssl/lib"
set -gx CPPFLAGS "-I/usr/local/opt/openssl/include"

Use brew info openssl to get up-to-date info.


回答 8

最近在High Sierra中出现了此问题,刚刚在virtualenv中安装了Python 3.7。

解决方案是使用更高版本的psycopg2。版本2.7.7有效,而版本2.7.1无效。

Recently had this problem in High Sierra, having just installed Python 3.7 in a virtualenv.

The solution is to use a later version of psycopg2. Version 2.7.7 worked, where 2.7.1 did not.


回答 9

而不是同一作者的psycopg2install,install psycopg2-binary

pip install psycopg2-binary

这是文档关于此PyPI软件包的说明:

您可以通过从PyPI安装psycopg2-binary软件包来获取不需要编译器或外部库的独立软件包:

$ pip install psycopg2-binary

二进制软件包是开发和测试的实际选择,但在生产中,建议使用从源构建的软件包。

Instead of installing psycopg2, install psycopg2-binary, from the same authors:

pip install psycopg2-binary

This is what the documentation says about this PyPI package:

You can […] obtain a stand-alone package, not requiring a compiler or external libraries, by installing the psycopg2-binary package from PyPI:

$ pip install psycopg2-binary

The binary package is a practical choice for development and testing but in production it is advised to use the package built from sources.


回答 10

我在莫哈韦沙漠上遇到这个问题。Mojave不会创建psycopg2需要安装的/ usr / include目录。这并不明显。我在这里找到解决方案: 如何从命令行更新Xcode,该命令行引用:https : //forums.developer.apple.com/thread/104296

I was having this issue on Mojave. Mojave does not create a /usr/include directory, which psycopg2 needs to install. This was not obvious. I found the solution here: How to update Xcode from command line, which references: https://forums.developer.apple.com/thread/104296


回答 11

我安装了cython后遇到了同样的错误,并解决了这个问题

I had this same error and got it to resolve after I pip installed cython


回答 12

从conda环境运行PyCharm,使用以下方法解决了我的问题:

--> conda install psycopg2
The following packages will be UPDATED: ...

...
Proceed ([y]/n)? 
--> y
--> pip3 install psycopg2
Installing collected packages: psycopg2
Running setup.py install for psycopg2 ... done
Successfully installed psycopg2-2.8.4

'''

Running PyCharm from conda environment, solved my issue using:

--> conda install psycopg2
The following packages will be UPDATED: ...

...
Proceed ([y]/n)? 
--> y
--> pip3 install psycopg2
Installing collected packages: psycopg2
Running setup.py install for psycopg2 ... done
Successfully installed psycopg2-2.8.4

'''



回答 13

我使用MacPorts安装了OpenSSL,因此目录与Brew不同。

sudo port install openssl

我通过执行以下操作找到了目录:

port contents openssl | grep lib
port contents openssl | grep include

然后我导出变量:

export LDFLAGS="-L/opt/local/lib"
export CPPFLAGS="-I/opt/local/include/openssl"

您可能还必须:

xcode-select --install

I installed OpenSSL using MacPorts therefore directories are not like those of Brew.

sudo port install openssl

I found the directories by doing:

port contents openssl | grep lib
port contents openssl | grep include

Then I exported the variables:

export LDFLAGS="-L/opt/local/lib"
export CPPFLAGS="-I/opt/local/include/openssl"

You might also have to:

xcode-select --install

回答 14

export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/opt/openssl/lib/

为我工作

export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/opt/openssl/lib/

worked for me


回答 15

我设法通过使用以下方法修复了该问题:

brew unlink openssl && brew link openssl --force

我不确定这与之前尝试在OpenSSL上进行的brew卸载/升级有何不同。我的假设是,这些操作留下了一些“错误的”共享库,这些库无法正常工作。请注意,这还解决了安装python加密模块的问题。

I’ve managed to fix it by using:

brew unlink openssl && brew link openssl --force

I am not sure how this differs from the brew uninstall/upgrades that I did on OpenSSL in prior attempts I’ve made. My assumption is that these operations left some of the “faulty” shared libraries which were preventing this from working. Note that this also fixed issues with installing python cryptography module.


Python(和Python C API):__new__与__init__

问题:Python(和Python C API):__new__与__init__

我要问的问题似乎是Python对__new__和__init__的重复使用?,但无论如何,我仍然不清楚__new__和之间的实际区别是什么__init__

在您急于告诉我__new__创建对象和__init__初始化对象之前,请让我明确:我明白了。 实际上,这种区分对我来说是很自然的,因为我在C ++中有经验,在那里我们放置了new,它类似地将对象分配与初始化分开。

Python的C API教程解释它是这样的:

新成员负责创建(而不是初始化)该类型的对象。它在Python中作为__new__()方法公开。… 实施新方法的原因之一是要确保实例变量的初始值

所以,是的-我明白__new__,但是尽管如此,我仍然不明白为什么它在Python中很有用。给出的示例说,__new__如果要“确保实例变量的初始值” ,这可能会很有用。好吧,这不正是要做__init__什么吗?

在C API教程中,显示​​了一个示例,其中创建了新的Type(称为“ Noddy”),并__new__定义了Type的功能。Noddy类型包含一个名为的字符串成员first,并且该字符串成员被初始化为一个空字符串,如下所示:

static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    .....

    self->first = PyString_FromString("");
    if (self->first == NULL)
    {
       Py_DECREF(self);
       return NULL;
    }

    .....
}

请注意,如果没有在此__new__定义的方法,我们将不得不使用PyType_GenericNew,它只会将所有实例变量成员初始化为NULL。因此,该__new__方法的唯一好处是实例变量将从一个空字符串开始,而不是NULL。 但是,为什么这会有用呢,因为如果我们要确保将实例变量初始化为某个默认值,那么我们可以在__init__方法中做到这一点?

The question I’m about to ask seems to be a duplicate of Python’s use of __new__ and __init__?, but regardless, it’s still unclear to me exactly what the practical difference between __new__ and __init__ is.

Before you rush to tell me that __new__ is for creating objects and __init__ is for initializing objects, let me be clear: I get that. In fact, that distinction is quite natural to me, since I have experience in C++ where we have placement new, which similarly separates object allocation from initialization.

The Python C API tutorial explains it like this:

The new member is responsible for creating (as opposed to initializing) objects of the type. It is exposed in Python as the __new__() method. … One reason to implement a new method is to assure the initial values of instance variables.

So, yeah – I get what __new__ does, but despite this, I still don’t understand why it’s useful in Python. The example given says that __new__ might be useful if you want to “assure the initial values of instance variables”. Well, isn’t that exactly what __init__ will do?

In the C API tutorial, an example is shown where a new Type (called a “Noddy”) is created, and the Type’s __new__ function is defined. The Noddy type contains a string member called first, and this string member is initialized to an empty string like so:

static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    .....

    self->first = PyString_FromString("");
    if (self->first == NULL)
    {
       Py_DECREF(self);
       return NULL;
    }

    .....
}

Note that without the __new__ method defined here, we’d have to use PyType_GenericNew, which simply initializes all of the instance variable members to NULL. So the only benefit of the __new__ method is that the instance variable will start out as an empty string, as opposed to NULL. But why is this ever useful, since if we cared about making sure our instance variables are initialized to some default value, we could have just done that in the __init__ method?


回答 0

差异主要发生在可变与不可变类型之间。

__new__接受一个类型作为第一个参数,并且(通常)返回该类型的新实例。因此,它适用于可变类型和不可变类型。

__init__接受一个实例作为第一个参数,并修改该实例的属性。这不适用于不可变类型,因为它允许在创建后通过调用修改它们obj.__init__(*args)

比较的行为tuplelist

>>> x = (1, 2)
>>> x
(1, 2)
>>> x.__init__([3, 4])
>>> x # tuple.__init__ does nothing
(1, 2)
>>> y = [1, 2]
>>> y
[1, 2]
>>> y.__init__([3, 4])
>>> y # list.__init__ reinitialises the object
[3, 4]

关于它们为什么分开的原因(除了简单的历史原因):__new__方法需要一堆样板才能正确(最初的对象创建,然后记得最后返回对象)。__init__相比之下,方法非常简单,因为您只需设置需要设置的任何属性即可。

除了__init__更易于编写的方法以及上面提到的可变与不可变的区别外,还可以利用这种分离,__init__通过在中设置任何绝对必要的实例不变式,使在子类中调用父类成为可选的__new__。不过,这通常是一种可疑的做法-通常在需要时仅调用父类__init__方法会更清晰。

The difference mainly arises with mutable vs immutable types.

__new__ accepts a type as the first argument, and (usually) returns a new instance of that type. Thus it is suitable for use with both mutable and immutable types.

__init__ accepts an instance as the first argument and modifies the attributes of that instance. This is inappropriate for an immutable type, as it would allow them to be modified after creation by calling obj.__init__(*args).

Compare the behaviour of tuple and list:

>>> x = (1, 2)
>>> x
(1, 2)
>>> x.__init__([3, 4])
>>> x # tuple.__init__ does nothing
(1, 2)
>>> y = [1, 2]
>>> y
[1, 2]
>>> y.__init__([3, 4])
>>> y # list.__init__ reinitialises the object
[3, 4]

As to why they’re separate (aside from simple historical reasons): __new__ methods require a bunch of boilerplate to get right (the initial object creation, and then remembering to return the object at the end). __init__ methods, by contrast, are dead simple, since you just set whatever attributes you need to set.

Aside from __init__ methods being easier to write, and the mutable vs immutable distinction noted above, the separation can also be exploited to make calling the parent class __init__ in subclasses optional by setting up any absolutely required instance invariants in __new__. This is generally a dubious practice though – it’s usually clearer to just call the parent class __init__ methods as necessary.


回答 1

可能还有其他用途,__new__但有一个真正显而易见的用途:如果不使用,就不能继承不可变类型__new__。例如,假设您要创建一个元组的子类,该子类只能包含0到之间的整数值size

class ModularTuple(tuple):
    def __new__(cls, tup, size=100):
        tup = (int(x) % size for x in tup)
        return super(ModularTuple, cls).__new__(cls, tup)

你根本无法做到这一点__init__-如果你试图修改self__init__,解释器会抱怨你试图修改不可变对象。

There are probably other uses for __new__ but there’s one really obvious one: You can’t subclass an immutable type without using __new__. So for example, say you wanted to create a subclass of tuple that can contain only integral values between 0 and size.

class ModularTuple(tuple):
    def __new__(cls, tup, size=100):
        tup = (int(x) % size for x in tup)
        return super(ModularTuple, cls).__new__(cls, tup)

You simply can’t do this with __init__ — if you tried to modify self in __init__, the interpreter would complain that you’re trying to modify an immutable object.


回答 2

__new__()可以返回与其绑定的类不同类型的对象。__init__()仅初始化该类的现有实例。

>>> class C(object):
...   def __new__(cls):
...     return 5
...
>>> c = C()
>>> print type(c)
<type 'int'>
>>> print c
5

__new__() can return objects of types other than the class it’s bound to. __init__() only initializes an existing instance of the class.

>>> class C(object):
...   def __new__(cls):
...     return 5
...
>>> c = C()
>>> print type(c)
<type 'int'>
>>> print c
5

回答 3

这不是一个完整的答案,但也许可以说明差异。

__new__当必须创建一个对象时,它将总是被调用。在某些情况下__init__不会被呼叫。一个示例是,当您从pickle文件中解开对象时,它们将被分配(__new__)但未初始化(__init__)。

Not a complete answer but perhaps something that illustrates the difference.

__new__ will always get called when an object has to be created. There are some situations where __init__ will not get called. One example is when you unpickle objects from a pickle file, they will get allocated (__new__) but not initialised (__init__).


回答 4

只是想添加一个关于定义vs 的意图(与行为相反)的词__new____init__

当我试图理解定义类工厂的最佳方法时,我遇到了这个问题。我意识到,在__new__概念上与之不同的一种方式__init__是,这样的好处__new__恰恰是问题中所陈述的事实:

因此__new__方法的唯一好处是实例变量将从一个空字符串开始,而不是NULL。但是为什么这会有用呢,因为如果我们要确保实例变量被初始化为某个默认值,那么我们可以在__init__方法中做到这一点?

考虑到上述情况,当实例实际上是类本身时,我们关心实例变量的初始值。因此,如果我们在运行时动态创建一个类对象,并且需要定义/控制一些有关正在创建的类的后续实例的特殊操作,则可以在__new__元类的方法中定义这些条件/属性。

我一直对此感到困惑,直到我真正考虑到该概念的应用,而不仅仅是其含义。这是一个希望可以使区别清楚的示例:

a = Shape(sides=3, base=2, height=12)
b = Shape(sides=4, length=2)
print(a.area())
print(b.area())

# I want `a` and `b` to be an instances of either of 'Square' or 'Triangle'
# depending on number of sides and also the `.area()` method to do the right
# thing. How do I do that without creating a Shape class with all the
# methods having a bunch of `if`s ? Here is one possibility

class Shape:
    def __new__(cls, sides, *args, **kwargs):
        if sides == 3:
            return Triangle(*args, **kwargs)
        else:
            return Square(*args, **kwargs)

class Triangle:
    def __init__(self, base, height):
        self.base = base
        self.height = height

    def area(self):
        return (self.base * self.height) / 2

class Square:
    def __init__(self, length):
        self.length = length

    def area(self):
        return self.length*self.length

请注意,这只是一个示例。有多种方法可以获取解决方案,而无需借助上述的类工厂方法,即使我们确实选择以这种方式来实现该解决方案,为简洁起见也有一些注意事项(例如,明确声明元类) )

如果您要创建常规类(又称为非元类),那么__new__除非真正有特殊意义,例如ncoghlan答案中的可变与不可变方案(实际上是定义概念的更具体示例),否则这没有什么意义通过创建的类/类型的初始值/属性,__new__然后通过进行初始化__init__

Just want to add a word about the intent (as opposed to the behavior) of defining __new__ versus __init__.

I came across this question (among others) when I was trying to understand the best way to define a class factory. I realized that one of the ways in which __new__ is conceptually different from __init__ is the fact that the benefit of __new__ is exactly what was stated in the question:

So the only benefit of the __new__ method is that the instance variable will start out as an empty string, as opposed to NULL. But why is this ever useful, since if we cared about making sure our instance variables are initialized to some default value, we could have just done that in the __init__ method?

Considering the stated scenario, we care about the initial values of the instance variables when the instance is in reality a class itself. So, if we are dynamically creating a class object at runtime and we need to define/control something special about the subsequent instances of this class being created, we would define these conditions/properties in a __new__ method of a metaclass.

I was confused about this until I actually thought about the application of the concept rather than just the meaning of it. Here’s an example that would hopefully make the difference clear:

a = Shape(sides=3, base=2, height=12)
b = Shape(sides=4, length=2)
print(a.area())
print(b.area())

# I want `a` and `b` to be an instances of either of 'Square' or 'Triangle'
# depending on number of sides and also the `.area()` method to do the right
# thing. How do I do that without creating a Shape class with all the
# methods having a bunch of `if`s ? Here is one possibility

class Shape:
    def __new__(cls, sides, *args, **kwargs):
        if sides == 3:
            return Triangle(*args, **kwargs)
        else:
            return Square(*args, **kwargs)

class Triangle:
    def __init__(self, base, height):
        self.base = base
        self.height = height

    def area(self):
        return (self.base * self.height) / 2

class Square:
    def __init__(self, length):
        self.length = length

    def area(self):
        return self.length*self.length

Note this is just an demonstartive example. There are multiple ways to get a solution without resorting to a class factory approach like above and even if we do choose to implelent the solution in this manner, there are a little caveats left out for sake of brevity (for instance, declaring the metaclass explicitly)

If you are creating a regular class (a.k.a a non-metaclass), then __new__ doesn’t really make sense unless it is special case like the mutable versus immutable scenario in ncoghlan’s answer answer (which is essentially a more specific example of the concept of defining the initial values/properties of the class/type being created via __new__ to be then initialized via __init__).


pip安装后,virtualenvwrapper.sh在哪里?

问题:pip安装后,virtualenvwrapper.sh在哪里?

我正在尝试在OSX上设置virtualenvwrapper,发现的所有说明和教程都告诉我向.profile添加源命令,指向virtualenvwrapper.sh。我已经检查了所有的python和site-packages目录,但找不到任何virtualenvwrapper.sh。这是我需要单独下载的东西吗?pip安装不正确吗?

这是/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/virtualenvwrapper的内容:

hook_loader.py      hook_loader.pyc     project.py      project.pyc     user_scripts.py     user_scripts.pyc

如您所见,没有virtualenvwrapper.sh。它在哪里?

I’m trying to setup virtualenvwrapper on OSX, and all the instructions and tutorials I’ve found tell me to add a source command to .profile, pointing towards virtualenvwrapper.sh. I’ve checked all the python and site-packages directories, and I can’t find any virtualenvwrapper.sh. Is this something I need to download separately? Is pip not installing correctly?

This is the contents of /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/virtualenvwrapper:

hook_loader.py      hook_loader.pyc     project.py      project.pyc     user_scripts.py     user_scripts.pyc

As you can see, no virtualenvwrapper.sh. Where is it?


回答 0

您可以使用以下find命令搜索文件:

find / -name virtualenvwrapper.sh

这将从根目录的所有目录中搜索该文件。


在ubuntu 12.04 LTS上,通过pip安装,它已安装到

/usr/local/bin/virtualenvwrapper.sh


在ubuntu 17.04上,以pip身份作为普通用户安装,它已安装到

~/.local/bin/virtualenvwrapper.sh

You can use the find command to search for a file:

find / -name virtualenvwrapper.sh

This will search all directories from the root for the file.


on ubuntu 12.04 LTS, installing through pip, it is installed to

/usr/local/bin/virtualenvwrapper.sh


on ubuntu 17.04, installing through pip as a normal user, it is installed to

~/.local/bin/virtualenvwrapper.sh


回答 1

您已经尝试过吗?

$ which virtualenvwrapper.sh

did you already try this ?

$ which virtualenvwrapper.sh

回答 2

我只是用pip重新安装了它。

sudo pip uninstall virtualenvwrapper
sudo pip install virtualenvwrapper

这次将其放在/ usr / local / bin中。

I just reinstalled it with pip.

sudo pip uninstall virtualenvwrapper
sudo pip install virtualenvwrapper

And this time it put it in /usr/local/bin.


回答 3

各个OS所存储/定位的virtualenvwrapper.sh 的确切路径 有所不同。即使在相同的操作系统中,它也因版本而异因此,我们需要适用于所有OS版本的通用解决方案。

我找到其路径的最简单方法是

pip uninstall virtualenvwrapper

这将提示您进行确认。说“否”,但确认的第一行显示virtualenvwrapper.sh的路径(提示提供了将删除的文件列表,如果您说是的话。此列表中的第一项包含您计算机中virtualenvwrapper.sh的路径)

The exact path where virtualenvwrapper.sh is stored/located varies from OS to OS. Even with in same OS, it varies from version to version. So we need a generic solution that works for all OS versions.

Easiest way I have found to find its path is: Do

pip uninstall virtualenvwrapper

This will prompt a confirmation. Say “No” But first line of confirmation shows the path of virtualenvwrapper.sh (Prompt gives a list of files it will delete, if you say Yes. First entry in this list contains path to virtualenvwrapper.sh in your machine)


回答 4

或者像我一样..只需卸载virtualenvwrapper

sudo pip卸载virtualenvwrapper

然后使用easy_install进行安装

sudo easy_install virtualenvwrapper

这次我发现已安装文件“ /usr/local/bin/virtualenvwrapper.sh ” …在此之前,即使通过此命令我也找不到任何位置的文件

查找/ -name virtualenvwrapper.sh

or, like I did..just uninstall virtualenvwrapper

sudo pip uninstall virtualenvwrapper

and then install it with easy_install

sudo easy_install virtualenvwrapper

this time I found the file “/usr/local/bin/virtualenvwrapper.sh” installed… Before that I weren’t finding that file anywhere even by this command

find / -name virtualenvwrapper.sh


回答 5

在Mac OS上

which virtualenvwrapper.sh

你懂得

/Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh

而且你可以

sudo ln /Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh /usr/local/bin/virtualenvwrapper.sh

在你的 .bash_profile

source /usr/local/bin/virtualenvwrapper.sh

或者你可以

source /Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh

On Mac OS

which virtualenvwrapper.sh

u got

/Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh

and u can

sudo ln /Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh /usr/local/bin/virtualenvwrapper.sh

and in your .bash_profile

source /usr/local/bin/virtualenvwrapper.sh

or u can

source /Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh

回答 6

在OS X 10.8.2中,使用Python 2.7:

/Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh

In OS X 10.8.2, with Python 2.7:

/Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh


回答 7

在OSx EI机长中,我将virtualenvwrapper安装为

sudo pip3 install virtualenvwrapper

,但是我在中找不到virtualenvwrapper.sh /user/local/bin,它终于在找到了/Library/Frameworks/Python.framework/Versions/3.4/bin/virtualenvwrapper.sh,您可以通过以下方式建立到/ usr / local / bin的软链接:

ln -s /Library/Frameworks/Python.framework/Versions/3.4/bin/virtualenvwrapper.sh /usr/local/bin/virtualenvwrapper.sh,您可以按照官方文档的说明按照安装指南进行操作。祝好运!

In OSx EI captain, I installed the virtualenvwrapper as

sudo pip3 install virtualenvwrapper

, however I cannot find the virtualenvwrapper.sh in /user/local/bin, it was finally found at /Library/Frameworks/Python.framework/Versions/3.4/bin/virtualenvwrapper.sh , and you can make an soft link to /usr/local/bin as

ln -s /Library/Frameworks/Python.framework/Versions/3.4/bin/virtualenvwrapper.sh /usr/local/bin/virtualenvwrapper.sh, and everything you can just follow the setup guide as the official document does. Good luck!


回答 8

对我来说是:

~/Library/Python/2.7/bin/virtualenvwrapper.sh

(对于OS X,带有pip install --user安装)

For me it was in :

~/Library/Python/2.7/bin/virtualenvwrapper.sh

(With OS X, with a pip install --user installation)


回答 9

我也有同样的问题。如果您使用的是virtualenvwrapper的旧版本,则pip无法正常工作。

http://pypi.python.org/pypi/virtualenvwrapper/3.6 和python setup.py安装文件下载src 。然后问题解决了。

I have the same problem. If you have older version of virtualenvwrapper, then pip wont work.

download src from http://pypi.python.org/pypi/virtualenvwrapper/3.6 and python setup.py install. Then the problem solved.


回答 10

对于基于RPM的发行版(如Fedora 19),运行sudo pip install virtualenvwrapper命令后,您可以在以下位置找到文件:

/usr/bin/virtualenvwrapper.sh

For RPM-based distributions(like Fedora 19), after running the sudo pip install virtualenvwrapper command, you may find the file at:

/usr/bin/virtualenvwrapper.sh

回答 11

使用普通用户在Ubuntu 15.10上使用pip安装了它,并~/.local/bin/virtualenvwrapper.sh通过运行找到了它:

$ find / -name virtualenvwrapper.sh 2>/dev/null

Installed it using pip on Ubuntu 15.10 using a normal user, it was put in ~/.local/bin/virtualenvwrapper.sh which I found by running:

$ find / -name virtualenvwrapper.sh 2>/dev/null


回答 12

使用

find / -name virtualenvwrapper.sh

我收到大量“拒绝权限”的信息,并且只有一个文件位置的打印输出。我错过了它,直到我用pip再次卸载/安装该文件时找到了该文件位置。

万一你好奇,那是在

/usr/local/share/python/virtualenvwrapper.sh

Using

find / -name virtualenvwrapper.sh

I got a TON of “permissions denied”s, and exactly one printout of the file location. I missed it until I found that file location when I uninstall/installed it again with pip.

In case you were curious, it was in

/usr/local/share/python/virtualenvwrapper.sh

回答 13

就我而言(OSX El Capitan,版本10.11.5),我需要按如下方式编辑.profile:

在终端中:

vim〜/ .profile

export WORKON_HOME=$HOME/.virtualenvs
export MSYS_HOME=C:\msys\1.0
source /Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh                                                                                   

然后重新加载配置文件(它将在当前会话中可用。)

来源〜/ .profile

希望它会帮助某人。

In my case (OSX El Capitan, version 10.11.5) I needed to edit the .profile like so:

In the terminal:

vim ~/.profile

export WORKON_HOME=$HOME/.virtualenvs
export MSYS_HOME=C:\msys\1.0
source /Library/Frameworks/Python.framework/Versions/2.7/bin/virtualenvwrapper.sh                                                                                   

And then reload the profile (that it will be availuble in the current session.)

source ~/.profile

Hope it will help someone.


回答 14

我在玩virtualenvwrapper-4.8.4时可以在macOS Mojave(10.14)中找到一个

/Library/Frameworks/Python.framework/Versions/3.7/bin/virtualenvwrapper.sh

I can find one in macOS Mojave (10.14) while playing with virtualenvwrapper-4.8.4

/Library/Frameworks/Python.framework/Versions/3.7/bin/virtualenvwrapper.sh


回答 15

尽管这是OS X的问题,但这是在Linux(Red Hat)上对我有用的东西。

我的virtualwrapper.sh在

~/.local/bin/virtualenvwrapper.sh

这可能是因为我使用--user标记在本地安装了virtualenvwrapper …

pip install --user virtualenvwrapper

……作为替代冒险的做法使用sudo pip

Although this is an OS X question, here’s what worked for me on Linux (Red Hat).

My virtualwrapper.sh was in

~/.local/bin/virtualenvwrapper.sh

This is probably because I installed virtualenvwrapper locally, using the --user flag…

pip install --user virtualenvwrapper

…as an alternative to the risky practice of using sudo pip.


回答 16

/usr/share/virtualenvwrapper/virtualenvwrapper.sh

我已经在Ubuntu 16.04上安装了它,并找到了这个位置。

/usr/share/virtualenvwrapper/virtualenvwrapper.sh

I’ve installed it on Ubuntu 16.04 and it resulted in this location.


回答 17

/usr/local/bin/virtualenvwrapper.sh
/usr/local/bin/virtualenvwrapper.sh

回答 18

小猎犬骨头黑(debian)也有同样的问题。

手动下载软件包并安装对我有用。

I had the same issue in with the beagle bone black(debian).

Manually downloading the package and installing worked for me.


回答 19

对于Ubuntu,
如果您刚刚安装了它,请检查Terminal上的输出,我在发布我的:

Running setup.py install for virtualenv-clone    
Installing virtualenv-clone script to /home/username/.local/bin
Successfully installed virtualenvwrapper virtualenv virtualenv-clone stevedore pbr six
Cleaning up...

第二行告诉您路径。对我来说/home/username/.local/bin

For Ubuntu
If you just installed it, check the output on Terminal, I’m posting mine :

Running setup.py install for virtualenv-clone    
Installing virtualenv-clone script to /home/username/.local/bin
Successfully installed virtualenvwrapper virtualenv virtualenv-clone stevedore pbr six
Cleaning up...

Here the second line tells you the path. For me it was at /home/username/.local/bin


回答 20

点子不会试图让您为难。

问题是基于命令的文件始终安装在/bin文件夹中,它们可以位于系统路径上的任何位置。

我遇到了同样的问题,发现我的文件中有这些文件

~/.local/bin/

文件夹而不是

/usr/loca/bin/

这是常见的情况,但我认为他们将默认路径更改为

~ 或$ HOME

目录,因为它对pip安装更隔离,并提供了apt-get软件包和pip软件包之间的区别。

所以说到这里,您有两种选择,要么转到 .bashrc,然后进行如下更改

# for virtualenv wrapper
export WORKON_HOME=$HOME/Envs
export PROJECT_HOME=$HOME/Devel
source $HOME/.local/bin/virtualenvwrapper.sh

然后在下面创建目录virtualenvwrapper/usr/share/然后像这样符号链接您的virtualwrapper_lazy.sh

sudo ln -s ~/.local/bin/virtualenvwrapper_lazy.sh /usr/share/virtualenvwrapper/virtualenvwrapper_lazy.sh

并且您可以检查您的workon命令是否正在运行,该命令将列出您现有的virtualenv。

pip will not try to make things difficult for you on purpose.

The thing is commands based files are always installed in /bin folders they can be anywhere on the system path.

I had the same problem and I found that I have these files in my

~/.local/bin/

folder instead of

/usr/loca/bin/

which is the common case, but I think they changed the default path to

~ or $HOME

directory because its more isolate for the pip installations and provides a distinction between apt-get packages and pip packages.

So coming to the point you have two choices here either you go to your .bashrc and make changes like this

# for virtualenv wrapper
export WORKON_HOME=$HOME/Envs
export PROJECT_HOME=$HOME/Devel
source $HOME/.local/bin/virtualenvwrapper.sh

and than create a directory virtualenvwrapper under /usr/share/ and than symlink your virtualwrapper_lazy.sh like this

sudo ln -s ~/.local/bin/virtualenvwrapper_lazy.sh /usr/share/virtualenvwrapper/virtualenvwrapper_lazy.sh

and you can check if your workon command is working which will list your existing virtualenv’s.


回答 21

如果您pip install virtualenvwrapper不使用sudo来执行,那么普通的用户pip将运行,但由于缺少权限而不会在所需位置复制文件

mortiz@florida:~# sudo pip3 install virtualenvwrapper

使用sudo,文件将在它们各自的路径下创建:

root@florida:/usr/local/bin# ls -ltr
total 8008
-rwxr-xr-x 1 root staff 8136192 Jun 11 17:45 chromedriver
-rwxr-xr-x 1 root staff   41697 Sep  5 16:06 virtualenvwrapper.sh
-rwxr-xr-x 1 root staff    2210 Sep  5 16:06 virtualenvwrapper_lazy.sh
-rwxr-xr-x 1 root staff     215 Sep  5 16:06 pbr
-rwxr-xr-x 1 root staff     218 Sep  5 16:06 virtualenv-clone
-rwxr-xr-x 1 root staff     213 Sep  5 16:06 virtualenv
root@florida:/usr/local/bin# 

在Debian GNU / Linux 9上为我工作

If you execute pip install virtualenvwrapper without sudo as a normal user pip will run but won’t copy the files in the required locations because the lack of permissions.

mortiz@florida:~# sudo pip3 install virtualenvwrapper

Use sudo and the files will be created under their respective paths:

root@florida:/usr/local/bin# ls -ltr
total 8008
-rwxr-xr-x 1 root staff 8136192 Jun 11 17:45 chromedriver
-rwxr-xr-x 1 root staff   41697 Sep  5 16:06 virtualenvwrapper.sh
-rwxr-xr-x 1 root staff    2210 Sep  5 16:06 virtualenvwrapper_lazy.sh
-rwxr-xr-x 1 root staff     215 Sep  5 16:06 pbr
-rwxr-xr-x 1 root staff     218 Sep  5 16:06 virtualenv-clone
-rwxr-xr-x 1 root staff     213 Sep  5 16:06 virtualenv
root@florida:/usr/local/bin# 

Worked for me on Debian GNU/Linux 9


回答 22

就我而言:/home/username/.local/bin/virtualenvwrapper.sh

in my case: /home/username/.local/bin/virtualenvwrapper.sh


回答 23

您是否使用sudo安装了它?在我的情况下是错误。

Have you installed it using sudo? Was the error in my case.


ImportError:没有名为win32api的模块

问题:ImportError:没有名为win32api的模块

我使用Python 2.7,我想使用pywin32-214Windows 7。我pywin32-214通过使用msi安装程序进行安装。但是,当我导入win32apiPython脚本时,它会引发错误:

no module named win32api. 

我该怎么办?我可以使用pywin32 apiWindows 7

I am using Python 2.7 and I want to use pywin32-214 on Windows 7. I installed pywin32-214 by using the msi installer. But when I import win32api in my Python script, it throws the error:

no module named win32api. 

What should I do? Can I use pywin32 api for Windows 7?


回答 0

这可以解决我的情况,如在 哪里可以找到Python的win32api模块?

pip install pypiwin32

This is resolve my case as found on Where to find the win32api module for Python?

pip install pypiwin32

回答 1

我遇到了一个相同的问题,通过重新启动Python编辑器和Shell解决了该问题。我已经安装了,pywin32但是直到重新启动后才拾取新模块。

如果您已经这样做了,请在Python安装中进行搜索,win32api然后win32api.pyd在下找到${PYTHON_HOME}\Lib\site-packages\win32

I had an identical problem, which I solved by restarting my Python editor and shell. I had installed pywin32 but the new modules were not picked up until the restarts.

If you’ve already done that, do a search in your Python installation for win32api and you should find win32api.pyd under ${PYTHON_HOME}\Lib\site-packages\win32.


回答 2

根据pywin32 github你必须运行

    pip install pywin32

然后,您必须运行

    python Scripts/pywin32_postinstall.py -install

我知道我正在恢复一个旧线程,但是我只是遇到了这个问题,这是解决它的唯一方法。

According to pywin32 github you must run

    pip install pywin32

and after that, you must run

    python Scripts/pywin32_postinstall.py -install

I know I’m reviving an old thread, but I just had this problem and this was the only way to solve it.


回答 3

在我的Python 3发行版中,我没有找到投票率最高的答案。

我有同样的问题,并解决了安装模块pywin32的问题:

在普通的python中:

pip install pywin32

在水蟒中:

conda install pywin32

我的python安装(用于Python的英特尔®分发)存在某种依赖性问题,并出现此错误。安装此模块后,它停止出现。

I didn’t find the package of the most voted answer in my Python 3 dist.

I had the same problem and solved it installing the module pywin32:

In a normal python:

pip install pywin32

In anaconda:

conda install pywin32

My python installation (Intel® Distribution for Python) had some kind of dependency problem and was giving this error. After installing this module it stopped appearing.


回答 4

安装pywin32之后

正确安装模块的步骤(pywin32)

  1. 第一次搜索您的python pip在哪里

    1a。例如在我的情况下pip的位置-C:\ Users \ username \ AppData \ Local \ Programs \ Python \ Python36-32 \ Scripts

  2. 然后打开命令提示符,并将目录更改为您的pip文件夹位置。

    cd C:\Users\username\AppData\Local\Programs\Python\Python36-32\Scripts
    
    C:\Users\username\AppData\Local\Programs\Python\Python36-32\Scripts>pip install 
    pypiwin32

重新启动IDE

现在所有操作都可以使用该模块了。

After installing pywin32

Steps to correctly install your module (pywin32)

  1. First search where is your python pip is present

    1a. For Example in my case location of pip – C:\Users\username\AppData\Local\Programs\Python\Python36-32\Scripts

  2. Then open your command prompt and change directory to your pip folder location.

    cd C:\Users\username\AppData\Local\Programs\Python\Python36-32\Scripts
    
    C:\Users\username\AppData\Local\Programs\Python\Python36-32\Scripts>pip install 
    pypiwin32
    

Restart your IDE

All done now you can use the module .


使用virtualenv恢复`–no-site-packages`选项

问题:使用virtualenv恢复`–no-site-packages`选项

我使用该--no-site-packages选项创建了virtualenv 并安装了许多库。现在,我想还原该--no-site-packages选项并使用全局包。

我可以不重新创建virtualenv来做到吗?

更确切地说:

我不知道究竟创建使用一个的virtualenv发生时,--no-site-packages相对于没有使用该选项的选择。

如果我知道会发生什么,那么我可以弄清楚如何撤消它。

I have created a virtualenv using the --no-site-packages option and installed lots of libraries. Now I would like to revert the --no-site-packages option and use also the global packages.

Can I do that without recreating the virtualenv?

More precisely:

I wonder what exactly happens when creating a virtualenv using the --no-site-packages option as opposed to not using that option.

If I know what happens then I can figure out how to undo it.


回答 0

尝试删除(或重命名)虚拟环境下文件夹no-global-site-packages.txt中的Lib文件。

其中venv是您的虚拟环境的名称,而python3.4对应于所涉及的任何python版本,例如:

$ rm venv/lib/python3.4/no-global-site-packages.txt

如果您改变主意并想放回原处:

$ touch venv/lib/python3.4/no-global-site-packages.txt

注意:如果看不到上述文件,则说明您有较新版本的virtualenv。你要遵循这个答案,而不是

Try removing (or renaming) the file no-global-site-packages.txt in your Lib folder under your virtual environment.

Where venv is the name of your virtual environment, and python3.4 corresponds to whichever version of python involved, for example:

$ rm venv/lib/python3.4/no-global-site-packages.txt

And if you change your mind and want to put it back:

$ touch venv/lib/python3.4/no-global-site-packages.txt

Note: If you don’t see the above file, then you have a newer version of virtualenv. You’ll want to follow this answer instead


回答 1

至少对于Python 3.5.2,pyvenv.cfg在virtualenv目录的根目录中有一个文件。您需要做的就是将include-system-site-packages标志从更改falsetrue

home = /usr/bin
include-system-site-packages = false  # <- change this to "true"
version = 3.5.2

At least for Python 3.5.2, there is pyvenv.cfg file in the root of virtualenv directory. All you need to do is to change include-system-site-packages flag from false to true:

home = /usr/bin
include-system-site-packages = false  # <- change this to "true"
version = 3.5.2

回答 2

使用virtualenvwrapper管理virtualenvs时,可以使用shell函数toggleglobalsitepackages在使用和不使用站点包之间进行切换。

When using virtualenvwrapper to manage virtualenvs, you can use the shell function toggleglobalsitepackages to switch between using and not using site packages.


回答 3

尝试在/virtualenv_root/lib/和之间添加符号链接/path/to/desired/site-packages/

Try adding a symlink between /virtualenv_root/lib/ and /path/to/desired/site-packages/


回答 4

转到您的venv文件夹并打开pyvenv.cfg。(例如,如果您的虚拟环境被调用,myenv则该文件将位于myenv\pyvenv.cfg

您会看到一个布尔设置,名为 include-system-site-packages

将该设置设置true为使用全局包

如果要禁用使用全局软件包,只需将该设置设置为即可false

Go to your venv folder and open pyvenv.cfg. (E.g. if your virtual environment is called myenv then the file will be located at myenv\pyvenv.cfg)

You’ll see a boolean setting called include-system-site-packages

Set that setting to true to use global packages

If you want to disable using global packages, just set that setting to false instead.


WebDriver click()与JavaScript click()

问题:WebDriver click()与JavaScript click()

故事:

在StackOverflow上,我看到用户报告他们无法通过selenium WebDriver“单击”命令单击元素,并且可以通过执行脚本来解决JavaScript单击问题。

Python中的示例:

element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)

WebDriverJS /量角器中的示例:

var elm = $("#myid");
browser.executeScript("arguments[0].click();", elm.getWebElement());

问题:

为什么在常规WebDriver单击不起作用时单击“通过JavaScript”有效?这到底是什么时候发生的,这种解决方法(如果有)的缺点是什么?

我个人使用此变通办法时并未完全理解为什么必须这样做以及它可能导致什么问题。

The Story:

Here on StackOverflow, I’ve seen users reporting that they cannot click an element via selenium WebDriver “click” command and can work around it with a JavaScript click by executing a script.

Example in Python:

element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)

Example in WebDriverJS/Protractor:

var elm = $("#myid");
browser.executeScript("arguments[0].click();", elm.getWebElement());

The Question:

Why is clicking “via JavaScript” works when a regular WebDriver click does not? When exactly is this happening and what is the downside of this workaround (if any)?

I personally used this workaround without fully understanding why I have to do it and what problems it can lead to.


回答 0

当前接受的答案所暗示的相反,关于PhantomJS并没有特定于WebDriver单击和使用JavaScript的区别。

区别

两种方法之间的本质区别是所有浏览器都共有的,可以很简单地解释一下:

  • WebDriver:当WebDriver进行单击时,它会尽可能地尝试模拟真实用户使用浏览器时发生的情况。假设您有一个元素A,它是一个表示“单击我”的按钮,一个元素B是一个div透明的元素,但具有其尺寸和zIndex设置,使其完全覆盖A。然后,您告诉WebDriver单击A。WebDriver将模拟点击,使B 首先获得点击。为什么?因为B涵盖了A,并且如果用户尝试单击A,则B将首先获得该事件。A是否最终会获得click事件取决于B如何处理该事件。无论如何,在这种情况下,WebDriver的行为与真实用户尝试单击A时的行为相同。

  • JavaScript:现在,假设您使用JavaScript来做A.click()这种单击方法不能重现用户尝试单击A时实际发生的情况。JavaScript将click事件直接发送给A,而B将不会获得任何事件。

为什么在WebDriver单击不起作用时JavaScript单击有效?

正如我上面提到的,WebDriver会尽可能地模拟真实用户使用浏览器时发生的情况。事实是,DOM可以包含用户无法与之交互的元素,并且WebDriver不允许您单击这些元素。除了我提到的重叠情况之外,这还意味着无法单击不可见元素。我在“堆栈溢出”问题中看到的一个常见案例是某人试图与DOM中已经存在的GUI元素进行交互,但只有在处理了其他某些元素后才可见。有时在下拉菜单中会发生这种情况:您必须先单击按钮,然后弹出菜单,然后才能选择菜单项。如果有人尝试在菜单可见之前单击菜单项,如果此人随后尝试使用JavaScript进行操作,那么它将起作用,因为事件是直接传递给元素的,而与可见性无关。

什么时候应该使用JavaScript进行点击?

如果您使用Selenium来测试应用程序,那么我对这个问题的回答是“几乎不会”。总的来说,您的Selenium测试应该重现用户对浏览器的操作。以下拉菜单为例:测试应单击首先显示下拉菜单的按钮,然后单击菜单项。如果由于按钮不可见而导致GUI出现问题,或者按钮无法显示菜单项或类似内容,则测试将失败并且您将检测到该错误。如果使用JavaScript单击鼠标,则将无法通过自动测试检测到这些错误。

我说“几乎从不”是因为使用JavaScript可能会有exceptions。但是,它们应该很少见。

如果您使用Selenium 抓取站点,则尝试重现用户行为并不那么重要。因此,使用JavaScript绕过GUI并不是什么大问题。

Contrarily to what the currently accepted answer suggests, there’s nothing specific to PhantomJS when it comes to the difference between having WebDriver do a click and doing it in JavaScript.

The Difference

The essential difference between the two methods is common to all browsers and can be explained pretty simply:

  • WebDriver: When WebDriver does the click, it attempts as best as it can to simulate what happens when a real user uses the browser. Suppose you have an element A which is a button that says “Click me” and an element B which is a div element which is transparent but has its dimensions and zIndex set so that it completely covers A. Then you tell WebDriver to click A. WebDriver will simulate the click so that B receives the click first. Why? Because B covers A, and if a user were to try to click on A, then B would get the event first. Whether or not A would eventually get the click event depends on how B handles the event. At any rate, the behavior with WebDriver in this case is the same as when a real user tries to click on A.

  • JavaScript: Now, suppose you use JavaScript to do A.click(). This method of clicking does not reproduce what really happens when the user tries to click A. JavaScript sends the click event directly to A, and B will not get any event.

Why a JavaScript Click Works When a WebDriver Click Does Not?

As I mentioned above WebDriver will try to simulate as best it can what happens when a real user is using a browser. The fact of the matter is that the DOM can contain elements that a user cannot interact with, and WebDriver won’t allow you to click on these element. Besides the overlapping case I mentioned, this also entails that invisible elements cannot be clicked. A common case I see in Stack Overflow questions is someone who is trying to interact with a GUI element that already exists in the DOM but becomes visible only when some other element has been manipulated. This sometimes happens with dropdown menus: you have to first click on the button the brings up the dropdown before a menu item can be selected. If someone tries to click the menu item before the menu is visible, WebDriver will balk and say that the element cannot be manipulated. If the person then tries to do it with JavaScript, it will work because the event is delivered directly to the element, irrespective of visibility.

When Should You Use JavaScript for Clicking?

If you are using Selenium for testing an application, my answer to this question is “almost never”. By and large, your Selenium test should reproduce what a user would do with the browser. Taking the example of the drop down menu: a test should click on the button that brings up the drop down first, and then click on the menu item. If there is a problem with the GUI because the button is invisible, or the button fails to show the menu items, or something similar, then your test will fail and you’ll have detected the bug. If you use JavaScript to click around, you won’t be able to detect these bugs through automated testing.

I say “almost never” because there may be exceptions where it makes sense to use JavaScript. They should be very rare, though.

If you are using Selenium for scraping sites, then it is not as critical to attempt to reproduce user behavior. So using JavaScript to bypass the GUI is less of an issue.


回答 1

驱动程序执行的单击尝试在JavaScript HTMLElement.click()click事件执行默认操作时,即使元素不可交互,也尽可能模拟真实用户的行为。

不同之处在于:

  • 驱动程序通过将元素滚动到视图中来确保该元素可见,并检查该元素是否可交互

    驱动程序将引发错误:

    • 当点击坐标顶部的元素不是目标元素或后代时
    • 当元素没有正尺寸或完全透明时
    • 当元素是禁用的输入或按​​钮(属性/属性disabledtrue)时
    • 当元素的鼠标指针被禁用(CSS pointer-eventsnone)时


    HTMLElement.click()如果元素被禁用, JavaScript 将始终执行默认操作,或者至多只会静默失败。

  • 如果元素是可聚焦的,则希望驾驶员将其聚焦。

    JavaScript HTMLElement.click()不会。

  • 希望驱动程序像真实用户一样发出所有事件(mousemove,mousedown,mouseup,click等)。

    JavaScript HTMLElement.click()仅发出click事件。该页面可能依赖于这些额外的事件,并且如果未发出这些事件,它们的行为可能会有所不同。

    这些是驱动程序发出的单击Chrome的事件:

    mouseover {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousemove {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousedown {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mouseup {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    click {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }

    这是JavaScript注入发出的事件:

    click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
  • JavaScript发出的事件.click() 不受信任,并且默认操作不能被调用:

    https://developer.mozilla.org/zh/docs/Web/API/Event/isTrusted
    https://googlechrome.github.io/samples/event-istrusted/index.html

    请注意,某些驱动程序仍在生成不受信任的事件。从2.1版开始,PhantomJS就是这种情况。

  • JavaScript发出的事件.click() 没有click的坐标

    属性clientX, clientY, screenX, screenY, layerX, layerY设置为0。该页面可能依赖于它们,并且可能会有所不同。


可以使用JavaScript .click()抓取一些数据,但这不是在测试环境中。由于它无法模拟用户的行为,因此无法达到测试的目的。因此,如果来自驱动程序的单击失败,则实际用户很可能也将在相同条件下无法执行相同的单击。


是什么使驱动程序在我们期望成功时无法单击元素?

  • 由于延迟或过渡效果,目标元素尚不可见/不可交互。

    一些例子 :

    https://developer.mozilla.org/fr/docs/Web(下拉导航菜单) http://materializecss.com/side-nav.html(下拉侧栏)

    工作环境:

    添加服务员以等待可见性,最小尺寸或稳定位置:

    // wait visible
    browser.wait(ExpectedConditions.visibilityOf(elem), 5000);
    
    // wait visible and not disabled
    browser.wait(ExpectedConditions.elementToBeClickable(elem), 5000);
    
    // wait for minimum width
    browser.wait(function minimumWidth() {
        return elem.getSize().then(size => size.width > 50);
    }, 5000);

    重试单击直到成功:

    browser.wait(function clickSuccessful() {
        return elem.click().then(() => true, (ex) => false);
    }, 5000);

    添加与动画/过渡的持续时间匹配的延迟:

    browser.sleep(250);


  • 目标元素最终被浮动元素覆盖一旦滚动到视图中:

    驱动程序自动将元素滚动到视图中以使其可见。如果页面包含浮动/粘滞元素(菜单,广告,页脚,通知,Cookie策略..),则该元素可能最终被覆盖,将不再可见/不可交互。

    示例:https//twitter.com/?lang = zh-CN

    解决方法:

    将窗口的大小设置为较大的大小,以避免滚动或浮动元素。

    Y将鼠标移到具有负偏移量的元素上,然后单击它:

      browser.actions()
         .mouseMove(elem, {x: 0, y: -250})
         .click()
         .perform();

    单击之前,将元素滚动到窗口的中心:

    browser.executeScript(function scrollCenter(elem) {
      var win = elem.ownerDocument.defaultView || window,
        box = elem.getBoundingClientRect(),
        dy = box.top - (win.innerHeight - box.height) / 2;
      win.scrollTo(win.pageXOffset, win.pageYOffset + dy);
    }, element);
    
    element.click();

    如果无法避免,请隐藏浮动元素:

    browser.executeScript(function scrollCenter(elem) {
      elem.style.display = 'none';
    }, element);

The click executed by the driver tries to simulate the behavior of a real user as close as possible while the JavaScript HTMLElement.click() performs the default action for the click event, even if the element is not interactable.

The differences are:

  • The driver ensures that the element is visible by scrolling it into the view and checks that the element is interactable.

    The driver will raise an error:

    • when the element on top at the coordinates of the click is not the targeted element or a descendant
    • when the element doesn’t have a positive size or if it is fully transparent
    • when the element is a disabled input or button (attribute/property disabled is true)
    • when the element has the mouse pointer disabled (CSS pointer-events is none)


    A JavaScript HTMLElement.click() will always perform the default action or will at best silently fail if the element is a disabled.

  • The driver is expected to bring the element into focus if it is focusable.

    A JavaScript HTMLElement.click() won’t.

  • The driver is expected to emit all the events (mousemove, mousedown, mouseup, click, …) just like like a real user.

    A JavaScript HTMLElement.click() emits only the click event. The page might rely on these extra events and might behave differently if they are not emitted.

    These are the events emitted by the driver for a click with Chrome:

    mouseover {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousemove {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mousedown {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    mouseup {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    click {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
    

    And this is the event emitted with a JavaScript injection:

    click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
    
  • The event emitted by a JavaScript .click() is not trusted and the default action may not be invoked:

    https://developer.mozilla.org/en/docs/Web/API/Event/isTrusted
    https://googlechrome.github.io/samples/event-istrusted/index.html

    Note that some of the drivers are still generating untrusted events. This is the case with PhantomJS as of version 2.1.

  • The event emitted by a JavaScript .click() doesn’t have the coordinates of the click.

    The properties clientX, clientY, screenX, screenY, layerX, layerY are set to 0. The page might rely on them and might behave differently.


It may be ok to use a JavaScript .click() to scrap some data, but it is not in a testing context. It defeats the purpose of the test since it doesn’t simulate the behavior of a user. So, if the click from the driver fails, then a real user will most likely also fail to perform the same click in the same conditions.


What makes the driver fail to click an element when we expect it to succeed?

  • The targeted element is not yet visible/interactable due to a delay or a transition effect.

    Some examples :

    https://developer.mozilla.org/fr/docs/Web (dropdown navigation menu) http://materializecss.com/side-nav.html (dropdown side bar)

    Workarrounds:

    Add a waiter to wait for the visibility, a minimum size or a steady position :

    // wait visible
    browser.wait(ExpectedConditions.visibilityOf(elem), 5000);
    
    // wait visible and not disabled
    browser.wait(ExpectedConditions.elementToBeClickable(elem), 5000);
    
    // wait for minimum width
    browser.wait(function minimumWidth() {
        return elem.getSize().then(size => size.width > 50);
    }, 5000);
    

    Retry to click until it succeeds :

    browser.wait(function clickSuccessful() {
        return elem.click().then(() => true, (ex) => false);
    }, 5000);
    

    Add a delay matching the duration of the animation/transition :

    browser.sleep(250);
    


  • The targeted element ends-up covered by a floating element once scrolled into the view:

    The driver automatically scrolls the element into the view to make it visible. If the page contains a floating/sticky element (menu, ads, footer, notification, cookie policy..), the element may end-up covered and will no longer be visible/interactable.

    Example: https://twitter.com/?lang=en

    Workarounds:

    Set the size of the window to a larger one to avoid the scrolling or the floating element.

    Mover over the element with a negative Y offset and then click it:

      browser.actions()
         .mouseMove(elem, {x: 0, y: -250})
         .click()
         .perform();
    

    Scroll the element to the center of the window before the click:

    browser.executeScript(function scrollCenter(elem) {
      var win = elem.ownerDocument.defaultView || window,
        box = elem.getBoundingClientRect(),
        dy = box.top - (win.innerHeight - box.height) / 2;
      win.scrollTo(win.pageXOffset, win.pageYOffset + dy);
    }, element);
    
    element.click();
    

    Hide the floating element if it can’t be avoided:

    browser.executeScript(function scrollCenter(elem) {
      elem.style.display = 'none';
    }, element);
    

回答 2

注意:我们将“点击”称为最终用户点击。“ js click”是通过JS点击的

为什么在常规WebDriver单击不起作用时单击“通过JavaScript”有效?

有两种情况会发生这种情况:

I. 如果您正在使用PhamtomJS

这是的最常见的已知行为PhantomJS。例如,某些元素有时不可单击<div>。这是因为PhantomJS最初是用来模拟浏览器引擎的(例如初始HTML + CSS->计算CSS->呈现)。但这并不意味着要以最终用户的方式进行交互(查看,单击,拖动)。因此PhamtomJS,最终用户交互仅部分支持。

JS为什么点击工作?至于任一点击,它们都是平均点击。它就像带有1个枪管2个扳机的枪。视口中的一个,JS中的一个。由于可以PhamtomJS很好地模拟浏览器的引擎,因此JS单击应该可以很好地工作。

二。“ click”的事件处理程序必须在糟糕的时间内绑定。

例如,我们得到了一个 <div>

  • ->我们做一些计算

  • ->然后将click事件绑定到<div>

  • ->加上一些错误的角度编码(例如,不能正确处理示波器的周期)

我们可能最终得到相同的结果。单击将不起作用,因为WebdriverJS在没有单击事件处理程序的情况下会尝试单击该元素。

JS为什么点击工作?JS单击就像将JS直接注入浏览器。可能有2种方式,

拳头是通过devtools控制台(是的,WebdriverJS确实与devtools的控制台进行通信)。

其次是将<script>标记直接注入HTML。

对于每个浏览器,其行为将有所不同。但是无论如何,这些方法比单击按钮更复杂。Click正在使用已经存在的内容(最终用户单击),js click正在通过后门。

对于js,单击将显示为异步任务。这与一个复杂的主题“ 浏览器异步任务和CPU任务调度 ”相关(一会儿再读也找不到文章)。简而言之,这主要是因为js click需要等待CPU任务调度周期,并且在click事件绑定后运行速度会变慢。 (当您发现元素有时可单击,有时却不可单击时,您可能会知道这种情况。)

这到底是什么时候发生的,这种解决方法(如果有)的缺点是什么?

=>如上所述,两者都意味着一个目的,但是关于使用哪个入口:

  • 点击:使用默认情况下提供的浏览器。
  • JS click:正在通过后门。

=>对于性能,很难说,因为它依赖于浏览器。但通常:

  • 单击:并不意味着更快,而只是在CPU执行任务的计划列表中签名更高的位置。
  • JS单击:并不意味着速度较慢,而仅是它登录到CPU任务计划列表的最后位置。

=>缺点:

  • 点击:除了您使用PhamtomJS之外,似乎没有其他缺点。
  • JS单击:对健康非常不利。您可能不小心单击了视图中没有的内容。使用此功能时,请确保该元素在那里并且可供查看,然后单击以作为最终用户的观点。

PS,如果您正在寻找解决方案。

  • 使用PhantomJS?我建议改用无头的Chrome。是的,您可以在Ubuntu上无头设置Chrome。事物的运行方式与Chrome一样,但它没有视图,并且像PhantomJS一样没有虫子。
  • 不使用PhamtomJS但仍然有问题吗?我建议使用带有browser.wait()(分度器的ExpectedCondition)(检查此以获得更多信息

(我想简短一点,但结局很糟。与理论有关的任何事情都难以解释…)

NOTE: let’s call ‘click’ is end-user click. ‘js click’ is click via JS

Why is clicking “via JavaScript” works when a regular WebDriver click does not?

There are 2 cases for this to happen:

I. If you are using PhamtomJS

Then this is the most common known behavior of PhantomJS . Some elements are sometimes not clickable, for example <div>. This is because PhantomJS was original made for simulating the engine of browsers (like initial HTML + CSS -> computing CSS -> rendering). But it does not mean to be interacted with as an end user’s way (viewing, clicking, dragging). Therefore PhamtomJS is only partially supported with end-users interaction.

WHY DOES JS CLICK WORK? As for either click, they are all mean click. It is like a gun with 1 barrel and 2 triggers. One from the viewport, one from JS. Since PhamtomJS great in simulating browser’s engine, a JS click should work perfectly.

II. The event handler of “click” got to bind in the bad period of time.

For example, we got a <div>

  • -> We do some calculation

  • -> then we bind event of click to the <div>.

  • -> Plus with some bad coding of angular (e.g. not handling scope’s cycle properly)

We may end up with the same result. Click won’t work, because WebdriverJS trying to click on the element when it has no click event handler.

WHY DOES JS CLICK WORK? Js click is like injecting js directly into the browser. Possible with 2 ways,

Fist is through devtools console (yes, WebdriverJS does communicate with devtools’ console).

Second is inject a <script> tag directly into HTML.

For each browser, the behavior will be different. But regardless, these methods are more complicating than clicking on the button. Click is using what already there (end-users click), js click is going through backdoor.

And for js click will appear to be an asynchronous task. This is related a with a kinda complex topic of ‘browser asynchronous task and CPU task scheduling‘ (read it a while back can’t find the article again). For short this will mostly result as js click will need to wait for a cycle of task scheduling of CPU and it will be ran a bit slower after the binding of the click event. (You could know this case when you found the element sometimes clickable, sometimes not. )

When exactly is this happening and what is the downside of this workaround (if any)?

=> As mention above, both mean for one purpose, but about using which entrance:

  • Click: is using what providing by default of browser.
  • JS click: is going through backdoor.

=> For performance, it is hard to say because it relies on browsers. But generally:

  • Click: doesn’t mean faster but only signed higher position in schedule list of CPU execution task.
  • JS click: doesn’t mean slower but only it signed into the last position of schedule list of CPU task.

=> Downsides:

  • Click: doesn’t seem to have any downside except you are using PhamtomJS.
  • JS click: very bad for health. You may accidentally click on something that doesn’t there on the view. When you use this, make sure the element is there and available to view and click as the point of view of end-user.

P.S. if you are looking for a solution.

  • Using PhantomJS? I will suggest using Chrome headless instead. Yes, you can set up Chrome headless on Ubuntu. Thing runs just like Chrome but it only does not have a view and less buggy like PhantomJS.
  • Not using PhamtomJS but still having problems? I will suggest using ExpectedCondition of Protractor with browser.wait() (check this for more information)

(I want to make it short, but ended up badly. Anything related with theory is complicated to explain…)


如何在asyncio中使用请求?

问题:如何在asyncio中使用请求?

我想在其中执行并行http请求任务asyncio,但是我发现这python-requests会阻止的事件循环asyncio。我找到了aiohttp,但它无法使用http代理提供http请求的服务。

所以我想知道是否有一种方法可以借助进行异步http请求asyncio

I want to do parallel http request tasks in asyncio, but I find that python-requests would block the event loop of asyncio. I’ve found aiohttp but it couldn’t provide the service of http request using a http proxy.

So I want to know if there’s a way to do asynchronous http requests with the help of asyncio.


回答 0

要将请求(或任何其他阻塞库)与asyncio一起使用,可以使用BaseEventLoop.run_in_executor在另一个线程中运行一个函数,并从该线程中屈服以获得结果。例如:

import asyncio
import requests

@asyncio.coroutine
def main():
    loop = asyncio.get_event_loop()
    future1 = loop.run_in_executor(None, requests.get, 'http://www.google.com')
    future2 = loop.run_in_executor(None, requests.get, 'http://www.google.co.uk')
    response1 = yield from future1
    response2 = yield from future2
    print(response1.text)
    print(response2.text)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

这将同时获得两个响应。

使用python 3.5可以使用new await/ async语法:

import asyncio
import requests

async def main():
    loop = asyncio.get_event_loop()
    future1 = loop.run_in_executor(None, requests.get, 'http://www.google.com')
    future2 = loop.run_in_executor(None, requests.get, 'http://www.google.co.uk')
    response1 = await future1
    response2 = await future2
    print(response1.text)
    print(response2.text)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

有关更多信息,请参见PEP0492

To use requests (or any other blocking libraries) with asyncio, you can use BaseEventLoop.run_in_executor to run a function in another thread and yield from it to get the result. For example:

import asyncio
import requests

@asyncio.coroutine
def main():
    loop = asyncio.get_event_loop()
    future1 = loop.run_in_executor(None, requests.get, 'http://www.google.com')
    future2 = loop.run_in_executor(None, requests.get, 'http://www.google.co.uk')
    response1 = yield from future1
    response2 = yield from future2
    print(response1.text)
    print(response2.text)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

This will get both responses in parallel.

With python 3.5 you can use the new await/async syntax:

import asyncio
import requests

async def main():
    loop = asyncio.get_event_loop()
    future1 = loop.run_in_executor(None, requests.get, 'http://www.google.com')
    future2 = loop.run_in_executor(None, requests.get, 'http://www.google.co.uk')
    response1 = await future1
    response2 = await future2
    print(response1.text)
    print(response2.text)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

See PEP0492 for more.


回答 1

aiohttp已经可以与HTTP代理一起使用:

import asyncio
import aiohttp


@asyncio.coroutine
def do_request():
    proxy_url = 'http://localhost:8118'  # your proxy address
    response = yield from aiohttp.request(
        'GET', 'http://google.com',
        proxy=proxy_url,
    )
    return response

loop = asyncio.get_event_loop()
loop.run_until_complete(do_request())

aiohttp can be used with HTTP proxy already:

import asyncio
import aiohttp


@asyncio.coroutine
def do_request():
    proxy_url = 'http://localhost:8118'  # your proxy address
    response = yield from aiohttp.request(
        'GET', 'http://google.com',
        proxy=proxy_url,
    )
    return response

loop = asyncio.get_event_loop()
loop.run_until_complete(do_request())

回答 2

上面的答案仍在使用旧的Python 3.4样式协程。如果您使用的是Python 3.5以上版本,则应编写以下内容。

aiohttp 现在支持 http代理

import aiohttp
import asyncio

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
            'http://python.org',
            'https://google.com',
            'http://yifei.me'
        ]
    tasks = []
    async with aiohttp.ClientSession() as session:
        for url in urls:
            tasks.append(fetch(session, url))
        htmls = await asyncio.gather(*tasks)
        for html in htmls:
            print(html[:100])

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

The answers above are still using the old Python 3.4 style coroutines. Here is what you would write if you got Python 3.5+.

aiohttp supports http proxy now

import aiohttp
import asyncio

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
            'http://python.org',
            'https://google.com',
            'http://yifei.me'
        ]
    tasks = []
    async with aiohttp.ClientSession() as session:
        for url in urls:
            tasks.append(fetch(session, url))
        htmls = await asyncio.gather(*tasks)
        for html in htmls:
            print(html[:100])

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

回答 3

请求目前不支持asyncio,也没有计划提供此类支持。这可能是因为你可以实现一个自定义的“传输适配器”(如讨论这里),它知道如何使用asyncio

如果我有一段时间的话,我可能会真正去研究,但是我什么也不能保证。

Requests does not currently support asyncio and there are no plans to provide such support. It’s likely that you could implement a custom “Transport Adapter” (as discussed here) that knows how to use asyncio.

If I find myself with some time it’s something I might actually look into, but I can’t promise anything.


回答 4

Pimin Konstantin Kefaloukos 在Python和asyncio上进行的简单并行HTTP请求中有一篇很好的案例,介绍了异步/等待循环和线程 :

为了最大程度地减少总完成时间,我们可以增加线程池的大小以匹配我们必须发出的请求数量。幸运的是,这很容易做到,接下来我们将看到。下面的代码示例是如何使用二十个工作线程的线程池发出二十个异步HTTP请求的示例:

# Example 3: asynchronous requests with larger thread pool
import asyncio
import concurrent.futures
import requests

async def main():

    with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:

        loop = asyncio.get_event_loop()
        futures = [
            loop.run_in_executor(
                executor, 
                requests.get, 
                'http://example.org/'
            )
            for i in range(20)
        ]
        for response in await asyncio.gather(*futures):
            pass


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

There is a good case of async/await loops and threading in an article by Pimin Konstantin Kefaloukos Easy parallel HTTP requests with Python and asyncio:

To minimize the total completion time, we could increase the size of the thread pool to match the number of requests we have to make. Luckily, this is easy to do as we will see next. The code listing below is an example of how to make twenty asynchronous HTTP requests with a thread pool of twenty worker threads:

# Example 3: asynchronous requests with larger thread pool
import asyncio
import concurrent.futures
import requests

async def main():

    with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:

        loop = asyncio.get_event_loop()
        futures = [
            loop.run_in_executor(
                executor, 
                requests.get, 
                'http://example.org/'
            )
            for i in range(20)
        ]
        for response in await asyncio.gather(*futures):
            pass


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

普通英语的WSGI和CGI是什么?

问题:普通英语的WSGI和CGI是什么?

每次阅读WSGI或CGI时,我都会感到畏缩。我尝试过阅读它,但没有任何卡住。

普通英语到底是什么?

它只是将请求通过管道传输到终端并重定向输出吗?

Every time I read either WSGI or CGI I cringe. I’ve tried reading on it before but nothing really has stuck.

What is it really in plain English?

Does it just pipe requests to a terminal and redirect the output?


回答 0

WSGI在Web服务器启动时(作为Web服务器进程的一部分(嵌入式模式)或作为单独的进程(守护程序模式))运行Python解释器,并将脚本加载到其中。每个请求都会导致调用脚本中的特定功能,并将请求环境作为参数传递给该功能。

CGI将脚本作为每个请求的单独进程运行,并使用环境变量,stdin和stdout与之“通信”。

WSGI runs the Python interpreter on web server start, either as part of the web server process (embedded mode) or as a separate process (daemon mode), and loads the script into it. Each request results in a specific function in the script being called, with the request environment passed as arguments to the function.

CGI runs the script as a separate process each request and uses environment variables, stdin, and stdout to “communicate” with it.


回答 1

从完全后退的角度来看,Blankman,这是我的Web服务网关接口的“简介页”:

第一部分:网络服务器

Web服务器提供响应。他们坐在那里,耐心等待,然后突然没有任何警告:

  • 客户端进程发送请求。客户端进程可以是Web服务器,机器人,移动应用程序等。简直就是“客户”
  • Web服务器收到此请求
  • 故意咕umble各种事情发生(见下文)
  • Web服务器将某些内容发送回客户端
  • Web服务器再次坐在附近

Web服务器(至少是更好的服务器)在这方面非常擅长。他们根据需求扩展和缩减处理,通过可靠的网络可靠地与最薄弱的客户进行对话,而我们永远不必担心。他们只是继续服役。

这就是我的观点:Web服务器就是:服务器。他们对内容一无所知,对用户一无所知,实际上除了如何耐心等待和可靠答复外,一无所知。

您选择的Web服务器应该反映您的交付偏好,而不是您的软件。您的网络服务器应负责服务,而不是处理或逻辑事务。

第二部分:(PYTHON)软件

软件不存在。软件仅在执行时存在。当软件在其环境中发生意外更改(文件不在期望的位置,重命名参数等)时,软件并不适应。尽管优化应该是设计的中心原则(当然),但是软件本身并不能优化。开发人员乐观。软件执行。软件会执行上面“故意含糊不清”部分中的所有内容。可以是任何东西。

您对软件的选择或设计应反映您的应用程序,功能的选择,而不是Web服务器的选择。

这是将语言“编译”到Web服务器的传统方法变得很痛苦的地方。您最终将代码放入应用程序中以应对物理服务器环境,或者至少被迫选择一个适当的“包装”库以在运行时包括在内,从而使跨Web服务器具有统一性的错觉。

那么WSGI是什么?

那么,最后,WSGI是什么?WSGI是一套规则,分为两部分。编写它们的方式可以将它们集成到任何欢迎集成的环境中。

为Web服务器端编写的第一部分说:“好吧,如果您要处理WSGI应用程序,则这是该软件在加载时的思考方式。这是您必须为应用程序提供的内容,这里是您可以期望每个应用程序具有的界面(布局)。此外,如果出现任何问题,这是应用程序的思维方式以及期望行为的方式。”

为Python应用程序软件编写的第二部分说:“好吧,如果您要处理WSGI服务器,这是服务器与您联系时的思考方式。这是您必须向服务器提供的东西,以及这是您可以期望每台服务器都具有的接口(布局)。此外,如果出现任何问题,这是您的行为方式,也应该告诉服务器。”

因此,有了它-服务器将成为服务器,软件将成为软件,这是它们可以很好地相处的一种方式,而不必为彼此的细节留出余地。这是WSGI。

mod_wsgi的,而另一方面,是Apache的一个插件,让它跟WSGI兼容的软件,换句话说,mod_wsgi的是一个实现 -在Apache中-上面的规则手册第一部分的规则。

至于CGI ….问其他人:-)

From a totally step-back point of view, Blankman, here is my “Intro Page” for Web Services Gateway Interface:

PART ONE: WEB SERVERS

Web servers serve up responses. They sit around, waiting patiently, and then with no warning at all, suddenly:

  • a client process sends a request. The client process could be a web server, a bot, a mobile app, whatever. It is simply “the client”
  • the web server receives this request
  • deliberate mumble various things happen (see below)
  • The web server sends back something to the client
  • web server sits around again

Web servers (at least, the better ones) are very VERY good at this. They scale up and down processing depending on demand, they reliably hold conversations with the flakiest of clients over really cruddy networks and we never really have to worry about it. They just keep on serving.

This is my point: web servers are just that: servers. They know nothing about content, nothing about users, nothing in fact other than how to wait a lot and reply reliably.

Your choice of web server should reflect your delivery preference, not your software. Your web server should be in charge of serving, not processing or logical stuff.

PART TWO: (PYTHON) SOFTWARE

Software does not sit around. Software only exists at execution time. Software is not terribly accommodating when it comes to unexpected changes in its environment (files not being where it expects, parameters being renamed etc). Although optimisation should be a central tenet of your design (of course), software itself does not optimise. Developers optimise. Software executes. Software does all the stuff in the ‘deliberate mumble’ section above. Could be anything.

Your choice or design of software should reflect your application, your choice of functionality, and not your choice of web server.

This is where the traditional method of “compiling in” languages to web servers becomes painful. You end up putting code in your application to cope with the physical server environment or, at least, being forced to choose an appropriate ‘wrapper’ library to include at runtime, to give the illusion of uniformity across web servers.

SO WHAT IS WSGI?

So, at last, what is WSGI? WSGI is a set of rules, written in two halves. They are written in such a way that they can be integrated into any environment that welcomes integration.

The first part, written for the web server side, says “OK, if you want to deal with a WSGI application, here’s how the software will be thinking when it loads. Here are the things you must make available to the application, and here is the interface (layout) that you can expect every application to have. Moreover, if anything goes wrong, here’s how the app will be thinking and how you can expect it to behave.”

The second part, written for the Python application software, says “OK, if you want to deal with a WSGI server, here’s how the server will be thinking when it contacts you. Here are the things you must make available to the server, and here is the interface (layout) that you can expect every server to have. Moreover, if anything goes wrong, here’s how you should behave and here’s what you should tell the server.”

So there you have it – servers will be servers and software will be software, and here’s a way they can get along just great without one having to make any allowances for the specifics of the other. This is WSGI.

mod_wsgi, on the other hand, is a plugin for Apache that lets it talk to WSGI-compliant software, in other words, mod_wsgi is an implementation – in Apache – of the rules of part one of the rulebook above.

As for CGI…. ask someone else :-)


回答 2

如果您不清楚这个领域中的所有术语,并且让我们面对现实,那是一个令人困惑的首字母缩写词,那么还有一个很好的背景阅读器,以官方的Python HOWTO形式提供,它讨论了CGI,FastCGI,WSGI等。上。希望我先读。

If you are unclear on all the terms in this space, and let’s face it, it’s a confusing acronym-laden one, there’s also a good background reader in the form of an official python HOWTO which discusses CGI vs. FastCGI vs. WSGI and so on. I wish I’d read it first.


回答 3

CGI和WSGI都定义了标准接口,程序可以使用这些标准接口来处理Web请求。CGI接口的级别低于WSGI,它涉及服务器设置环境变量,该环境变量包含HTTP请求中的数据,程序返回的格式类似于裸HTTP服务器响应。

另一方面,WSGI是特定于Python的更高级别的接口,它使程序员可以编写与服务器无关的应用程序,并且可以将其包装在其他WSGI应用程序(中间件)中。

Both CGI and WSGI define standard interfaces that programs can use to handle web requests. The CGI interface is at a lower level than WSGI, and involves the server setting up environment variables containing the data from the HTTP request, with the program returning something formatted pretty much like a bare HTTP server response.

WSGI, on the other hand, is a Python-specific, slightly higher-level interface that allows programmers to write applications that are server-agnostic and which can be wrapped in other WSGI applications (middleware).