标签归档:python-3.x

如何从字符串中删除所有空格

问题:如何从字符串中删除所有空格

如何删除python字符串中的所有空格?例如,我希望将一个字符串strip my spaces转换成stripmyspaces,但是我似乎无法通过以下方式完成此操作strip()

>>> 'strip my spaces'.strip()
'strip my spaces'

How do I strip all the spaces in a python string? For example, I want a string like strip my spaces to be turned into stripmyspaces, but I cannot seem to accomplish that with strip():

>>> 'strip my spaces'.strip()
'strip my spaces'

回答 0

利用没有sep参数的str.split的行为:

>>> s = " \t foo \n bar "
>>> "".join(s.split())
'foobar'

如果只想删除空格而不是所有空格:

>>> s.replace(" ", "")
'\tfoo\nbar'

过早的优化

尽管效率不是主要目标(编写清晰的代码是),但以下是一些初始时间:

$ python -m timeit '"".join(" \t foo \n bar ".split())'
1000000 loops, best of 3: 1.38 usec per loop
$ python -m timeit -s 'import re' 're.sub(r"\s+", "", " \t foo \n bar ")'
100000 loops, best of 3: 15.6 usec per loop

请注意,正则表达式已缓存,因此它没有您想象的那么慢。编译事前帮助一些,但在实践中,如果你把这个只会重要很多倍:

$ python -m timeit -s 'import re; e = re.compile(r"\s+")' 'e.sub("", " \t foo \n bar ")'
100000 loops, best of 3: 7.76 usec per loop

即使re.sub慢了11.3倍,但请记住,您的瓶颈肯定会在其他地方。大多数程序不会注意到这三个选择之间的区别。

Taking advantage of str.split’s behavior with no sep parameter:

>>> s = " \t foo \n bar "
>>> "".join(s.split())
'foobar'

If you just want to remove spaces instead of all whitespace:

>>> s.replace(" ", "")
'\tfoo\nbar'

Premature optimization

Even though efficiency isn’t the primary goal—writing clear code is—here are some initial timings:

$ python -m timeit '"".join(" \t foo \n bar ".split())'
1000000 loops, best of 3: 1.38 usec per loop
$ python -m timeit -s 'import re' 're.sub(r"\s+", "", " \t foo \n bar ")'
100000 loops, best of 3: 15.6 usec per loop

Note the regex is cached, so it’s not as slow as you’d imagine. Compiling it beforehand helps some, but would only matter in practice if you call this many times:

$ python -m timeit -s 'import re; e = re.compile(r"\s+")' 'e.sub("", " \t foo \n bar ")'
100000 loops, best of 3: 7.76 usec per loop

Even though re.sub is 11.3x slower, remember your bottlenecks are assuredly elsewhere. Most programs would not notice the difference between any of these 3 choices.


回答 1

>>> import re
>>> re.sub(r'\s+', '', 'strip my spaces')
'stripmyspaces'

还可以处理您不会想到的所有空白字符(相信我,有很多)。

For Python 3:

>>> import re
>>> re.sub(r'\s+', '', 'strip my \n\t\r ASCII and \u00A0 \u2003 Unicode spaces')
'stripmyASCIIandUnicodespaces'
>>> # Or, depending on the situation:
>>> re.sub(r'(\s|\u180B|\u200B|\u200C|\u200D|\u2060|\uFEFF)+', '', \
... '\uFEFF\t\t\t strip all \u000A kinds of \u200B whitespace \n')
'stripallkindsofwhitespace'

…handles any whitespace characters that you’re not thinking of – and believe us, there are plenty.

\s on its own always covers the ASCII whitespace:

  • (regular) space
  • tab
  • new line (\n)
  • carriage return (\r)
  • form feed
  • vertical tab

Additionally:

  • for Python 2 with re.UNICODE enabled,
  • for Python 3 without any extra actions,

\s also covers the Unicode whitespace characters, for example:

  • non-breaking space,
  • em space,
  • ideographic space,

…etc. See the full list here, under “Unicode characters with White_Space property”.

However \s DOES NOT cover characters not classified as whitespace, which are de facto whitespace, such as among others:

  • zero-width joiner,
  • Mongolian vowel separator,
  • zero-width non-breaking space (a.k.a. byte order mark),

…etc. See the full list here, under “Related Unicode characters without White_Space property”.

So these 6 characters are covered by the list in the second regex, \u180B|\u200B|\u200C|\u200D|\u2060|\uFEFF.

Sources:


回答 2

或者,

"strip my spaces".translate( None, string.whitespace )

这是Python3版本:

"strip my spaces".translate(str.maketrans('', '', string.whitespace))

Alternatively,

"strip my spaces".translate( None, string.whitespace )

And here is Python3 version:

"strip my spaces".translate(str.maketrans('', '', string.whitespace))

回答 3

最简单的方法是使用replace:

"foo bar\t".replace(" ", "").replace("\t", "")

或者,使用正则表达式:

import re
re.sub(r"\s", "", "foo bar\t")

The simplest is to use replace:

"foo bar\t".replace(" ", "").replace("\t", "")

Alternatively, use a regular expression:

import re
re.sub(r"\s", "", "foo bar\t")

回答 4

在Python中删除起始空间

string1="    This is Test String to strip leading space"
print string1
print string1.lstrip()

在Python中删除尾随或结尾空格

string2="This is Test String to strip trailing space     "
print string2
print string2.rstrip()

在Python中从字符串的开头和结尾删除空格

string3="    This is Test String to strip leading and trailing space      "
print string3
print string3.strip()

删除python中的所有空格

string4="   This is Test String to test all the spaces        "
print string4
print string4.replace(" ", "")

Remove the Starting Spaces in Python

string1="    This is Test String to strip leading space"
print string1
print string1.lstrip()

Remove the Trailing or End Spaces in Python

string2="This is Test String to strip trailing space     "
print string2
print string2.rstrip()

Remove the whiteSpaces from Beginning and end of the string in Python

string3="    This is Test String to strip leading and trailing space      "
print string3
print string3.strip()

Remove all the spaces in python

string4="   This is Test String to test all the spaces        "
print string4
print string4.replace(" ", "")

回答 5

尝试使用regex re.sub。您可以搜索所有空格并替换为空字符串。

\s模式中的匹配空格字符-不仅是空格(制表符,换行符等)。您可以在手册中了解更多信息。

Try a regex with re.sub. You can search for all whitespace and replace with an empty string.

\s in your pattern will match whitespace characters – and not just a space (tabs, newlines, etc). You can read more about it in the manual.


回答 6

import re
re.sub(' ','','strip my spaces')
import re
re.sub(' ','','strip my spaces')

回答 7

如Roger Pate所述,以下代码为我工作:

s = " \t foo \n bar "
"".join(s.split())
'foobar'

我正在使用Jupyter Notebook运行以下代码:

i=0
ProductList=[]
while i < len(new_list): 
   temp=''                            # new_list[i]=temp=' Plain   Utthapam  '
   #temp=new_list[i].strip()          #if we want o/p as: 'Plain Utthapam'
   temp="".join(new_list[i].split())  #o/p: 'PlainUtthapam' 
   temp=temp.upper()                  #o/p:'PLAINUTTHAPAM' 
   ProductList.append(temp)
   i=i+2

As mentioned by Roger Pate following code worked for me:

s = " \t foo \n bar "
"".join(s.split())
'foobar'

I am using Jupyter Notebook to run following code:

i=0
ProductList=[]
while i < len(new_list): 
   temp=''                            # new_list[i]=temp=' Plain   Utthapam  '
   #temp=new_list[i].strip()          #if we want o/p as: 'Plain Utthapam'
   temp="".join(new_list[i].split())  #o/p: 'PlainUtthapam' 
   temp=temp.upper()                  #o/p:'PLAINUTTHAPAM' 
   ProductList.append(temp)
   i=i+2

回答 8

可以使用过滤列表的标准技术,尽管它们不如split/jointranslate方法有效。

我们需要一组空格:

>>> import string
>>> ws = set(string.whitespace)

filter内置:

>>> "".join(filter(lambda c: c not in ws, "strip my spaces"))
'stripmyspaces'

列表理解(是,请使用方括号:请参见下面的基准):

>>> import string
>>> "".join([c for c in "strip my spaces" if c not in ws])
'stripmyspaces'

折:

>>> import functools
>>> "".join(functools.reduce(lambda acc, c: acc if c in ws else acc+c, "strip my spaces"))
'stripmyspaces'

基准测试:

>>> from timeit import timeit
>>> timeit('"".join("strip my spaces".split())')
0.17734256500003198
>>> timeit('"strip my spaces".translate(ws_dict)', 'import string; ws_dict = {ord(ws):None for ws in string.whitespace}')
0.457635745999994
>>> timeit('re.sub(r"\s+", "", "strip my spaces")', 'import re')
1.017787621000025

>>> SETUP = 'import string, operator, functools, itertools; ws = set(string.whitespace)'
>>> timeit('"".join([c for c in "strip my spaces" if c not in ws])', SETUP)
0.6484303600000203
>>> timeit('"".join(c for c in "strip my spaces" if c not in ws)', SETUP)
0.950212219999969
>>> timeit('"".join(filter(lambda c: c not in ws, "strip my spaces"))', SETUP)
1.3164566040000523
>>> timeit('"".join(functools.reduce(lambda acc, c: acc if c in ws else acc+c, "strip my spaces"))', SETUP)
1.6947649049999995

The standard techniques to filter a list apply, although they are not as efficient as the split/join or translate methods.

We need a set of whitespaces:

>>> import string
>>> ws = set(string.whitespace)

The filter builtin:

>>> "".join(filter(lambda c: c not in ws, "strip my spaces"))
'stripmyspaces'

A list comprehension (yes, use the brackets: see benchmark below):

>>> import string
>>> "".join([c for c in "strip my spaces" if c not in ws])
'stripmyspaces'

A fold:

>>> import functools
>>> "".join(functools.reduce(lambda acc, c: acc if c in ws else acc+c, "strip my spaces"))
'stripmyspaces'

Benchmark:

>>> from timeit import timeit
>>> timeit('"".join("strip my spaces".split())')
0.17734256500003198
>>> timeit('"strip my spaces".translate(ws_dict)', 'import string; ws_dict = {ord(ws):None for ws in string.whitespace}')
0.457635745999994
>>> timeit('re.sub(r"\s+", "", "strip my spaces")', 'import re')
1.017787621000025

>>> SETUP = 'import string, operator, functools, itertools; ws = set(string.whitespace)'
>>> timeit('"".join([c for c in "strip my spaces" if c not in ws])', SETUP)
0.6484303600000203
>>> timeit('"".join(c for c in "strip my spaces" if c not in ws)', SETUP)
0.950212219999969
>>> timeit('"".join(filter(lambda c: c not in ws, "strip my spaces"))', SETUP)
1.3164566040000523
>>> timeit('"".join(functools.reduce(lambda acc, c: acc if c in ws else acc+c, "strip my spaces"))', SETUP)
1.6947649049999995

回答 9

TL / DR

该解决方案已使用Python 3.6进行了测试

要在Python3中从字符串中去除所有空格,可以使用以下函数:

