标签归档:python-3.4

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.


如何在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())

没有循环导入的Python类型提示

问题:没有循环导入的Python类型提示

我正试图将我的大班分成两部分;好吧,基本上是进入“主”类和具有其他功能的mixin的,就像这样:

main.py 文件:

import mymixin.py

class Main(object, MyMixin):
    def func1(self, xxx):
        ...

mymixin.py 文件:

class MyMixin(object):
    def func2(self: Main, xxx):  # <--- note the type hint
        ...

现在,尽管这很好用,但是类型提示MyMixin.func2当然不起作用。我无法导入main.py,因为会进行周期性导入,并且没有提示,我的编辑器(PyCharm)无法分辨出什么self

我使用的是Python 3.4,如果在那里有解决方案,我愿意移至3.5。

有什么办法可以将我的Class分成两个文件并保留所有“连接”,以便我的IDE仍然可以自动完成以及知道类型的所有其他优点。

I’m trying to split my huge class into two; well, basically into the “main” class and a mixin with additional functions, like so:

main.py file:

import mymixin.py

class Main(object, MyMixin):
    def func1(self, xxx):
        ...

mymixin.py file:

class MyMixin(object):
    def func2(self: Main, xxx):  # <--- note the type hint
        ...

Now, while this works just fine, the type hint in MyMixin.func2 of course can’t work. I can’t import main.py, because I’d get a cyclic import and without the hint, my editor (PyCharm) can’t tell what self is.

I’m using Python 3.4, willing to move to 3.5 if a solution is available there.

Is there any way I can split my class into two files and keep all the “connections” so that my IDE still offers me auto completion & all the other goodies that come from it knowing the types?


回答 0

恐怕通常没有一种非常优雅的方式来处理导入周期。您的选择是重新设计代码以消除循环依赖性,或者如果不可行,请执行以下操作:

# some_file.py

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    def func2(self, some_param: 'Main'):
        ...

TYPE_CHECKING常量始终False在运行时运行,因此不会评估导入,但是mypy(和其他类型检查工具)将评估该块的内容。

我们还需要将Main类型注释放入字符串中,以有效地向前声明它,因为该Main符号在运行时不可用。

如果您使用的是Python 3.7+,我们至少可以通过利用PEP 563来跳过必须提供显式字符串注释的情况:

# some_file.py

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    # Hooray, cleaner annotations!
    def func2(self, some_param: Main):
        ...

from __future__ import annotations进口将使所有类型提示弦而跳过评估他们。这可以使我们的代码更符合人体工程学。

综上所述,与mypy一起使用mixins可能需要比您现在拥有的结构更多的结构。Mypy 建议一种基本上就是deceze所描述的方法-创建一个ABC,您的类MainMyMixin类都继承。如果您最终需要做一些类似的事情以使Pycharm的检查器满意,我不会感到惊讶。

There isn’t a hugely elegant way to handle import cycles in general, I’m afraid. Your choices are to either redesign your code to remove the cyclic dependency, or if it isn’t feasible, do something like this:

# some_file.py

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    def func2(self, some_param: 'Main'):
        ...

The TYPE_CHECKING constant is always False at runtime, so the import won’t be evaluated, but mypy (and other type-checking tools) will evaluate the contents of that block.

We also need to make the Main type annotation into a string, effectively forward declaring it since the Main symbol isn’t available at runtime.

If you are using Python 3.7+, we can at least skip having to provide an explicit string annotation by taking advantage of PEP 563:

# some_file.py

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from main import Main

class MyObject(object):
    # Hooray, cleaner annotations!
    def func2(self, some_param: Main):
        ...

The from __future__ import annotations import will make all type hints be strings and skip evaluating them. This can help make our code here mildly more ergonomic.

All that said, using mixins with mypy will likely require a bit more structure then you currently have. Mypy recommends an approach that’s basically what deceze is describing — to create an ABC that both your Main and MyMixin classes inherit. I wouldn’t be surprised if you ended up needing to do something similar in order to make Pycharm’s checker happy.


回答 1

对于仅在导入类以进行类型检查时陷入困境的人们:您可能希望使用前向引用(PEP 484-类型提示):