def remove_spaces(in_string: str):
    return in_string.translate(str.maketrans({' ': ''})

要删除任何空格字符(’\ t \ n \ r \ x0b \ x0c’),可以使用以下功能:

import string
def remove_whitespace(in_string: str):
    return in_string.translate(str.maketrans(dict.fromkeys(string.whitespace)))

说明

Python的str.translate方法是str的内置类方法,它获取一个表并返回字符串的副本,其中每个字符都通过传递的转换表进行映射。str.translate的完整文档

使用创建转换表str.maketrans。此方法是的另一个内置类方法str。在这里,我们仅将其与一个参数一起使用,在本例中为字典,其中的键是要替换的字符,映射到具有字符替换值的值。它返回一个转换表以与一起使用str.translatestr.maketrans的完整文档

stringpython中的模块包含一些常见的字符串操作和常量。string.whitespace是一个常量,它返回一个字符串,其中包含所有被视为空格的ASCII字符。这包括字符空格,制表符,换行符,返回符,换页符和垂直制表符。字符串的完整文档

在第二个函数dict.fromkeys中,用于创建字典,其中的键是string.whitespace每个带有value 的字符串返回的字符Nonedict.fromkeys的完整文档

TL/DR

This solution was tested using Python 3.6

To strip all spaces from a string in Python3 you can use the following function:

def remove_spaces(in_string: str):
    return in_string.translate(str.maketrans({' ': ''})

To remove any whitespace characters (‘ \t\n\r\x0b\x0c’) you can use the following function:

import string
def remove_whitespace(in_string: str):
    return in_string.translate(str.maketrans(dict.fromkeys(string.whitespace)))

Explanation

Python’s str.translate method is a built-in class method of str, it takes a table and returns a copy of the string with each character mapped through the passed translation table. Full documentation for str.translate

To create the translation table str.maketrans is used. This method is another built-in class method of str. Here we use it with only one parameter, in this case a dictionary, where the keys are the characters to be replaced mapped to values with the characters replacement value. It returns a translation table for use with str.translate. Full documentation for str.maketrans

The string module in python contains some common string operations and constants. string.whitespace is a constant which returns a string containing all ASCII characters that are considered whitespace. This includes the characters space, tab, linefeed, return, formfeed, and vertical tab.Full documentation for string

In the second function dict.fromkeys is used to create a dictionary where the keys are the characters in the string returned by string.whitespace each with value None. Full documentation for dict.fromkeys


回答 10

如果不是最佳性能的要求,而您只想简单地做一些事情,则可以使用字符串类的内置“ isspace”方法定义一个基本函数来测试每个字符:

def remove_space(input_string):
    no_white_space = ''
    for c in input_string:
        if not c.isspace():
            no_white_space += c
    return no_white_space

no_white_space这种方式构建字符串将不会具有理想的性能,但是解决方案很容易理解。

>>> remove_space('strip my spaces')
'stripmyspaces'

如果您不想定义一个函数,则可以将其转换为与列表理解相似的东西。从最佳答案的join解决方案中借用:

>>> "".join([c for c in "strip my spaces" if not c.isspace()])
'stripmyspaces'

If optimal performance is not a requirement and you just want something dead simple, you can define a basic function to test each character using the string class’s built in “isspace” method:

def remove_space(input_string):
    no_white_space = ''
    for c in input_string:
        if not c.isspace():
            no_white_space += c
    return no_white_space

Building the no_white_space string this way will not have ideal performance, but the solution is easy to understand.

>>> remove_space('strip my spaces')
'stripmyspaces'

If you don’t want to define a function, you can convert this into something vaguely similar with list comprehension. Borrowing from the top answer’s join solution:

>>> "".join([c for c in "strip my spaces" if not c.isspace()])
'stripmyspaces'

找不到满足需求张量流的版本

问题:找不到满足需求张量流的版本

我安装了最新版本的Python (3.6.4 64-bit)和最新版本的PyCharm (2017.3.3 64-bit)。然后我在PyCharm中安装了一些模块(Numpy,Pandas等),但是当我尝试安装Tensorflow时却没有安装,并且出现了错误消息:

找不到满足TensorFlow要求的版本(来自版本:)找不到与TensorFlow匹配的发行版。

然后我尝试从命令提示符下安装TensorFlow,并得到了相同的错误消息。但是,我确实成功安装了tflearn。

我还安装了Python 2.7,但又收到了相同的错误消息。我搜索了该错误,并尝试了一些建议给其他人的方法,但是没有任何效果(包括安装Flask)。

我该如何安装Tensorflow?谢谢。

I installed the latest version of Python (3.6.4 64-bit) and the latest version of PyCharm (2017.3.3 64-bit). Then I installed some modules in PyCharm (Numpy, Pandas, etc), but when I tried installing Tensorflow it didn’t install, and I got the error message:

Could not find a version that satisfies the requirement TensorFlow (from versions: ) No matching distribution found for TensorFlow.

Then I tried installing TensorFlow from the command prompt and I got the same error message. I did however successfully install tflearn.

I also installed Python 2.7, but I got the same error message again. I googled the error and tried some of the things which were suggested to other people, but nothing worked (this included installing Flask).

How can I install Tensorflow? Thanks.


回答 0

截至2018年8月13日的Tensorflow支持Python 3.6.x和仅64位版本。

As of October 2020:

  • Tensorflow only supports the 64-bit version of Python

  • Tensorflow only supports Python 3.5 to 3.8

So, if you’re using an out-of-range version of Python (older or newer) or a 32-bit version, then you’ll need to use a different version.


回答 1

安装Tensorflow有两个重要规则:

  • 您必须安装Python x64。它在32b上不起作用,并且给出与您相同的错误。

  • 支持最新版本的Python3 = 3.7。

例如,您可以安装Python3.6.2-64bit,它的工作原理类似于Charm。

更新资料

据说在评论中,它可以在x64版本的Python3.8中使用。

There are a few important rules to install Tensorflow:

  • You have to install Python x64. It doesn’t work on 32b and it gives the same error as yours.

  • It doesn’t support Python versions later than 3.8 and Python 3.8 requires TensorFlow 2.2 or later.

For example, you can install Python3.8.6-64bit and it works like a charm.


回答 2

我成功安装了 pip install https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.8.0-py3-none-any.whl

I installed it successfully by pip install https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.8.0-py3-none-any.whl


回答 3

如果您使用anaconda,则默认情况下会安装python 3.7,因此您必须将其降级为3.6:

康达安装python = 3.6

然后:

点安装tensorflow

它在Ubuntu中为我工作。

if you are using anaconda, python 3.7 is installed by default, so you have to downgrade it to 3.6:

conda install python=3.6

then:

pip install tensorflow

it worked for me in Ubuntu.


回答 4

我正在为Windows提供它

如果您使用的是python-3

  1. 使用以下命令将pip升级到最新版本 py -m pip install --upgrade pip
  2. 使用安装软件包 py -m pip install <package-name>

如果您使用的是python-2

  1. 使用以下命令将pip升级到最新版本 py -2 -m pip install --upgrade pip
  2. 使用安装软件包 py -2 -m pip install <package-name>

对我有用

I am giving it for Windows

If you are using python-3

  1. Upgrade pip to the latest version using py -m pip install --upgrade pip
  2. Install package using py -m pip install <package-name>

If you are using python-2

  1. Upgrade pip to the latest version using py -2 -m pip install --upgrade pip
  2. Install package using py -2 -m pip install <package-name>

It worked for me


回答 5

根据Tensorflow python 3.8文档页面(截至2019年12月4日),该版本不可用。您将必须降级到python 3.7

Tensorflow isn’t available for python 3.8 (as of Dec 4th 2019) according to their documentation page. You will have to downgrade to python 3.7.


回答 6

卸载Python然后重新安装解决了我的问题,并且我能够成功安装TensorFlow。

Uninstalling Python and then reinstalling solved my issue and I was able to successfully install TensorFlow.


回答 7

不支持Python版本卸载python

https://www.python.org/downloads/release/python-362/

您应该在安装页面中检查并使用确切的版本。 https://www.tensorflow.org/install/install_windows

python 3.6.2或python 3.5.2为我解决了这个问题

Python version is not supported Uninstall python

https://www.python.org/downloads/release/python-362/

You should check and use the exact version in install page. https://www.tensorflow.org/install/install_windows

python 3.6.2 or python 3.5.2 solved this issue for me


回答 8

Tensorflow 2.2.0支持Python3.8

首先,请确保安装Python 3.8 64bit。出于某种原因,官方网站默认为32位。使用python -VV(两个大写字母V,不是W)验证此内容。然后照常继续:

python -m pip install --upgrade pip
python -m pip install wheel  # not necessary
python -m pip install tensorflow

与往常一样,请确保已安装CUDA 10.1和CuDNN。

Tensorflow 2.2.0 supports Python3.8

First, make sure to install Python 3.8 64bit. For some reason, the official site defaults to 32bit. Verify this using python -VV (two capital V, not W). Then continue as usual:

python -m pip install --upgrade pip
python -m pip install wheel  # not necessary
python -m pip install tensorflow

As usual, make sure you have CUDA 10.1 and CuDNN installed.


回答 9

看起来问题出在Python 3.8。请改用Python 3.7。我已采取步骤解决此问题。

  • 使用conda创建了python 3.7环境
  • 列表项在环境中使用pip install rasa安装了rasa。

为我工作。

Looks like the problem is with Python 3.8. Use Python 3.7 instead. Steps I took to solve this.

  • Created a python 3.7 environment with conda
  • List item Installed rasa using pip install rasa within the environment.

Worked for me.


回答 10

我在ubunu 18.04上使用python 3.6.8,对我来说解决方案是只升级pip

pip install --upgrade pip
pip install tensorflow==2.1.0

I am using python 3.6.8, on ubunu 18.04, for me the solution was to just upgrade pip

pip install --upgrade pip
pip install tensorflow==2.1.0

回答 11

Tensorflow似乎需要特殊版本的工具和库。Pip仅负责python版本。

要以专业的方式处理此问题(意味着它为我和其他人节省了Tremendos的时间),您必须为每个这样的软件设置一个特殊的环境。

为此,conda是一种高级工具。

我使用以下命令安装了Tensorflow:

sudo apt安装python3

sudo update-alternatives –install / usr / bin / python python / usr / bin / python3 1

sudo apt安装python3-pip

须藤apt-get install curl

卷曲https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh > Miniconda3-latest-Linux-x86_64.sh

bash Miniconda3-最新-Linux-x86_64.sh

来源〜/ .bashrc

  • 安装自己的phyton等

纳米.bashrc

  • 也许在这里插入您的代理等。

conda创建–name your_name python = 3

conda激活your_name

conda安装-c conda-forge tensorflow

  • 检查一切顺利

python -c“将tensorflow导入为tf; tf.enable_eager_execution(); print(tf.reduce_sum(tf.random_normal([1000,1000])))”“

PS:一些可能有助于conda搜索tensorflow的命令

https://www.tensorflow.org/install/pip

使用virtualenv。康达更胜任。迷你主义者就足够了;不需要完整的conda

Tensorflow seems to need special versions of tools and libs. Pip only takes care of python version.

To handle this in a professional way (means it save tremendos time for me and others) you have to set a special environment for each software like this.

An advanced tool for this is conda.

I installed Tensorflow with this commands:

sudo apt install python3

sudo update-alternatives –install /usr/bin/python python /usr/bin/python3 1

sudo apt install python3-pip

sudo apt-get install curl

curl https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh > Miniconda3-latest-Linux-x86_64.sh

bash Miniconda3-latest-Linux-x86_64.sh

yes

source ~/.bashrc

  • installs its own phyton etc

nano .bashrc

  • maybe insert here your proxies etc.

conda create –name your_name python=3

conda activate your_name

conda install -c conda-forge tensorflow

  • check everything went well

python -c “import tensorflow as tf; tf.enable_eager_execution(); print(tf.reduce_sum(tf.random_normal([1000, 1000])))”

PS: some commands that may be helpful conda search tensorflow

https://www.tensorflow.org/install/pip

uses virtualenv. Conda is more capable. Miniconda ist sufficient; the full conda is not necessary


回答 12

tensorflow安装为我解决之前运行此命令:

pip install "pip>=19"

正如tensorflow的系统要求所述:

点19.0或更高版本

Running this before the tensorflow installation solved it for me:

pip install "pip>=19"

As the tensorflow‘s system requirements states:

pip 19.0 or later


回答 13

使用python 3.6或3.7版本,但重要的是您应该安装python版本的64位。

use python version 3.6 or 3.7 but the important thing is you should install the python version of 64-bit.


回答 14

对于TensorFlow 2.2版本:

  1. 确保您拥有python 3.8

尝试: python --version

要么 python3 --version

要么 py --version

  1. 升级python版本3.8的pip

尝试: python3 -m pip install --upgrade pip

要么 python -m pip install --upgrade pip

要么 py -m pip install --upgrade pip

  1. 安装TensorFlow:

尝试: python3 -m pip install TensorFlow

要么 python -m pip install TensorFlow

要么 py -m pip install TensorFlow

  1. 确保使用正确的python运行文件:

尝试: python3 file.py

要么 python file.py

要么 py file.py

For version TensorFlow 2.2:

  1. Make sure you have python 3.8

try: python --version

or python3 --version

or py --version

  1. Upgrade the pip of the python which has version 3.8

try: python3 -m pip install --upgrade pip

or python -m pip install --upgrade pip

or py -m pip install --upgrade pip

  1. Install TensorFlow:

try: python3 -m pip install TensorFlow

or python -m pip install TensorFlow

or py -m pip install TensorFlow

  1. Make sure to run the file with the correct python:

try: python3 file.py

or python file.py

or py file.py


回答 15

通过一一安装所需的所有软件包,我解决了与python 3.7相同的问题

步骤如下:

  1. 安装套件
  2. 请参阅错误消息:

    找不到满足要求的版本-所需模块的名称

  3. 安装所需的模块。通常,安装所需的模块需要安装另一个模块,以及另一个模块-其他两个模块,依此类推。

这样,我安装了30多个软件包,并有所帮助。现在我有了python 3.7中最新版本的tensorflow,而不必降级内核。

I solved the same problem with python 3.7 by installing one by one all the packages required

Here are the steps:

  1. Install the package
  2. See the error message:

    couldn’t find a version that satisfies the requirement — the name of the module required

  3. Install the module required. Very often, installation of the required module requires the installation of another module, and another module – a couple of the others and so on.

This way I installed more than 30 packages and it helped. Now I have tensorflow of the latest version in Python 3.7 and didn’t have to downgrade the kernel.


相对导入-ModuleNotFoundError:没有名为x的模块

问题:相对导入-ModuleNotFoundError:没有名为x的模块

这是我第一次真正坐下来尝试python 3,但似乎失败了。我有以下两个文件:

  1. test.py
  2. config.py

config.py中定义了一些函数以及一些变量。我将其简化为以下内容:

config.py

debug = True

test.py

import config
print (config.debug)

我也有一个 __init__.py

但是,出现以下错误:

ModuleNotFoundError: No module named 'config'

我知道py3约定要使用绝对导入:

from . import config

但是,这导致以下错误:

ImportError: cannot import name 'config'

因此,我对此无所适从……任何帮助将不胜感激。:)

This is the first time I’ve really sat down and tried python 3, and seem to be failing miserably. I have the following two files:

  1. test.py
  2. config.py

config.py has a few functions defined in it as well as a few variables. I’ve stripped it down to the following:

config.py

debug = True

test.py

import config
print (config.debug)

I also have an __init__.py

However, I’m getting the following error:

ModuleNotFoundError: No module named 'config'

I’m aware that the py3 convention is to use absolute imports:

from . import config

However, this leads to the following error:

ImportError: cannot import name 'config'

So I’m at a loss as to what to do here… Any help is greatly appreciated. :)


回答 0

TL; DR:由于模块不是包的一部分,因此无法从执行的文件中进行相对导入__main__

绝对导入 -导入可用的内容sys.path

相对导入 -相对于当前模块的导入,必须是包的一部分

如果您以完全相同的方式运行两个变体,则其中一个应该可以工作。无论如何,这是一个示例,应该可以帮助您了解正在发生的事情,让我们添加main.py具有总体目录结构的另一个文件,如下所示:

.
./main.py
./ryan/__init__.py
./ryan/config.py
./ryan/test.py

让我们更新test.py以查看发生了什么:

# config.py
debug = True


# test.py
print(__name__)

try:
    # Trying to find module in the parent package
    from . import config
    print(config.debug)
    del config
except ImportError:
    print('Relative import failed')

try:
    # Trying to find module on sys.path
    import config
    print(config.debug)
except ModuleNotFoundError:
    print('Absolute import failed')
# main.py
import ryan.test

让我们先运行test.py:

$ python ryan/test.py
__main__
Relative import failed
True

这里的“测试” __main__模块,不知道属于什么包。但是import config应该可以,因为该ryan文件夹将被添加到sys.path中。