当类型提示包含尚未定义的名称时,该定义可以表示为字符串文字,以便稍后解析。

所以代替:

class Tree:
    def __init__(self, left: Tree, right: Tree):
        self.left = left
        self.right = right

你做:

class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right

For people struggling with cyclic imports when importing class only for Type checking: you will likely want to use a Forward Reference (PEP 484 – Type Hints):

When a type hint contains names that have not been defined yet, that definition may be expressed as a string literal, to be resolved later.

So instead of:

class Tree:
    def __init__(self, left: Tree, right: Tree):
        self.left = left
        self.right = right

you do:

class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right

回答 2

更大的问题是,您的类型一开始并不理智。MyMixin进行硬编码的假设是将其混合到中Main,而可以将其混合到任何其他数量的类中,在这种情况下,它可能会损坏。如果将mixin硬编码为混合到一个特定的类中,则不妨将方法直接写入该类中,而不用将它们分开。

要使用合理的输入方式正确执行此操作,MyMixin应使用Python的说法对interface或abstract class 进行编码:

import abc


class MixinDependencyInterface(abc.ABC):
    @abc.abstractmethod
    def foo(self):
        pass


class MyMixin:
    def func2(self: MixinDependencyInterface, xxx):
        self.foo()  # ← mixin only depends on the interface


class Main(MixinDependencyInterface, MyMixin):
    def foo(self):
        print('bar')

The bigger issue is that your types aren’t sane to begin with. MyMixin makes a hardcoded assumption that it will be mixed into Main, whereas it could be mixed into any number of other classes, in which case it would probably break. If your mixin is hardcoded to be mixed into one specific class, you may as well write the methods directly into that class instead of separating them out.

To properly do this with sane typing, MyMixin should be coded against an interface, or abstract class in Python parlance:

import abc


class MixinDependencyInterface(abc.ABC):
    @abc.abstractmethod
    def foo(self):
        pass


class MyMixin:
    def func2(self: MixinDependencyInterface, xxx):
        self.foo()  # ← mixin only depends on the interface


class Main(MixinDependencyInterface, MyMixin):
    def foo(self):
        print('bar')

回答 3

事实证明,我最初的尝试也非常接近解决方案。这是我目前正在使用的:

# main.py
import mymixin.py

class Main(object, MyMixin):
    def func1(self, xxx):
        ...


# mymixin.py
if False:
    from main import Main

class MyMixin(object):
    def func2(self: 'Main', xxx):  # <--- note the type hint
        ...

请注意,import inside if False语句永远不会被导入(但IDE仍然知道它),并且将该Main类用作字符串,因为在运行时不知道。

Turns out my original attempt was quite close to the solution as well. This is what I’m currently using:

# main.py
import mymixin.py

class Main(object, MyMixin):
    def func1(self, xxx):
        ...


# mymixin.py
if False:
    from main import Main

class MyMixin(object):
    def func2(self: 'Main', xxx):  # <--- note the type hint
        ...

Note the import within if False statement that never gets imported (but IDE knows about it anyway) and using the Main class as string because it’s not known at runtime.


回答 4

我认为,完美的方法应该是将所有类和依赖项导入文件(如__init__.py),然后再导入所有from __init__ import *其他文件。

在这种情况下

  1. 避免对这些文件和类的多次引用,并且
  2. 也只需在其他每个文件中添加一行
  3. 第三个是知道您可能使用的所有类的pycharm。

I think the perfect way should be to import all the classes and dependencies in a file (like __init__.py) and then from __init__ import * in all the other files.

In this case you are

  1. avoiding multiple references to those files and classes and
  2. also only have to add one line in each of the other files and
  3. the third would be the pycharm knowing about all of the classes that you might use.

Python3项目删除__pycache__文件夹和.pyc文件

问题:Python3项目删除__pycache__文件夹和.pyc文件

从python3项目中清除所有__pycache__ 文件夹和.pyc/.pyo文件的最佳方法是什么?我已经看到多个用户建议pyclean与Debian捆绑在一起的脚本,但这不会删除文件夹。我想要一种简单的方法来将项目推送到我的DVS之前清理项目。

What is the BEST way to clear out all the __pycache__ folders and .pyc/.pyo files from a python3 project. I have seen multiple users suggest the pyclean script bundled with Debian, but this does not remove the folders. I want a simple way to clean up the project before pushing the files to my DVS.


回答 0

您可以使用下一条命令手动进行操作:

find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf

这将递归地删除当前目录中的所有* .pyc文件和__pycache__目录。

You can do it manually with the next command:

find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf

This will remove all *.pyc files and __pycache__ directories recursively in the current directory.


回答 1

当我将pyclean输错为pycclean时,我自己找到了答案:

    No command 'pycclean' found, did you mean:
     Command 'py3clean' from package 'python3-minimal' (main)
     Command 'pyclean' from package 'python-minimal' (main)
    pycclean: command not found

运行py3clean .清理它很好。

I found the answer myself when I mistyped pyclean as pycclean:

    No command 'pycclean' found, did you mean:
     Command 'py3clean' from package 'python3-minimal' (main)
     Command 'pyclean' from package 'python-minimal' (main)
    pycclean: command not found

Running py3clean . cleaned it up very nicely.


回答 2

macOS和Linux

BSD find在macOS上的实现不同于GNU find-这与BSD和GNU find兼容。使用-name和的-ofor -将这个函数放入.bashrc文件中,从全局实现开始。

pyclean () {
    find . -type f -name '*.py[co]' -delete -o -type d -name __pycache__ -delete
}

然后cd到您要递归清理的目录,然后键入pyclean

GNU仅查找

这是GNU唯一的解决方案(即Linux)解决方案,但是我觉得使用regex会更好一些:

pyclean () {
    find . -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
}

任何使用Python 3的平台

在Windows上,您甚至可能没有find。但是,您可能确实拥有Python 3,从3.4开始,它具有便捷的pathlib模块:

python3 -Bc "import pathlib; [p.unlink() for p in pathlib.Path('.').rglob('*.py[co]')]"
python3 -Bc "import pathlib; [p.rmdir() for p in pathlib.Path('.').rglob('__pycache__')]"

-B标志告诉Python不要写.pyc文件。(另请参见PYTHONDONTWRITEBYTECODE环境变量。)

上面的滥用列出了对循环的理解,但是使用时python -c,样式是次要的问题。或者,我们可以滥用(例如)__import__

python3 -Bc "for p in __import__('pathlib').Path('.').rglob('*.py[co]'): p.unlink()"
python3 -Bc "for p in __import__('pathlib').Path('.').rglob('__pycache__'): p.rmdir()"

批判答案

最常见的答案是:

find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf

这似乎效率较低,因为它使用了三个过程。find需要一个正则表达式,因此我们不需要单独调用grep。同样,它已经-delete,所以我们并不需要单独调用rm-和违背评论在这里,它只要他们得到凭借正则表达式匹配的清空删除非空目录。

xargs手册页:

find /tmp -depth -name core -type f -delete

在/ tmp目录下或目录下查找名为core的文件并将其删除,但是比上一个示例更有效(因为我们避免了需要使用fork(2)和exec(2)来启动rm,并且不需要额外的xargs流程)。

macOS & Linux

BSD’s find implementation on macOS is different from GNU find – this is compatible with both BSD and GNU find. Start with a globbing implementation, using -name and the -o for or – Put this function in your .bashrc file:

pyclean () {
    find . -type f -name '*.py[co]' -delete -o -type d -name __pycache__ -delete
}

Then cd to the directory you want to recursively clean, and type pyclean.

GNU find-only

This is a GNU find, only (i.e. Linux) solution, but I feel it’s a little nicer with the regex:

pyclean () {
    find . -regex '^.*\(__pycache__\|\.py[co]\)$' -delete
}

Any platform, using Python 3

On Windows, you probably don’t even have find. You do, however, probably have Python 3, which starting in 3.4 has the convenient pathlib module:

python3 -Bc "import pathlib; [p.unlink() for p in pathlib.Path('.').rglob('*.py[co]')]"
python3 -Bc "import pathlib; [p.rmdir() for p in pathlib.Path('.').rglob('__pycache__')]"