让我们运行main.py代替:

$ python main.py
ryan.test
True
Absolute import failed

这里的测试在“ ryan”包中,可以执行相对的导入。import config失败,因为Python 3中不允许隐式相对导入。

希望这会有所帮助。

PS:如果您坚持使用Python 3,则__init__.py文件中不再需要。

TL;DR: You can’t do relative imports from the file you execute since __main__ module is not a part of a package.

Absolute imports – import something available on sys.path

Relative imports – import something relative to the current module, must be a part of a package

If you’re running both variants in exactly the same way, one of them should work. Here is an example that should help you understand what’s going on. Let’s add another main.py file with the overall directory structure like this:

.
./main.py
./ryan/__init__.py
./ryan/config.py
./ryan/test.py

And let’s update test.py to see what’s going on:

# config.py
debug = True
# test.py
print(__name__)

try:
    # Trying to find module in the parent package
    from . import config
    print(config.debug)
    del config
except ImportError:
    print('Relative import failed')

try:
    # Trying to find module on sys.path
    import config
    print(config.debug)
except ModuleNotFoundError:
    print('Absolute import failed')
# main.py
import ryan.test

Let’s run test.py first:

$ python ryan/test.py
__main__
Relative import failed
True

Here “test” is the __main__ module and doesn’t know anything about belonging to a package. However import config should work, since the ryan folder will be added to sys.path.

Let’s run main.py instead:

$ python main.py
ryan.test
True
Absolute import failed

And here test is inside of the “ryan” package and can perform relative imports. import config fails since implicit relative imports are not allowed in Python 3.

Hope this helped.

P.S.: If you’re sticking with Python 3 there is no more need for __init__.py files.


回答 1

我想到了。非常令人沮丧,尤其是来自python2。

.无论模块是相对的还是绝对的,都必须向模块添加a 。

我创建目录设置如下。

/main.py
--/lib
  --/__init__.py
  --/mody.py
  --/modx.py

修改器

def does_something():
    return "I gave you this string."

from modx import does_something

def loaded():
    string = does_something()
    print(string)

main.py

from lib import mody

mody.loaded()

当我执行main时,会发生这种情况

$ python main.py
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    from lib import mody
  File "/mnt/c/Users/Austin/Dropbox/Source/Python/virtualenviron/mock/package/lib/mody.py", line 1, in <module>
    from modx import does_something
ImportError: No module named 'modx'

我运行了2to3,核心输出是

RefactoringTool: Refactored lib/mody.py
--- lib/mody.py (original)
+++ lib/mody.py (refactored)
@@ -1,4 +1,4 @@
-from modx import does_something
+from .modx import does_something

 def loaded():
     string = does_something()
RefactoringTool: Files that need to be modified:
RefactoringTool: lib/modx.py
RefactoringTool: lib/mody.py

我不得不修改mody.py的import语句来修复它

try:
    from modx import does_something
except ImportError:
    from .modx import does_something


def loaded():
    string = does_something()
    print(string)

然后我再次运行main.py并获得了预期的输出

$ python main.py
I gave you this string.

最后,只是清理一下并使其在2到3之间可移植。

from __future__ import absolute_import
from .modx import does_something

I figured it out. Very frustrating, especially coming from python2.

You have to add a . to the module, regardless of whether or not it is relative or absolute.

I created the directory setup as follows.

/main.py
--/lib
  --/__init__.py
  --/mody.py
  --/modx.py

modx.py

def does_something():
    return "I gave you this string."

mody.py

from modx import does_something

def loaded():
    string = does_something()
    print(string)

main.py

from lib import mody

mody.loaded()

when I execute main, this is what happens

$ python main.py
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    from lib import mody
  File "/mnt/c/Users/Austin/Dropbox/Source/Python/virtualenviron/mock/package/lib/mody.py", line 1, in <module>
    from modx import does_something
ImportError: No module named 'modx'

I ran 2to3, and the core output was this

RefactoringTool: Refactored lib/mody.py
--- lib/mody.py (original)
+++ lib/mody.py (refactored)
@@ -1,4 +1,4 @@
-from modx import does_something
+from .modx import does_something

 def loaded():
     string = does_something()
RefactoringTool: Files that need to be modified:
RefactoringTool: lib/modx.py
RefactoringTool: lib/mody.py

I had to modify mody.py’s import statement to fix it

try:
    from modx import does_something
except ImportError:
    from .modx import does_something


def loaded():
    string = does_something()
    print(string)

Then I ran main.py again and got the expected output

$ python main.py
I gave you this string.

Lastly, just to clean it up and make it portable between 2 and 3.

from __future__ import absolute_import
from .modx import does_something

回答 2

设置PYTHONPATH也可以解决此问题。

这是在Windows上可以完成的方法

set PYTHONPATH=.

Setting PYTHONPATH can also help with this problem.

Here is how it can be done on Windows

set PYTHONPATH=.


回答 3

您必须将模块的路径附加到PYTHONPATH


对于UNIX(Linux,OSX等)

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"

对于Windows

set PYTHONPATH=%PYTHONPATH%;C:\path\to\your\module\

You have to append your project’s path to PYTHONPATH and make sure to use absolute imports.


For UNIX (Linux, OSX, …)

export PYTHONPATH="${PYTHONPATH}:/path/to/your/project/"

For Windows

set PYTHONPATH=%PYTHONPATH%;C:\path\to\your\project\

Absolute imports

Assuming that we have the following project structure,

└── myproject
    ├── mypackage
    │   ├── a.py
    └── anotherpackage
        ├── b.py
        ├── c.py
        └── mysubpackage
            └── d.py

just make sure to reference each import starting from the project’s root directory. For instance,

# in module a.py
import anotherpackage.mysubpackage.d

# in module b
import anotherpackage.c
import mypackage.a

回答 4

试过你的例子

from . import config

得到了以下SystemError:
/usr/bin/python3.4 test.py
Traceback(最近一次调用最近):
文件“ test.py”,第1行,位于
中。导入配置
SystemError:父模块“”未加载,无法执行相对导入


这对我有用:

import config
print('debug=%s'%config.debug)

>>>debug=True

使用Python:3.4.2测试-PyCharm 2016.3.2


除了此PyCharm,您还可以导入该名称
您必须单击,config然后出现帮助图标

Tried your example

from . import config

got the following SystemError:
/usr/bin/python3.4 test.py
Traceback (most recent call last):
File “test.py”, line 1, in
from . import config
SystemError: Parent module ” not loaded, cannot perform relative import


This will work for me:

import config
print('debug=%s'%config.debug)

>>>debug=True

Tested with Python:3.4.2 – PyCharm 2016.3.2


Beside this PyCharm offers you to Import this name.
You hav to click on config and a help icon appears.


回答 5

您只需将以下文件添加到测试目录中,然后python将在测试之前运行它

__init__.py file

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

You can simply add following file to your tests directory, and then python will run it before the tests

__init__.py file

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

回答 6

PYTHONPATH在根项目目录中设置环境变量。

考虑类UNIX:

export PYTHONPATH=.

Set PYTHONPATH environment variable in root project directory.

Considering UNIX-like:

export PYTHONPATH=.

回答 7

此示例在Python 3.6上有效。

我建议进入Run -> Edit ConfigurationsPyCharm,删除那里的所有条目,然后尝试再次通过PyCharm运行代码。

如果这不起作用,请检查项目解释器(“设置”->“项目解释器”)并运行默认配置(“运行”->“编辑配置…”)。

This example works on Python 3.6.

I suggest going to Run -> Edit Configurations in PyCharm, deleting any entries there, and trying to run the code through PyCharm again.

If that doesn’t work, check your project interpreter (Settings -> Project Interpreter) and run configuration defaults (Run -> Edit Configurations…).


回答 8

在调用模块之前,声明正确的sys.path列表:

import os, sys

#'/home/user/example/parent/child'
current_path = os.path.abspath('.')

#'/home/user/example/parent'
parent_path = os.path.dirname(current_path)

sys.path.append(parent_path)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'child.settings')

Declare correct sys.path list before you call module:

import os, sys

#'/home/user/example/parent/child'
current_path = os.path.abspath('.')

#'/home/user/example/parent'
parent_path = os.path.dirname(current_path)

sys.path.append(parent_path)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'child.settings')

回答 9

如原始帖子的评论中所述,这似乎是我出于任何原因使用的python解释器的问题,而不是python脚本出了点问题。我从WinPython包切换到了python.org上的官方python 3.6,它工作得很好。感谢大家的帮助:)

As was stated in the comments to the original post, this seemed to be an issue with the python interpreter I was using for whatever reason, and not something wrong with the python scripts. I switched over from the WinPython bundle to the official python 3.6 from python.org and it worked just fine. thanks for the help everyone :)


回答 10

如果您使用的是python 3+,请尝试添加以下行

import os, sys
dir_path = os.path.dirname(os.path.realpath(__file__))
parent_dir_path = os.path.abspath(os.path.join(dir_path, os.pardir))
sys.path.insert(0, parent_dir_path)

If you are using python 3+ then try adding below lines

import os, sys
dir_path = os.path.dirname(os.path.realpath(__file__))
parent_dir_path = os.path.abspath(os.path.join(dir_path, os.pardir))
sys.path.insert(0, parent_dir_path)

回答 11

尝试

from . import config

这是从同一文件夹级别导入的。如果您直接尝试导入,则假定它是下属

Try

from . import config

What that does is import from the same folder level. If you directly try to import it assumes it’s a subordinate


Python 3将范围转换为列表

问题:Python 3将范围转换为列表

我正在尝试列出其中的数字1-1000。显然,这会令人烦恼,因此我试图创建一个包含范围的列表。在Python 2中,似乎:

some_list = range(1,1000)

本来可以用,但是在Python 3中,范围类似于xrangePython 2?

谁能对此提供一些见识?

I’m trying to make a list with numbers 1-1000 in it. Obviously this would be annoying to write/read, so I’m attempting to make a list with a range in it. In Python 2 it seems that:

some_list = range(1,1000)

would have worked, but in Python 3 the range is similar to the xrange of Python 2?

Can anyone provide some insight into this?


回答 0

您可以从range对象构造一个列表:

my_list = list(range(1, 1001))

这也是您使用python2.x中的生成器进行操作的方式。通常来说,虽然您可能不需要列表,但因为可以得到my_list[i]更有效(i + 1)的值,如果只需要遍历该列表,则可以依靠range

另请注意,在python2.x上,xrange仍可索引1。这意味着range在python3.x上也具有相同的属性2

1print xrange(30)[12]适用于python2.x

2 python3.x中与1相似的语句是print(range(30)[12])并且也起作用。

You can just construct a list from the range object:

my_list = list(range(1, 1001))

This is how you do it with generators in python2.x as well. Typically speaking, you probably don’t need a list though since you can come by the value of my_list[i] more efficiently (i + 1), and if you just need to iterate over it, you can just fall back on range.

Also note that on python2.x, xrange is still indexable1. This means that range on python3.x also has the same property2

1print xrange(30)[12] works for python2.x

2The analogous statement to 1 in python3.x is print(range(30)[12]) and that works also.


回答 1

在Pythons <= 3.4中,您可以按照其他建议使用list(range(10)),以使列表超出范围(通常,任何可迭代的列表)。

在Python中3.5以解压缩概括引入的另一种替代方法是*在列表文字中使用[]

>>> r = range(10)
>>> l = [*r]
>>> print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

尽管这等效于list(r),但是它是字面语法,并且不涉及任何函数调用的事实确实使它执行得更快。如果您需要打高尔夫球,它的字符也更少:-)

In Pythons <= 3.4 you can, as others suggested, use list(range(10)) in order to make a list out of a range (In general, any iterable).

Another alternative, introduced in Python 3.5 with its unpacking generalizations, is by using * in a list literal []:

>>> r = range(10)
>>> l = [*r]
>>> print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Though this is equivalent to list(r), it’s literal syntax and the fact that no function call is involved does let it execute faster. It’s also less characters, if you need to code golf :-)


回答 2

在Python 3.x中,该range()函数具有自己的类型。所以在这种情况下,您必须使用迭代器

list(range(1000))

in Python 3.x, the range() function got its own type. so in this case you must use iterator

list(range(1000))


回答 3

Python3缺少直接获取范围列表的功能的原因是因为最初的Python3设计器在Python2中是新手。他只考虑了range()在for循环中使用函数,因此,该列表永远不需要扩展。实际上,很多时候我们确实需要使用range()函数来生成列表并传递给函数。

因此,在这种情况下,与Python2相比,Python3不那么方便,因为:

  • 在Python2,我们xrange()range() ;
  • 在Python3,我们range()list(range())

尽管如此,您仍然可以通过以下方式使用列表扩展:

[*range(N)]

The reason why Python3 lacks a function for directly getting a ranged list is because the original Python3 designer was quite novice in Python2. He only considered the use of range() function in a for loop, thus, the list should never need to be expanded. In fact, very often we do need to use the range() function to produce a list and pass into a function.

Therefore, in this case, Python3 is less convenient as compared to Python2 because:

  • In Python2, we have xrange() and range();
  • In Python3, we have range() and list(range())

Nonetheless, you can still use list expansion in this way:

[*range(N)]

回答 4

您实际上不需要在列表中使用数字1-1000。但是,如果由于某些原因您确实需要这些数字,则可以这样做:

[i for i in range(1, 1001)]

清单理解概述:

上面的列表理解转换为:

nums = []
for i in range(1, 1001):
    nums.append(i)

尽管只是2.x版本,但这只是列表理解语法。我知道这可以在python 3中使用,但是不确定是否还有升级的语法

范围开始于第一个参数;但以不包括第二个参数为结束(当提供2个参数时;如果第一个参数保留,则其将从’0’开始)

range(start, end+1)
[start, start+1, .., end]

You really shouldn’t need to use the numbers 1-1000 in a list. But if for some reason you really do need these numbers, then you could do:

[i for i in range(1, 1001)]

List Comprehension in a nutshell:

The above list comprehension translates to:

nums = []
for i in range(1, 1001):
    nums.append(i)

This is just the list comprehension syntax, though from 2.x. I know that this will work in python 3, but am not sure if there is an upgraded syntax as well

Range starts inclusive of the first parameter; but ends Up To, Not Including the second Parameter (when supplied 2 parameters; if the first parameter is left off, it’ll start at ‘0’)

range(start, end+1)
[start, start+1, .., end]

回答 5

实际上,如果您想要1-1000(含),请使用range(...)带有参数1和1001:range(1, 1001)range(start, end)函数,因为该函数从开始到(结束-1)(含)。

Actually, if you want 1-1000 (inclusive), use the range(...) function with parameters 1 and 1001: range(1, 1001), because the range(start, end) function goes from start to (end-1), inclusive.


回答 6

在Python 3中使用范围

这是一个在两个数字之间返回的示例函数

def get_between_numbers(a, b):
    """
    This function will return in between numbers from two numbers.
    :param a:
    :param b:
    :return:
    """
    x = []
    if b < a:
        x.extend(range(b, a))
        x.append(a)
    else:
        x.extend(range(a, b))
        x.append(b)

    return x

结果

print(get_between_numbers(5, 9))
print(get_between_numbers(9, 5))

[5, 6, 7, 8, 9]  
[5, 6, 7, 8, 9]

Use Range in Python 3.

Here is a example function that return in between numbers from two numbers

def get_between_numbers(a, b):
    """
    This function will return in between numbers from two numbers.
    :param a:
    :param b:
    :return:
    """
    x = []
    if b < a:
        x.extend(range(b, a))
        x.append(a)
    else:
        x.extend(range(a, b))
        x.append(b)

    return x

Result

print(get_between_numbers(5, 9))
print(get_between_numbers(9, 5))

[5, 6, 7, 8, 9]  
[5, 6, 7, 8, 9]

回答 7

实际上,与Python2相比,这是对Python3的追溯。当然,使用range()和xrange()的Python2比分别使用list(range())和range()的Python3更方便。原因是因为Python3的原始设计人员经验不足,他们只考虑了许多初学者使用范围函数来遍历内存和CPU效率低下的大量元素。但是他们忽略了使用range函数生成数字列表。现在,对他们来说已经变回来为时已晚。

如果要成为Python3的设计师,我将:

  1. 使用irange返回序列迭代器
  2. 使用lrange返回序列表
  3. 使用range返回一个序列迭代器(如果元素数量很大,例如range(9999999))或一个序列列表(如果元素数量很小,例如range(10))

那应该是最佳的。

In fact, this is a retro-gradation of Python3 as compared to Python2. Certainly, Python2 which uses range() and xrange() is more convenient than Python3 which uses list(range()) and range() respectively. The reason is because the original designer of Python3 is not very experienced, they only considered the use of the range function by many beginners to iterate over a large number of elements where it is both memory and CPU inefficient; but they neglected the use of the range function to produce a number list. Now, it is too late for them to change back already.

If I was to be the designer of Python3, I will:

  1. use irange to return a sequence iterator
  2. use lrange to return a sequence list
  3. use range to return either a sequence iterator (if the number of elements is large, e.g., range(9999999) or a sequence list (if the number of elements is small, e.g., range(10))

That should be optimal.


让JSON对象接受字节或让urlopen输出字符串

问题:让JSON对象接受字节或让urlopen输出字符串

使用Python 3,我需要从URL请求json文档。

response = urllib.request.urlopen(request)

response对象是带有readreadline方法的类似文件的对象。通常,可以使用在文本模式下打开的文件来创建JSON对象。

obj = json.load(fp)

我想做的是:

obj = json.load(response)

但是,此方法不起作用,因为urlopen以二进制模式返回文件对象。

解决方法当然是:

str_response = response.read().decode('utf-8')
obj = json.loads(str_response)

但这感觉不好…

有没有更好的方法可以将字节文件对象转换为字符串文件对象?还是我缺少任何一个参数urlopenjson.load给出编码?

With Python 3 I am requesting a json document from a URL.

response = urllib.request.urlopen(request)

The response object is a file-like object with read and readline methods. Normally a JSON object can be created with a file opened in text mode.

obj = json.load(fp)

What I would like to do is:

obj = json.load(response)

This however does not work as urlopen returns a file object in binary mode.

A work around is of course:

str_response = response.read().decode('utf-8')
obj = json.loads(str_response)

but this feels bad…

Is there a better way that I can transform a bytes file object to a string file object? Or am I missing any parameters for either urlopen or json.load to give an encoding?


回答 0

HTTP发送字节。如果所讨论的资源是文本,则通常通过Content-Type HTTP标头或其他机制(RFC,HTML meta http-equiv等)指定字符编码。

urllib 应该知道如何将字节编码为字符串,但这太幼稚了-这是一个功能强大且功能强大的非Pythonic库。

深入Python 3提供了有关情况的概述。

您的“变通方法”很好-尽管感觉不对,但这是正确的方法。

HTTP sends bytes. If the resource in question is text, the character encoding is normally specified, either by the Content-Type HTTP header or by another mechanism (an RFC, HTML meta http-equiv,…).

urllib should know how to encode the bytes to a string, but it’s too naïve—it’s a horribly underpowered and un-Pythonic library.

Dive Into Python 3 provides an overview about the situation.

Your “work-around” is fine—although it feels wrong, it’s the correct way to do it.


导入语句python3中的更改

问题:导入语句python3中的更改

我不了解pep-0404的以下内容

在Python 3中,包内的隐式相对导入不再可用-仅支持绝对导入和显式相对导入。此外,仅在模块级别代码中允许星号导入(例如,从x import *导入)。

什么是相对进口?在python2中还允许在其他什么地方导入星号?请举例说明。

I don’t understand the following from pep-0404

In Python 3, implicit relative imports within packages are no longer available – only absolute imports and explicit relative imports are supported. In addition, star imports (e.g. from x import *) are only permitted in module level code.

What is a relative import? In what other places star import was allowed in python2? Please explain with examples.


回答 0

每当导入相对于当前脚本/软件包的软件包时,就会进行相对导入。

例如,考虑以下树:

mypkg
├── base.py
└── derived.py

现在,您derived.py需要从中获得一些东西base.py。在Python 2中,您可以这样做(在中derived.py):

from base import BaseThing

Python 3不再支持该功能,因为它是否明确要求“相对”还是“绝对” base。换句话说,如果base系统中安装了一个名为Python的软件包,那么您将得到错误的软件包。

相反,它要求您使用显式导入,这些显式导入在类似路径的基础上显式指定模块的位置。您derived.py将看起来像:

from .base import BaseThing

领导.说“ base从模块目录导入”;换句话说,.base映射到./base.py

同样,有一个..前缀沿目录层次结构向上../(如..mod映射到../mod.py),然后沿...两个层次向上(../../mod.py),依此类推。

但是请注意,上面列出的相对路径是相对于当前模块(derived.py)所在的目录的,而不是相对于当前工作目录的。


@BrenBarn已经解释了star导入案例。为了完整性,我将不得不说相同;)。

例如,您需要使用一些math功能,但只能在单个功能中使用它们。在Python 2中,您被允许是半懒惰的:

def sin_degrees(x):
    from math import *
    return sin(degrees(x))

请注意,它已经在Python 2中触发了警告:

a.py:1: SyntaxWarning: import * only allowed at module level
  def sin_degrees(x):

在现代Python 2代码中,您应该这样做,而在Python 3中,您必须执行以下任一操作:

def sin_degrees(x):
    from math import sin, degrees
    return sin(degrees(x))

要么:

from math import *

def sin_degrees(x):
    return sin(degrees(x))

Relative import happens whenever you are importing a package relative to the current script/package.

Consider the following tree for example:

mypkg
├── base.py
└── derived.py

Now, your derived.py requires something from base.py. In Python 2, you could do it like this (in derived.py):

from base import BaseThing

Python 3 no longer supports that since it’s not explicit whether you want the ‘relative’ or ‘absolute’ base. In other words, if there was a Python package named base installed in the system, you’d get the wrong one.

Instead it requires you to use explicit imports which explicitly specify location of a module on a path-alike basis. Your derived.py would look like:

from .base import BaseThing

The leading . says ‘import base from module directory’; in other words, .base maps to ./base.py.

Similarly, there is .. prefix which goes up the directory hierarchy like ../ (with ..mod mapping to ../mod.py), and then ... which goes two levels up (../../mod.py) and so on.

Please however note that the relative paths listed above were relative to directory where current module (derived.py) resides in, not the current working directory.


@BrenBarn has already explained the star import case. For completeness, I will have to say the same ;).

For example, you need to use a few math functions but you use them only in a single function. In Python 2 you were permitted to be semi-lazy:

def sin_degrees(x):
    from math import *
    return sin(degrees(x))

Note that it already triggers a warning in Python 2:

a.py:1: SyntaxWarning: import * only allowed at module level
  def sin_degrees(x):

In modern Python 2 code you should and in Python 3 you have to do either:

def sin_degrees(x):
    from math import sin, degrees
    return sin(degrees(x))

or:

from math import *

def sin_degrees(x):
    return sin(degrees(x))

回答 1

有关相对进口的信息,请参阅文档。相对导入是指从模块中相对于该模块位置的导入,而不是绝对从中导入sys.path

至于import *,Python 2允许在函数内导入星形,例如:

>>> def f():
...     from math import *
...     print sqrt

在Python 2(至少是最新版本)中为此发出警告。在Python 3中,它不再被允许,并且您只能在模块的顶层(而不是在函数或类内部)进行星形导入。

For relative imports see the documentation. A relative import is when you import from a module relative to that module’s location, instead of absolutely from sys.path.

As for import *, Python 2 allowed star imports within functions, for instance:

>>> def f():
...     from math import *
...     print sqrt

A warning is issued for this in Python 2 (at least recent versions). In Python 3 it is no longer allowed and you can only do star imports at the top level of a module (not inside functions or classes).


回答 2

要同时支持Python 2和Python 3,请使用如下所示的显式相对导入。它们相对于当前模块。从2.5开始支持它们。

from .sister import foo
from . import brother
from ..aunt import bar
from .. import uncle

To support both Python 2 and Python 3, use explicit relative imports as below. They are relative to the current module. They have been supported starting from 2.5.

from .sister import foo
from . import brother
from ..aunt import bar
from .. import uncle

回答 3

在MichałGórny的答案中添加了另一个案例:

请注意,相对导入基于当前模块的名称。由于主模块的名称始终为“ __main__”,因此用作Python应用程序主模块的模块必须始终使用绝对导入。

Added another case to Michał Górny’s answer:

Note that relative imports are based on the name of the current module. Since the name of the main module is always “__main__“, modules intended for use as the main module of a Python application must always use absolute imports.


在Python 3中将int转换为字节

问题:在Python 3中将int转换为字节

我试图在Python 3中构建此byte对象:

b'3\r\n'

所以我尝试了显而易见的(对我来说),发现了一个奇怪的行为:

>>> bytes(3) + b'\r\n'
b'\x00\x00\x00\r\n'

显然:

>>> bytes(10)
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

我无法看到有关为什么字节转换以这种方式阅读文档的任何指示。但是,在此Python问题中,我确实发现了一些有关添加format到字节的惊奇消息(另请参见Python 3字节格式):

http://bugs.python.org/issue3982

现在与byte(int)之类的奇数的相互作用更差,现在返回零

和:

如果bytes(int)返回该int的ASCIIfication,对我来说将更加方便;但老实说,即使是错误也比这种行为要好。(如果我想要这种行为-我从未有过-我宁愿它是一种类方法,就像“ bytes.zeroes(n)”一样被调用。)

有人可以向我解释这种行为的来源吗?

I was trying to build this bytes object in Python 3:

b'3\r\n'

so I tried the obvious (for me), and found a weird behaviour:

>>> bytes(3) + b'\r\n'
b'\x00\x00\x00\r\n'

Apparently:

>>> bytes(10)
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

I’ve been unable to see any pointers on why the bytes conversion works this way reading the documentation. However, I did find some surprise messages in this Python issue about adding format to bytes (see also Python 3 bytes formatting):

http://bugs.python.org/issue3982

This interacts even more poorly with oddities like bytes(int) returning zeroes now

and:

It would be much more convenient for me if bytes(int) returned the ASCIIfication of that int; but honestly, even an error would be better than this behavior. (If I wanted this behavior – which I never have – I’d rather it be a classmethod, invoked like “bytes.zeroes(n)”.)

Can someone explain me where this behaviour comes from?


回答 0

那就是它的设计方式-很有道理,因为通常,您将调用bytes一个可迭代而不是单个整数:

>>> bytes([3])
b'\x03'

文档说明这一点,以及文档字符串为bytes

 >>> help(bytes)
 ...
 bytes(int) -> bytes object of size given by the parameter initialized with null bytes

That’s the way it was designed – and it makes sense because usually, you would call bytes on an iterable instead of a single integer:

>>> bytes([3])
b'\x03'

The docs state this, as well as the docstring for bytes:

 >>> help(bytes)
 ...
 bytes(int) -> bytes object of size given by the parameter initialized with null bytes

回答 1

从python 3.2你可以做

>>> (1024).to_bytes(2, byteorder='big')
b'\x04\x00'

https://docs.python.org/3/library/stdtypes.html#int.to_bytes