The -B flag tells Python not to write .pyc files. (See also the PYTHONDONTWRITEBYTECODE environment variable.)

The above abuses list comprehensions for looping, but when using python -c, style is rather a secondary concern. Alternatively we could abuse (for example) __import__:

python3 -Bc "for p in __import__('pathlib').Path('.').rglob('*.py[co]'): p.unlink()"
python3 -Bc "for p in __import__('pathlib').Path('.').rglob('__pycache__'): p.rmdir()"

Critique of an answer

The top answer used to say:

find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf

This would seem to be less efficient because it uses three processes. find takes a regular expression, so we don’t need a separate invocation of grep. Similarly, it has -delete, so we don’t need a separate invocation of rm —and contrary to a comment here, it will delete non-empty directories so long as they get emptied by virtue of the regular expression match.

From the xargs man page:

find /tmp -depth -name core -type f -delete

Find files named core in or below the directory /tmp and delete them, but more efficiently than in the previous example (because we avoid the need to use fork(2) and exec(2) to launch rm and we don’t need the extra xargs process).


回答 3

由于这是一个Python 3项目,因此您只需要删除__pycache__目录-所有.pyc/ .pyo文件都在其中。

find . -type d -name __pycache__ -exec rm -r {} \+

或更简单的形式

find . -type d -name __pycache__ -delete

出于某种原因对我不起作用(文件已删除,但目录未删除),因此出于完整性考虑,我将两者都包括在内。


另外,如果在受版本控制的目录中执行此操作,则可以告诉RCS __pycache__递归忽略文件夹。然后,在需要的时刻,只需清理所有被忽略的文件。这可能会更方便,因为可能需要清理的不仅仅是余地__pycache__

Since this is a Python 3 project, you only need to delete __pycache__ directories — all .pyc/.pyo files are inside them.

find . -type d -name __pycache__ -exec rm -r {} \+

or its simpler form,

find . -type d -name __pycache__ -delete

which didn’t work for me for some reason (files were deleted but directories weren’t), so I’m including both for the sake of completeness.


Alternatively, if you’re doing this in a directory that’s under revision control, you can tell the RCS to ignore __pycache__ folders recursively. Then, at the required moment, just clean up all the ignored files. This will likely be more convenient because there’ll probably be more to clean up than just __pycache__.


回答 4

这是我的别名,可与Python 2和Python 3一起使用,.pyc .pyo__pycache__递归方式删除所有文件以及目录。

alias pyclean='find . -name "*.py[co]" -o -name __pycache__ -exec rm -rf {} +'

This is my alias that works both with Python 2 and Python 3 removing all .pyc .pyo files as well __pycache__ directories recursively.

alias pyclean='find . -name "*.py[co]" -o -name __pycache__ -exec rm -rf {} +'

回答 5

如果需要永久解决方案以将Python缓存文件保留在项目目录之外:

Python 3.8开始,您可以使用环境变量PYTHONPYCACHEPREFIX为Python定义一个缓存目录。

从Python文档中:

如果设置了该选项,Python将在此路径的镜像目录树中而不是源树中的pycache目录中写入.pyc文件。这等效于指定-X pycache_prefix = PATH选项。

如果./profile将以下行添加到Linux中:

export PYTHONPYCACHEPREFIX="$HOME/.cache/cpython/"

Python不会__pycache__在您的项目目录中创建烦人的目录,而是将所有这些目录放在~/.cache/cpython/

If you need a permanent solution for keeping Python cache files out of your project directories:

Starting with Python 3.8 you can use the environment variable PYTHONPYCACHEPREFIX to define a cache directory for Python.

From the Python docs:

If this is set, Python will write .pyc files in a mirror directory tree at this path, instead of in pycache directories within the source tree. This is equivalent to specifying the -X pycache_prefix=PATH option.

Example

If you add the following line to your ./profile in Linux:

export PYTHONPYCACHEPREFIX="$HOME/.cache/cpython/"

Python won’t create the annoying __pycache__ directories in your project directory, instead it will put all of them under ~/.cache/cpython/


回答 6

我使用的命令:

find . -type d -name "__pycache__" -exec rm -r {} +

说明:

  1. 首先查找__pycache__当前目录中的所有文件夹。

  2. 执行rm -r {} +以上步骤删除每个文件夹({} 表示占位符并+结束命令)

编辑1:

我使用的是Linux,要重用我将以下行添加到~/.bashrc文件中的命令

alias rm-pycache='find . -type d -name  "__pycache__" -exec rm -r {} +'

编辑2: 如果您使用的是VS Code,则无需__pycache__手动删除。您可以将以下代码段添加到settings.json文件中。之后,VS Code将为您隐藏所有__pycache__文件夹

"files.exclude": {
     "**/__pycache__": true
}

希望能帮助到你 !!!

The command I’ve used:

find . -type d -name "__pycache__" -exec rm -r {} +

Explains:

  1. First finds all __pycache__ folders in current directory.

  2. Execute rm -r {} + to delete each folder at step above ({} signify for placeholder and + to end the command)

Edited 1:

I’m using Linux, to reuse the command I’ve added the line below to the ~/.bashrc file

alias rm-pycache='find . -type d -name  "__pycache__" -exec rm -r {} +'

Edited 2: If you’re using VS Code, you don’t need to remove __pycache__ manually. You can add the snippet below to settings.json file. After that, VS Code will hide all __pycache__ folders for you

"files.exclude": {
     "**/__pycache__": true
}

Hope it helps !!!


回答 7

从项目目录中键入以下内容:

删除所有.pyc文件

find . -path "*/*.pyc" -delete

删除所有.pyo文件:

find . -path "*/*.pyo" -delete

最后,要删除所有‘__pycache__’,请输入:

find . -path "*/__pycache__" -type d -exec rm -r {} ';'

如果遇到权限拒绝错误,请在上述所有命令的开头添加sudo

From the project directory type the following:

Deleting all .pyc files

find . -path "*/*.pyc" -delete

Deleting all .pyo files:

find . -path "*/*.pyo" -delete

Finally, to delete all ‘__pycache__’, type:

find . -path "*/__pycache__" -type d -exec rm -r {} ';'

If you encounter permission denied error, add sudo at the begining of all the above command.


回答 8

使用PyCharm

删除Python编译文件

  1. 在中Project Tool Window,右键单击应从中删除Python编译文件的项目或目录。

  2. 在上下文菜单上,选择Clean Python compiled files

.pyc驻留在所选目录中的文件将被静默删除。

Using PyCharm

To remove Python compiled files

  1. In the Project Tool Window, right-click a project or directory, where Python compiled files should be deleted from.

  2. On the context menu, choose Clean Python compiled files.

The .pyc files residing in the selected directory are silently deleted.


回答 9

非常感谢其他答案,基于这些答案,这就是我用于Debian软件包prerm文件的内容:

#!/bin/sh
set -e

deb_package='package-name'
python_package='package_name'

if which pyclean >/dev/null 2>&1; then
    py3clean -p $deb_package
else
    dpkg -L $deb_package | grep ${python_package}$ | while read file
    do
        find ${file} -type d -name __pycache__ -exec rm -r {} \+
    done
fi

Thanks a lot for the other answers, based on them this is what I used for my Debian package’s prerm file:

#!/bin/sh
set -e

deb_package='package-name'
python_package='package_name'

if which pyclean >/dev/null 2>&1; then
    py3clean -p $deb_package
else
    dpkg -L $deb_package | grep ${python_package}$ | while read file
    do
        find ${file} -type d -name __pycache__ -exec rm -r {} \+
    done
fi

回答 10

为什么不只是使用rm -rf __pycache__git add -A然后运行以将其从存储库中删除,然后添加__pycache__/到您的.gitignore文件中。

Why not just use rm -rf __pycache__? Run git add -A afterwards to remove them from your repository and add __pycache__/ to your .gitignore file.


回答 11

请直接到您的终端,然后输入:

$rm __pycache__

它将被删除。

Please just go to your terminal then type:

$rm __pycache__

and it will be removed.