def int_to_bytes(x: int) -> bytes:
    return x.to_bytes((x.bit_length() + 7) // 8, 'big')

def int_from_bytes(xbytes: bytes) -> int:
    return int.from_bytes(xbytes, 'big')

因此,x == int_from_bytes(int_to_bytes(x))。请注意,此编码仅适用于无符号(非负)整数。

From python 3.2 you can do

>>> (1024).to_bytes(2, byteorder='big')
b'\x04\x00'

https://docs.python.org/3/library/stdtypes.html#int.to_bytes

def int_to_bytes(x: int) -> bytes:
    return x.to_bytes((x.bit_length() + 7) // 8, 'big')
    
def int_from_bytes(xbytes: bytes) -> int:
    return int.from_bytes(xbytes, 'big')

Accordingly, x == int_from_bytes(int_to_bytes(x)). Note that the above encoding works only for unsigned (non-negative) integers.

For signed integers, the bit length is a bit more tricky to calculate:

def int_to_bytes(number: int) -> bytes:
    return number.to_bytes(length=(8 + (number + (number < 0)).bit_length()) // 8, byteorder='big', signed=True)

def int_from_bytes(binary_data: bytes) -> Optional[int]:
    return int.from_bytes(binary_data, byteorder='big', signed=True)

回答 2

您可以使用结构包

In [11]: struct.pack(">I", 1)
Out[11]: '\x00\x00\x00\x01'

“>”是字节顺序(big-endian),而“ I”是格式字符。因此,如果您要执行其他操作,则可以具体说明:

In [12]: struct.pack("<H", 1)
Out[12]: '\x01\x00'

In [13]: struct.pack("B", 1)
Out[13]: '\x01'

这在python 2和python 3上都相同。

注意:逆运算(字节到int)可以使用unpack完成。

You can use the struct’s pack:

In [11]: struct.pack(">I", 1)
Out[11]: '\x00\x00\x00\x01'

The “>” is the byte-order (big-endian) and the “I” is the format character. So you can be specific if you want to do something else:

In [12]: struct.pack("<H", 1)
Out[12]: '\x01\x00'

In [13]: struct.pack("B", 1)
Out[13]: '\x01'

This works the same on both python 2 and python 3.

Note: the inverse operation (bytes to int) can be done with unpack.


回答 3

Python 3.5+ printf为字节引入了%插值(-style格式)

>>> b'%d\r\n' % 3
b'3\r\n'

请参阅PEP 0461-将%格式添加到字节和字节数组

在早期版本中,您可以使用str.encode('ascii')结果:

>>> s = '%d\r\n' % 3
>>> s.encode('ascii')
b'3\r\n'

注意:它与产生的东西int.to_bytes不同:

>>> n = 3
>>> n.to_bytes((n.bit_length() + 7) // 8, 'big') or b'\0'
b'\x03'
>>> b'3' == b'\x33' != '\x03'
True

Python 3.5+ introduces %-interpolation (printf-style formatting) for bytes:

>>> b'%d\r\n' % 3
b'3\r\n'

See PEP 0461 — Adding % formatting to bytes and bytearray.

On earlier versions, you could use str and .encode('ascii') the result:

>>> s = '%d\r\n' % 3
>>> s.encode('ascii')
b'3\r\n'

Note: It is different from what int.to_bytes produces:

>>> n = 3
>>> n.to_bytes((n.bit_length() + 7) // 8, 'big') or b'\0'
b'\x03'
>>> b'3' == b'\x33' != '\x03'
True

回答 4

该文档说:

bytes(int) -> bytes object of size given by the parameter
              initialized with null bytes

序列:

b'3\r\n'

它是字符“ \ r”(13)和“ \ n”(10)的字符“ 3”(十进制51)。

因此,该方式将这样对待它,例如:

>>> bytes([51, 13, 10])
b'3\r\n'

>>> bytes('3', 'utf8') + b'\r\n'
b'3\r\n'

>>> n = 3
>>> bytes(str(n), 'ascii') + b'\r\n'
b'3\r\n'

在IPython 1.1.0和Python 3.2.3上测试

The documentation says:

bytes(int) -> bytes object of size given by the parameter
              initialized with null bytes

The sequence:

b'3\r\n'

It is the character ‘3’ (decimal 51) the character ‘\r’ (13) and ‘\n’ (10).

Therefore, the way would treat it as such, for example:

>>> bytes([51, 13, 10])
b'3\r\n'

>>> bytes('3', 'utf8') + b'\r\n'
b'3\r\n'

>>> n = 3
>>> bytes(str(n), 'ascii') + b'\r\n'
b'3\r\n'

Tested on IPython 1.1.0 & Python 3.2.3


回答 5

3的ASCII "\x33""\x03"

这就是python所做的事情,str(3)但是对于字节来说,这是完全错误的,因为应该将它们视为二进制数据的数组,而不应将其当作字符串来使用。

实现所需内容最简单的方法是bytes((3,)),它比bytes([3])因为初始化列表的开销要大得多,因此更好,因此,在可以使用元组时不要使用列表。您可以使用转换较大的整数int.to_bytes(3, "little")

初始化具有给定长度的字节是有意义的,并且是最有用的,因为它们通常用于创建某种类型的缓冲区,您需要为其分配一些给定大小的内存。我在初始化数组或通过向其写入零来扩展某些文件时经常使用它。

The ASCIIfication of 3 is "\x33" not "\x03"!

That is what python does for str(3) but it would be totally wrong for bytes, as they should be considered arrays of binary data and not be abused as strings.

The most easy way to achieve what you want is bytes((3,)), which is better than bytes([3]) because initializing a list is much more expensive, so never use lists when you can use tuples. You can convert bigger integers by using int.to_bytes(3, "little").

Initializing bytes with a given length makes sense and is the most useful, as they are often used to create some type of buffer for which you need some memory of given size allocated. I often use this when initializing arrays or expanding some file by writing zeros to it.


回答 6

int (包括Python2的 long)可以bytes使用以下函数转换为:

import codecs

def int2bytes(i):
    hex_value = '{0:x}'.format(i)
    # make length of hex_value a multiple of two
    hex_value = '0' * (len(hex_value) % 2) + hex_value
    return codecs.decode(hex_value, 'hex_codec')

反向转换可以由另一种完成:

import codecs
import six  # should be installed via 'pip install six'

long = six.integer_types[-1]

def bytes2int(b):
    return long(codecs.encode(b, 'hex_codec'), 16)

这两个函数都可以在Python2和Python3上使用。

int (including Python2’s long) can be converted to bytes using following function:

import codecs

def int2bytes(i):
    hex_value = '{0:x}'.format(i)
    # make length of hex_value a multiple of two
    hex_value = '0' * (len(hex_value) % 2) + hex_value
    return codecs.decode(hex_value, 'hex_codec')

The reverse conversion can be done by another one:

import codecs
import six  # should be installed via 'pip install six'

long = six.integer_types[-1]

def bytes2int(b):
    return long(codecs.encode(b, 'hex_codec'), 16)

Both functions work on both Python2 and Python3.


回答 7

我很好奇范围内单个int的各种方法的性能[0, 255],因此我决定进行一些时序测试。

基于下面的定时,和从从尝试许多不同的值和结构中观察到的总的趋势,struct.pack似乎是最快,其次int.to_bytesbytes和与str.encode(勿庸置疑)是最慢的。请注意,结果显示出比所显示的更多的变化,int.to_bytes并且bytes有时在测试过程中切换速度排名,但struct.pack显然是最快的。

Windows上CPython 3.7的结果:

Testing with 63:
bytes_: 100000 loops, best of 5: 3.3 usec per loop
to_bytes: 100000 loops, best of 5: 2.72 usec per loop
struct_pack: 100000 loops, best of 5: 2.32 usec per loop
chr_encode: 50000 loops, best of 5: 3.66 usec per loop

测试模块(名为int_to_byte.py):

"""Functions for converting a single int to a bytes object with that int's value."""

import random
import shlex
import struct
import timeit

def bytes_(i):
    """From Tim Pietzcker's answer:
    https://stackoverflow.com/a/21017834/8117067
    """
    return bytes([i])

def to_bytes(i):
    """From brunsgaard's answer:
    https://stackoverflow.com/a/30375198/8117067
    """
    return i.to_bytes(1, byteorder='big')

def struct_pack(i):
    """From Andy Hayden's answer:
    https://stackoverflow.com/a/26920966/8117067
    """
    return struct.pack('B', i)

# Originally, jfs's answer was considered for testing,
# but the result is not identical to the other methods
# https://stackoverflow.com/a/31761722/8117067

def chr_encode(i):
    """Another method, from Quuxplusone's answer here:
    https://codereview.stackexchange.com/a/210789/140921

    Similar to g10guang's answer:
    https://stackoverflow.com/a/51558790/8117067
    """
    return chr(i).encode('latin1')

converters = [bytes_, to_bytes, struct_pack, chr_encode]

def one_byte_equality_test():
    """Test that results are identical for ints in the range [0, 255]."""
    for i in range(256):
        results = [c(i) for c in converters]
        # Test that all results are equal
        start = results[0]
        if any(start != b for b in results):
            raise ValueError(results)

def timing_tests(value=None):
    """Test each of the functions with a random int."""
    if value is None:
        # random.randint takes more time than int to byte conversion
        # so it can't be a part of the timeit call
        value = random.randint(0, 255)
    print(f'Testing with {value}:')
    for c in converters:
        print(f'{c.__name__}: ', end='')
        # Uses technique borrowed from https://stackoverflow.com/q/19062202/8117067
        timeit.main(args=shlex.split(
            f"-s 'from int_to_byte import {c.__name__}; value = {value}' " +
            f"'{c.__name__}(value)'"
        ))

I was curious about performance of various methods for a single int in the range [0, 255], so I decided to do some timing tests.

Based on the timings below, and from the general trend I observed from trying many different values and configurations, struct.pack seems to be the fastest, followed by int.to_bytes, bytes, and with str.encode (unsurprisingly) being the slowest. Note that the results show some more variation than is represented, and int.to_bytes and bytes sometimes switched speed ranking during testing, but struct.pack is clearly the fastest.

Results in CPython 3.7 on Windows:

Testing with 63:
bytes_: 100000 loops, best of 5: 3.3 usec per loop
to_bytes: 100000 loops, best of 5: 2.72 usec per loop
struct_pack: 100000 loops, best of 5: 2.32 usec per loop
chr_encode: 50000 loops, best of 5: 3.66 usec per loop

Test module (named int_to_byte.py):

"""Functions for converting a single int to a bytes object with that int's value."""

import random
import shlex
import struct
import timeit

def bytes_(i):
    """From Tim Pietzcker's answer:
    https://stackoverflow.com/a/21017834/8117067
    """
    return bytes([i])

def to_bytes(i):
    """From brunsgaard's answer:
    https://stackoverflow.com/a/30375198/8117067
    """
    return i.to_bytes(1, byteorder='big')

def struct_pack(i):
    """From Andy Hayden's answer:
    https://stackoverflow.com/a/26920966/8117067
    """
    return struct.pack('B', i)

# Originally, jfs's answer was considered for testing,
# but the result is not identical to the other methods
# https://stackoverflow.com/a/31761722/8117067

def chr_encode(i):
    """Another method, from Quuxplusone's answer here:
    https://codereview.stackexchange.com/a/210789/140921

    Similar to g10guang's answer:
    https://stackoverflow.com/a/51558790/8117067
    """
    return chr(i).encode('latin1')

converters = [bytes_, to_bytes, struct_pack, chr_encode]

def one_byte_equality_test():
    """Test that results are identical for ints in the range [0, 255]."""
    for i in range(256):
        results = [c(i) for c in converters]
        # Test that all results are equal
        start = results[0]
        if any(start != b for b in results):
            raise ValueError(results)

def timing_tests(value=None):
    """Test each of the functions with a random int."""
    if value is None:
        # random.randint takes more time than int to byte conversion
        # so it can't be a part of the timeit call
        value = random.randint(0, 255)
    print(f'Testing with {value}:')
    for c in converters:
        print(f'{c.__name__}: ', end='')
        # Uses technique borrowed from https://stackoverflow.com/q/19062202/8117067
        timeit.main(args=shlex.split(
            f"-s 'from int_to_byte import {c.__name__}; value = {value}' " +
            f"'{c.__name__}(value)'"
        ))

回答 8

尽管brunsgaard的先前答案是有效的编码,但它仅适用于无符号整数。这是它的基础,可同时用于有符号和无符号整数。

def int_to_bytes(i: int, *, signed: bool = False) -> bytes:
    length = ((i + ((i * signed) < 0)).bit_length() + 7 + signed) // 8
    return i.to_bytes(length, byteorder='big', signed=signed)

def bytes_to_int(b: bytes, *, signed: bool = False) -> int:
    return int.from_bytes(b, byteorder='big', signed=signed)

# Test unsigned:
for i in range(1025):
    assert i == bytes_to_int(int_to_bytes(i))

# Test signed:
for i in range(-1024, 1025):
    assert i == bytes_to_int(int_to_bytes(i, signed=True), signed=True)

对于编码器,不仅(i + ((i * signed) < 0)).bit_length()要使用编码器,i.bit_length()因为后者会导致-128,-32768等的无效编码。


图片来源:CervEd,用于解决效率低下的问题。

Although the prior answer by brunsgaard is an efficient encoding, it works only for unsigned integers. This one builds upon it to work for both signed and unsigned integers.

def int_to_bytes(i: int, *, signed: bool = False) -> bytes:
    length = ((i + ((i * signed) < 0)).bit_length() + 7 + signed) // 8
    return i.to_bytes(length, byteorder='big', signed=signed)

def bytes_to_int(b: bytes, *, signed: bool = False) -> int:
    return int.from_bytes(b, byteorder='big', signed=signed)

# Test unsigned:
for i in range(1025):
    assert i == bytes_to_int(int_to_bytes(i))

# Test signed:
for i in range(-1024, 1025):
    assert i == bytes_to_int(int_to_bytes(i, signed=True), signed=True)

For the encoder, (i + ((i * signed) < 0)).bit_length() is used instead of just i.bit_length() because the latter leads to an inefficient encoding of -128, -32768, etc.


Credit: CervEd for fixing a minor inefficiency.


回答 9

该行为来自以下事实:在版本3之前的Python中,bytes它只是的别名str。在Python3.x中bytes是的不可变版本bytearray-全新类型,不向后兼容。

The behaviour comes from the fact that in Python prior to version 3 bytes was just an alias for str. In Python3.x bytes is an immutable version of bytearray – completely new type, not backwards compatible.


回答 10

字节文档

因此,构造函数参数被解释为针对bytearray()。

然后,从bytearray docs

可选的source参数可以通过几种不同的方式用于初始化数组:

  • 如果它是整数,则数组将具有该大小,并将使用空字节初始化。

请注意,这与2.x(其中x> = 6)行为不同,其中bytes只是str

>>> bytes is str
True

PEP 3112

2.6 str与3.0的字节类型在各种方面有所不同。最值得注意的是,构造函数完全不同。

From bytes docs:

Accordingly, constructor arguments are interpreted as for bytearray().

Then, from bytearray docs:

The optional source parameter can be used to initialize the array in a few different ways:

  • If it is an integer, the array will have that size and will be initialized with null bytes.

Note, that differs from 2.x (where x >= 6) behavior, where bytes is simply str:

>>> bytes is str
True

PEP 3112:

The 2.6 str differs from 3.0’s bytes type in various ways; most notably, the constructor is completely different.


回答 11

有些答案不能大量使用。

将整数转换为十六进制表示形式,然后将其转换为字节:

def int_to_bytes(number):
    hrepr = hex(number).replace('0x', '')
    if len(hrepr) % 2 == 1:
        hrepr = '0' + hrepr
    return bytes.fromhex(hrepr)

结果:

>>> int_to_bytes(2**256 - 1)
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'

Some answers don’t work with large numbers.

Convert integer to the hex representation, then convert it to bytes:

def int_to_bytes(number):
    hrepr = hex(number).replace('0x', '')
    if len(hrepr) % 2 == 1:
        hrepr = '0' + hrepr
    return bytes.fromhex(hrepr)

Result:

>>> int_to_bytes(2**256 - 1)
b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'

回答 12

如果问题是如何将整数本身(而不是等效的字符串)转换为字节,我认为可靠的答案是:

>>> i = 5
>>> i.to_bytes(2, 'big')
b'\x00\x05'
>>> int.from_bytes(i.to_bytes(2, 'big'), byteorder='big')
5

有关这些方法的更多信息,请参见:

  1. https://docs.python.org/3.8/library/stdtypes.html#int.to_bytes
  2. https://docs.python.org/3.8/library/stdtypes.html#int.from_bytes

If the question is how to convert an integer itself (not its string equivalent) into bytes, I think the robust answer is:

>>> i = 5
>>> i.to_bytes(2, 'big')
b'\x00\x05'
>>> int.from_bytes(i.to_bytes(2, 'big'), byteorder='big')
5

More information on these methods here:

  1. https://docs.python.org/3.8/library/stdtypes.html#int.to_bytes
  2. https://docs.python.org/3.8/library/stdtypes.html#int.from_bytes

如何在Python3中将“二进制字符串”转换为普通字符串?

问题:如何在Python3中将“二进制字符串”转换为普通字符串?

例如,我有一个像这样的字符串(返回值subprocess.check_output):

>>> b'a string'
b'a string'

无论我对它做了什么,它总是b'在字符串之前印有烦人的字样:

>>> print(b'a string')
b'a string'
>>> print(str(b'a string'))
b'a string'

是否有人对如何将其用作普通字符串或将其转换为普通字符串有任何想法?

For example, I have a string like this(return value of subprocess.check_output):

>>> b'a string'
b'a string'

Whatever I did to it, it is always printed with the annoying b' before the string:

>>> print(b'a string')
b'a string'
>>> print(str(b'a string'))
b'a string'

Does anyone have any ideas about how to use it as a normal string or convert it into a normal string?


回答 0

解码它。

>>> b'a string'.decode('ascii')
'a string'

要从字符串获取字节,请对其进行编码。

>>> 'a string'.encode('ascii')
b'a string'

Decode it.

>>> b'a string'.decode('ascii')
'a string'

To get bytes from string, encode it.

>>> 'a string'.encode('ascii')
b'a string'

回答 1

如果来自falsetru的答案不起作用,您还可以尝试:

>>> b'a string'.decode('utf-8')
'a string'

If the answer from falsetru didn’t work you could also try:

>>> b'a string'.decode('utf-8')
'a string'

回答 2

请参阅图书馆的官方资料encode()decode()文档codecsutf-8是函数的默认编码,但是Python 3中有几种标准编码,例如latin_1utf_32

Please, see oficial encode() and decode() documentation from codecs library. utf-8 is the default encoding for the functions, but there are severals standard encodings in Python 3, like latin_1 or utf_32.


在IPython Notebook中同时使用Python 2.x和Python 3.x

问题:在IPython Notebook中同时使用Python 2.x和Python 3.x

我使用IPython笔记本,并且希望能够选择在IPython中创建2.x或3.x python笔记本。

我最初有Anaconda。使用Anaconda时,必须更改全局环境变量以选择所需的python版本,然后才能启动IPython。这不是我想要的,所以我卸载了Anaconda,现在使用MacPorts和PiP设置了自己的安装。看来我还是要用

port select --set python <python version> 

在python 2.x和3.x之间切换。这并不比anaconda解决方案好。

启动IPython笔记本后,是否有一种方法可以选择要使用的python版本,最好使用当前的MacPorts构建?

I use IPython notebooks and would like to be able to select to create a 2.x or 3.x python notebook in IPython.

I initially had Anaconda. With Anaconda a global environment variable had to be changed to select what version of python you want and then IPython could be started. This is not what I was looking for so I uninstalled Anaconda and now have set up my own installation using MacPorts and PiP. It seems that I still have to use

port select --set python <python version> 

to toggle between python 2.x and 3.x. which is no better than the anaconda solution.

Is there a way to select what version of python you want to use after you start an IPython notebook, preferably with my current MacPorts build?


回答 0

这里的想法是安装多个ipython内核。这是有关Python的说明。如果你不使用Python,我最近添加的说明采用纯virtualenvs。

水蟒> = 4.1.0

从版本4.1.0开始,anaconda包含一个特殊的程序包nb_conda_kernels,该程序包可检测笔记本内核的conda环境并自动注册它们。这使得使用新的python版本就像创建新的conda环境一样容易:

conda create -n py27 python=2.7 ipykernel
conda create -n py36 python=3.6 ipykernel

重新启动jupyter notebook之后,新内核可通过图形界面使用。请注意,必须将新软件包明确安装到新环境中。conda文档中的“ 管理环境”部分提供了更多信息。

手动注册内核

不想使用nb_conda_kernels或仍使用旧版本的anaconda的用户可以使用以下步骤来手动注册ipython内核。

配置python2.7环境:

conda create -n py27 python=2.7
conda activate py27
conda install notebook ipykernel
ipython kernel install --user

配置python3.6环境:

conda create -n py36 python=3.6
conda activate py36
conda install notebook ipykernel
ipython kernel install --user

在此之后,你应该能够之间进行选择python2
python3创造的接口一个新的笔记本时。

另外,如果要更改内核名称,可以将--name--display-name选项传递给ipython kernel install。请参阅ipython kernel install --help以获取更多信息。

The idea here is to install multiple ipython kernels. Here are instructions for anaconda. If you are not using anaconda, I recently added instructions using pure virtualenvs.

Anaconda >= 4.1.0

Since version 4.1.0, anaconda includes a special package nb_conda_kernels that detects conda environments with notebook kernels and automatically registers them. This makes using a new python version as easy as creating new conda environments:

conda create -n py27 python=2.7 ipykernel
conda create -n py36 python=3.6 ipykernel

After a restart of jupyter notebook, the new kernels are available over the graphical interface. Please note that new packages have to be explicitly installed into the new environments. The Managing environments section in conda’s docs provides further information.

Manually registering kernels

Users who do not want to use nb_conda_kernels or still use older versions of anaconda can use the following steps to manually register ipython kernels.

configure the python2.7 environment:

conda create -n py27 python=2.7
conda activate py27
conda install notebook ipykernel
ipython kernel install --user

configure the python3.6 environment:

conda create -n py36 python=3.6
conda activate py36
conda install notebook ipykernel
ipython kernel install --user

After that you should be able to choose between python2
and python3 when creating a new notebook in the interface.

Additionally you can pass the --name and --display-name options to ipython kernel install if you want to change the names of your kernels. See ipython kernel install --help for more informations.


回答 1

如果您在Python 3上运行Jupyter,则可以这样设置Python 2内核:

python2 -m pip install ipykernel

python2 -m ipykernel install --user

http://ipython.readthedocs.io/en/stable/install/kernel_install.html

If you’re running Jupyter on Python 3, you can set up a Python 2 kernel like this:

python2 -m pip install ipykernel

python2 -m ipykernel install --user

http://ipython.readthedocs.io/en/stable/install/kernel_install.html


回答 2

这些说明说明了如何为非anaconda用户在单独的虚拟环境中安装python2和python3内核。如果您使用anaconda,请找到我的其他答案,以直接针对anaconda量身定制解决方案。

我假设您已经jupyter notebook安装了。


首先,请确保您有python2和提供的python3口译员pip

在ubuntu上,您可以通过以下方式安装它们:

sudo apt-get install python-dev python3-dev python-pip python3-pip

接下来准备并注册内核环境

python -m pip install virtualenv --user

# configure python2 kernel
python -m virtualenv -p python2 ~/py2_kernel
source ~/py2_kernel/bin/activate
python -m pip install ipykernel
ipython kernel install --name py2 --user
deactivate

# configure python3 kernel
python -m virtualenv -p python3 ~/py3_kernel
source ~/py3_kernel/bin/activate
python -m pip install ipykernel
ipython kernel install --name py3 --user
deactivate

为了简化操作,您可能需要将激活命令的外壳别名添加到外壳配置文件中。根据不同的系统和外壳使用,这可以是例如~/.bashrc~/.bash_profile~/.zshrc

alias kernel2='source ~/py2_kernel/bin/activate'
alias kernel3='source ~/py3_kernel/bin/activate'

重新启动外壳程序后,现在可以在激活要使用的环境后安装新软件包。

kernel2
python -m pip install <pkg-name>
deactivate

要么

kernel3
python -m pip install <pkg-name>
deactivate

These instructions explain how to install a python2 and python3 kernel in separate virtual environments for non-anaconda users. If you are using anaconda, please find my other answer for a solution directly tailored to anaconda.

I assume that you already have jupyter notebook installed.


First make sure that you have a python2 and a python3 interpreter with pip available.

On ubuntu you would install these by:

sudo apt-get install python-dev python3-dev python-pip python3-pip

Next prepare and register the kernel environments

python -m pip install virtualenv --user

# configure python2 kernel
python -m virtualenv -p python2 ~/py2_kernel
source ~/py2_kernel/bin/activate
python -m pip install ipykernel
ipython kernel install --name py2 --user
deactivate

# configure python3 kernel
python -m virtualenv -p python3 ~/py3_kernel
source ~/py3_kernel/bin/activate
python -m pip install ipykernel
ipython kernel install --name py3 --user
deactivate

To make things easier, you may want to add shell aliases for the activation command to your shell config file. Depending on the system and shell you use, this can be e.g. ~/.bashrc, ~/.bash_profile or ~/.zshrc

alias kernel2='source ~/py2_kernel/bin/activate'
alias kernel3='source ~/py3_kernel/bin/activate'

After restarting your shell, you can now install new packages after activating the environment you want to use.

kernel2
python -m pip install <pkg-name>
deactivate

or

kernel3
python -m pip install <pkg-name>
deactivate

回答 3

使用当前版本的Notebook / Jupyter,您可以创建Python3内核。使用Python 2从命令行启动新的笔记本应用程序后,您应该在下拉菜单“新建”中看到条目“ Python 3”。这为您提供了一个使用Python 3的笔记本。因此,您可以并排放置两个笔记本,并使用不同的Python版本。

细节

  1. 创建此目录: mkdir -p ~/.ipython/kernels/python3
  2. ~/.ipython/kernels/python3/kernel.json使用以下内容创建此文件:

    {
        "display_name": "IPython (Python 3)", 
        "language": "python", 
        "argv": [
            "python3", 
            "-c", "from IPython.kernel.zmq.kernelapp import main; main()", 
            "-f", "{connection_file}"
        ], 
        "codemirror_mode": {
            "version": 2, 
            "name": "ipython"
        }
    }
  3. 重新启动笔记本服务器。

  4. 从下拉菜单“新建”中选择“ Python 3”
  5. 使用Python 3笔记本
  6. 从下拉菜单“新建”中选择“ Python 2”
  7. 使用Python 2笔记本

With a current version of the Notebook/Jupyter, you can create a Python3 kernel. After starting a new notebook application from the command line with Python 2 you should see an entry „Python 3“ in the dropdown menu „New“. This gives you a notebook that uses Python 3. So you can have two notebooks side-by-side with different Python versions.

The Details

  1. Create this directory: mkdir -p ~/.ipython/kernels/python3
  2. Create this file ~/.ipython/kernels/python3/kernel.json with this content:

    {
        "display_name": "IPython (Python 3)", 
        "language": "python", 
        "argv": [
            "python3", 
            "-c", "from IPython.kernel.zmq.kernelapp import main; main()", 
            "-f", "{connection_file}"
        ], 
        "codemirror_mode": {
            "version": 2, 
            "name": "ipython"
        }
    }
    
  3. Restart the notebook server.

  4. Select „Python 3“ from the dropdown menu „New“
  5. Work with a Python 3 Notebook
  6. Select „Python 2“ from the dropdown menu „New“
  7. Work with a Python 2 Notebook

回答 4

提供了一个解决方案,该解决方案允许我通过配置Ipython kernelspec来保留MacPorts的安装。

要求:

  • MacPorts安装在通常的/ opt目录中
  • python 2.7是通过macports安装的
  • python 3.4通过macports安装
  • 为python 2.7安装了ipython
  • 为python 3.4安装了ipython

对于python 2.x:

$ cd /opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin
$ sudo ./ipython kernelspec install-self

对于python 3.x:

$ cd /opt/local/Library/Frameworks/Python.framework/Versions/3.4/bin
$ sudo ./ipython kernelspec install-self

现在,您可以打开一个Ipython笔记本,然后选择python 2.x或python 3.x笔记本。

A solution is available that allows me to keep my MacPorts installation by configuring the Ipython kernelspec.

Requirements:

  • MacPorts is installed in the usual /opt directory
  • python 2.7 is installed through macports
  • python 3.4 is installed through macports
  • Ipython is installed for python 2.7
  • Ipython is installed for python 3.4

For python 2.x:

$ cd /opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin
$ sudo ./ipython kernelspec install-self

For python 3.x:

$ cd /opt/local/Library/Frameworks/Python.framework/Versions/3.4/bin
$ sudo ./ipython kernelspec install-self

Now you can open an Ipython notebook and then choose a python 2.x or a python 3.x notebook.


回答 5

通过我的Linux安装,我做到了:

sudo ipython2 kernelspec install-self

现在,我的python 2又回到了列表中。

参考:

http://ipython.readthedocs.org/en/latest/install/kernel_install.html


更新:

上面的方法现已弃用,将来会被删除。新方法应为:

sudo ipython2 kernel install

From my Linux installation I did:

sudo ipython2 kernelspec install-self

And now my python 2 is back on the list.

Reference:

http://ipython.readthedocs.org/en/latest/install/kernel_install.html


UPDATE:

The method above is now deprecated and will be dropped in the future. The new method should be:

sudo ipython2 kernel install


回答 6

以下是将python2内核添加到jupyter笔记本的步骤:

打开一个终端并创建一个新的python 2环境: conda create -n py27 python=2.7

激活环境:Linux source activate py27或Windowsactivate py27

在环境中安装内核: conda install notebook ipykernel

在env外部安装内核: ipython kernel install --user

关闭环境: source deactivate

尽管答案很晚,希望有人发现它有用:p

Following are the steps to add the python2 kernel to jupyter notebook::

open a terminal and create a new python 2 environment: conda create -n py27 python=2.7

activate the environment: Linux source activate py27 or windows activate py27

install the kernel in the env: conda install notebook ipykernel

install the kernel for outside the env: ipython kernel install --user

close the env: source deactivate

Although a late answer hope someone finds it useful :p


回答 7

使用sudo pip3 install jupyter安装了python3 jupyter和sudo pip install jupyter安装jupyter笔记本python2。然后,您可以调用ipython kernel install命令来启用两种类型的笔记本以在jupyter笔记本中进行选择。

Use sudo pip3 install jupyter for installing jupyter for python3 and sudo pip install jupyter for installing jupyter notebook for python2. Then, you can call ipython kernel install command to enable both types of notebook to choose from in jupyter notebook.


回答 8

我查看了这个出色的信息,然后想知道

  1. 我已经安装了python2,python3和IPython,
  2. 我安装了PyCharm,
  3. PyCharm将IPython用于其Python控制台,

如果 PyCharm将使用

  1. IPython的-PY2时菜单>文件>设置>项目>项目解释== PY2
  2. 当菜单>文件>设置>项目>项目解释器== py3时,IPython-py3

答案:是的!

PS我也安装了适用于Windows的Python启动器。

I looked at this excellent info and then wondered, since

  1. i have python2, python3 and IPython all installed,
  2. i have PyCharm installed,
  3. PyCharm uses IPython for its Python Console,

if PyCharm would use

  1. IPython-py2 when Menu>File>Settings>Project>Project Interpreter == py2 AND
  2. IPython-py3 when Menu>File>Settings>Project>Project Interpreter == py3

ANSWER: Yes!

P.S. i have Python Launcher for Windows installed as well.


回答 9

在Windows 7下,我安装了anaconda和anaconda3。我走进去\Users\me\anaconda\Scripts执行

sudo .\ipython kernelspec install-self

然后我走进去\Users\me\anaconda3\Scripts执行

sudo .\ipython kernel install

(我知道了 jupyter kernelspec install-self is DEPRECATED as of 4.0. You probably want 'ipython kernel install' to install the IPython kernelspec.

启动后jupyter notebook(在anaconda3中),我在右上角的“新建”下获得了一个整洁的下拉菜单,让我在Python 2 odr和Python 3内核之间进行选择。

Under Windows 7 I had anaconda and anaconda3 installed. I went into \Users\me\anaconda\Scripts and executed

sudo .\ipython kernelspec install-self

then I went into \Users\me\anaconda3\Scripts and executed

sudo .\ipython kernel install

(I got jupyter kernelspec install-self is DEPRECATED as of 4.0. You probably want 'ipython kernel install' to install the IPython kernelspec.)

After starting jupyter notebook (in anaconda3) I got a neat dropdown menu in the upper right corner under “New” letting me choose between Python 2 odr Python 3 kernels.


回答 10

  • 如果您在虚拟环境中运行anaconda。
  • 当您创建一个新笔记本时,我没有显示选择虚拟环境内核。
  • 然后,您必须使用以下命令将其设置到ipykernel中
$ pip install --user ipykernel
$ python -m ipykernel install --user --name=test2
  • If you are running anaconda in virtual environment.
  • And when you create a new notebook but i’s not showing to select the virtual environment kernel.
  • Then you have to set it into the ipykernel using the following command
$ pip install --user ipykernel
$ python -m ipykernel install --user --name=test2

Python 3.5中的类型提示是什么?

问题:Python 3.5中的类型提示是什么?

类型提示是Python 3.5中讨论最多的功能之一。

的一个例子类型提示中提到的这篇文章这一个,同时还提负责任地使用类型提示。有人可以解释它们的更多信息,何时使用它们,何时不使用?

One of the most talked about features in Python 3.5 is type hints.

An example of type hints is mentioned in this article and this one while also mentioning to use type hints responsibly. Can someone explain more about them and when they should be used and when not?


回答 0

我建议阅读PEP 483PEP 484和观看演示由Guido的类型提示。

简而言之类型提示从字面上看是什么意思,您可以提示所使用的对象的类型

由于Python 的动态特性,推断或检查所使用对象的类型特别困难。这个事实使开发人员很难理解他们尚未编写的代码中到底发生了什么,而且最重要的是,对于许多IDE所使用的类型检查工具[PyCharm,PyDev想到],由于以下事实而受到限制:他们没有任何指示物是什么类型的指标。结果,他们求助于推断类型(如演示中所述),成功率约为50%。


摘录“类型提示”演示文稿中的两个重要幻灯片:

为什么要输入提示?

  1. 帮助类型检查器通过提示您希望对象成为哪种类型,例如,类型检查器可以轻松检测是否要传递的对象类型不是预期的类型。
  2. 帮助提供文档:查看您的代码的第三方将知道预期的用途,遍历,如何使用它而无需获取它们TypeErrors
  3. 帮助IDE开发更准确和健壮的工具:当知道对象的类型时,开发环境将更适合建议合适的方法。您可能曾经在某个IDE上遇到过这种情况,点击.并弹出未为对象定义的方法/属性。

为什么要使用静态类型检查器?

  • 尽早发现错误:我相信,这是不言而喻的。
  • 项目越大,就越需要:同样,这很有意义。静态语言提供了动态语言所缺乏的鲁棒性和控制力。您的应用程序越大,越复杂,就需要越多的控制和可预测性(从行为方面)。
  • 大型团队已经在进行静态分析:我猜这可以验证前两点。

作为这个小介绍的结束语:这是可选的功能,据我了解,已引入该功能是为了获得静态类型化的某些好处。

通常您无需担心它,并且绝对不需要使用它(尤其是在将Python用作辅助脚本语言的情况下)。在开发大型项目时,它应该会很有帮助,因为它提供了非常需要的鲁棒性,控制和其他调试功能


用mypy输入提示

为了使这个答案更完整,我认为稍作示范是合适的。我将使用mypy,它启发了PEP中介绍的Type Hints的库。这主要是为任何遇到此问题并想从哪里开始的人编写的。

在此之前,我要重申以下内容:PEP 484不执行任何操作;它只是为功能注释设置方向,并就如何 /应该执行类型检查。您可以注释功能,并根据需要提示任意多的内容。无论注释是否存在,您的脚本仍将运行,因为Python本身不使用它们。

无论如何,如PEP中所述,提示类型通常应采用三种形式:

此外,您将要结合使用类型提示和中typing引入的新模块Py3.5。其中定义了许多(附加)ABC(抽象基类)以及用于静态检查的辅助功能和装饰器。包含大多数内容ABCscollections.abcGeneric以允许订阅的形式(通过定义__getitem__()方法)。

对于那些对这些内容有更深入说明的人来说,mypy documentation它的编写非常好,并且有许多代码示例演示/描述了其检查器的功能。绝对值得一读。

功能注释和特殊注释:

首先,观察使用特殊注释时可以得到的某些行为很有趣。特别# type: type如果不能直接推断出对象的类型,则可以在变量分配期间添加注释以指示对象的类型。通常可以轻松推断出简单的任务,但是其他任务,例如列表(就其内容而言)则不能。

注意:如果要使用的任何派生形式Containers并需要为该容器指定内容,则必须使用模块中的泛型类型typing这些支持索引。

# generic List, supports indexing.
from typing import List

# In this case, the type is easily inferred as type: int.
i = 0

# Even though the type can be inferred as of type list
# there is no way to know the contents of this list.
# By using type: List[str] we indicate we want to use a list of strings.
a = []  # type: List[str]

# Appending an int to our list
# is statically not correct.
a.append(i)

# Appending a string is fine.
a.append("i")

print(a)  # [0, 'i']

如果我们将这些命令添加到文件中并使用解释器执行它们,则一切工作正常,print(a)仅打印list的内容a。这些# type注释已被丢弃,被视为无附加语义含义的普通注释

mypy另一方面,通过运行,我们得到以下响应:

(Python3)jimmi@jim: mypy typeHintsCode.py
typesInline.py:14: error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"

表示str对象列表不能包含int,从静态上讲是声音。可以通过遵循a和仅添加str对象的类型来解决此问题,也可以通过更改内容的类型a来表明任何值都是可接受的(直观地用List[Any]after Any导入from来执行typing)来解决此问题。

param_name : type在函数签名中的每个参数之后,以形式添加函数注释,并在-> type结束函数冒号之前使用表示法指定返回类型;所有注释都__annotations__以方便的字典形式存储在该函数的属性中。使用一个简单的示例(不需要typing模块中的其他类型):

def annotated(x: int, y: str) -> bool:
    return x < y

annotated.__annotations__属性现在具有以下值:

{'y': <class 'str'>, 'return': <class 'bool'>, 'x': <class 'int'>}

如果我们是一个完整的noobie,或者我们熟悉Py2.7概念并且因此不知道TypeError在比较中存在潜伏性annotated,那么我们可以执行另一项静态检查,捕获错误并为我们节省一些麻烦:

(Python3)jimmi@jim: mypy typeHintsCode.py
typeFunction.py: note: In function "annotated":
typeFunction.py:2: error: Unsupported operand types for > ("str" and "int")

除其他外,使用无效参数调用该函数也将被捕获:

annotated(20, 20)

# mypy complains:
typeHintsCode.py:4: error: Argument 2 to "annotated" has incompatible type "int"; expected "str"

这些基本可以扩展到任何用例,并且捕获的错误比基本调用和操作要扩展的更多。您可以检查的类型非常灵活,我只是对其潜能进行了简要介绍。通过查看typing模块,PEP或mypy文档,您将对所提供的功能有更全面的了解。

存根文件:

存根文件可以在两种不同的非互斥情况下使用:

  • 您需要键入检查您不想直接更改功能签名的模块
  • 您想编写模块并进行类型检查,但又希望将注释与内容分开。

存根文件(扩展名为.pyi)是您正在/将要使用的模块的带注释的接口。它们包含要键入的功能的签名,并丢弃了这些功能的主体。为了了解这一点,给定名为模块的三个随机函数randfunc.py

def message(s):
    print(s)

def alterContents(myIterable):
    return [i for i in myIterable if i % 2 == 0]

def combine(messageFunc, itFunc):
    messageFunc("Printing the Iterable")
    a = alterContents(range(1, 20))
    return set(a)

我们可以创建一个存根文件randfunc.pyi,如果需要的话,可以在其中放置一些限制。不利的一面是,在不了解存根的情况下查看源代码的人在试图理解应该传递到何处时将不会真正获得注释帮助。

无论如何,存根文件的结构都非常简单:添加带有空主体(pass填充)的所有函数定义,并根据您的要求提供注释。在这里,假设我们只想使用int容器的类型。

# Stub for randfucn.py
from typing import Iterable, List, Set, Callable

def message(s: str) -> None: pass

def alterContents(myIterable: Iterable[int])-> List[int]: pass

def combine(
    messageFunc: Callable[[str], Any],
    itFunc: Callable[[Iterable[int]], List[int]]
)-> Set[int]: pass

combine函数提供了一个指示,说明为什么您可能要在其他文件中使用批注,它们有时会使代码混乱,并降低可读性(对于Python来说,很大的缺点)。您当然可以使用类型别名,但有时会比其有用之处更加混乱(因此请明智地使用它们)。


这应该使您熟悉Python中的类型提示的基本概念。即使使用了类型检查器, mypy您也应该逐渐开始看到它们的更多弹出窗口,其中一些内部是IDE(PyCharm),其他是标准python模块。当我发现它们(或建议)时,我将尝试在以下列表中添加其他检查器/相关程序包。

我知道的跳棋

  • Mypy:如此处所述。
  • PyType:由Google使用,与我收集到的符号不同,可能值得一看。

相关软件包/项目

  • 类型:官方Python回购,其中包含标准库的各种存根文件。

typeshed实际上,该项目是您可以查看的最佳场所之一,以了解如何在自己的项目中使用类型提示。让我们以相应文件中该类__init__笨拙Counter为例.pyi

class Counter(Dict[_T, int], Generic[_T]):
        @overload
        def __init__(self) -> None: ...
        @overload
        def __init__(self, Mapping: Mapping[_T, int]) -> None: ...
        @overload
        def __init__(self, iterable: Iterable[_T]) -> None: ...

在哪里_T = TypeVar('_T')用来定义泛型类。对于Counter该类,我们可以看到它可以在其初始值设定项中不接受任何参数,可以将Mapping任何类型的单个值获取为an,int 可以采用Iterable任何类型的。


注意:我忘记提及的一件事是该typing模块是临时引入的。从PEP 411

临时包可以在“升级”为“稳定”状态之前对其API进行修改。一方面,这种状态为软件包提供了正式加入Python发行版的好处。另一方面,核心开发团队明确声明,对于包API的稳定性没有任何保证,在下一发行版中可能会更改。虽然这被认为是不太可能的结果,但是如果对它们的API或维护的担心被证明是有根据的,那么甚至可以在不弃用期限的情况下从标准库中删除此类软件包。

所以在这里放些盐。我怀疑它将以重大方式被删除或更改,但是人们永远不会知道。


**另一个主题,但在类型提示的范围内完全有效PEP 526::变量注释的语法# type通过引入新的语法来替换注释的工作,该语法允许用户在简单的varname: type语句中注释变量的类型。

请参阅什么是Python 3.6中的变量注释?,如前所述,有关这些内容的小介绍。

I would suggest reading PEP 483 and PEP 484 and watching this presentation by Guido on Type Hinting.

In a nutshell: Type hinting is literally what the words mean, you hint the type of the object(s) you’re using.

Due to the dynamic nature of Python, inferring or checking the type of an object being used is especially hard. This fact makes it hard for developers to understand what exactly is going on in code they haven’t written and, most importantly, for type checking tools found in many IDEs [PyCharm, PyDev come to mind] that are limited due to the fact that they don’t have any indicator of what type the objects are. As a result they resort to trying to infer the type with (as mentioned in the presentation) around 50% success rate.


To take two important slides from the Type Hinting presentation:

Why Type Hints?

  1. Helps Type Checkers: By hinting at what type you want the object to be the type checker can easily detect if, for instance, you’re passing an object with a type that isn’t expected.
  2. Helps with documentation: A third person viewing your code will know what is expected where, ergo, how to use it without getting them TypeErrors.
  3. Helps IDEs develop more accurate and robust tools: Development Environments will be better suited at suggesting appropriate methods when know what type your object is. You have probably experienced this with some IDE at some point, hitting the . and having methods/attributes pop up which aren’t defined for an object.

Why use Static Type Checkers?

  • Find bugs sooner: This is self evident, I believe.
  • The larger your project the more you need it: Again, makes sense. Static languages offer a robustness and control that dynamic languages lack. The bigger and more complex your application becomes the more control and predictability (from a behavioral aspect) you require.
  • Large teams are already running static analysis: I’m guessing this verifies the first two points.

As a closing note for this small introduction: This is an optional feature and, from what I understand, it has been introduced in order to reap some of the benefits of static typing.

You generally do not need to worry about it and definitely don’t need to use it (especially in cases where you use Python as an auxiliary scripting language). It should be helpful when developing large projects as it offers much needed robustness, control and additional debugging capabilities.


Type Hinting with mypy:

In order to make this answer more complete, I think a little demonstration would be suitable. I’ll be using mypy, the library which inspired Type Hints as they are presented in the PEP. This is mainly written for anybody bumping into this question and wondering where to begin.

Before I do that let me reiterate the following: PEP 484 doesn’t enforce anything; it is simply setting a direction for function annotations and proposing guidelines for how type checking can/should be performed. You can annotate your functions and hint as many things as you want; your scripts will still run regardless of the presence of annotations because Python itself doesn’t use them.

Anyways, as noted in the PEP, hinting types should generally take three forms:

Additionally, you’ll want to use type hints in conjunction with the new typing module introduced in Py3.5. In it, many (additional) ABCs (Abstract Base Classes) are defined along with helper functions and decorators for use in static checking. Most ABCs in collections.abc are included but in a Generic form in order to allow subscription (by defining a __getitem__() method).

For anyone interested in a more in-depth explanation of these, the mypy documentation is written very nicely and has a lot of code samples demonstrating/describing the functionality of their checker; it is definitely worth a read.

Function annotations and special comments:

First, it’s interesting to observe some of the behavior we can get when using special comments. Special # type: type comments can be added during variable assignments to indicate the type of an object if one cannot be directly inferred. Simple assignments are generally easily inferred but others, like lists (with regard to their contents), cannot.

Note: If we want to use any derivative of Containers and need to specify the contents for that container we must use the generic types from the typing module. These support indexing.

# generic List, supports indexing.
from typing import List

# In this case, the type is easily inferred as type: int.
i = 0

# Even though the type can be inferred as of type list
# there is no way to know the contents of this list.
# By using type: List[str] we indicate we want to use a list of strings.
a = []  # type: List[str]

# Appending an int to our list
# is statically not correct.
a.append(i)

# Appending a string is fine.
a.append("i")

print(a)  # [0, 'i']

If we add these commands to a file and execute them with our interpreter, everything works just fine and print(a) just prints the contents of list a. The # type comments have been discarded, treated as plain comments which have no additional semantic meaning.

By running this with mypy, on the other hand, we get the following responce:

(Python3)jimmi@jim: mypy typeHintsCode.py
typesInline.py:14: error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"

Indicating that a list of str objects cannot contain an int, which, statically speaking, is sound. This can be fixed by either abiding to the type of a and only appending str objects or by changing the type of the contents of a to indicate that any value is acceptable (Intuitively performed with List[Any] after Any has been imported from typing).

Function annotations are added in the form param_name : type after each parameter in your function signature and a return type is specified using the -> type notation before the ending function colon; all annotations are stored in the __annotations__ attribute for that function in a handy dictionary form. Using a trivial example (which doesn’t require extra types from the typing module):

def annotated(x: int, y: str) -> bool:
    return x < y

The annotated.__annotations__ attribute now has the following values:

{'y': <class 'str'>, 'return': <class 'bool'>, 'x': <class 'int'>}

If we’re a complete noobie, or we are familiar with Py2.7 concepts and are consequently unaware of the TypeError lurking in the comparison of annotated, we can perform another static check, catch the error and save us some trouble:

(Python3)jimmi@jim: mypy typeHintsCode.py
typeFunction.py: note: In function "annotated":
typeFunction.py:2: error: Unsupported operand types for > ("str" and "int")

Among other things, calling the function with invalid arguments will also get caught:

annotated(20, 20)

# mypy complains:
typeHintsCode.py:4: error: Argument 2 to "annotated" has incompatible type "int"; expected "str"

These can be extended to basically any use-case and the errors caught extend further than basic calls and operations. The types you can check for are really flexible and I have merely given a small sneak peak of its potential. A look in the typing module, the PEPs or the mypy docs will give you a more comprehensive idea of the capabilities offered.

Stub Files:

Stub files can be used in two different non mutually exclusive cases:

  • You need to type check a module for which you do not want to directly alter the function signatures
  • You want to write modules and have type-checking but additionally want to separate annotations from content.

What stub files (with an extension of .pyi) are is an annotated interface of the module you are making/want to use. They contain the signatures of the functions you want to type-check with the body of the functions discarded. To get a feel of this, given a set of three random functions in a module named randfunc.py:

def message(s):
    print(s)

def alterContents(myIterable):
    return [i for i in myIterable if i % 2 == 0]

def combine(messageFunc, itFunc):
    messageFunc("Printing the Iterable")
    a = alterContents(range(1, 20))
    return set(a)

We can create a stub file randfunc.pyi, in which we can place some restrictions if we wish to do so. The downside is that somebody viewing the source without the stub won’t really get that annotation assistance when trying to understand what is supposed to be passed where.

Anyway, the structure of a stub file is pretty simplistic: Add all function definitions with empty bodies (pass filled) and supply the annotations based on your requirements. Here, let’s assume we only want to work with int types for our Containers.

# Stub for randfucn.py
from typing import Iterable, List, Set, Callable

def message(s: str) -> None: pass

def alterContents(myIterable: Iterable[int])-> List[int]: pass

def combine(
    messageFunc: Callable[[str], Any],
    itFunc: Callable[[Iterable[int]], List[int]]
)-> Set[int]: pass

The combine function gives an indication of why you might want to use annotations in a different file, they some times clutter up the code and reduce readability (big no-no for Python). You could of course use type aliases but that sometime confuses more than it helps (so use them wisely).


This should get you familiarized with the basic concepts of Type Hints in Python. Even though the type checker used has been mypy you should gradually start to see more of them pop-up, some internally in IDEs (PyCharm,) and others as standard python modules. I’ll try and add additional checkers/related packages in the following list when and if I find them (or if suggested).

Checkers I know of:

  • Mypy: as described here.
  • PyType: By Google, uses different notation from what I gather, probably worth a look.

Related Packages/Projects:

  • typeshed: Official Python repo housing an assortment of stub files for the standard library.

The typeshed project is actually one of the best places you can look to see how type hinting might be used in a project of your own. Let’s take as an example the __init__ dunders of the Counter class in the corresponding .pyi file:

class Counter(Dict[_T, int], Generic[_T]):
        @overload
        def __init__(self) -> None: ...
        @overload
        def __init__(self, Mapping: Mapping[_T, int]) -> None: ...
        @overload
        def __init__(self, iterable: Iterable[_T]) -> None: ...

Where _T = TypeVar('_T') is used to define generic classes. For the Counter class we can see that it can either take no arguments in its initializer, get a single Mapping from any type to an int or take an Iterable of any type.


Notice: One thing I forgot to mention was that the typing module has been introduced on a provisional basis. From PEP 411:

A provisional package may have its API modified prior to “graduating” into a “stable” state. On one hand, this state provides the package with the benefits of being formally part of the Python distribution. On the other hand, the core development team explicitly states that no promises are made with regards to the the stability of the package’s API, which may change for the next release. While it is considered an unlikely outcome, such packages may even be removed from the standard library without a deprecation period if the concerns regarding their API or maintenance prove well-founded.

So take things here with a pinch of salt; I’m doubtfull it will be removed or altered in significant ways but one can never know.


** Another topic altogether but valid in the scope of type-hints: PEP 526: Syntax for Variable Annotations is an effort to replace # type comments by introducing new syntax which allows users to annotate the type of variables in simple varname: type statements.

See What are variable annotations in Python 3.6?, as previously mentioned, for a small intro on these.


回答 1

添加到吉姆精心设计的答案中:

检查typing模块 -该模块支持PEP 484指定的类型提示。

例如,下面的函数采用并返回type的值,str并且其注释如下:

def greeting(name: str) -> str:
    return 'Hello ' + name

typing模块还支持:

  1. 输入别名
  2. 回调函数的类型提示。
  3. 泛型 -抽象基类已扩展为支持预订,以表示容器元素的预期类型。
  4. 用户定义的通用类型 -用户定义的类可以定义为通用类。
  5. 任何类型 -每个类型都是Any的子类型。

Adding to Jim’s elaborate answer:

Check the typing module — this module supports type hints as specified by PEP 484.

For example, the function below takes and returns values of type str and is annotated as follows:

def greeting(name: str) -> str:
    return 'Hello ' + name

The typing module also supports:

  1. Type aliasing.
  2. Type hinting for callback functions.
  3. Generics – Abstract base classes have been extended to support subscription to denote expected types for container elements.
  4. User-defined generic types – A user-defined class can be defined as a generic class.
  5. Any type – Every type is a subtype of Any.

回答 2

新发布的PyCharm 5支持类型提示。在有关它的博客文章中(请参阅PyCharm 5中的Python 3.5类型提示),他们提供了关于什么是类型提示和不存在类型提示的很好的解释,并提供了一些示例和插图说明如何在代码中使用它们。

此外,Python 2.7支持它,如以下注释中所述

PyCharm支持来自PyPI的用于Python 2.7,Python 3.2-3.4的键入模块。对于2.7,您必须在* .pyi存根文件中放入类型提示,因为函数注释是在Python 3.0中添加的

The newly released PyCharm 5 supports type hinting. In their blog post about it (see Python 3.5 type hinting in PyCharm 5) they offer a great explanation of what type hints are and aren’t along with several examples and illustrations for how to use them in your code.

Additionally, it is supported in Python 2.7, as explained in this comment:

PyCharm supports the typing module from PyPI for Python 2.7, Python 3.2-3.4. For 2.7 you have to put type hints in *.pyi stub files since function annotations were added in Python 3.0.


回答 3

类型提示是对动态语言的最新补充,数十年来人们一直宣誓像匈牙利语一样简单的命名约定(对象标签的首字母为b =布尔语,c =字符,d =字典,i =整数,l =列表,n =数字,s =字符串,t =元组),太麻烦了,但是现在决定了,哦,等等……使用语言(type())来识别对象和我们花哨的IDE实在是太麻烦了需要帮助来完成任何复杂的事情,并且动态分配的对象值使它们无论如何都变得毫无用处,而对于任何开发人员而言,一个简单的命名约定就可以解决所有问题。

Type hint are a recent addition to a dynamic language where for decades folks swore naming conventions as simple as Hungarian (object label with first letter b = boolian, c = character, d = dictionary, i = integer, l = list, n = numeric, s = string, t= tuple) were not needed, too cumbersome, but now have decided that, oh wait … it is way too much trouble to use the language (type()) to recognize objects, and our fancy IDEs need help doing anything that complicated, and that dynamically assigned object values make them completely useless anyhow, whereas a simple naming convention could have resolved all of it, for any developer, at a mere glance.


回答 4

类型提示是为了可维护性,不会被Python解释。在下面的代码中,该行def add(self, ic:int)直到下一return...行才导致错误:

class C1:
    def __init__(self):
        self.idn = 1
    def add(self, ic: int):
        return self.idn + ic
    
c1 = C1()
c1.add(2)

c1.add(c1)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 5, in add
TypeError: unsupported operand type(s) for +: 'int' and 'C1'
 

Type-hints are for maintainability and don’t get interpreted by Python. In the code below, the line def add(self, ic:int) doesn’t result in an error until the next return... line:

class C1:
    def __init__(self):
        self.idn = 1
    def add(self, ic: int):
        return self.idn + ic
    
c1 = C1()
c1.add(2)

c1.add(c1)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 5, in add
TypeError: unsupported operand type(s) for +: 'int' and 'C1'