标签归档:python-3.x

Python 3中的raw_input()和input()有什么区别?

问题:Python 3中的raw_input()和input()有什么区别?

raw_input()input()Python 3有什么区别?

What is the difference between raw_input() and input() in Python 3?


回答 0

区别在于raw_input()Python 3.x中不存在,而input()确实存在。实际上,raw_input()已将旧名称重命名为input(),而旧名称input()已消失,但是可以使用轻松地对其进行模拟eval(input())。(请记住这eval()是邪恶的。如果可能,请尝试使用更安全的方法来解析输入。)

The difference is that raw_input() does not exist in Python 3.x, while input() does. Actually, the old raw_input() has been renamed to input(), and the old input() is gone, but can easily be simulated by using eval(input()). (Remember that eval() is evil. Try to use safer ways of parsing your input if possible.)


回答 1

在Python 2中raw_input()返回一个字符串,并input()尝试将输入作为Python表达式运行。

由于获取字符串几乎总是您想要的,因此Python 3做到了input()。正如Sven所说,如果您想要旧的行为,那就eval(input())可以了。

In Python 2, raw_input() returns a string, and input() tries to run the input as a Python expression.

Since getting a string was almost always what you wanted, Python 3 does that with input(). As Sven says, if you ever want the old behaviour, eval(input()) works.


回答 2

Python 2:

  • raw_input() 完全接受用户键入的内容,并将其作为字符串传递回。

  • input()首先采用raw_input(),然后对其执行eval()

主要区别在于,input()期望语法正确的python语句raw_input()没有。

Python 3:

  • raw_input()被重命名为,input()因此现在input()返回确切的字符串。
  • 旧的input()被删除。

如果要使用旧的input()(意味着需要将用户输入评估为python语句),则必须使用手动进行操作eval(input())

Python 2:

  • raw_input() takes exactly what the user typed and passes it back as a string.

  • input() first takes the raw_input() and then performs an eval() on it as well.

The main difference is that input() expects a syntactically correct python statement where raw_input() does not.

Python 3:

  • raw_input() was renamed to input() so now input() returns the exact string.
  • Old input() was removed.

If you want to use the old input(), meaning you need to evaluate a user input as a python statement, you have to do it manually by using eval(input()).


回答 3

在Python 3中,raw_input()不存在Sven已经提到的内容。

在Python 2中,该input()函数评估您的输入。

例:

name = input("what is your name ?")
what is your name ?harsha

Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    name = input("what is your name ?")
  File "<string>", line 1, in <module>
NameError: name 'harsha' is not defined

在上面的示例中,Python 2.x尝试将rahda评估为变量而非字符串。为了避免这种情况,我们可以在输入中使用双引号,例如“ harsha”:

>>> name = input("what is your name?")
what is your name?"harsha"
>>> print(name)
harsha

raw_input()

raw_input()函数不会求值,它只会读取您输入的内容。

例:

name = raw_input("what is your name ?")
what is your name ?harsha
>>> name
'harsha'

例:

 name = eval(raw_input("what is your name?"))
what is your name?harsha

Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    name = eval(raw_input("what is your name?"))
  File "<string>", line 1, in <module>
NameError: name 'harsha' is not defined

在上面的示例中,我只是尝试使用该eval函数评估用户输入。

In Python 3, raw_input() doesn’t exist which was already mentioned by Sven.

In Python 2, the input() function evaluates your input.

Example:

name = input("what is your name ?")
what is your name ?harsha

Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    name = input("what is your name ?")
  File "<string>", line 1, in <module>
NameError: name 'harsha' is not defined

In the example above, Python 2.x is trying to evaluate harsha as a variable rather than a string. To avoid that, we can use double quotes around our input like “harsha”:

>>> name = input("what is your name?")
what is your name?"harsha"
>>> print(name)
harsha

raw_input()

The raw_input()` function doesn’t evaluate, it will just read whatever you enter.

Example:

name = raw_input("what is your name ?")
what is your name ?harsha
>>> name
'harsha'

Example:

 name = eval(raw_input("what is your name?"))
what is your name?harsha

Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    name = eval(raw_input("what is your name?"))
  File "<string>", line 1, in <module>
NameError: name 'harsha' is not defined

In example above, I was just trying to evaluate the user input with the eval function.


回答 4

我想在每个人为python 2用户提供的解释中添加更多细节。raw_input(),到现在为止,您已经知道该功能可以评估用户以字符串形式输入的数据。这意味着python甚至不会尝试再次理解输入的数据。它只会考虑输入的数据将是字符串,无论它是实际的字符串还是int或其他任何值。

input()在另一方面试图理解用户输入的数据。因此,像这样的输入helloworld甚至会将错误显示为’ helloworld is undefined‘。

总之,对于python 2来说,也要输入字符串,您需要像’ helloworld‘ 一样输入它,这是python中使用字符串的常用结构。

I’d like to add a little more detail to the explanation provided by everyone for the python 2 users. raw_input(), which, by now, you know that evaluates what ever data the user enters as a string. This means that python doesn’t try to even understand the entered data again. All it will consider is that the entered data will be string, whether or not it is an actual string or int or anything.

While input() on the other hand tries to understand the data entered by the user. So the input like helloworld would even show the error as ‘helloworld is undefined‘.

In conclusion, for python 2, to enter a string too you need to enter it like ‘helloworld‘ which is the common structure used in python to use strings.


回答 5

如果您想确保自己的代码与python2和python3一起运行,请在脚本中使用function input()并将其添加到脚本的开头:

from sys import version_info
if version_info.major == 3:
    pass
elif version_info.major == 2:
    try:
        input = raw_input
    except NameError:
        pass
else:
    print ("Unknown python version - input function not safe")

If You want to ensure, that your code is running with python2 and python3, use function input () in your script and add this to begin of your script:

from sys import version_info
if version_info.major == 3:
    pass
elif version_info.major == 2:
    try:
        input = raw_input
    except NameError:
        pass
else:
    print ("Unknown python version - input function not safe")

在Python中连接字符串的首选方法是什么?

问题:在Python中连接字符串的首选方法是什么?

由于string无法更改Python ,因此我想知道如何更有效地连接字符串?

我可以这样写:

s += stringfromelsewhere

或像这样:

s = []
s.append(somestring)

later

s = ''.join(s)

在写这个问题时,我找到了一篇很好的文章,谈论这个话题。

http://www.skymind.com/~ocrow/python_string/

但是它在Python 2.x中,所以问题是在Python 3中会有所改变吗?

Since Python’s string can’t be changed, I was wondering how to concatenate a string more efficiently?

I can write like it:

s += stringfromelsewhere

or like this:

s = []
s.append(somestring)

later

s = ''.join(s)

While writing this question, I found a good article talking about the topic.

http://www.skymind.com/~ocrow/python_string/

But it’s in Python 2.x., so the question would be did something change in Python 3?


回答 0

将字符串附加到字符串变量的最佳方法是使用++=。这是因为它可读且快速。它们的速度也一样快,您选择的是一个品味问题,后者是最常见的。以下是该timeit模块的时间安排:

a = a + b:
0.11338996887207031
a += b:
0.11040496826171875

但是,那些建议拥有列表并附加到列表然后再连接这些列表的人之所以这么做,是因为将字符串附加到列表与扩展字符串相比可能非常快。在某些情况下,这可能是正确的。例如,这里是一字符字符串的一百万个追加,首先是字符串,然后是列表:

a += b:
0.10780501365661621
a.append(b):
0.1123361587524414

好的,事实证明,即使结果字符串的长度为一百万个字符,追加操作仍然更快。

现在让我们尝试将十千个字符长的字符串追加十万次:

a += b:
0.41823482513427734
a.append(b):
0.010656118392944336

因此,最终字符串的长度约为100MB。那太慢了,追加到列表上要快得多。那个时机不包括决赛a.join()。那要花多长时间?

a.join(a):
0.43739795684814453

哎呀 即使在这种情况下,append / join也较慢。

那么,该建议来自何处?Python 2?

a += b:
0.165287017822
a.append(b):
0.0132720470428
a.join(a):
0.114929914474

好吧,如果您使用的是非常长的字符串(通常不是,那么内存中100MB的字符串会是什么),append / join的速度会稍微快一些。

但是真正的关键是Python 2.3。我什至不告诉您时间安排,因为它是如此之慢以至于还没有完成。这些测试突然耗时数分钟。除了append / join之外,它和以后的Python一样快。

对。在石器时代,字符串连接在Python中非常缓慢。但是在2.4上已经不存在了(或者至少是Python 2.4.7),因此在2008年Python 2.3停止更新时,使用append / join的建议已过时,您应该停止使用它。:-)

(更新:当我更仔细地进行测试时发现,使用++=在Python 2.3上使用两个字符串的速度也更快。关于使用的建议''.join()一定是一种误解)

但是,这是CPython。其他实现可能还有其他问题。这是过早优化是万恶之源的又一个原因。除非先进行测量,否则不要使用被认为“更快”的技术。

因此,进行字符串连接的“最佳”版本是使用+或+ =。如果事实证明这对您来说很慢,那是不太可能的,那么请执行其他操作。

那么,为什么在我的代码中使用大量的添加/联接?因为有时它实际上更清晰。尤其是当您应将其串联在一起时,应以空格,逗号或换行符分隔。

The best way of appending a string to a string variable is to use + or +=. This is because it’s readable and fast. They are also just as fast, which one you choose is a matter of taste, the latter one is the most common. Here are timings with the timeit module:

a = a + b:
0.11338996887207031
a += b:
0.11040496826171875

However, those who recommend having lists and appending to them and then joining those lists, do so because appending a string to a list is presumably very fast compared to extending a string. And this can be true, in some cases. Here, for example, is one million appends of a one-character string, first to a string, then to a list:

a += b:
0.10780501365661621
a.append(b):
0.1123361587524414

OK, turns out that even when the resulting string is a million characters long, appending was still faster.

Now let’s try with appending a thousand character long string a hundred thousand times:

a += b:
0.41823482513427734
a.append(b):
0.010656118392944336

The end string, therefore, ends up being about 100MB long. That was pretty slow, appending to a list was much faster. That that timing doesn’t include the final a.join(). So how long would that take?

a.join(a):
0.43739795684814453

Oups. Turns out even in this case, append/join is slower.

So where does this recommendation come from? Python 2?

a += b:
0.165287017822
a.append(b):
0.0132720470428
a.join(a):
0.114929914474

Well, append/join is marginally faster there if you are using extremely long strings (which you usually aren’t, what would you have a string that’s 100MB in memory?)

But the real clincher is Python 2.3. Where I won’t even show you the timings, because it’s so slow that it hasn’t finished yet. These tests suddenly take minutes. Except for the append/join, which is just as fast as under later Pythons.

Yup. String concatenation was very slow in Python back in the stone age. But on 2.4 it isn’t anymore (or at least Python 2.4.7), so the recommendation to use append/join became outdated in 2008, when Python 2.3 stopped being updated, and you should have stopped using it. :-)

(Update: Turns out when I did the testing more carefully that using + and += is faster for two strings on Python 2.3 as well. The recommendation to use ''.join() must be a misunderstanding)

However, this is CPython. Other implementations may have other concerns. And this is just yet another reason why premature optimization is the root of all evil. Don’t use a technique that’s supposed “faster” unless you first measure it.

Therefore the “best” version to do string concatenation is to use + or +=. And if that turns out to be slow for you, which is pretty unlikely, then do something else.

So why do I use a lot of append/join in my code? Because sometimes it’s actually clearer. Especially when whatever you should concatenate together should be separated by spaces or commas or newlines.


回答 1

如果要串联很多值,那么两者都不是。追加列表很昂贵。您可以为此使用StringIO。特别是如果您要通过大量操作来构建它。

from cStringIO import StringIO
# python3:  from io import StringIO

buf = StringIO()

buf.write('foo')
buf.write('foo')
buf.write('foo')

buf.getvalue()
# 'foofoofoo'

如果您已经有其他操作返回的完整列表,则只需使用 ''.join(aList)

从python常见问题解答:将许多字符串连接在一起的最有效方法是什么?

str和bytes对象是不可变的,因此将多个字符串连接在一起效率不高,因为每个串联都会创建一个新对象。在一般情况下,总运行时成本在总字符串长度中是二次方的。

要累积许多str对象,建议的惯用法是将它们放入列表中,并在最后调用str.join():

chunks = []
for s in my_strings:
    chunks.append(s)
result = ''.join(chunks)

(另一个合理有效的习惯用法是使用io.StringIO)

要累积许多字节对象,建议的惯用法是使用就地串联(+ =运算符)扩展一个bytearray对象:

result = bytearray()
for b in my_bytes_objects:
    result += b

编辑:我很愚蠢,并且将结果向后粘贴,使其看起来比cStringIO更快。我还添加了针对bytearray / str concat的测试,以及使用较大列表和较大字符串的第二轮测试。(python 2.7.3)

大量字符串的ipython测试示例

try:
    from cStringIO import StringIO
except:
    from io import StringIO

source = ['foo']*1000

%%timeit buf = StringIO()
for i in source:
    buf.write(i)
final = buf.getvalue()
# 1000 loops, best of 3: 1.27 ms per loop

%%timeit out = []
for i in source:
    out.append(i)
final = ''.join(out)
# 1000 loops, best of 3: 9.89 ms per loop

%%timeit out = bytearray()
for i in source:
    out += i
# 10000 loops, best of 3: 98.5 µs per loop

%%timeit out = ""
for i in source:
    out += i
# 10000 loops, best of 3: 161 µs per loop

## Repeat the tests with a larger list, containing
## strings that are bigger than the small string caching 
## done by the Python
source = ['foo']*1000

# cStringIO
# 10 loops, best of 3: 19.2 ms per loop

# list append and join
# 100 loops, best of 3: 144 ms per loop

# bytearray() +=
# 100 loops, best of 3: 3.8 ms per loop

# str() +=
# 100 loops, best of 3: 5.11 ms per loop

If you are concatenating a lot of values, then neither. Appending a list is expensive. You can use StringIO for that. Especially if you are building it up over a lot of operations.

from cStringIO import StringIO
# python3:  from io import StringIO

buf = StringIO()

buf.write('foo')
buf.write('foo')
buf.write('foo')

buf.getvalue()
# 'foofoofoo'

If you already have a complete list returned to you from some other operation, then just use the ''.join(aList)

From the python FAQ: What is the most efficient way to concatenate many strings together?

str and bytes objects are immutable, therefore concatenating many strings together is inefficient as each concatenation creates a new object. In the general case, the total runtime cost is quadratic in the total string length.

To accumulate many str objects, the recommended idiom is to place them into a list and call str.join() at the end:

chunks = []
for s in my_strings:
    chunks.append(s)
result = ''.join(chunks)

(another reasonably efficient idiom is to use io.StringIO)

To accumulate many bytes objects, the recommended idiom is to extend a bytearray object using in-place concatenation (the += operator):

result = bytearray()
for b in my_bytes_objects:
    result += b

Edit: I was silly and had the results pasted backwards, making it look like appending to a list was faster than cStringIO. I have also added tests for bytearray/str concat, as well as a second round of tests using a larger list with larger strings. (python 2.7.3)

ipython test example for large lists of strings

try:
    from cStringIO import StringIO
except:
    from io import StringIO

source = ['foo']*1000

%%timeit buf = StringIO()
for i in source:
    buf.write(i)
final = buf.getvalue()
# 1000 loops, best of 3: 1.27 ms per loop

%%timeit out = []
for i in source:
    out.append(i)
final = ''.join(out)
# 1000 loops, best of 3: 9.89 ms per loop

%%timeit out = bytearray()
for i in source:
    out += i
# 10000 loops, best of 3: 98.5 µs per loop

%%timeit out = ""
for i in source:
    out += i
# 10000 loops, best of 3: 161 µs per loop

## Repeat the tests with a larger list, containing
## strings that are bigger than the small string caching 
## done by the Python
source = ['foo']*1000

# cStringIO
# 10 loops, best of 3: 19.2 ms per loop

# list append and join
# 100 loops, best of 3: 144 ms per loop

# bytearray() +=
# 100 loops, best of 3: 3.8 ms per loop

# str() +=
# 100 loops, best of 3: 5.11 ms per loop

回答 2

在Python> = 3.6中,新的f字符串是连接字符串的有效方法。

>>> name = 'some_name'
>>> number = 123
>>>
>>> f'Name is {name} and the number is {number}.'
'Name is some_name and the number is 123.'

In Python >= 3.6, the new f-string is an efficient way to concatenate a string.

>>> name = 'some_name'
>>> number = 123
>>>
>>> f'Name is {name} and the number is {number}.'
'Name is some_name and the number is 123.'

回答 3

推荐的方法仍然是使用附加和联接。

The recommended method is still to use append and join.


回答 4

如果要串联的字符串是文字,请使用字符串文字串联

re.compile(
        "[A-Za-z_]"       # letter or underscore
        "[A-Za-z0-9_]*"   # letter, digit or underscore
    )

如果要对字符串的一部分进行注释(如上)或要使用原始字符串,这将很有用文本的一部分(但不是全部)或三引号,。

由于这是在语法层发生的,因此它使用零个串联运算符。

If the strings you are concatenating are literals, use String literal concatenation

re.compile(
        "[A-Za-z_]"       # letter or underscore
        "[A-Za-z0-9_]*"   # letter, digit or underscore
    )

This is useful if you want to comment on part of a string (as above) or if you want to use raw strings or triple quotes for part of a literal but not all.

Since this happens at the syntax layer it uses zero concatenation operators.


回答 5

你写这个函数

def str_join(*args):
    return ''.join(map(str, args))

然后,您可以随时随地调用

str_join('Pine')  # Returns : Pine
str_join('Pine', 'apple')  # Returns : Pineapple
str_join('Pine', 'apple', 3)  # Returns : Pineapple3

You write this function

def str_join(*args):
    return ''.join(map(str, args))

Then you can call simply wherever you want

str_join('Pine')  # Returns : Pine
str_join('Pine', 'apple')  # Returns : Pineapple
str_join('Pine', 'apple', 3)  # Returns : Pineapple3

回答 6

虽然有些过时,代码像Pythonista:地道的Python建议join()+ 本节。就像PythonSpeedPerformanceTips在其有关字符串连接的部分中一样,具有以下免责声明:

对于更高版本的Python,本节的准确性存在争议。在CPython 2.5中,字符串连接相当快,尽管这可能不适用于其他Python实现。有关讨论,请参见ConcatenationTestCode。

While somewhat dated, Code Like a Pythonista: Idiomatic Python recommends join() over + in this section. As does PythonSpeedPerformanceTips in its section on string concatenation, with the following disclaimer:

The accuracy of this section is disputed with respect to later versions of Python. In CPython 2.5, string concatenation is fairly fast, although this may not apply likewise to other Python implementations. See ConcatenationTestCode for a discussion.


回答 7

就稳定性和交叉实现而言,最糟糕的串联方法是使用’+’进行就地字符串串联,因为它不支持所有值。PEP8标准不鼓励这样做,并鼓励长期使用format(),join()和append()。

如链接的“编程建议”部分所述:

例如,对于形式为+ = b或a = a + b的语句,请不要依赖CPython有效地实现就地字符串连接。即使在CPython中,这种优化也是脆弱的(仅适用于某些类型),并且在不使用引用计数的实现中根本没有这种优化。在库的性能敏感部分,应改用”.join()形式。这将确保在各种实现中串联发生在线性时间内。

Using in place string concatenation by ‘+’ is THE WORST method of concatenation in terms of stability and cross implementation as it does not support all values. PEP8 standard discourages this and encourages the use of format(), join() and append() for long term use.

As quoted from the linked “Programming Recommendations” section:

For example, do not rely on CPython’s efficient implementation of in-place string concatenation for statements in the form a += b or a = a + b. This optimization is fragile even in CPython (it only works for some types) and isn’t present at all in implementations that don’t use refcounting. In performance sensitive parts of the library, the ”.join() form should be used instead. This will ensure that concatenation occurs in linear time across various implementations.


回答 8

如@jdi所述,Python文档建议使用str.joinio.StringIO进行字符串连接。并说开发人员应该从+=循环中期待二次时间,即使自Python 2.4开始进行了优化。正如这个答案所说:

如果Python检测到left参数没有其他引用,它将调用realloc来尝试通过调整字符串的大小来避免复制。这不是您应该依靠的东西,因为它是一个实现细节,并且因为如果realloc最终需要频繁移动字符串,那么性能会下降到O(n ^ 2)。

我将展示一个天真地依赖于+=这种优化的真实代码示例,但它并不适用。下面的代码将可迭代的短字符串转换为更大的块,以用于批量API。

def test_concat_chunk(seq, split_by):
    result = ['']
    for item in seq:
        if len(result[-1]) + len(item) > split_by: 
            result.append('')
        result[-1] += item
    return result

由于二次时间的复杂性,该代码可能在文学上运行数小时。以下是具有建议的数据结构的替代方案:

import io

def test_stringio_chunk(seq, split_by):
    def chunk():
        buf = io.StringIO()
        size = 0
        for item in seq:
            if size + len(item) <= split_by:
                size += buf.write(item)
            else:
                yield buf.getvalue()
                buf = io.StringIO()
                size = buf.write(item)
        if size:
            yield buf.getvalue()

    return list(chunk())

def test_join_chunk(seq, split_by):
    def chunk():
        buf = []
        size = 0
        for item in seq:
            if size + len(item) <= split_by:
                buf.append(item)
                size += len(item)
            else:
                yield ''.join(buf)                
                buf.clear()
                buf.append(item)
                size = len(item)
        if size:
            yield ''.join(buf)

    return list(chunk())

还有一个微基准测试:

import timeit
import random
import string
import matplotlib.pyplot as plt

line = ''.join(random.choices(
    string.ascii_uppercase + string.digits, k=512)) + '\n'
x = []
y_concat = []
y_stringio = []
y_join = []
n = 5
for i in range(1, 11):
    x.append(i)
    seq = [line] * (20 * 2 ** 20 // len(line))
    chunk_size = i * 2 ** 20
    y_concat.append(
        timeit.timeit(lambda: test_concat_chunk(seq, chunk_size), number=n) / n)
    y_stringio.append(
        timeit.timeit(lambda: test_stringio_chunk(seq, chunk_size), number=n) / n)
    y_join.append(
        timeit.timeit(lambda: test_join_chunk(seq, chunk_size), number=n) / n)
plt.plot(x, y_concat)
plt.plot(x, y_stringio)
plt.plot(x, y_join)
plt.legend(['concat', 'stringio', 'join'], loc='upper left')
plt.show()

微观基准

As @jdi mentions Python documentation suggests to use str.join or io.StringIO for string concatenation. And says that a developer should expect quadratic time from += in a loop, even though there’s an optimisation since Python 2.4. As this answer says:

If Python detects that the left argument has no other references, it calls realloc to attempt to avoid a copy by resizing the string in place. This is not something you should ever rely on, because it’s an implementation detail and because if realloc ends up needing to move the string frequently, performance degrades to O(n^2) anyway.

I will show an example of real-world code that naively relied on += this optimisation, but it didn’t apply. The code below converts an iterable of short strings into bigger chunks to be used in a bulk API.

def test_concat_chunk(seq, split_by):
    result = ['']
    for item in seq:
        if len(result[-1]) + len(item) > split_by: 
            result.append('')
        result[-1] += item
    return result

This code can literary run for hours because of quadratic time complexity. Below are alternatives with suggested data structures:

import io

def test_stringio_chunk(seq, split_by):
    def chunk():
        buf = io.StringIO()
        size = 0
        for item in seq:
            if size + len(item) <= split_by:
                size += buf.write(item)
            else:
                yield buf.getvalue()
                buf = io.StringIO()
                size = buf.write(item)
        if size:
            yield buf.getvalue()

    return list(chunk())

def test_join_chunk(seq, split_by):
    def chunk():
        buf = []
        size = 0
        for item in seq:
            if size + len(item) <= split_by:
                buf.append(item)
                size += len(item)
            else:
                yield ''.join(buf)                
                buf.clear()
                buf.append(item)
                size = len(item)
        if size:
            yield ''.join(buf)

    return list(chunk())

And a micro-benchmark:

import timeit
import random
import string
import matplotlib.pyplot as plt

line = ''.join(random.choices(
    string.ascii_uppercase + string.digits, k=512)) + '\n'
x = []
y_concat = []
y_stringio = []
y_join = []
n = 5
for i in range(1, 11):
    x.append(i)
    seq = [line] * (20 * 2 ** 20 // len(line))
    chunk_size = i * 2 ** 20
    y_concat.append(
        timeit.timeit(lambda: test_concat_chunk(seq, chunk_size), number=n) / n)
    y_stringio.append(
        timeit.timeit(lambda: test_stringio_chunk(seq, chunk_size), number=n) / n)
    y_join.append(
        timeit.timeit(lambda: test_join_chunk(seq, chunk_size), number=n) / n)
plt.plot(x, y_concat)
plt.plot(x, y_stringio)
plt.plot(x, y_join)
plt.legend(['concat', 'stringio', 'join'], loc='upper left')
plt.show()

micro-benchmark


回答 9

您可以采用不同的方式。

str1 = "Hello"
str2 = "World"
str_list = ['Hello', 'World']
str_dict = {'str1': 'Hello', 'str2': 'World'}

# Concatenating With the + Operator
print(str1 + ' ' + str2)  # Hello World

# String Formatting with the % Operator
print("%s %s" % (str1, str2))  # Hello World

# String Formatting with the { } Operators with str.format()
print("{}{}".format(str1, str2))  # Hello World
print("{0}{1}".format(str1, str2))  # Hello World
print("{str1} {str2}".format(str1=str_dict['str1'], str2=str_dict['str2']))  # Hello World
print("{str1} {str2}".format(**str_dict))  # Hello World

# Going From a List to a String in Python With .join()
print(' '.join(str_list))  # Hello World

# Python f'strings --> 3.6 onwards
print(f"{str1} {str2}")  # Hello World

我通过以下文章创建了这个小总结。

You can do in different ways.

str1 = "Hello"
str2 = "World"
str_list = ['Hello', 'World']
str_dict = {'str1': 'Hello', 'str2': 'World'}

# Concatenating With the + Operator
print(str1 + ' ' + str2)  # Hello World

# String Formatting with the % Operator
print("%s %s" % (str1, str2))  # Hello World

# String Formatting with the { } Operators with str.format()
print("{}{}".format(str1, str2))  # Hello World
print("{0}{1}".format(str1, str2))  # Hello World
print("{str1} {str2}".format(str1=str_dict['str1'], str2=str_dict['str2']))  # Hello World
print("{str1} {str2}".format(**str_dict))  # Hello World

# Going From a List to a String in Python With .join()
print(' '.join(str_list))  # Hello World

# Python f'strings --> 3.6 onwards
print(f"{str1} {str2}")  # Hello World

I created this little summary through following articles.


回答 10

我的用例略有不同。我不得不构造一个查询,其中有20多个字段是动态的。我遵循了这种使用格式化方法的方法

query = "insert into {0}({1},{2},{3}) values({4}, {5}, {6})"
query.format('users','name','age','dna','suzan',1010,'nda')

这对我来说相对来说比较简单,而不是使用+或其他方式

my use case was slight different. I had to construct a query where more then 20 fields were dynamic. I followed this approach of using format method

query = "insert into {0}({1},{2},{3}) values({4}, {5}, {6})"
query.format('users','name','age','dna','suzan',1010,'nda')

this was comparatively simpler for me instead of using + or other ways


回答 11

您也可以使用此(更有效)。(/software/304445/why-is-s-better-than-for-concatenation

s += "%s" %(stringfromelsewhere)

python 3中execfile的替代方法是什么?

问题:python 3中execfile的替代方法是什么?

看来他们在Python 3中取消了通过删除以下命令快速加载脚本的所有简便方法 execfile()

我是否有明显的替代品?

It seems they canceled in Python 3 all the easy way to quickly load a script by removing execfile()

Is there an obvious alternative I’m missing?


回答 0

根据文档,而不是

execfile("./filename") 

采用

exec(open("./filename").read())

看到:

According to the documentation, instead of

execfile("./filename") 

Use

exec(open("./filename").read())

See:


回答 1

您只应该自己读取文件并执行代码。2to3电流替代

execfile("somefile.py", global_vars, local_vars)

with open("somefile.py") as f:
    code = compile(f.read(), "somefile.py", 'exec')
    exec(code, global_vars, local_vars)

(并非严格要求进行编译调用,但是它将文件名与代码对象相关联,从而使调试更加容易。)

看到:

You are just supposed to read the file and exec the code yourself. 2to3 current replaces

execfile("somefile.py", global_vars, local_vars)

as

with open("somefile.py") as f:
    code = compile(f.read(), "somefile.py", 'exec')
    exec(code, global_vars, local_vars)

(The compile call isn’t strictly needed, but it associates the filename with the code object making debugging a little easier.)

See:


回答 2

尽管exec(open("filename").read())通常被用作的替代方案execfile("filename"),但它错过了execfile支持的重要细节。

Python3.x的以下功能与直接执行文件具有相同的行为。匹配运行python /path/to/somefile.py

def execfile(filepath, globals=None, locals=None):
    if globals is None:
        globals = {}
    globals.update({
        "__file__": filepath,
        "__name__": "__main__",
    })
    with open(filepath, 'rb') as file:
        exec(compile(file.read(), filepath, 'exec'), globals, locals)

# execute the file
execfile("/path/to/somefile.py")

笔记:

  • 使用二进制读取以避免编码问题
  • 保证关闭文件(Python3.x警告)
  • 定义__main__,某些脚本依赖于此来检查它们是否作为模块加载,例如。if __name__ == "__main__"
  • 设置__file__异常消息更好,某些脚本用于__file__获取其他文件相对于它们的路径。
  • 接受可选的globals和locals参数,就地进行修改execfile-您可以在运行后通过读回变量来访问定义的任何变量。

  • 与Python2不同,execfile这默认情况下不会修改当前命名空间。为此,您必须显式传入globals()locals()

While exec(open("filename").read()) is often given as an alternative to execfile("filename"), it misses important details that execfile supported.

The following function for Python3.x is as close as I could get to having the same behavior as executing a file directly. That matches running python /path/to/somefile.py.

def execfile(filepath, globals=None, locals=None):
    if globals is None:
        globals = {}
    globals.update({
        "__file__": filepath,
        "__name__": "__main__",
    })
    with open(filepath, 'rb') as file:
        exec(compile(file.read(), filepath, 'exec'), globals, locals)

# execute the file
execfile("/path/to/somefile.py")

Notes:

  • Uses binary reading to avoid encoding issues
  • Guaranteed to close the file (Python3.x warns about this)
  • Defines __main__, some scripts depend on this to check if they are loading as a module or not for eg. if __name__ == "__main__"
  • Setting __file__ is nicer for exception messages and some scripts use __file__ to get the paths of other files relative to them.
  • Takes optional globals & locals arguments, modifying them in-place as execfile does – so you can access any variables defined by reading back the variables after running.

  • Unlike Python2’s execfile this does not modify the current namespace by default. For that you have to explicitly pass in globals() & locals().


回答 3

正如最近在python-dev邮件列表上建议那样runpy模块可能是一个可行的替代方案。引用该消息:

https://docs.python.org/3/library/runpy.html#runpy.run_path

import runpy
file_globals = runpy.run_path("file.py")

与以下内容有细微的差异execfile

  • run_path总是创建一个新的命名空间。它作为模块执行代码,因此全局变量和局部变量之间没有区别(这就是为什么只有init_globals参数的原因)。返回全局变量。

    execfile在当前命名空间或给定命名空间中执行。的语义localsglobals,如果给定的,类似于当地人和全局类定义中。

  • run_path 不仅可以执行文件,还可以执行蛋和目录(有关详细信息,请参阅其文档)。

As suggested on the python-dev mailinglist recently, the runpy module might be a viable alternative. Quoting from that message:

https://docs.python.org/3/library/runpy.html#runpy.run_path

import runpy
file_globals = runpy.run_path("file.py")

There are subtle differences to execfile:

  • run_path always creates a new namespace. It executes the code as a module, so there is no difference between globals and locals (which is why there is only a init_globals argument). The globals are returned.

    execfile executed in the current namespace or the given namespace. The semantics of locals and globals, if given, were similar to locals and globals inside a class definition.

  • run_path can not only execute files, but also eggs and directories (refer to its documentation for details).


回答 4

这是更好的方法,因为它从调用者那里获取了全局变量和本地变量:

import sys
def execfile(filename, globals=None, locals=None):
    if globals is None:
        globals = sys._getframe(1).f_globals
    if locals is None:
        locals = sys._getframe(1).f_locals
    with open(filename, "r") as fh:
        exec(fh.read()+"\n", globals, locals)

This one is better, since it takes the globals and locals from the caller:

import sys
def execfile(filename, globals=None, locals=None):
    if globals is None:
        globals = sys._getframe(1).f_globals
    if locals is None:
        locals = sys._getframe(1).f_locals
    with open(filename, "r") as fh:
        exec(fh.read()+"\n", globals, locals)

回答 5

您可以编写自己的函数:

def xfile(afile, globalz=None, localz=None):
    with open(afile, "r") as fh:
        exec(fh.read(), globalz, localz)

如果您真的需要…

You could write your own function:

def xfile(afile, globalz=None, localz=None):
    with open(afile, "r") as fh:
        exec(fh.read(), globalz, localz)

If you really needed to…


回答 6

如果要加载的脚本与运行的脚本位于同一目录中,则也许“ import”可以完成此工作?

如果您需要动态导入代码,则值得研究内置函数__ import__和模块imp

>>> import sys
>>> sys.path = ['/path/to/script'] + sys.path
>>> __import__('test')
<module 'test' from '/path/to/script/test.pyc'>
>>> __import__('test').run()
'Hello world!'

test.py:

def run():
        return "Hello world!"

如果您使用的是Python 3.1或更高版本,则还应该看看importlib

If the script you want to load is in the same directory than the one you run, maybe “import” will do the job ?

If you need to dynamically import code the built-in function __ import__ and the module imp are worth looking at.

>>> import sys
>>> sys.path = ['/path/to/script'] + sys.path
>>> __import__('test')
<module 'test' from '/path/to/script/test.pyc'>
>>> __import__('test').run()
'Hello world!'

test.py:

def run():
        return "Hello world!"

If you’re using Python 3.1 or later, you should also take a look at importlib.


回答 7

这就是我所拥有的(file两个示例中的源代码都已将其分配给文件的路径):

execfile(file)

这是我替换为的内容:

exec(compile(open(file).read(), file, 'exec'))

我最喜欢的部分:第二个版本在Python 2和3中都可以正常工作,这意味着不必添加依赖于版本的逻辑。

Here’s what I had (file is already assigned to the path to the file with the source code in both examples):

execfile(file)

Here’s what I replaced it with:

exec(compile(open(file).read(), file, 'exec'))

My favorite part: the second version works just fine in both Python 2 and 3, meaning it’s not necessary to add in version dependent logic.


回答 8

请注意,如果您使用的不是非ascii或utf-8的PEP-263编码声明,上述模式将失败。您需要找到数据的编码,并在将其交给exec()之前对其进行正确的编码。

class python3Execfile(object):
    def _get_file_encoding(self, filename):
        with open(filename, 'rb') as fp:
            try:
                return tokenize.detect_encoding(fp.readline)[0]
            except SyntaxError:
                return "utf-8"

    def my_execfile(filename):
        globals['__file__'] = filename
        with open(filename, 'r', encoding=self._get_file_encoding(filename)) as fp:
            contents = fp.read()
        if not contents.endswith("\n"):
            # http://bugs.python.org/issue10204
            contents += "\n"
        exec(contents, globals, globals)

Note that the above pattern will fail if you’re using PEP-263 encoding declarations that aren’t ascii or utf-8. You need to find the encoding of the data, and encode it correctly before handing it to exec().

class python3Execfile(object):
    def _get_file_encoding(self, filename):
        with open(filename, 'rb') as fp:
            try:
                return tokenize.detect_encoding(fp.readline)[0]
            except SyntaxError:
                return "utf-8"

    def my_execfile(filename):
        globals['__file__'] = filename
        with open(filename, 'r', encoding=self._get_file_encoding(filename)) as fp:
            contents = fp.read()
        if not contents.endswith("\n"):
            # http://bugs.python.org/issue10204
            contents += "\n"
        exec(contents, globals, globals)

回答 9

另外,虽然不是纯粹的Python解决方案,但如果您使用的是IPython(无论如何也应该这样做),则可以执行以下操作:

%run /path/to/filename.py

这同样容易。

Also, while not a pure Python solution, if you’re using IPython (as you probably should anyway), you can do:

%run /path/to/filename.py

Which is equally easy.


回答 10

我只是这里的新手,所以如果发现了这个,也许纯粹是运气:

尝试使用命令从解释器提示符>>>运行脚本后

    execfile('filename.py')

为此,我得到了“ NameError:名称’execfile’未定义”,我尝试了一个非常基本的

    import filename

它运作良好:-)

我希望这会有所帮助,并感谢大家提供的出色提示,示例以及所有那些对新手有很大启发的精妙注释的代码!

我使用Ubuntu 16.014 LTS x64。 Linux上的Python 3.5.2(默认值,2016年11月17日,17:05:23)[GCC 5.4.0 20160609]

I’m just a newbie here so maybe it’s pure luck if I found this :

After trying to run a script from the interpreter prompt >>> with the command

    execfile('filename.py')

for which I got a “NameError: name ‘execfile’ is not defined” I tried a very basic

    import filename

it worked well :-)

I hope this can be helpful and thank you all for the great hints, examples and all those masterly commented pieces of code that are a great inspiration for newcomers !

I use Ubuntu 16.014 LTS x64. Python 3.5.2 (default, Nov 17 2016, 17:05:23) [GCC 5.4.0 20160609] on linux


回答 11

对我来说,最干净的方法是importlib按路径使用和导入文件作为模块,如下所示:

from importlib import util

def load_file(name, path):
    spec = util.spec_from_file_location(name, path)
    module = util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

使用范例

让我们有一个文件foo.py

print('i got imported')
def hello():
    print('hello from foo')

现在就像导入普通模块一样使用它:

>>> foo = load_file('foo', './foo.py')
i got imported
>>> foo.hello()
hello from foo

与直接方法相比,我更喜欢这种技术,exec(open(...))因为它不会使您的命名空间混乱或不必要地造成混乱$PATH

To me, the cleanest approach is to use importlib and import the file as a module by path, like so:

from importlib import util

def load_file(name, path):
    spec = util.spec_from_file_location(name, path)
    module = util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

Usage example

Let’s have a file foo.py:

print('i got imported')
def hello():
    print('hello from foo')

Now just import and use it like a normal module:

>>> foo = load_file('foo', './foo.py')
i got imported
>>> foo.hello()
hello from foo

I prefer this technique over direct approaches like exec(open(...)) because it does not clutter your namespaces or unnecessarily messes with $PATH.


Python中字典的深层副本

问题:Python中字典的深层副本

我想dict在python中制作一个深层副本。不幸的是,该.deepcopy()方法不存在dict。我怎么做?

>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = my_dict.deepcopy()
Traceback (most recent calll last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'deepcopy'
>>> my_copy = my_dict.copy()
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
7

最后一行应为3

我希望所做的修改my_dict不会影响快照my_copy

我怎么做?该解决方案应与Python 3.x兼容。

I would like to make a deep copy of a dict in python. Unfortunately the .deepcopy() method doesn’t exist for the dict. How do I do that?

>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = my_dict.deepcopy()
Traceback (most recent calll last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'deepcopy'
>>> my_copy = my_dict.copy()
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
7

The last line should be 3.

I would like that modifications in my_dict don’t impact the snapshot my_copy.

How do I do that? The solution should be compatible with Python 3.x.


回答 0

怎么样:

import copy
d = { ... }
d2 = copy.deepcopy(d)

Python 2或3:

Python 3.2 (r32:88445, Feb 20 2011, 21:30:00) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import copy
>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = copy.deepcopy(my_dict)
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
3
>>>

How about:

import copy
d = { ... }
d2 = copy.deepcopy(d)

Python 2 or 3:

Python 3.2 (r32:88445, Feb 20 2011, 21:30:00) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import copy
>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = copy.deepcopy(my_dict)
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
3
>>>

回答 1

dict.copy()是字典
id的浅表复制函数, 是内置函数,可为您提供变量的地址

首先,您需要了解“为什么会发生此特定问题?”

In [1]: my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}

In [2]: my_copy = my_dict.copy()

In [3]: id(my_dict)
Out[3]: 140190444167808

In [4]: id(my_copy)
Out[4]: 140190444170328

In [5]: id(my_copy['a'])
Out[5]: 140190444024104

In [6]: id(my_dict['a'])
Out[6]: 140190444024104

键“ a”的两个字典中都存在的列表地址指向同一位置。
因此,当您在my_dict中更改列表的值时,my_copy中的列表也会更改。


问题中提到的数据结构解决方案:

In [7]: my_copy = {key: value[:] for key, value in my_dict.items()}

In [8]: id(my_copy['a'])
Out[8]: 140190444024176

或者您可以使用上述的Deepcopy。

dict.copy() is a shallow copy function for dictionary
id is built-in function that gives you the address of variable

First you need to understand “why is this particular problem is happening?”

In [1]: my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}

In [2]: my_copy = my_dict.copy()

In [3]: id(my_dict)
Out[3]: 140190444167808

In [4]: id(my_copy)
Out[4]: 140190444170328

In [5]: id(my_copy['a'])
Out[5]: 140190444024104

In [6]: id(my_dict['a'])
Out[6]: 140190444024104

The address of the list present in both the dicts for key ‘a’ is pointing to same location.
Therefore when you change value of the list in my_dict, the list in my_copy changes as well.


Solution for data structure mentioned in the question:

In [7]: my_copy = {key: value[:] for key, value in my_dict.items()}

In [8]: id(my_copy['a'])
Out[8]: 140190444024176

Or you can use deepcopy as mentioned above.


回答 2

Python 3.x

从复制导入深度复制

my_dict = {'one': 1, 'two': 2}
new_dict_deepcopy = deepcopy(my_dict)

如果没有Deepcopy,我将无法从域字典中删除主机名字典。

没有Deepcopy,我会收到以下错误:

"RuntimeError: dictionary changed size during iteration"

…当我尝试从另一本字典中的字典中删除所需的元素时。

import socket
import xml.etree.ElementTree as ET
from copy import deepcopy

域是一个字典对象

def remove_hostname(domain, hostname):
    domain_copy = deepcopy(domain)
    for domains, hosts in domain_copy.items():
        for host, port in hosts.items():
           if host == hostname:
                del domain[domains][host]
    return domain

输出示例:[ orginal ] domains = {‘localdomain’:{‘localhost’:{‘all’:’4000’}}}

[new] domains = {”localdomain’:{}}}

因此,这里发生的是我正在遍历字典的副本,而不是遍历字典本身。使用此方法,您可以根据需要删除元素。

Python 3.x

from copy import deepcopy

my_dict = {'one': 1, 'two': 2}
new_dict_deepcopy = deepcopy(my_dict)

Without deepcopy, I am unable to remove the hostname dictionary from within my domain dictionary.

Without deepcopy I get the following error:

"RuntimeError: dictionary changed size during iteration"

…when I try to remove the desired element from my dictionary inside of another dictionary.

import socket
import xml.etree.ElementTree as ET
from copy import deepcopy

domain is a dictionary object

def remove_hostname(domain, hostname):
    domain_copy = deepcopy(domain)
    for domains, hosts in domain_copy.items():
        for host, port in hosts.items():
           if host == hostname:
                del domain[domains][host]
    return domain

Example output: [orginal]domains = {‘localdomain’: {‘localhost’: {‘all’: ‘4000’}}}

[new]domains = {‘localdomain’: {} }}

So what’s going on here is I am iterating over a copy of a dictionary rather than iterating over the dictionary itself. With this method, you are able to remove elements as needed.


回答 3

我喜欢Lasse V. Karlsen并从中学到了很多。我将其修改为以下示例,该示例很好地突出了浅字典副本和深副本之间的区别:

    import copy

    my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
    my_copy = copy.copy(my_dict)
    my_deepcopy = copy.deepcopy(my_dict)

现在,如果你改变

    my_dict['a'][2] = 7

并做

    print("my_copy a[2]: ",my_copy['a'][2],",whereas my_deepcopy a[2]: ", my_deepcopy['a'][2])

你得到

    >> my_copy a[2]:  7 ,whereas my_deepcopy a[2]:  3

I like and learned a lot from Lasse V. Karlsen. I modified it into the following example, which highlights pretty well the difference between shallow dictionary copies and deep copies:

    import copy

    my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
    my_copy = copy.copy(my_dict)
    my_deepcopy = copy.deepcopy(my_dict)

Now if you change

    my_dict['a'][2] = 7

and do

    print("my_copy a[2]: ",my_copy['a'][2],",whereas my_deepcopy a[2]: ", my_deepcopy['a'][2])

you get

    >> my_copy a[2]:  7 ,whereas my_deepcopy a[2]:  3

回答 4

一个更简单(在我看来)的解决方案是创建一个新词典并用旧词典的内容进行更新:

my_dict={'a':1}

my_copy = {}

my_copy.update( my_dict )

my_dict['a']=2

my_dict['a']
Out[34]: 2

my_copy['a']
Out[35]: 1

这种方法的问题在于它可能不够“深入”。即没有递归的深度。对于简单的对象已经足够好了,但对于嵌套字典却不够。这是一个示例,可能不够深:

my_dict1={'b':2}

my_dict2={'c':3}

my_dict3={ 'b': my_dict1, 'c':my_dict2 }

my_copy = {}

my_copy.update( my_dict3 )

my_dict1['b']='z'

my_copy
Out[42]: {'b': {'b': 'z'}, 'c': {'c': 3}}

通过使用Deepcopy(),我可以消除半浅行为,但是我认为必须确定哪种方法适合您的应用程序。在大多数情况下,您可能并不在意,但应注意可能存在的陷阱…最后的示例:

import copy

my_copy2 = copy.deepcopy( my_dict3 )

my_dict1['b']='99'

my_copy2
Out[46]: {'b': {'b': 'z'}, 'c': {'c': 3}}

A simpler (in my view) solution is to create a new dictionary and update it with the contents of the old one:

my_dict={'a':1}

my_copy = {}

my_copy.update( my_dict )

my_dict['a']=2

my_dict['a']
Out[34]: 2

my_copy['a']
Out[35]: 1

The problem with this approach is it may not be ‘deep enough’. i.e. is not recursively deep. good enough for simple objects but not for nested dictionaries. Here is an example where it may not be deep enough:

my_dict1={'b':2}

my_dict2={'c':3}

my_dict3={ 'b': my_dict1, 'c':my_dict2 }

my_copy = {}

my_copy.update( my_dict3 )

my_dict1['b']='z'

my_copy
Out[42]: {'b': {'b': 'z'}, 'c': {'c': 3}}

By using Deepcopy() I can eliminate the semi-shallow behavior, but I think one must decide which approach is right for your application. In most cases you may not care, but should be aware of the possible pitfalls… final example:

import copy

my_copy2 = copy.deepcopy( my_dict3 )

my_dict1['b']='99'

my_copy2
Out[46]: {'b': {'b': 'z'}, 'c': {'c': 3}}

使用Python 3从网上下载文件

问题:使用Python 3从网上下载文件

我正在创建一个程序,该程序将通过读取同一游戏/应用程序的.jad文件中指定的URL从Web服务器下载.jar(java)文件。我正在使用Python 3.2.1

我设法从JAD文件中提取JAR文件的URL(每个JAD文件都包含指向JAR文件的URL),但是正如您所想象的,提取的值是type()字符串。

相关功能如下:

def downloadFile(URL=None):
    import httplib2
    h = httplib2.Http(".cache")
    resp, content = h.request(URL, "GET")
    return content

downloadFile(URL_from_file)

但是,我总是得到一个错误,指出上面函数中的类型必须是字节,而不是字符串。我尝试使用URL.encode(’utf-8’)和字节(URL,encoding =’utf-8’),但是我总是会遇到相同或相似的错误。

因此,基本上我的问题是,当URL以字符串类型存储时,如何从服务器下载文件?

I am creating a program that will download a .jar (java) file from a web server, by reading the URL that is specified in the .jad file of the same game/application. I’m using Python 3.2.1

I’ve managed to extract the URL of the JAR file from the JAD file (every JAD file contains the URL to the JAR file), but as you may imagine, the extracted value is type() string.

Here’s the relevant function:

def downloadFile(URL=None):
    import httplib2
    h = httplib2.Http(".cache")
    resp, content = h.request(URL, "GET")
    return content

downloadFile(URL_from_file)

However I always get an error saying that the type in the function above has to be bytes, and not string. I’ve tried using the URL.encode(‘utf-8′), and also bytes(URL,encoding=’utf-8’), but I’d always get the same or similar error.

So basically my question is how to download a file from a server when the URL is stored in a string type?


回答 0

如果要将网页的内容转换为变量,则只需read响应urllib.request.urlopen

import urllib.request
...
url = 'http://example.com/'
response = urllib.request.urlopen(url)
data = response.read()      # a `bytes` object
text = data.decode('utf-8') # a `str`; this step can't be used if data is binary

下载和保存文件的最简单方法是使用以下urllib.request.urlretrieve功能:

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
urllib.request.urlretrieve(url, file_name)
import urllib.request
...
# Download the file from `url`, save it in a temporary directory and get the
# path to it (e.g. '/tmp/tmpb48zma.txt') in the `file_name` variable:
file_name, headers = urllib.request.urlretrieve(url)

但是请记住,这urlretrieve被认为是遗留的,并且可能会被弃用(尽管不确定为什么)。

因此,最正确的方法是使用urllib.request.urlopen函数返回代表HTTP响应的类似文件的对象,然后使用将其复制到真实文件中shutil.copyfileobj

import urllib.request
import shutil
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)

如果这看起来太复杂,则可能要简化一些并将整个下载存储在一个bytes对象中,然后将其写入文件。但这仅适用于小文件。

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    data = response.read() # a `bytes` object
    out_file.write(data)

可以动态提取.gz(可能还有其他格式)压缩数据,但是这种操作可能需要HTTP服务器支持对文件的随机访问。

import urllib.request
import gzip
...
# Read the first 64 bytes of the file inside the .gz archive located at `url`
url = 'http://example.com/something.gz'
with urllib.request.urlopen(url) as response:
    with gzip.GzipFile(fileobj=response) as uncompressed:
        file_header = uncompressed.read(64) # a `bytes` object
        # Or do anything shown above using `uncompressed` instead of `response`.

If you want to obtain the contents of a web page into a variable, just read the response of urllib.request.urlopen:

import urllib.request
...
url = 'http://example.com/'
response = urllib.request.urlopen(url)
data = response.read()      # a `bytes` object
text = data.decode('utf-8') # a `str`; this step can't be used if data is binary

The easiest way to download and save a file is to use the urllib.request.urlretrieve function:

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
urllib.request.urlretrieve(url, file_name)
import urllib.request
...
# Download the file from `url`, save it in a temporary directory and get the
# path to it (e.g. '/tmp/tmpb48zma.txt') in the `file_name` variable:
file_name, headers = urllib.request.urlretrieve(url)

But keep in mind that urlretrieve is considered legacy and might become deprecated (not sure why, though).

So the most correct way to do this would be to use the urllib.request.urlopen function to return a file-like object that represents an HTTP response and copy it to a real file using shutil.copyfileobj.

import urllib.request
import shutil
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)

If this seems too complicated, you may want to go simpler and store the whole download in a bytes object and then write it to a file. But this works well only for small files.

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    data = response.read() # a `bytes` object
    out_file.write(data)

It is possible to extract .gz (and maybe other formats) compressed data on the fly, but such an operation probably requires the HTTP server to support random access to the file.

import urllib.request
import gzip
...
# Read the first 64 bytes of the file inside the .gz archive located at `url`
url = 'http://example.com/something.gz'
with urllib.request.urlopen(url) as response:
    with gzip.GzipFile(fileobj=response) as uncompressed:
        file_header = uncompressed.read(64) # a `bytes` object
        # Or do anything shown above using `uncompressed` instead of `response`.

回答 1

requests每当我想要与HTTP请求相关的内容时,我都会使用package,因为它的API很容易开头:

首先,安装 requests

$ pip install requests

然后是代码:

from requests import get  # to make GET request


def download(url, file_name):
    # open in binary mode
    with open(file_name, "wb") as file:
        # get request
        response = get(url)
        # write to file
        file.write(response.content)

I use requests package whenever I want something related to HTTP requests because its API is very easy to start with:

first, install requests

$ pip install requests

then the code:

from requests import get  # to make GET request


def download(url, file_name):
    # open in binary mode
    with open(file_name, "wb") as file:
        # get request
        response = get(url)
        # write to file
        file.write(response.content)

回答 2

我希望我理解正确的问题,那就是:当URL以字符串类型存储时,如何从服务器下载文件?

我下载文件并使用以下代码将其保存在本地:

import requests

url = 'https://www.python.org/static/img/python-logo.png'
fileName = 'D:\Python\dwnldPythonLogo.png'
req = requests.get(url)
file = open(fileName, 'wb')
for chunk in req.iter_content(100000):
    file.write(chunk)
file.close()

I hope I understood the question right, which is: how to download a file from a server when the URL is stored in a string type?

I download files and save it locally using the below code:

import requests

url = 'https://www.python.org/static/img/python-logo.png'
fileName = 'D:\Python\dwnldPythonLogo.png'
req = requests.get(url)
file = open(fileName, 'wb')
for chunk in req.iter_content(100000):
    file.write(chunk)
file.close()

回答 3

在这里,我们可以在Python3中使用urllib的Legacy接口:

以下函数和类是从Python 2模块urllib(与urllib2相对)移植的。他们可能在将来的某个时候被弃用。

示例(两行代码)

import urllib.request

url = 'https://www.python.org/static/img/python-logo.png'
urllib.request.urlretrieve(url, "logo.png")

Here we can use urllib’s Legacy interface in Python3:

The following functions and classes are ported from the Python 2 module urllib (as opposed to urllib2). They might become deprecated at some point in the future.

Example (2 lines code):

import urllib.request

url = 'https://www.python.org/static/img/python-logo.png'
urllib.request.urlretrieve(url, "logo.png")

回答 4

您可以使用wget,它是流行的下载shell工具。https://pypi.python.org/pypi/wget 这将是最简单的方法,因为它不需要打开目标文件。这是一个例子。

import wget
url = 'https://i1.wp.com/python3.codes/wp-content/uploads/2015/06/Python3-powered.png?fit=650%2C350'  
wget.download(url, '/Users/scott/Downloads/cat4.jpg') 

You can use wget which is popular downloading shell tool for that. https://pypi.python.org/pypi/wget This will be the simplest method since it does not need to open up the destination file. Here is an example.

import wget
url = 'https://i1.wp.com/python3.codes/wp-content/uploads/2015/06/Python3-powered.png?fit=650%2C350'  
wget.download(url, '/Users/scott/Downloads/cat4.jpg') 

回答 5

是的,绝对请求是用于与HTTP请求相关的东西的很好的程序包。但是我们需要注意传入数据的编码类型,下面是一个说明差异的示例


from requests import get

# case when the response is byte array
url = 'some_image_url'

response = get(url)
with open('output', 'wb') as file:
    file.write(response.content)


# case when the response is text
# Here unlikely if the reponse content is of type **iso-8859-1** we will have to override the response encoding
url = 'some_page_url'

response = get(url)
# override encoding by real educated guess as provided by chardet
r.encoding = r.apparent_encoding

with open('output', 'w', encoding='utf-8') as file:
    file.write(response.content)

Yes, definietly requests is great package to use in something related to HTTP requests. but we need to be careful with the encoding type of the incoming data as well below is an example which explains the difference


from requests import get

# case when the response is byte array
url = 'some_image_url'

response = get(url)
with open('output', 'wb') as file:
    file.write(response.content)


# case when the response is text
# Here unlikely if the reponse content is of type **iso-8859-1** we will have to override the response encoding
url = 'some_page_url'

response = get(url)
# override encoding by real educated guess as provided by chardet
r.encoding = r.apparent_encoding

with open('output', 'w', encoding='utf-8') as file:
    file.write(response.content)


回答 6

动机

有时,我们想要获取图片,但无需将其下载到真实文件中,

下载数据并将其保存在内存中。

例如,如果我使用机器学习方法,则训练一个可以识别带有数字(条形码)图像的模型。

当我搜寻一些具有这些图像的网站时,我可以使用模型来识别它,

而且我不想将这些图片保存在磁盘驱动器上,

那么您可以尝试以下方法来帮助您将下载数据保留在内存中。

点数

import requests
from io import BytesIO
response = requests.get(url)
with BytesIO as io_obj:
    for chunk in response.iter_content(chunk_size=4096):
        io_obj.write(chunk)

基本上,就像@Ranvijay Kumar

一个例子

import requests
from typing import NewType, TypeVar
from io import StringIO, BytesIO
import matplotlib.pyplot as plt
import imageio

URL = NewType('URL', str)
T_IO = TypeVar('T_IO', StringIO, BytesIO)


def download_and_keep_on_memory(url: URL, headers=None, timeout=None, **option) -> T_IO:
    chunk_size = option.get('chunk_size', 4096)  # default 4KB
    max_size = 1024 ** 2 * option.get('max_size', -1)  # MB, default will ignore.
    response = requests.get(url, headers=headers, timeout=timeout)
    if response.status_code != 200:
        raise requests.ConnectionError(f'{response.status_code}')

    instance_io = StringIO if isinstance(next(response.iter_content(chunk_size=1)), str) else BytesIO
    io_obj = instance_io()
    cur_size = 0
    for chunk in response.iter_content(chunk_size=chunk_size):
        cur_size += chunk_size
        if 0 < max_size < cur_size:
            break
        io_obj.write(chunk)
    io_obj.seek(0)
    """ save it to real file.
    with open('temp.png', mode='wb') as out_f:
        out_f.write(io_obj.read())
    """
    return io_obj


def main():
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7',
        'Cache-Control': 'max-age=0',
        'Connection': 'keep-alive',
        'Host': 'statics.591.com.tw',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'
    }
    io_img = download_and_keep_on_memory(URL('http://statics.591.com.tw/tools/showPhone.php?info_data=rLsGZe4U%2FbphHOimi2PT%2FhxTPqI&type=rLEFMu4XrrpgEw'),
                                         headers,  # You may need this. Otherwise, some websites will send the 404 error to you.
                                         max_size=4)  # max loading < 4MB
    with io_img:
        plt.rc('axes.spines', top=False, bottom=False, left=False, right=False)
        plt.rc(('xtick', 'ytick'), color=(1, 1, 1, 0))  # same of plt.axis('off')
        plt.imshow(imageio.imread(io_img, as_gray=False, pilmode="RGB"))
        plt.show()


if __name__ == '__main__':
    main()

Motivation

Sometimes, we are want to get the picture but not need to download it to real files,

i.e., download the data and keep it on memory.

For example, If I use the machine learning method, train a model that can recognize an image with the number (bar code).

When I spider some websites and that have those images so I can use the model to recognize it,

and I don’t want to save those pictures on my disk drive,

then you can try the below method to help you keep download data on memory.

Points

import requests
from io import BytesIO
response = requests.get(url)
with BytesIO as io_obj:
    for chunk in response.iter_content(chunk_size=4096):
        io_obj.write(chunk)

basically, is like to @Ranvijay Kumar

An Example

import requests
from typing import NewType, TypeVar
from io import StringIO, BytesIO
import matplotlib.pyplot as plt
import imageio

URL = NewType('URL', str)
T_IO = TypeVar('T_IO', StringIO, BytesIO)


def download_and_keep_on_memory(url: URL, headers=None, timeout=None, **option) -> T_IO:
    chunk_size = option.get('chunk_size', 4096)  # default 4KB
    max_size = 1024 ** 2 * option.get('max_size', -1)  # MB, default will ignore.
    response = requests.get(url, headers=headers, timeout=timeout)
    if response.status_code != 200:
        raise requests.ConnectionError(f'{response.status_code}')

    instance_io = StringIO if isinstance(next(response.iter_content(chunk_size=1)), str) else BytesIO
    io_obj = instance_io()
    cur_size = 0
    for chunk in response.iter_content(chunk_size=chunk_size):
        cur_size += chunk_size
        if 0 < max_size < cur_size:
            break
        io_obj.write(chunk)
    io_obj.seek(0)
    """ save it to real file.
    with open('temp.png', mode='wb') as out_f:
        out_f.write(io_obj.read())
    """
    return io_obj


def main():
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7',
        'Cache-Control': 'max-age=0',
        'Connection': 'keep-alive',
        'Host': 'statics.591.com.tw',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'
    }
    io_img = download_and_keep_on_memory(URL('http://statics.591.com.tw/tools/showPhone.php?info_data=rLsGZe4U%2FbphHOimi2PT%2FhxTPqI&type=rLEFMu4XrrpgEw'),
                                         headers,  # You may need this. Otherwise, some websites will send the 404 error to you.
                                         max_size=4)  # max loading < 4MB
    with io_img:
        plt.rc('axes.spines', top=False, bottom=False, left=False, right=False)
        plt.rc(('xtick', 'ytick'), color=(1, 1, 1, 0))  # same of plt.axis('off')
        plt.imshow(imageio.imread(io_img, as_gray=False, pilmode="RGB"))
        plt.show()


if __name__ == '__main__':
    main()


回答 7

from urllib import request

def get(url):
    with request.urlopen(url) as r:
        return r.read()


def download(url, file=None):
    if not file:
        file = url.split('/')[-1]
    with open(file, 'wb') as f:
        f.write(get(url))
from urllib import request

def get(url):
    with request.urlopen(url) as r:
        return r.read()


def download(url, file=None):
    if not file:
        file = url.split('/')[-1]
    with open(file, 'wb') as f:
        f.write(get(url))

如何在OS X上将Python的默认版本设置为3.x?

问题:如何在OS X上将Python的默认版本设置为3.x?

我正在运行Mountain Lion,而基本的默认Python版本是2.7。我下载了Python 3.3,并希望将其设置为默认值。

目前:

$ python
    version 2.7.5
$ python3.3
    version 3.3

如何设置它,以便每次运行$ python时都能打开3.3?

I’m running Mountain Lion and the basic default Python version is 2.7. I downloaded Python 3.3 and want to set it as default.

Currently:

$ python
    version 2.7.5
$ python3.3
    version 3.3

How do I set it so that every time I run $ python it opens 3.3?


回答 0

在系统范围内更改默认python可执行文件的版本可能会破坏某些依赖python2的应用程序。

但是,您可以在大多数外壳程序中为命令加上别名,因为macOS中的默认外壳程序(10.14及以下版本中的bash; 10.15中的zsh)具有相似的语法。您可以在您的中放置别名python =’python3′ ~/.profile,然后~/.profile在您~/.bash_profile和/或您的源代码中~/.zsh_profile输入以下内容:

[ -e ~/.profile ] && . ~/.profile

这样,您的别名将可在所有shell中使用。

这样,python命令现在将被调用python3。如果您想偶尔调用“原始” python(指python2),则可以使用command python,这将使别名保持不变,并且适用于所有shell。

如果您更频繁地启动解释器(我愿意),则总是可以创建更多别名来添加,即:

alias 2='python2'
alias 3='python3'

提示:对于脚本,而不是使用shebang之类的方法:

#!/usr/bin/env python

采用:

#!/usr/bin/env python3

这样,系统将使用python3运行python 可执行文件

Changing the default python executable’s version system-wide could break some applications that depend on python2.

However, you can alias the commands in most shells, Since the default shells in macOS (bash in 10.14 and below; zsh in 10.15) share a similar syntax. You could put alias python=’python3′ in your ~/.profile, and then source ~/.profile in your ~/.bash_profile and/or your~/.zsh_profile with a line like:

[ -e ~/.profile ] && . ~/.profile

This way, your alias will work across shells.

With this, python command now invokes python3. If you want to invoke the “original” python (that refers to python2) on occasion, you can use command python, which will leaving the alias untouched, and works in all shells.

If you launch interpreters more often (I do), you can always create more aliases to add as well, i.e.:

alias 2='python2'
alias 3='python3'

Tip: For scripts, instead of using a shebang like:

#!/usr/bin/env python

use:

#!/usr/bin/env python3

This way, the system will use python3 for running python executables.


回答 1

您可以通过符号链接来解决。

unlink /usr/local/bin/python
ln -s /usr/local/bin/python3.3 /usr/local/bin/python

You can solve it by symbolic link.

unlink /usr/local/bin/python
ln -s /usr/local/bin/python3.3 /usr/local/bin/python

回答 2

打开〜/ .bash_profile文件。

vi ~/.bash_profile

然后按如下所示放置别名:

alias python='python3'

现在保存文件,然后运行〜/ .bash_profile文件。

source ~/.bash_profile

恭喜!!!现在,您可以通过键入python使用python3 。

python --version

的Python 3.7.3

Open ~/.bash_profile file.

vi ~/.bash_profile

Then put the alias as follows:

alias python='python3'

Now save the file and then run the ~/.bash_profile file.

source ~/.bash_profile

Congratulation !!! Now, you can use python3 by typing python.

python --version

Python 3.7.3


回答 3

转到终端类型:

alias python=python3.x

这会将默认python设置为python3.x

Go to terminal type:

alias python=python3.x

This will setup default python as python3.x


回答 4

以下为我工作

cd /usr/local/bin
mv python python.old
ln -s python3 python

The following worked for me

cd /usr/local/bin
mv python python.old
ln -s python3 python

回答 5

我在这个游戏上有点晚了,但是我认为我应该发布更新的答案,因为我自己才遇到这个问题。请注意,这仅适用于基于Mac的设置(我没有在Windows或任何版本的Linux上尝试过)。

最简单的方法是通过Brew安装Python 。如果您未安装brew,则需要先执行该操作。安装完成后,在终端上执行以下操作:

brew install python

这将安装Python3。安装后,运行以下命令:

ls -l /usr/local/bin/python*

您将看到brew创建的所有安装到其Python安装的链接。它看起来像这样:

lrwxr-xr-x  1 username  admin  36 Oct  1 13:35 /usr/local/bin/python3@ -> ../Cellar/python/3.7.4_1/bin/python3
lrwxr-xr-x  1 username  admin  43 Oct  1 13:35 /usr/local/bin/python3-config@ -> ../Cellar/python/3.7.4_1/bin/python3-config
lrwxr-xr-x  1 username  admin  38 Oct  1 13:35 /usr/local/bin/python3.7@ -> ../Cellar/python/3.7.4_1/bin/python3.7
lrwxr-xr-x  1 username  admin  45 Oct  1 13:35 /usr/local/bin/python3.7-config@ -> ../Cellar/python/3.7.4_1/bin/python3.7-config
lrwxr-xr-x  1 username  admin  39 Oct  1 13:35 /usr/local/bin/python3.7m@ -> ../Cellar/python/3.7.4_1/bin/python3.7m
lrwxr-xr-x  1 username  admin  46 Oct  1 13:35 /usr/local/bin/python3.7m-config@ -> ../Cellar/python/3.7.4_1/bin/python3.7m-config

此示例的第一行显示了python3符号链接。要将其设置为默认python符号链接,请运行以下命令:

ln -s -f /usr/local/bin/python3 /usr/local/bin/python

设置后,您可以执行以下操作:

which python

它应该显示:

/usr/local/bin/python

您将必须重新加载当前的终端shell,才能在该shell中使用新的符号链接,但是,所有新打开的shell会话将(应该)自动使用它。要对此进行测试,请打开一个新的终端外壳并运行以下命令:

python --version

I’m a little late to the game on this one, but I thought I should post an updated answer since I just encountered this issue for myself. Please note that this will only apply to a Mac-based setup (I haven’t tried it with Windows or any flavor of Linux).

The simplest way to get this working is to install Python via Brew. If you don’t have brew installed, you will need to do that first. Once installed, do the following in at the terminal:

brew install python

This will install Python 3. After it’s installed, run this:

ls -l /usr/local/bin/python*

You will see all of the links created by brew to its Python install. It will look something like this:

lrwxr-xr-x  1 username  admin  36 Oct  1 13:35 /usr/local/bin/python3@ -> ../Cellar/python/3.7.4_1/bin/python3
lrwxr-xr-x  1 username  admin  43 Oct  1 13:35 /usr/local/bin/python3-config@ -> ../Cellar/python/3.7.4_1/bin/python3-config
lrwxr-xr-x  1 username  admin  38 Oct  1 13:35 /usr/local/bin/python3.7@ -> ../Cellar/python/3.7.4_1/bin/python3.7
lrwxr-xr-x  1 username  admin  45 Oct  1 13:35 /usr/local/bin/python3.7-config@ -> ../Cellar/python/3.7.4_1/bin/python3.7-config
lrwxr-xr-x  1 username  admin  39 Oct  1 13:35 /usr/local/bin/python3.7m@ -> ../Cellar/python/3.7.4_1/bin/python3.7m
lrwxr-xr-x  1 username  admin  46 Oct  1 13:35 /usr/local/bin/python3.7m-config@ -> ../Cellar/python/3.7.4_1/bin/python3.7m-config

The first row in this example shows the python3 symlink. To set it as the default python symlink run the following:

ln -s -f /usr/local/bin/python3 /usr/local/bin/python

Once set, you can do:

which python

and it should show:

/usr/local/bin/python

You will have to reload your current terminal shell for it to use the new symlink in that shell, however, all newly opened shell sessions will (should) automatically use it. To test this, open a new terminal shell and run the following:

python --version

回答 6

转到“应用程序”,进入“ Python”文件夹,应该有一个名为“ Update Shell Profile.command”或类似名称的bash脚本。运行该脚本,它应该这样做。

更新:看来您不应该更新它:如何更改默认python版本?

Go to ‘Applications’, enter ‘Python’ folder, there should be a bash script called ‘Update Shell Profile.command’ or similar. Run that script and it should do it.

Update: It looks like you should not update it: how to change default python version?


回答 7

这对我有用。我添加了别名并重新启动了终端

alias python=/usr/local/bin/python3

This worked for me. I added alias and restarted my terminal:

alias python=/usr/local/bin/python3

回答 8

我相信大多数登陆这里的人都在使用ZSH thorugh iterm或其他工具,这为您带来了答案

您必须改为添加/修改命令~/.zshrc

I believe most of people landed here are using ZSH thorugh iterm or whatever, and that brings you to this answer.

You have to add/modify your commands in ~/.zshrc instead.


回答 9

我不确定在OS X上是否可用,但是在Linux上我会使用该module命令。 看这里

正确设置modulefile,然后将以下内容添加到rc文件中(例如〜/ .bashrc):

module load python3.3

这样一来,登录时即可根据需要切换路径,而不会影响任何系统默认值。

I’m not sure if this is available on OS X, but on linux I would make use of the module command. See here.

Set up the modulefile correctly, then add something like this to your rc file (e.g. ~/.bashrc):

module load python3.3

This will make it so that your paths get switched around as required when you log in without impacting any system defaults.


回答 10

我认为安装python时会将导出路径语句放入〜/ .bash_profile文件中。因此,如果您不再打算使用Python 2,则可以从那里删除该语句。如上所述的别名也是一种很好的方法。

这是从〜/ .bash_profile中删除引用的方法-vim ./.bash_profile-删除引用(也类似:export PATH =“ / Users / bla / anaconda:$ PATH”)-保存并退出-源./ .bash_profile保存更改

I think when you install python it puts export path statements into your ~/.bash_profile file. So if you do not intend to use Python 2 anymore you can just remove that statement from there. Alias as stated above is also a great way to do it.

Here is how to remove the reference from ~/.bash_profile – vim ./.bash_profile – remove the reference (AKA something like: export PATH=”/Users/bla/anaconda:$PATH”) – save and exit – source ./.bash_profile to save the changes


回答 11

$ sudo ln -s -f $(which python3) $(which python)

完成。

$ sudo ln -s -f $(which python3) $(which python)

done.


回答 12

在Mac上将Python 3设置为默认的正确和错误的方法

在本文中,作者讨论了设置默认python的三种方法:

  1. 什么不该做。
  2. 我们可以做(但也不应该)。
  3. 我们应该做什么!

所有这些方式都有效。您决定哪个更好。

The RIGHT and WRONG way to set Python 3 as default on a Mac

In this article author discuss three ways of setting default python:

  1. What NOT to do.
  2. What we COULD do (but also shouldn’t).
  3. What we SHOULD do!

All these ways are working. You decide which is better.


回答 13

如果virtualenvwrapper使用which virtualenvwrapper.sh,则可以使用进行定位,然后使用vim或任何其他编辑器将其打开,然后更改以下内容

# Locate the global Python where virtualenvwrapper is installed.
if [ "${VIRTUALENVWRAPPER_PYTHON:-}" = "" ]
then
    VIRTUALENVWRAPPER_PYTHON="$(command \which python)"
fi

将行更改VIRTUALENVWRAPPER_PYTHON="$(command \which python)"VIRTUALENVWRAPPER_PYTHON="$(command \which python3)"

If you are using a virtualenvwrapper, you can just locate it using which virtualenvwrapper.sh, then open it using vim or any other editor then change the following

# Locate the global Python where virtualenvwrapper is installed.
if [ "${VIRTUALENVWRAPPER_PYTHON:-}" = "" ]
then
    VIRTUALENVWRAPPER_PYTHON="$(command \which python)"
fi

Change the line VIRTUALENVWRAPPER_PYTHON="$(command \which python)" to VIRTUALENVWRAPPER_PYTHON="$(command \which python3)".


回答 14

对我来说,解决方案是使用PyCharm并将默认的python版本设置为我需要使用的版本。

安装PyCharm并转到文件==>新项目的首选项,然后为项目选择所需的解释器,在这种情况下为python 3.3

For me the solution was using PyCharm and setting the default python version to the the one that i need to work with.

install PyCharm and go to file ==> preferences for new project, then choose the interpreter you want for your projects, in this case python 3.3


回答 15

如果您使用macports,则不需要使用别名或环境变量,只需使用macports已经提供的方法,此问答将对此进行说明:

作法:Macports选择python

TL; DR:

sudo port select --set python python27

If you use macports, you do not need to play with aliases or environment variables, just use the the method macports already offers, explained by this Q&A:

How to: Macports select python

TL;DR:

sudo port select --set python python27

回答 16

如果您使用的是Macports,则有一种更简单的方法:

跑:

port install python37

安装后,设置默认值:

sudo port select --set python python37

sudo port select --set python3 python37

重新启动您的cmd窗口,完成。

If you are using macports, that has a easier way to do:

run:

port install python37

after install, set default:

sudo port select --set python python37

sudo port select --set python3 python37

restart your cmd window, finished.


回答 17

好吧…有点老了。但是仍然值得一个好的答案。

优点之一是您不想触摸Mac上的默认Python。

通过Homebrew或其他方式安装所需的任何Python版本,然后在virtualenv中使用它。Virtualenv通常被认为是胡扯,但还是比在系统范围内更改python版本(macOS可能会保护自己免受此类操作)或用户范围,bash范围……好得多。只需忘记默认的Python。使用venv这样的游乐场是您的操作系统最感谢的事情。

例如,这种情况是,许多现代Linux发行版都摆脱了现成安装的Python2的安装,仅在系统中保留了Python3。但是每次您尝试使用python2作为依赖项安装旧版本时…希望您理解我的意思。一个好的开发者不在乎。好的开发人员可以使用他们想要的python版本创建干净的游乐场。

Well… It’s kinda old. But still deserves a good answer.

And the good one is You Don’t Wanna Touch The Default Python On Mac.

Install any Python version you need via Homebrew or whatever and use it in virtualenv. Virtualenv is often considered to be something crap-like, but it’s still way, wayyyy better than changing python version system-wide (macOS is likely to protect itself from such actions) or user-wide, bash-wide… whatever. Just forget about the default Python. Using playgrounds like venv is what your OS will be most, very most grateful for.

The case is, for example, many modern Linux distributions get rid of Python2 installed out-of-the-box, leaving only Python3 in the system. But everytime you try to install something old with python2 as a dependency… hope you understand what I mean. A good developer doesn’t care. Good developers create clean playgrounds with python version they desire.


回答 18

Mac用户只需要在终端上运行以下代码

brew switch python 3.x.x

3.xx应该是新的python版本。

这将更新所有系统链接。

Mac users just need to run the following code on terminal

brew switch python 3.x.x

3.x.x should be the new python version.

This will update all the system links.


回答 19

建议将python别名为python3会导致设置python版本的虚拟环境出现问题(例如:pyenv)。使用pyenv,您可以像下面这样全局设置版本:

pyenv global 3.8.2

然后在任何特定项目中,您都可以创建一个.python-version文件,其中包含python版本:

pyenv local 2.7.1

我认为这是在系统上管理多个版本的python的最佳方法。

Suggestions to alias python to python3 will cause problems with virtual environments that set the version of python (eg: pyenv). With pyenv, you can set the version globally like so:

pyenv global 3.8.2

and then in any specific project, you can create a .python-version file which has the python version inside of it:

pyenv local 2.7.1

This is the best way to manage multiple versions of python on a system in my opinion.


列出对象的属性

问题:列出对象的属性

有没有办法获取类实例上存在的属性列表?

class new_class():
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

a = new_class(2)
print(', '.join(a.SOMETHING))

理想的结果是将输出“ multi,str”。我希望它可以查看脚本各个部分的当前属性。

Is there a way to grab a list of attributes that exist on instances of a class?

class new_class():
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

a = new_class(2)
print(', '.join(a.SOMETHING))

The desired result is that “multi, str” will be output. I want this to see the current attributes from various parts of a script.


回答 0

>>> class new_class():
...   def __init__(self, number):
...     self.multi = int(number) * 2
...     self.str = str(number)
... 
>>> a = new_class(2)
>>> a.__dict__
{'multi': 4, 'str': '2'}
>>> a.__dict__.keys()
dict_keys(['multi', 'str'])

您可能还会发现pprint有帮助。

>>> class new_class():
...   def __init__(self, number):
...     self.multi = int(number) * 2
...     self.str = str(number)
... 
>>> a = new_class(2)
>>> a.__dict__
{'multi': 4, 'str': '2'}
>>> a.__dict__.keys()
dict_keys(['multi', 'str'])

You may also find pprint helpful.


回答 1

dir(instance)
# or (same value)
instance.__dir__()
# or
instance.__dict__

然后,您可以测试的类型type()或的方法callable()

dir(instance)
# or (same value)
instance.__dir__()
# or
instance.__dict__

Then you can test what type is with type() or if is a method with callable().


回答 2

vars(obj) 返回对象的属性。

vars(obj) returns the attributes of an object.


回答 3

先前的所有答案都是正确的,您可以根据自己的需求选择三种方式

  1. dir()

  2. vars()

  3. __dict__

>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']
>>> vars(a)
{'multi': 4, 'str': '2'}
>>> a.__dict__
{'multi': 4, 'str': '2'}

All previous answers are correct, you have three options for what you are asking

  1. dir()

  2. vars()

  3. __dict__

>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']
>>> vars(a)
{'multi': 4, 'str': '2'}
>>> a.__dict__
{'multi': 4, 'str': '2'}

回答 4

>>> ', '.join(i for i in dir(a) if not i.startswith('__'))
'multi, str'

当然,这将打印类定义中的所有方法或属性。您可以通过更改i.startwith('__')为排除“私有”方法i.startwith('_')

>>> ', '.join(i for i in dir(a) if not i.startswith('__'))
'multi, str'

This of course will print any methods or attributes in the class definition. You can exclude “private” methods by changing i.startwith('__') to i.startwith('_')


回答 5

检查模块提供了简便的方法来检查的对象:

检查模块提供了几个有用的功能,以帮助获取有关活动对象的信息,例如模块,类,方法,函数,回溯,框架对象和代码对象。


使用,getmembers()您可以查看类的所有属性及其值。要排除私有或受保护的属性,请使用.startswith('_')。要排除方法或功能,请使用inspect.ismethod()inspect.isfunction()

import inspect


class NewClass(object):
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

    def func_1(self):
        pass


a = NewClass(2)

for i in inspect.getmembers(a):
    # Ignores anything starting with underscore 
    # (that is, private and protected attributes)
    if not i[0].startswith('_'):
        # Ignores methods
        if not inspect.ismethod(i[1]):
            print(i)

请注意,由于第一个ismethod()元素i只是一个字符串(其名称),因此它用于第二个元素。

主题:使用CamelCase作为类名。

The inspect module provides easy ways to inspect an object:

The inspect module provides several useful functions to help get information about live objects such as modules, classes, methods, functions, tracebacks, frame objects, and code objects.


Using getmembers() you can see all attributes of your class, along with their value. To exclude private or protected attributes use .startswith('_'). To exclude methods or functions use inspect.ismethod() or inspect.isfunction().

import inspect


class NewClass(object):
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

    def func_1(self):
        pass


a = NewClass(2)

for i in inspect.getmembers(a):
    # Ignores anything starting with underscore 
    # (that is, private and protected attributes)
    if not i[0].startswith('_'):
        # Ignores methods
        if not inspect.ismethod(i[1]):
            print(i)

Note that ismethod() is used on the second element of i since the first is simply a string (its name).

Offtopic: Use CamelCase for class names.


回答 6

您可以dir(your_object)用来获取属性和getattr(your_object, your_object_attr)获取值

用法:

for att in dir(your_object):
    print (att, getattr(your_object,att))

如果您的对象没有__dict__,这将特别有用。如果不是这种情况,您也可以尝试var(your_object)

You can use dir(your_object) to get the attributes and getattr(your_object, your_object_attr) to get the values

usage :

for att in dir(your_object):
    print (att, getattr(your_object,att))

This is particularly useful if your object have no __dict__. If that is not the case you can try var(your_object) also


回答 7

人们经常提到要列出完整的属性列表,您应该使用dir()。但是请注意,与普遍看法相反,这dir()并不能体现所有属性。例如,即使您可以从类本身访问它,您也可能会注意到__name__dir()列表中可能缺少该类。从dir()Python 2Python 3)的文档中:

因为dir()的主要提供是为了方便在交互式提示符下使用,所以它尝试提供一组有趣的名称,而不是尝试提供一组严格或一致定义的名称,并且其详细行为可能会因版本而异。例如,当参数是类时,元类属性不在结果列表中。

像下图的功能更趋于完善,虽然有因为返回的列表中没有完整的担保dir()可以由许多因素,包括实施的影响的__dir__()方法,或自定义__getattr__()__getattribute__()对类或它的某个父。有关更多详细信息,请参见提供的链接。

def dirmore(instance):
    visible = dir(instance)
    visible += [a for a in set(dir(type)).difference(visible)
                if hasattr(instance, a)]
    return sorted(visible)

It’s often mentioned that to list a complete list of attributes you should use dir(). Note however that contrary to popular belief dir() does not bring out all attributes. For example you might notice that __name__ might be missing from a class’s dir() listing even though you can access it from the class itself. From the doc on dir() (Python 2, Python 3):

Because dir() is supplied primarily as a convenience for use at an interactive prompt, it tries to supply an interesting set of names more than it tries to supply a rigorously or consistently defined set of names, and its detailed behavior may change across releases. For example, metaclass attributes are not in the result list when the argument is a class.

A function like the following tends to be more complete, although there’s no guarantee of completeness since the list returned by dir() can be affected by many factors including implementing the __dir__() method, or customizing __getattr__() or __getattribute__() on the class or one of its parents. See provided links for more details.

def dirmore(instance):
    visible = dir(instance)
    visible += [a for a in set(dir(type)).difference(visible)
                if hasattr(instance, a)]
    return sorted(visible)

回答 8

你要干嘛 在不知道确切意图的情况下,可能很难获得最佳答案。

  • 如果要以特定的方式显示类的实例,几乎总是最好手动进行此操作。这将完全包括您想要的内容,而不包括您不需要的内容,并且顺序是可以预测的。

    如果您正在寻找一种显示类内容的方法,请手动设置您关心的属性的格式,并将其作为类的__str__or __repr__方法提供。

  • 如果要了解对象存在哪些方法等,以了解其工作原理,请使用helphelp(a)将根据对象的文档字符串显示有关该对象的类的格式化输出。

  • dir存在以编程方式获取对象的所有属性。(访问__dict__将执行与我相同的操作,但不会使用我自己。)但是,这可能不包括您想要的东西,也可能包括您不想要的东西。它是不可靠的,人们认为他们想要的次数比他们想要的要多得多。

  • 有点正交,目前对Python 3的支持很少。如果您对编写真正的软件感兴趣,那么您将需要第三方产品,例如numpy,lxml,Twisted,PIL或任何数量的尚不支持Python 3并且没有计划很快的计划的Web框架。2.6和3.x分支之间的差异很小,但是库支持方面的差异很大。

What do you want this for? It may be hard to get you the best answer without knowing your exact intent.

  • It is almost always better to do this manually if you want to display an instance of your class in a specific way. This will include exactly what you want and not include what you don’t want, and the order will be predictable.

    If you are looking for a way to display the content of a class, manually format the attributes you care about and provide this as the __str__ or __repr__ method for your class.

  • If you want to learn about what methods and such exist for an object to understand how it works, use help. help(a) will show you a formatted output about the object’s class based on its docstrings.

  • dir exists for programatically getting all the attributes of an object. (Accessing __dict__ does something I would group as the same but that I wouldn’t use myself.) However, this may not include things you want and it may include things you do not want. It is unreliable and people think they want it a lot more often than they do.

  • On a somewhat orthogonal note, there is very little support for Python 3 at the current time. If you are interested in writing real software you are going to want third-party stuff like numpy, lxml, Twisted, PIL, or any number of web frameworks that do not yet support Python 3 and do not have plans to any time too soon. The differences between 2.6 and the 3.x branch are small, but the difference in library support is huge.


回答 9

有多种方法可以做到这一点:

#! /usr/bin/env python3
#
# This demonstrates how to pick the attiributes of an object

class C(object) :

  def __init__ (self, name="q" ):
    self.q = name
    self.m = "y?"

c = C()

print ( dir(c) )

运行时,此代码将生成:

jeffs@jeff-desktop:~/skyset$ python3 attributes.py 
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__',      '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'm', 'q']

jeffs@jeff-desktop:~/skyset$

There is more than one way to do it:

#! /usr/bin/env python3
#
# This demonstrates how to pick the attiributes of an object

class C(object) :

  def __init__ (self, name="q" ):
    self.q = name
    self.m = "y?"

c = C()

print ( dir(c) )

When run, this code produces:

jeffs@jeff-desktop:~/skyset$ python3 attributes.py 
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__',      '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'm', 'q']

jeffs@jeff-desktop:~/skyset$

回答 10

请查看按顺序执行的python shell脚本,在这里您将获得以字符串格式(用逗号分隔)的类的属性。

>>> class new_class():
...     def __init__(self, number):
...         self.multi = int(number)*2
...         self.str = str(number)
... 
>>> a = new_class(4)
>>> ",".join(a.__dict__.keys())
'str,multi'<br/>

我正在使用python 3.4

Please see the python shell script which has been executed in sequence, here you will get the attributes of a class in string format separated by comma.

>>> class new_class():
...     def __init__(self, number):
...         self.multi = int(number)*2
...         self.str = str(number)
... 
>>> a = new_class(4)
>>> ",".join(a.__dict__.keys())
'str,multi'<br/>

I am using python 3.4


回答 11

除了这些答案之外,我还将包括一个函数(python 3),用于生成几乎所有值的整个结构。它用于dir建立属性名称的完整列表,然后getattr与每个名称一起使用。它显示值的每个成员的类型,并在可能的情况下还显示整个成员:

import json

def get_info(obj):

  type_name = type(obj).__name__
  print('Value is of type {}!'.format(type_name))
  prop_names = dir(obj)

  for prop_name in prop_names:
    prop_val = getattr(obj, prop_name)
    prop_val_type_name = type(prop_val).__name__
    print('{} has property "{}" of type "{}"'.format(type_name, prop_name, prop_val_type_name))

    try:
      val_as_str = json.dumps([ prop_val ], indent=2)[1:-1]
      print('  Here\'s the {} value: {}'.format(prop_name, val_as_str))
    except:
      pass

现在,以下任何一项都应提供洞察力:

get_info(None)
get_info('hello')

import numpy
get_info(numpy)
# ... etc.

In addition to these answers, I’ll include a function (python 3) for spewing out virtually the entire structure of any value. It uses dir to establish the full list of property names, then uses getattr with each name. It displays the type of every member of the value, and when possible also displays the entire member:

import json

def get_info(obj):

  type_name = type(obj).__name__
  print('Value is of type {}!'.format(type_name))
  prop_names = dir(obj)

  for prop_name in prop_names:
    prop_val = getattr(obj, prop_name)
    prop_val_type_name = type(prop_val).__name__
    print('{} has property "{}" of type "{}"'.format(type_name, prop_name, prop_val_type_name))

    try:
      val_as_str = json.dumps([ prop_val ], indent=2)[1:-1]
      print('  Here\'s the {} value: {}'.format(prop_name, val_as_str))
    except:
      pass

Now any of the following should give insight:

get_info(None)
get_info('hello')

import numpy
get_info(numpy)
# ... etc.

回答 12

获取对象的属性

class new_class():
    def __init__(self, number):
    self.multi = int(number) * 2
    self.str = str(number)

new_object = new_class(2)                
print(dir(new_object))                   #total list attributes of new_object
attr_value = new_object.__dict__         
print(attr_value)                        #Dictionary of attribute and value for new_class                   

for attr in attr_value:                  #attributes on  new_class
    print(attr)

输出量

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__','__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']

{'multi': 4, 'str': '2'}

multi
str

Get attributes of an object

class new_class():
    def __init__(self, number):
    self.multi = int(number) * 2
    self.str = str(number)

new_object = new_class(2)                
print(dir(new_object))                   #total list attributes of new_object
attr_value = new_object.__dict__         
print(attr_value)                        #Dictionary of attribute and value for new_class                   

for attr in attr_value:                  #attributes on  new_class
    print(attr)

Output

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__','__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']

{'multi': 4, 'str': '2'}

multi
str

回答 13

如前所述,使用obj.__dict__可以处理常见情况,但是某些类没有__dict__属性和使用__slots__(主要是为了提高内存效率)。

更具弹性的方法示例:

class A(object):
    __slots__ = ('x', 'y', )
    def __init__(self, x, y):
        self.x = x
        self.y = y


class B(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


def get_object_attrs(obj):
    try:
        return obj.__dict__
    except AttributeError:
        return {attr: getattr(obj, attr) for attr in obj.__slots__}


a = A(1,2)
b = B(1,2)
assert not hasattr(a, '__dict__')

print(get_object_attrs(a))
print(get_object_attrs(b))

此代码的输出:

{'x': 1, 'y': 2}
{'x': 1, 'y': 2}

注意1:
Python是一种动态语言,因此最好还是了解试图从中获取属性的类,因为即使这段代码也可能会丢失某些情况。

注意2:
此代码仅输出实例变量,这意味着未提供类变量。例如:

class A(object):
    url = 'http://stackoverflow.com'
    def __init__(self, path):
        self.path = path

print(A('/questions').__dict__)

代码输出:

{'path': '/questions'}

此代码不会显示urlclass属性,并且可能会省略所需的class属性。
有时,我们可能会认为属性是实例成员,但并非如此,因此在本示例中不会显示。

As written before using obj.__dict__ can handle common cases but some classes do not have the __dict__ attribute and use __slots__ (mostly for memory efficiency).

example for a more resilient way of doing this:

class A(object):
    __slots__ = ('x', 'y', )
    def __init__(self, x, y):
        self.x = x
        self.y = y


class B(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


def get_object_attrs(obj):
    try:
        return obj.__dict__
    except AttributeError:
        return {attr: getattr(obj, attr) for attr in obj.__slots__}


a = A(1,2)
b = B(1,2)
assert not hasattr(a, '__dict__')

print(get_object_attrs(a))
print(get_object_attrs(b))

this code’s output:

{'x': 1, 'y': 2}
{'x': 1, 'y': 2}

Note1:
Python is a dynamic language and it is always better knowing the classes you trying to get the attributes from as even this code can miss some cases.

Note2:
this code outputs only instance variables meaning class variables are not provided. for example:

class A(object):
    url = 'http://stackoverflow.com'
    def __init__(self, path):
        self.path = path

print(A('/questions').__dict__)

code outputs:

{'path': '/questions'}

This code does not print the url class attribute and might omit wanted class attributes.
Sometimes we might think an attribute is an instance member but it is not and won’t be shown using this example.


回答 14

  • 使用__dict__vars 不起作用,因为它错过了__slots__
  • 使用__dict____slots__ 不起作用,因为它错过了__slots__基类。
  • 使用dir 不起作用,因为它包括类属性(例如方法或属性)以及对象属性。
  • 使用vars等同于使用__dict__

这是我最好的:

from typing import Dict

def get_attrs( x : object ) -> Dict[str, object]:
    mro      = type( x ).mro()
    attrs    = { }
    has_dict = False
    sentinel = object()

    for klass in mro:
        for slot in getattr( klass, "__slots__", () ):
            v = getattr( x, slot, sentinel )

            if v is sentinel:
                continue

            if slot == "__dict__":
                assert not has_dict, "Multiple __dicts__?"
                attrs.update( v )
                has_dict = True
            else:
                attrs[slot] = v

    if not has_dict:
        attrs.update( getattr( x, "__dict__", { } ) )

    return attrs
  • Using __dict__ or vars does not work because it misses out __slots__.
  • Using __dict__ and __slots__ does not work because it misses out __slots__ from base classes.
  • Using dir does not work because it includes class attributes, such as methods or properties, as well as the object attributes.
  • Using vars is equivalent to using __dict__.

This is the best I have:

from typing import Dict

def get_attrs( x : object ) -> Dict[str, object]:
    mro      = type( x ).mro()
    attrs    = { }
    has_dict = False
    sentinel = object()

    for klass in mro:
        for slot in getattr( klass, "__slots__", () ):
            v = getattr( x, slot, sentinel )

            if v is sentinel:
                continue

            if slot == "__dict__":
                assert not has_dict, "Multiple __dicts__?"
                attrs.update( v )
                has_dict = True
            else:
                attrs[slot] = v

    if not has_dict:
        attrs.update( getattr( x, "__dict__", { } ) )

    return attrs

回答 15

attributes_list = [attribute for attribute in dir(obj) if attribute[0].islower()]
attributes_list = [attribute for attribute in dir(obj) if attribute[0].islower()]

回答 16

请按顺序查看以下Python Shell脚本执行,它将提供从创建类到提取实例的字段名称的解决方案。

>>> class Details:
...       def __init__(self,name,age):
...           self.name=name
...           self.age =age
...       def show_details(self):
...           if self.name:
...              print "Name : ",self.name
...           else:
...              print "Name : ","_"
...           if self.age:
...              if self.age>0:
...                 print "Age  : ",self.age
...              else:
...                 print "Age can't be -ve"
...           else:
...              print "Age  : ","_"
... 
>>> my_details = Details("Rishikesh",24)
>>> 
>>> print my_details
<__main__.Details instance at 0x10e2e77e8>
>>> 
>>> print my_details.name
Rishikesh
>>> print my_details.age
24
>>> 
>>> my_details.show_details()
Name :  Rishikesh
Age  :  24
>>> 
>>> person1 = Details("",34)
>>> person1.name
''
>>> person1.age
34
>>> person1.show_details
<bound method Details.show_details of <__main__.Details instance at 0x10e2e7758>>
>>> 
>>> person1.show_details()
Name :  _
Age  :  34
>>>
>>> person2 = Details("Rob Pike",0)
>>> person2.name
'Rob Pike'
>>> 
>>> person2.age
0
>>> 
>>> person2.show_details()
Name :  Rob Pike
Age  :  _
>>> 
>>> person3 = Details("Rob Pike",-45)
>>> 
>>> person3.name
'Rob Pike'
>>> 
>>> person3.age
-45
>>> 
>>> person3.show_details()
Name :  Rob Pike
Age can't be -ve
>>>
>>> person3.__dict__
{'age': -45, 'name': 'Rob Pike'}
>>>
>>> person3.__dict__.keys()
['age', 'name']
>>>
>>> person3.__dict__.values()
[-45, 'Rob Pike']
>>>

Please see the following Python shell scripting execution in sequence, it will give the solution from creation of class to extracting the field names of instances.

>>> class Details:
...       def __init__(self,name,age):
...           self.name=name
...           self.age =age
...       def show_details(self):
...           if self.name:
...              print "Name : ",self.name
...           else:
...              print "Name : ","_"
...           if self.age:
...              if self.age>0:
...                 print "Age  : ",self.age
...              else:
...                 print "Age can't be -ve"
...           else:
...              print "Age  : ","_"
... 
>>> my_details = Details("Rishikesh",24)
>>> 
>>> print my_details
<__main__.Details instance at 0x10e2e77e8>
>>> 
>>> print my_details.name
Rishikesh
>>> print my_details.age
24
>>> 
>>> my_details.show_details()
Name :  Rishikesh
Age  :  24
>>> 
>>> person1 = Details("",34)
>>> person1.name
''
>>> person1.age
34
>>> person1.show_details
<bound method Details.show_details of <__main__.Details instance at 0x10e2e7758>>
>>> 
>>> person1.show_details()
Name :  _
Age  :  34
>>>
>>> person2 = Details("Rob Pike",0)
>>> person2.name
'Rob Pike'
>>> 
>>> person2.age
0
>>> 
>>> person2.show_details()
Name :  Rob Pike
Age  :  _
>>> 
>>> person3 = Details("Rob Pike",-45)
>>> 
>>> person3.name
'Rob Pike'
>>> 
>>> person3.age
-45
>>> 
>>> person3.show_details()
Name :  Rob Pike
Age can't be -ve
>>>
>>> person3.__dict__
{'age': -45, 'name': 'Rob Pike'}
>>>
>>> person3.__dict__.keys()
['age', 'name']
>>>
>>> person3.__dict__.values()
[-45, 'Rob Pike']
>>>

回答 17

__attr__ 给出实例的属性列表。

>>> import requests
>>> r=requests.get('http://www.google.com')
>>> r.__attrs__
['_content', 'status_code', 'headers', 'url', 'history', 'encoding', 'reason', 'cookies', 'elapsed', 'request']
>>> r.url
'http://www.google.com/'
>>>

__attr__ gives the list of attributes of an instance.

>>> import requests
>>> r=requests.get('http://www.google.com')
>>> r.__attrs__
['_content', 'status_code', 'headers', 'url', 'history', 'encoding', 'reason', 'cookies', 'elapsed', 'request']
>>> r.url
'http://www.google.com/'
>>>

Python 3 ImportError:没有名为“ ConfigParser”的模块

问题:Python 3 ImportError:没有名为“ ConfigParser”的模块

我想pip installMySQL-python包,但我得到的ImportError

Jans-MacBook-Pro:~ jan$ /Library/Frameworks/Python.framework/Versions/3.3/bin/pip-3.3 install MySQL-python
Downloading/unpacking MySQL-python
  Running setup.py egg_info for package MySQL-python
    Traceback (most recent call last):
      File "<string>", line 16, in <module>
      File "/var/folders/lf/myf7bjr57_jg7_5c4014bh640000gn/T/pip-build/MySQL-python/setup.py", line 14, in <module>
        from setup_posix import get_config
      File "./setup_posix.py", line 2, in <module>
        from ConfigParser import SafeConfigParser
    ImportError: No module named 'ConfigParser'
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

  File "<string>", line 16, in <module>

  File "/var/folders/lf/myf7bjr57_jg7_5c4014bh640000gn/T/pip-build/MySQL-python/setup.py", line 14, in <module>

    from setup_posix import get_config

  File "./setup_posix.py", line 2, in <module>

    from ConfigParser import SafeConfigParser

ImportError: No module named 'ConfigParser'

----------------------------------------
Command python setup.py egg_info failed with error code 1 in /var/folders/lf/myf7bjr57_jg7_5c4014bh640000gn/T/pip-build/MySQL-python
Storing complete log in /Users/jan/.pip/pip.log
Jans-MacBook-Pro:~ jan$ 

有任何想法吗?

I am trying to pip install the MySQL-python package, but I get an ImportError.

Jans-MacBook-Pro:~ jan$ /Library/Frameworks/Python.framework/Versions/3.3/bin/pip-3.3 install MySQL-python
Downloading/unpacking MySQL-python
  Running setup.py egg_info for package MySQL-python
    Traceback (most recent call last):
      File "<string>", line 16, in <module>
      File "/var/folders/lf/myf7bjr57_jg7_5c4014bh640000gn/T/pip-build/MySQL-python/setup.py", line 14, in <module>
        from setup_posix import get_config
      File "./setup_posix.py", line 2, in <module>
        from ConfigParser import SafeConfigParser
    ImportError: No module named 'ConfigParser'
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

  File "<string>", line 16, in <module>

  File "/var/folders/lf/myf7bjr57_jg7_5c4014bh640000gn/T/pip-build/MySQL-python/setup.py", line 14, in <module>

    from setup_posix import get_config

  File "./setup_posix.py", line 2, in <module>

    from ConfigParser import SafeConfigParser

ImportError: No module named 'ConfigParser'

----------------------------------------
Command python setup.py egg_info failed with error code 1 in /var/folders/lf/myf7bjr57_jg7_5c4014bh640000gn/T/pip-build/MySQL-python
Storing complete log in /Users/jan/.pip/pip.log
Jans-MacBook-Pro:~ jan$ 

Any ideas?


回答 0

在Python 3中,ConfigParser已被重命名configparser为PEP 8合规性。您正在安装的软件包似乎不支持Python 3。

In Python 3, ConfigParser has been renamed to configparser for PEP 8 compliance. It looks like the package you are installing does not support Python 3.


回答 1

您可以改为使用该mysqlclient软件包作为MySQL-python的直接替代品。它是MySQL-python对Python 3的新增支持。

我很幸运

pip install mysqlclient

在我的python3.4 virtualenv之后

sudo apt-get install python3-dev libmysqlclient-dev

这显然是针对ubuntu / debian的,但我只是想分享我的成功:)

You can instead use the mysqlclient package as a drop-in replacement for MySQL-python. It is a fork of MySQL-python with added support for Python 3.

I had luck with simply

pip install mysqlclient

in my python3.4 virtualenv after

sudo apt-get install python3-dev libmysqlclient-dev

which is obviously specific to ubuntu/debian, but I just wanted to share my success :)


回答 2

这是一个在Python 2.x和3.x中均应适用的代码

显然,您将需要该six模块,但是几乎不可能编写在两个版本中都没有六个版本的模块。

try:
    import configparser
except:
    from six.moves import configparser

Here is a code that should work in both Python 2.x and 3.x

Obviously you will need the six module, but it’s almost impossible to write modules that work in both versions without six.

try:
    import configparser
except:
    from six.moves import configparser

回答 3

pip install configparser
sudo cp /usr/lib/python3.6/configparser.py /usr/lib/python3.6/ConfigParser.py

然后尝试再次安装MYSQL-python。对我有用

pip install configparser
sudo cp /usr/lib/python3.6/configparser.py /usr/lib/python3.6/ConfigParser.py

Then try to install the MYSQL-python again. That Worked for me


回答 4

python3不支持MySQL-python,您可以使用mysqlclient

如果您正在fedora/centos/Red Hat安装以下软件包

  1. yum install python3-devel
  2. pip install mysqlclient

MySQL-python is not supported on python3 instead of this you can use mysqlclient

If you are on fedora/centos/Red Hat install following package

  1. yum install python3-devel
  2. pip install mysqlclient

回答 5

如果您使用的是CentOS,则需要使用

  1. yum install python34-devel.x86_64
  2. yum groupinstall -y 'development tools'
  3. pip3 install mysql-connector
  4. pip install mysqlclient

If you are using CentOS, then you need to use

  1. yum install python34-devel.x86_64
  2. yum groupinstall -y 'development tools'
  3. pip3 install mysql-connector
  4. pip install mysqlclient

回答 6

configparser可以通过six库简单地解决Python 2/3的兼容性

from six.moves import configparser

Compatibility of Python 2/3 for configparser can be solved simply by six library

from six.moves import configparser

回答 7

pip3 install PyMySQL然后再做pip3 install mysqlclient。为我工作

Do pip3 install PyMySQL and then pip3 install mysqlclient. Worked for me


回答 8

我遇到了同样的问题。原来,我需要在centos上安装python3 devel。首先,您需要搜索与系统兼容的软件包。

yum search python3 | grep devel

然后,将软件包安装为:

yum install -y python3-devel.x86_64

然后,从pip安装mysqlclient

pip install mysqlclient

I was having the same problem. Turns out, I needed to install python3 devel on my centos. First, you need to search for the package that is compatible with your system.

yum search python3 | grep devel

Then, install the package as:

yum install -y python3-devel.x86_64

Then, install mysqlclient from pip

pip install mysqlclient

回答 9

我进一步了解了Valeres的答案:

pip install configparser sudo cp /usr/lib/python3.6/configparser.py /usr/lib/python3.6/ConfigParser.py然后尝试再次安装MYSQL-python。对我有用

我建议链接文件而不是复制它。保存更新。我将文件链接到/usr/lib/python3/目录。

I got further with Valeres answer:

pip install configparser sudo cp /usr/lib/python3.6/configparser.py /usr/lib/python3.6/ConfigParser.py Then try to install the MYSQL-python again. That Worked for me

I would suggest to link the file instead of copy it. It is save to update. I linked the file to /usr/lib/python3/ directory.


回答 10

试试这个对我来说很好的解决方案。

基本上它是重新安装/升级到最新版本的MySQL冲泡,然后安装mysqlclientMySQL-Pythonglobal pip3代替virtualenv pip3

然后访问virtualenv并成功安装mysqlclientMySQL-Python

Try this solution which worked fine for me.

Basically it’s to reinstall/upgrade to latest version of mysql from brew, and then installing mysqlclient or MySQL-Python from global pip3 instead of virtualenv pip3.

Then accessing the virtualenv and successfully install mysqlclient or MySQL-Python.


回答 11

如何检查您首先使用的Python版本。

import six
if six.PY2:
    import ConfigParser as configparser
else:
    import configparser

how about checking the version of Python you are using first.

import six
if six.PY2:
    import ConfigParser as configparser
else:
    import configparser

回答 12

我运行kali linux- Rolling,并在更新到python 3.6.0之后尝试在终端中运行cupp.py时遇到了这个问题。一些研究和试验后,我发现,改变 ConfigParserconfigparser我的工作,但那时,我发现另一个问题就来了。

config = configparser.configparser() AttributeError: module 'configparser' has no attribute 'configparser'

经过更多研究,我意识到python 3 ConfigParser已更改为, configparser但请注意它具有属性 ConfigParser()

I run kali linux- Rolling and I came across this problem ,when I tried running cupp.py in the terminal, after updating to python 3.6.0. After some research and trial I found that changing ConfigParser to configparser worked for me but then I came across another issue.

config = configparser.configparser() AttributeError: module 'configparser' has no attribute 'configparser'

After a bit more research I realised that for python 3 ConfigParser is changed to configparser but note that it has an attribute ConfigParser().


回答 13

我在Mac OS 10,Python 3.7.6和Django 2.2.7上遇到了相同的错误。在尝试了多种解决方案之后,我想借此机会分享对我有用的东西。

脚步

  1. 通过链接为Mac OS安装了Connector / Python 8.0.20

  2. 将当前依赖项复制到requirements.txt文件,停用当前虚拟环境,并使用删除它;

    创建文件(如果尚未创建的话); touch requirements.txt

    将依赖项复制到文件; python -m pip3 freeze > requirements.txt

    停用并删除当前虚拟环境; deactivate && rm -rf <virtual-env-name>

  3. 创建另一个虚拟环境并使用激活它; python -m venv <virtual-env-name> && source <virtual-env-name>/bin/activate

  4. 使用安装以前的依赖项; python -m pip3 install -r requirements.txt

I was getting the same error on Mac OS 10, Python 3.7.6 & Django 2.2.7. I want to use this opportunity to share what worked for me after trying out numerous solutions.

Steps

  1. Installed Connector/Python 8.0.20 for Mac OS from link

  2. Copy current dependencies into requirements.txt file, deactivated the current virtual env, and deleted it using;

    create the file if not already created with; touch requirements.txt

    copy dependency to file; python -m pip3 freeze > requirements.txt

    deactivate and delete current virtual env; deactivate && rm -rf <virtual-env-name>

  3. Created another virtual env and activated it using; python -m venv <virtual-env-name> && source <virtual-env-name>/bin/activate

  4. Install previous dependencies using; python -m pip3 install -r requirements.txt


回答 14

请看看/usr/bin/python指的是什么

如果它指向python3 or higher 更改为python2.7

这应该可以解决问题。

我收到所有python软件包的安装错误。安倍·卡普拉斯(Abe Karplus)的解决方案和讨论向我暗示了可能是什么问题。然后我回想起我已经手动将/usr/bin/pythonfrom从更改python2.7/usr/bin/python3.5,这实际上是导致问题的原因。有一次我reverted一样。解决了。

Kindly to see what is /usr/bin/python pointing to

if it is pointing to python3 or higher change to python2.7

This should solve the issue.

I was getting install error for all the python packages. Abe Karplus’s solution & discussion gave me the hint as to what could be the problem. Then I recalled that I had manually changed the /usr/bin/python from python2.7 to /usr/bin/python3.5, which actually was causing the issue. Once I reverted the same. It got solved.


回答 15

这对我有用

cp /usr/local/lib/python3.5/configparser.py /usr/local/lib/python3.5/ConfigParser.py

This worked for me

cp /usr/local/lib/python3.5/configparser.py /usr/local/lib/python3.5/ConfigParser.py

TypeError:需要类似字节的对象,而在Python3中写入文件时不是’str’

问题:TypeError:需要类似字节的对象,而在Python3中写入文件时不是’str’

我最近已经迁移到Py 3.5。这段代码在Python 2.7中正常工作:

with open(fname, 'rb') as f:
    lines = [x.strip() for x in f.readlines()]

for line in lines:
    tmp = line.strip().lower()
    if 'some-pattern' in tmp: continue
    # ... code

升级到3.5后,我得到了:

TypeError: a bytes-like object is required, not 'str'

最后一行错误(模式搜索代码)。

我试过使用.decode()语句两侧的函数,也尝试过:

if tmp.find('some-pattern') != -1: continue

-无济于事。

我能够很快解决几乎所有的2:3问题,但是这个小小的声明困扰着我。

I’ve very recently migrated to Py 3.5. This code was working properly in Python 2.7:

with open(fname, 'rb') as f:
    lines = [x.strip() for x in f.readlines()]

for line in lines:
    tmp = line.strip().lower()
    if 'some-pattern' in tmp: continue
    # ... code

After upgrading to 3.5, I’m getting the:

TypeError: a bytes-like object is required, not 'str'

error on the last line (the pattern search code).

I’ve tried using the .decode() function on either side of the statement, also tried:

if tmp.find('some-pattern') != -1: continue

– to no avail.

I was able to resolve almost all 2:3 issues quickly, but this little statement is bugging me.


回答 0

您以二进制模式打开文件:

with open(fname, 'rb') as f:

这意味着从文件读取的所有数据都作为bytes对象而不是作为对象返回str。然后,您不能在收容测试中使用字符串:

if 'some-pattern' in tmp: continue

您必须改为使用一个bytes对象进行测试tmp

if b'some-pattern' in tmp: continue

或以文本文件形式打开文件,而不是将'rb'模式替换为'r'

You opened the file in binary mode:

with open(fname, 'rb') as f:

This means that all data read from the file is returned as bytes objects, not str. You cannot then use a string in a containment test:

if 'some-pattern' in tmp: continue

You’d have to use a bytes object to test against tmp instead:

if b'some-pattern' in tmp: continue

or open the file as a textfile instead by replacing the 'rb' mode with 'r'.


回答 1

您可以使用以下方式对字符串进行编码 .encode()

例:

'Hello World'.encode()

You can encode your string by using .encode()

Example:

'Hello World'.encode()

回答 2

就像已经提到的一样,您正在以二进制模式读取文件,然后创建字节列表。在下面的for循环中,您将字符串与字节进行比较,这就是代码失败的地方。

在将字节添加到列表时对字节进行解码应该可以。更改后的代码应如下所示:

with open(fname, 'rb') as f:
    lines = [x.decode('utf8').strip() for x in f.readlines()]

字节类型是在Python 3中引入的,这就是为什么您的代码在Python 2中可以工作的原因。在Python 2中,没有字节的数据类型:

>>> s=bytes('hello')
>>> type(s)
<type 'str'>

Like it has been already mentioned, you are reading the file in binary mode and then creating a list of bytes. In your following for loop you are comparing string to bytes and that is where the code is failing.

Decoding the bytes while adding to the list should work. The changed code should look as follows:

with open(fname, 'rb') as f:
    lines = [x.decode('utf8').strip() for x in f.readlines()]

The bytes type was introduced in Python 3 and that is why your code worked in Python 2. In Python 2 there was no data type for bytes:

>>> s=bytes('hello')
>>> type(s)
<type 'str'>

回答 3

您必须从wb更改为w:

def __init__(self):
    self.myCsv = csv.writer(open('Item.csv', 'wb')) 
    self.myCsv.writerow(['title', 'link'])

def __init__(self):
    self.myCsv = csv.writer(open('Item.csv', 'w'))
    self.myCsv.writerow(['title', 'link'])

更改此设置后,错误消失,但是您无法写入文件(以我为例)。毕竟,我没有答案吗?

来源:如何删除^ M

更改为“ rb”会给我带来另一个错误:io.UnsupportedOperation:写入

You have to change from wb to w:

def __init__(self):
    self.myCsv = csv.writer(open('Item.csv', 'wb')) 
    self.myCsv.writerow(['title', 'link'])

to

def __init__(self):
    self.myCsv = csv.writer(open('Item.csv', 'w'))
    self.myCsv.writerow(['title', 'link'])

After changing this, the error disappears, but you can’t write to the file (in my case). So after all, I don’t have an answer?

Source: How to remove ^M

Changing to ‘rb’ brings me the other error: io.UnsupportedOperation: write


回答 4

对于这个小例子:import socket

mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect(('www.py4inf.com', 80))
mysock.send(**b**'GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\n\n')

while True:
    data = mysock.recv(512)
    if ( len(data) < 1 ) :
        break
    print (data);

mysock.close()

在’GET http://www.py4inf.com/code/romeo.txt HTTP / 1.0 \ n \ n’ 之前添加“ b” 解决了我的问题

for this small example: import socket

mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mysock.connect(('www.py4inf.com', 80))
mysock.send(**b**'GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\n\n')

while True:
    data = mysock.recv(512)
    if ( len(data) < 1 ) :
        break
    print (data);

mysock.close()

adding the “b” before ‘GET http://www.py4inf.com/code/romeo.txt HTTP/1.0\n\n’ solved my problem


回答 5

与单引号中给出的硬编码字符串值一起使用encode()函数。

例如:

file.write(answers[i] + '\n'.encode())

要么

line.split(' +++$+++ '.encode())

Use encode() function along with hardcoded String value given in a single quote.

Ex:

file.write(answers[i] + '\n'.encode())

OR

line.split(' +++$+++ '.encode())

回答 6

您以二进制模式打开文件:

以下代码将引发TypeError:需要一个类似字节的对象,而不是’str’。

for line in lines:
    print(type(line))# <class 'bytes'>
    if 'substring' in line:
       print('success')

以下代码将起作用-您必须使用encode()函数:

for line in lines:
    line = line.decode()
    print(type(line))# <class 'str'>
    if 'substring' in line:
       print('success')

You opened the file in binary mode:

The following code will throw a TypeError: a bytes-like object is required, not ‘str’.

for line in lines:
    print(type(line))# <class 'bytes'>
    if 'substring' in line:
       print('success')

The following code will work – you have to use the decode() function:

for line in lines:
    line = line.decode()
    print(type(line))# <class 'str'>
    if 'substring' in line:
       print('success')

回答 7

为什么不尝试以文本形式打开文件?

with open(fname, 'rt') as f:
    lines = [x.strip() for x in f.readlines()]

此外,以下是官方页面上python 3.x的链接:https : //docs.python.org/3/library/io.html 这是开放功能:https : //docs.python.org/3 /library/functions.html#open

如果您确实想将其作为二进制文件处理,则考虑对字符串进行编码。

why not try opening your file as text?

with open(fname, 'rt') as f:
    lines = [x.strip() for x in f.readlines()]

Additionally here is a link for python 3.x on the official page: https://docs.python.org/3/library/io.html And this is the open function: https://docs.python.org/3/library/functions.html#open

If you are really trying to handle it as a binary then consider encoding your string.


回答 8

当我尝试将char(或字符串)转换为时,出现此错误bytes,代码在Python 2.7中是这样的:

# -*- coding: utf-8 -*-
print( bytes('ò') )

这是Python 2.7处理Unicode字符的方式。

这在Python 3.6中不起作用,因为bytes需要一个额外的参数来编码,但这可能有点棘手,因为不同的编码可能会输出不同的结果:

print( bytes('ò', 'iso_8859_1') ) # prints: b'\xf2'
print( bytes('ò', 'utf-8') ) # prints: b'\xc3\xb2'

就我而言,我不得不使用 iso_8859_1在对字节进行编码时来解决问题。

希望这对某人有帮助。

I got this error when I was trying to convert a char (or string) to bytes, the code was something like this with Python 2.7:

# -*- coding: utf-8 -*-
print( bytes('ò') )

This is the way of Python 2.7 when dealing with unicode chars.

This won’t work with Python 3.6, since bytes require an extra argument for encoding, but this can be little tricky, since different encoding may output different result:

print( bytes('ò', 'iso_8859_1') ) # prints: b'\xf2'
print( bytes('ò', 'utf-8') ) # prints: b'\xc3\xb2'

In my case I had to use iso_8859_1 when encoding bytes in order to solve the issue.

Hope this helps someone.


要求用户提供输入,直到他们给出有效的答复

问题:要求用户提供输入,直到他们给出有效的答复

我正在编写一个接受用户输入的程序。

#note: Python 2.7 users should use `raw_input`, the equivalent of 3.X's `input`
age = int(input("Please enter your age: "))
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

只要用户输入有意义的数据,该程序就会按预期运行。

C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!

但是如果用户输入无效数据,它将失败:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Traceback (most recent call last):
  File "canyouvote.py", line 1, in <module>
    age = int(input("Please enter your age: "))
ValueError: invalid literal for int() with base 10: 'dickety six'

除了崩溃,我希望程序再次请求输入。像这样:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Sorry, I didn't understand that.
Please enter your age: 26
You are able to vote in the United States!

输入非意义的数据时,如何使程序要求有效的输入而不是崩溃?

在这种情况下-1,我如何才能拒绝类似的值,这是有效的int,但却毫无意义?

I am writing a program that accepts an input from the user.

#note: Python 2.7 users should use `raw_input`, the equivalent of 3.X's `input`
age = int(input("Please enter your age: "))
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

The program works as expected as long as the the user enters meaningful data.

C:\Python\Projects> canyouvote.py
Please enter your age: 23
You are able to vote in the United States!

But it fails if the user enters invalid data:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Traceback (most recent call last):
  File "canyouvote.py", line 1, in <module>
    age = int(input("Please enter your age: "))
ValueError: invalid literal for int() with base 10: 'dickety six'

Instead of crashing, I would like the program to ask for the input again. Like this:

C:\Python\Projects> canyouvote.py
Please enter your age: dickety six
Sorry, I didn't understand that.
Please enter your age: 26
You are able to vote in the United States!

How can I make the program ask for valid inputs instead of crashing when non-sensical data is entered?

How can I reject values like -1, which is a valid int, but nonsensical in this context?


回答 0

完成此操作的最简单方法是将input方法置于while循环中。continue当输入错误时使用,break当您感到满意时使用。

当您的输入可能引发异常时

使用tryexcept检测用户何时输入无法解析的数据。

while True:
    try:
        # Note: Python 2.x users should use raw_input, the equivalent of 3.x's input
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        #better try again... Return to the start of the loop
        continue
    else:
        #age was successfully parsed!
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

实施您自己的验证规则

如果要拒绝Python可以成功解析的值,则可以添加自己的验证逻辑。

while True:
    data = input("Please enter a loud message (must be all caps): ")
    if not data.isupper():
        print("Sorry, your response was not loud enough.")
        continue
    else:
        #we're happy with the value given.
        #we're ready to exit the loop.
        break

while True:
    data = input("Pick an answer from A to D:")
    if data.lower() not in ('a', 'b', 'c', 'd'):
        print("Not an appropriate choice.")
    else:
        break

结合异常处理和自定义验证

以上两种技术都可以组合成一个循环。

while True:
    try:
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        continue

    if age < 0:
        print("Sorry, your response must not be negative.")
        continue
    else:
        #age was successfully parsed, and we're happy with its value.
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

将其全部封装在一个函数中

如果您需要询问用户许多不同的值,则将此代码放入函数中可能会很有用,因此不必每次都重新键入。

def get_non_negative_int(prompt):
    while True:
        try:
            value = int(input(prompt))
        except ValueError:
            print("Sorry, I didn't understand that.")
            continue

        if value < 0:
            print("Sorry, your response must not be negative.")
            continue
        else:
            break
    return value

age = get_non_negative_int("Please enter your age: ")
kids = get_non_negative_int("Please enter the number of children you have: ")
salary = get_non_negative_int("Please enter your yearly earnings, in dollars: ")

放在一起

您可以扩展此思想,以创建非常通用的输入函数:

def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
    if min_ is not None and max_ is not None and max_ < min_:
        raise ValueError("min_ must be less than or equal to max_.")
    while True:
        ui = input(prompt)
        if type_ is not None:
            try:
                ui = type_(ui)
            except ValueError:
                print("Input type must be {0}.".format(type_.__name__))
                continue
        if max_ is not None and ui > max_:
            print("Input must be less than or equal to {0}.".format(max_))
        elif min_ is not None and ui < min_:
            print("Input must be greater than or equal to {0}.".format(min_))
        elif range_ is not None and ui not in range_:
            if isinstance(range_, range):
                template = "Input must be between {0.start} and {0.stop}."
                print(template.format(range_))
            else:
                template = "Input must be {0}."
                if len(range_) == 1:
                    print(template.format(*range_))
                else:
                    expected = " or ".join((
                        ", ".join(str(x) for x in range_[:-1]),
                        str(range_[-1])
                    ))
                    print(template.format(expected))
        else:
            return ui

用法如下:

age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))

常见的陷阱以及为什么要避免它们

冗余input语句的冗余使用

此方法有效,但通常被认为是较差的样式:

data = input("Please enter a loud message (must be all caps): ")
while not data.isupper():
    print("Sorry, your response was not loud enough.")
    data = input("Please enter a loud message (must be all caps): ")

由于它比while True方法短,一开始可能看起来很吸引人,但是它违反了软件开发的“ 不要重复自己”的原理。这增加了系统中错误的可能性。如果要更改inputraw_input,将其反向移植到2.7 input,怎么办?这SyntaxError只是一个等待发生的事情。

递归会毁了你的栈

如果您刚刚了解了递归,则可能会想使用它,get_non_negative_int以便可以处理while循环。

def get_non_negative_int(prompt):
    try:
        value = int(input(prompt))
    except ValueError:
        print("Sorry, I didn't understand that.")
        return get_non_negative_int(prompt)

    if value < 0:
        print("Sorry, your response must not be negative.")
        return get_non_negative_int(prompt)
    else:
        return value

在大多数情况下,这似乎可以正常工作,但是如果用户输入无效数据的次数足够多,脚本将以终止RuntimeError: maximum recursion depth exceeded。您可能会认为“没有傻瓜会连续犯1000个错误”,但是您却低估了傻瓜的创造力!

The simplest way to accomplish this is to put the input method in a while loop. Use continue when you get bad input, and break out of the loop when you’re satisfied.

When Your Input Might Raise an Exception

Use try and except to detect when the user enters data that can’t be parsed.

while True:
    try:
        # Note: Python 2.x users should use raw_input, the equivalent of 3.x's input
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        #better try again... Return to the start of the loop
        continue
    else:
        #age was successfully parsed!
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Implementing Your Own Validation Rules

If you want to reject values that Python can successfully parse, you can add your own validation logic.

while True:
    data = input("Please enter a loud message (must be all caps): ")
    if not data.isupper():
        print("Sorry, your response was not loud enough.")
        continue
    else:
        #we're happy with the value given.
        #we're ready to exit the loop.
        break

while True:
    data = input("Pick an answer from A to D:")
    if data.lower() not in ('a', 'b', 'c', 'd'):
        print("Not an appropriate choice.")
    else:
        break

Combining Exception Handling and Custom Validation

Both of the above techniques can be combined into one loop.

while True:
    try:
        age = int(input("Please enter your age: "))
    except ValueError:
        print("Sorry, I didn't understand that.")
        continue

    if age < 0:
        print("Sorry, your response must not be negative.")
        continue
    else:
        #age was successfully parsed, and we're happy with its value.
        #we're ready to exit the loop.
        break
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Encapsulating it All in a Function

If you need to ask your user for a lot of different values, it might be useful to put this code in a function, so you don’t have to retype it every time.

def get_non_negative_int(prompt):
    while True:
        try:
            value = int(input(prompt))
        except ValueError:
            print("Sorry, I didn't understand that.")
            continue

        if value < 0:
            print("Sorry, your response must not be negative.")
            continue
        else:
            break
    return value

age = get_non_negative_int("Please enter your age: ")
kids = get_non_negative_int("Please enter the number of children you have: ")
salary = get_non_negative_int("Please enter your yearly earnings, in dollars: ")

Putting It All Together

You can extend this idea to make a very generic input function:

def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
    if min_ is not None and max_ is not None and max_ < min_:
        raise ValueError("min_ must be less than or equal to max_.")
    while True:
        ui = input(prompt)
        if type_ is not None:
            try:
                ui = type_(ui)
            except ValueError:
                print("Input type must be {0}.".format(type_.__name__))
                continue
        if max_ is not None and ui > max_:
            print("Input must be less than or equal to {0}.".format(max_))
        elif min_ is not None and ui < min_:
            print("Input must be greater than or equal to {0}.".format(min_))
        elif range_ is not None and ui not in range_:
            if isinstance(range_, range):
                template = "Input must be between {0.start} and {0.stop}."
                print(template.format(range_))
            else:
                template = "Input must be {0}."
                if len(range_) == 1:
                    print(template.format(*range_))
                else:
                    expected = " or ".join((
                        ", ".join(str(x) for x in range_[:-1]),
                        str(range_[-1])
                    ))
                    print(template.format(expected))
        else:
            return ui

With usage such as:

age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))

Common Pitfalls, and Why you Should Avoid Them

The Redundant Use of Redundant input Statements

This method works but is generally considered poor style:

data = input("Please enter a loud message (must be all caps): ")
while not data.isupper():
    print("Sorry, your response was not loud enough.")
    data = input("Please enter a loud message (must be all caps): ")

It might look attractive initially because it’s shorter than the while True method, but it violates the Don’t Repeat Yourself principle of software development. This increases the likelihood of bugs in your system. What if you want to backport to 2.7 by changing input to raw_input, but accidentally change only the first input above? It’s a SyntaxError just waiting to happen.

Recursion Will Blow Your Stack

If you’ve just learned about recursion, you might be tempted to use it in get_non_negative_int so you can dispose of the while loop.

def get_non_negative_int(prompt):
    try:
        value = int(input(prompt))
    except ValueError:
        print("Sorry, I didn't understand that.")
        return get_non_negative_int(prompt)

    if value < 0:
        print("Sorry, your response must not be negative.")
        return get_non_negative_int(prompt)
    else:
        return value

This appears to work fine most of the time, but if the user enters invalid data enough times, the script will terminate with a RuntimeError: maximum recursion depth exceeded. You may think “no fool would make 1000 mistakes in a row”, but you’re underestimating the ingenuity of fools!


回答 1

您为什么要先执行a while True然后再退出此循环,而您也可以只将需求放在while语句中,因为您想要的只是在达到年龄后就停止?

age = None
while age is None:
    input_value = input("Please enter your age: ")
    try:
        # try and convert the string input to a number
        age = int(input_value)
    except ValueError:
        # tell the user off
        print("{input} is not a number, please enter a number only".format(input=input_value))
if age >= 18:
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

这将导致以下结果:

Please enter your age: *potato*
potato is not a number, please enter a number only
Please enter your age: *5*
You are not able to vote in the United States.

这是可行的,因为年龄永远不会有没有意义的值,并且代码遵循“业务流程”的逻辑

Why would you do a while True and then break out of this loop while you can also just put your requirements in the while statement since all you want is to stop once you have the age?

age = None
while age is None:
    input_value = input("Please enter your age: ")
    try:
        # try and convert the string input to a number
        age = int(input_value)
    except ValueError:
        # tell the user off
        print("{input} is not a number, please enter a number only".format(input=input_value))
if age >= 18:
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

This would result in the following:

Please enter your age: *potato*
potato is not a number, please enter a number only
Please enter your age: *5*
You are not able to vote in the United States.

this will work since age will never have a value that will not make sense and the code follows the logic of your “business process”


回答 2

尽管公认的答案是惊人的。我也想分享一个快速解决此问题的方法。(这也解决了负面的年龄问题。)

f=lambda age: (age.isdigit() and ((int(age)>=18  and "Can vote" ) or "Cannot vote")) or \
f(input("invalid input. Try again\nPlease enter your age: "))
print(f(input("Please enter your age: ")))

PS此代码适用于python3.x。

Though the accepted answer is amazing. I would also like to share a quick hack for this problem. (This takes care of the negative age problem as well.)

f=lambda age: (age.isdigit() and ((int(age)>=18  and "Can vote" ) or "Cannot vote")) or \
f(input("invalid input. Try again\nPlease enter your age: "))
print(f(input("Please enter your age: ")))

P.S. This code is for python 3.x.


回答 3

因此,我最近在搞些类似的事情,于是我想到了以下解决方案,该解决方案使用了一种获取垃圾输入的方式,甚至可以以任何逻辑方式对其进行检查。

read_single_keypress()https://stackoverflow.com/a/6599441/4532996提供

def read_single_keypress() -> str:
    """Waits for a single keypress on stdin.
    -- from :: https://stackoverflow.com/a/6599441/4532996
    """

    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    try:
        ret = sys.stdin.read(1) # returns a single character
    except KeyboardInterrupt:
        ret = 0
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return ret

def until_not_multi(chars) -> str:
    """read stdin until !(chars)"""
    import sys
    chars = list(chars)
    y = ""
    sys.stdout.flush()
    while True:
        i = read_single_keypress()
        _ = sys.stdout.write(i)
        sys.stdout.flush()
        if i not in chars:
            break
        y += i
    return y

def _can_you_vote() -> str:
    """a practical example:
    test if a user can vote based purely on keypresses"""
    print("can you vote? age : ", end="")
    x = int("0" + until_not_multi("0123456789"))
    if not x:
        print("\nsorry, age can only consist of digits.")
        return
    print("your age is", x, "\nYou can vote!" if x >= 18 else "Sorry! you can't vote")

_can_you_vote()

您可以在此处找到完整的模块。

例:

$ ./input_constrain.py
can you vote? age : a
sorry, age can only consist of digits.
$ ./input_constrain.py 
can you vote? age : 23<RETURN>
your age is 23
You can vote!
$ _

请注意,此实现的性质是,一旦读取了不是数字的内容,它将立即关闭stdin。我没有按回车键a,但是我需要按数字。

您可以将此thismany()功能与同一模块中的功能合并,以仅允许输入三位数。

So, I was messing around with something similar to this recently, and I came up with the following solution, which uses a way of getting input that rejects junk, before it’s even checked in any logical way.

read_single_keypress() courtesy https://stackoverflow.com/a/6599441/4532996

def read_single_keypress() -> str:
    """Waits for a single keypress on stdin.
    -- from :: https://stackoverflow.com/a/6599441/4532996
    """

    import termios, fcntl, sys, os
    fd = sys.stdin.fileno()
    # save old state
    flags_save = fcntl.fcntl(fd, fcntl.F_GETFL)
    attrs_save = termios.tcgetattr(fd)
    # make raw - the way to do this comes from the termios(3) man page.
    attrs = list(attrs_save) # copy the stored version to update
    # iflag
    attrs[0] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK
                  | termios.ISTRIP | termios.INLCR | termios. IGNCR
                  | termios.ICRNL | termios.IXON )
    # oflag
    attrs[1] &= ~termios.OPOST
    # cflag
    attrs[2] &= ~(termios.CSIZE | termios. PARENB)
    attrs[2] |= termios.CS8
    # lflag
    attrs[3] &= ~(termios.ECHONL | termios.ECHO | termios.ICANON
                  | termios.ISIG | termios.IEXTEN)
    termios.tcsetattr(fd, termios.TCSANOW, attrs)
    # turn off non-blocking
    fcntl.fcntl(fd, fcntl.F_SETFL, flags_save & ~os.O_NONBLOCK)
    # read a single keystroke
    try:
        ret = sys.stdin.read(1) # returns a single character
    except KeyboardInterrupt:
        ret = 0
    finally:
        # restore old state
        termios.tcsetattr(fd, termios.TCSAFLUSH, attrs_save)
        fcntl.fcntl(fd, fcntl.F_SETFL, flags_save)
    return ret

def until_not_multi(chars) -> str:
    """read stdin until !(chars)"""
    import sys
    chars = list(chars)
    y = ""
    sys.stdout.flush()
    while True:
        i = read_single_keypress()
        _ = sys.stdout.write(i)
        sys.stdout.flush()
        if i not in chars:
            break
        y += i
    return y

def _can_you_vote() -> str:
    """a practical example:
    test if a user can vote based purely on keypresses"""
    print("can you vote? age : ", end="")
    x = int("0" + until_not_multi("0123456789"))
    if not x:
        print("\nsorry, age can only consist of digits.")
        return
    print("your age is", x, "\nYou can vote!" if x >= 18 else "Sorry! you can't vote")

_can_you_vote()

You can find the complete module here.

Example:

$ ./input_constrain.py
can you vote? age : a
sorry, age can only consist of digits.
$ ./input_constrain.py 
can you vote? age : 23<RETURN>
your age is 23
You can vote!
$ _

Note that the nature of this implementation is it closes stdin as soon as something that isn’t a digit is read. I didn’t hit enter after a, but I needed to after the numbers.

You could merge this with the thismany() function in the same module to only allow, say, three digits.


回答 4

功能性方法或“ 看起来没有循环! ”:

from itertools import chain, repeat

prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Not a number! Try again:  b
Not a number! Try again:  1
1

或者,如果您想将“错误输入”消息与输入提示分开,如其他答案所示:

prompt_msg = "Enter a number: "
bad_input_msg = "Sorry, I didn't understand that."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Sorry, I didn't understand that.
Enter a number:  b
Sorry, I didn't understand that.
Enter a number:  1
1

它是如何工作的?

  1. prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
    的组合itertools.chainitertools.repeat将创建一个迭代器,这将产生串"Enter a number: "一次,"Not a number! Try again: "中无数次:
    for prompt in prompts:
        print(prompt)
    Enter a number: 
    Not a number! Try again: 
    Not a number! Try again: 
    Not a number! Try again: 
    # ... and so on
  2. replies = map(input, prompts)-这里map会将prompts上一步中的所有字符串应用于input函数。例如:
    for reply in replies:
        print(reply)
    Enter a number:  a
    a
    Not a number! Try again:  1
    1
    Not a number! Try again:  it doesn't care now
    it doesn't care now
    # and so on...
  3. 我们使用filterstr.isdigit过滤掉那些只包含数字的字符串:
    only_digits = filter(str.isdigit, replies)
    for reply in only_digits:
        print(reply)
    Enter a number:  a
    Not a number! Try again:  1
    1
    Not a number! Try again:  2
    2
    Not a number! Try again:  b
    Not a number! Try again: # and so on...
    并且仅使用第一个数字字符串next

其他验证规则:

  1. 字符串方法:当然,您可以使用其他字符串方法,例如str.isalpha仅获取字母字符串或str.isupper仅获取大写字母。请参阅文档以获取完整列表。

  2. 成员资格测试:
    有几种不同的执行方式。其中之一是通过使用__contains__方法:

    from itertools import chain, repeat
    
    fruits = {'apple', 'orange', 'peach'}
    prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
    replies = map(input, prompts)
    valid_response = next(filter(fruits.__contains__, replies))
    print(valid_response)
    Enter a fruit:  1
    I don't know this one! Try again:  foo
    I don't know this one! Try again:  apple
    apple
  3. 数字比较:
    这里有一些有用的比较方法。例如,对于__lt__<):

    from itertools import chain, repeat
    
    prompts = chain(["Enter a positive number:"], repeat("I need a positive number! Try again:"))
    replies = map(input, prompts)
    numeric_strings = filter(str.isnumeric, replies)
    numbers = map(float, numeric_strings)
    is_positive = (0.).__lt__
    valid_response = next(filter(is_positive, numbers))
    print(valid_response)
    Enter a positive number: a
    I need a positive number! Try again: -5
    I need a positive number! Try again: 0
    I need a positive number! Try again: 5
    5.0

    或者,如果您不喜欢使用dunder方法(dunder =双下划线),则始终可以定义自己的函数,也可以使用 operator模块中。

  4. 路径存在:
    这里可以使用pathlib库及其Path.exists方法:

    from itertools import chain, repeat
    from pathlib import Path
    
    prompts = chain(["Enter a path: "], repeat("This path doesn't exist! Try again: "))
    replies = map(input, prompts)
    paths = map(Path, replies)
    valid_response = next(filter(Path.exists, paths))
    print(valid_response)
    Enter a path:  a b c
    This path doesn't exist! Try again:  1
    This path doesn't exist! Try again:  existing_file.txt
    existing_file.txt

限制尝试次数:

如果您不想无限次地问某人来折磨他,可以在呼叫中指定一个限制itertools.repeat。这可以与为next函数提供默认值结合使用:

from itertools import chain, repeat

prompts = chain(["Enter a number:"], repeat("Not a number! Try again:", 2))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies), None)
print("You've failed miserably!" if valid_response is None else 'Well done!')
Enter a number: a
Not a number! Try again: b
Not a number! Try again: c
You've failed miserably!

预处理输入数据:

有时,如果用户不小心以大写形式提供了输入,或者在字符串的开头或结尾有空格,我们就不想拒绝输入。为了考虑这些简单的错误,我们可以通过应用str.lowerstr.strip方法对输入数据进行预处理。例如,对于成员资格测试,代码如下所示:

from itertools import chain, repeat

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
lowercased_replies = map(str.lower, replies)
stripped_replies = map(str.strip, lowercased_replies)
valid_response = next(filter(fruits.__contains__, stripped_replies))
print(valid_response)
Enter a fruit:  duck
I don't know this one! Try again:     Orange
orange

如果要使用许多函数进行预处理,则使用执行函数合成的函数可能会更容易。例如,使用此处的一个:

from itertools import chain, repeat

from lz.functional import compose

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
process = compose(str.strip, str.lower)  # you can add more functions here
processed_replies = map(process, replies)
valid_response = next(filter(fruits.__contains__, processed_replies))
print(valid_response)
Enter a fruit:  potato
I don't know this one! Try again:   PEACH
peach

合并验证规则:

例如,在一个简单的情况下,当程序要求输入1到120岁之间的年龄时,可以添加另一个filter

from itertools import chain, repeat

prompt_msg = "Enter your age (1-120): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
numeric_replies = filter(str.isdigit, replies)
ages = map(int, numeric_replies)
positive_ages = filter((0).__lt__, ages)
not_too_big_ages = filter((120).__ge__, positive_ages)
valid_response = next(not_too_big_ages)
print(valid_response)

但是,在规则很多的情况下,最好实现执行逻辑合取的函数。在下面的例子中我将使用一个现成的一个位置

from functools import partial
from itertools import chain, repeat

from lz.logical import conjoin


def is_one_letter(string: str) -> bool:
    return len(string) == 1


rules = [str.isalpha, str.isupper, is_one_letter, 'C'.__le__, 'P'.__ge__]

prompt_msg = "Enter a letter (C-P): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(conjoin(*rules), replies))
print(valid_response)
Enter a letter (C-P):  5
Wrong input.
Enter a letter (C-P):  f
Wrong input.
Enter a letter (C-P):  CDE
Wrong input.
Enter a letter (C-P):  Q
Wrong input.
Enter a letter (C-P):  N
N

不幸的是,如果有人需要为每个失败的情况下,自定义消息,然后,我很害怕,也没有漂亮的功能性的方式。或者,至少,我找不到一个。

Functional approach or “look mum no loops!“:

from itertools import chain, repeat

prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Not a number! Try again:  b
Not a number! Try again:  1
1

or if you want to have a “bad input” message separated from an input prompt as in other answers:

prompt_msg = "Enter a number: "
bad_input_msg = "Sorry, I didn't understand that."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies))
print(valid_response)
Enter a number:  a
Sorry, I didn't understand that.
Enter a number:  b
Sorry, I didn't understand that.
Enter a number:  1
1

How does it work?

  1. prompts = chain(["Enter a number: "], repeat("Not a number! Try again: "))
    
    This combination of itertools.chain and itertools.repeat will create an iterator which will yield strings "Enter a number: " once, and "Not a number! Try again: " an infinite number of times:
    for prompt in prompts:
        print(prompt)
    
    Enter a number: 
    Not a number! Try again: 
    Not a number! Try again: 
    Not a number! Try again: 
    # ... and so on
    
  2. replies = map(input, prompts) – here map will apply all the prompts strings from the previous step to the input function. E.g.:
    for reply in replies:
        print(reply)
    
    Enter a number:  a
    a
    Not a number! Try again:  1
    1
    Not a number! Try again:  it doesn't care now
    it doesn't care now
    # and so on...
    
  3. We use filter and str.isdigit to filter out those strings that contain only digits:
    only_digits = filter(str.isdigit, replies)
    for reply in only_digits:
        print(reply)
    
    Enter a number:  a
    Not a number! Try again:  1
    1
    Not a number! Try again:  2
    2
    Not a number! Try again:  b
    Not a number! Try again: # and so on...
    
    And to get only the first digits-only string we use next.

Other validation rules:

  1. String methods: Of course you can use other string methods like str.isalpha to get only alphabetic strings, or str.isupper to get only uppercase. See docs for the full list.

  2. Membership testing:
    There are several different ways to perform it. One of them is by using __contains__ method:

    from itertools import chain, repeat
    
    fruits = {'apple', 'orange', 'peach'}
    prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
    replies = map(input, prompts)
    valid_response = next(filter(fruits.__contains__, replies))
    print(valid_response)
    
    Enter a fruit:  1
    I don't know this one! Try again:  foo
    I don't know this one! Try again:  apple
    apple
    
  3. Numbers comparison:
    There are useful comparison methods which we can use here. For example, for __lt__ (<):

    from itertools import chain, repeat
    
    prompts = chain(["Enter a positive number:"], repeat("I need a positive number! Try again:"))
    replies = map(input, prompts)
    numeric_strings = filter(str.isnumeric, replies)
    numbers = map(float, numeric_strings)
    is_positive = (0.).__lt__
    valid_response = next(filter(is_positive, numbers))
    print(valid_response)
    
    Enter a positive number: a
    I need a positive number! Try again: -5
    I need a positive number! Try again: 0
    I need a positive number! Try again: 5
    5.0
    

    Or, if you don’t like using dunder methods (dunder = double-underscore), you can always define your own function, or use the ones from the operator module.

  4. Path existance:
    Here one can use pathlib library and its Path.exists method:

    from itertools import chain, repeat
    from pathlib import Path
    
    prompts = chain(["Enter a path: "], repeat("This path doesn't exist! Try again: "))
    replies = map(input, prompts)
    paths = map(Path, replies)
    valid_response = next(filter(Path.exists, paths))
    print(valid_response)
    
    Enter a path:  a b c
    This path doesn't exist! Try again:  1
    This path doesn't exist! Try again:  existing_file.txt
    existing_file.txt
    

Limiting number of tries:

If you don’t want to torture a user by asking him something an infinite number of times, you can specify a limit in a call of itertools.repeat. This can be combined with providing a default value to the next function:

from itertools import chain, repeat

prompts = chain(["Enter a number:"], repeat("Not a number! Try again:", 2))
replies = map(input, prompts)
valid_response = next(filter(str.isdigit, replies), None)
print("You've failed miserably!" if valid_response is None else 'Well done!')
Enter a number: a
Not a number! Try again: b
Not a number! Try again: c
You've failed miserably!

Preprocessing input data:

Sometimes we don’t want to reject an input if the user accidentally supplied it IN CAPS or with a space in the beginning or an end of the string. To take these simple mistakes into account we can preprocess the input data by applying str.lower and str.strip methods. For example, for the case of membership testing the code will look like this:

from itertools import chain, repeat

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
lowercased_replies = map(str.lower, replies)
stripped_replies = map(str.strip, lowercased_replies)
valid_response = next(filter(fruits.__contains__, stripped_replies))
print(valid_response)
Enter a fruit:  duck
I don't know this one! Try again:     Orange
orange

In the case when you have many functions to use for preprocessing, it might be easier to use a function performing a function composition. For example, using the one from here:

from itertools import chain, repeat

from lz.functional import compose

fruits = {'apple', 'orange', 'peach'}
prompts = chain(["Enter a fruit: "], repeat("I don't know this one! Try again: "))
replies = map(input, prompts)
process = compose(str.strip, str.lower)  # you can add more functions here
processed_replies = map(process, replies)
valid_response = next(filter(fruits.__contains__, processed_replies))
print(valid_response)
Enter a fruit:  potato
I don't know this one! Try again:   PEACH
peach

Combining validation rules:

For a simple case, for example, when the program asks for age between 1 and 120, one can just add another filter:

from itertools import chain, repeat

prompt_msg = "Enter your age (1-120): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
numeric_replies = filter(str.isdigit, replies)
ages = map(int, numeric_replies)
positive_ages = filter((0).__lt__, ages)
not_too_big_ages = filter((120).__ge__, positive_ages)
valid_response = next(not_too_big_ages)
print(valid_response)

But in the case when there are many rules, it’s better to implement a function performing a logical conjunction. In the following example I will use a ready one from here:

from functools import partial
from itertools import chain, repeat

from lz.logical import conjoin


def is_one_letter(string: str) -> bool:
    return len(string) == 1


rules = [str.isalpha, str.isupper, is_one_letter, 'C'.__le__, 'P'.__ge__]

prompt_msg = "Enter a letter (C-P): "
bad_input_msg = "Wrong input."
prompts = chain([prompt_msg], repeat('\n'.join([bad_input_msg, prompt_msg])))
replies = map(input, prompts)
valid_response = next(filter(conjoin(*rules), replies))
print(valid_response)
Enter a letter (C-P):  5
Wrong input.
Enter a letter (C-P):  f
Wrong input.
Enter a letter (C-P):  CDE
Wrong input.
Enter a letter (C-P):  Q
Wrong input.
Enter a letter (C-P):  N
N

Unfortunately, if someone needs a custom message for each failed case, then, I’m afraid, there is no pretty functional way. Or, at least, I couldn’t find one.


回答 5

使用点击

请点击是一个用于命令行界面的库,它提供了向用户询问有效响应的功能。

简单的例子:

import click

number = click.prompt('Please enter a number', type=float)
print(number)
Please enter a number: 
 a
Error: a is not a valid floating point value
Please enter a number: 
 10
10.0

注意如何将字符串值自动转换为浮点数。

检查值是否在范围内:

提供了不同的自定义类型。要获得特定范围内的数字,我们可以使用IntRange

age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
What's your age?: 
 a
Error: a is not a valid integer
What's your age?: 
 0
Error: 0 is not in the valid range of 1 to 120.
What's your age?: 
 5
5

我们还可以只指定其中一个限制,minmax

age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
What's your age?: 
 0
Error: 0 is smaller than the minimum valid value 14.
What's your age?: 
 18
18

会员资格测试:

使用click.Choice类型。默认情况下,此检查区分大小写。

choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
Provide a fruit (apple, peach, orange): 
 banana
Error: invalid choice: banana. (choose from apple, peach, orange)
Provide a fruit (apple, peach, orange): 
 OrAnGe
orange

使用路径和文件:

使用click.Path类型,我们可以检查现有路径并解决它们:

path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
Provide path: 
 nonexistent
Error: Path "nonexistent" does not exist.
Provide path: 
 existing_folder
'/path/to/existing_folder

读写文件可以通过以下方式完成click.File

file = click.prompt('In which file to write data?', type=click.File('w'))
with file.open():
    file.write('Hello!')
# More info about `lazy=True` at:
# https://click.palletsprojects.com/en/7.x/arguments/#file-opening-safety
file = click.prompt('Which file you wanna read?', type=click.File(lazy=True))
with file.open():
    print(file.read())
In which file to write data?: 
         # <-- provided an empty string, which is an illegal name for a file
In which file to write data?: 
 some_file.txt
Which file you wanna read?: 
 nonexistent.txt
Error: Could not open file: nonexistent.txt: No such file or directory
Which file you wanna read?: 
 some_file.txt
Hello!

其他例子:

确认密码:

password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
print(password)
Enter password: 
 ······
Repeat for confirmation: 
 ·
Error: the two entered values do not match
Enter password: 
 ······
Repeat for confirmation: 
 ······
qwerty

默认值:

在这种情况下,只需按Enter(或您使用的任何键)而不输入值,即可得到默认值:

number = click.prompt('Please enter a number', type=int, default=42)
print(number)
Please enter a number [42]: 
 a
Error: a is not a valid integer
Please enter a number [42]: 

42

Using Click:

Click is a library for command-line interfaces and it provides functionality for asking a valid response from a user.

Simple example:

import click

number = click.prompt('Please enter a number', type=float)
print(number)
Please enter a number: 
 a
Error: a is not a valid floating point value
Please enter a number: 
 10
10.0

Note how it converted the string value to a float automatically.

Checking if a value is within a range:

There are different custom types provided. To get a number in a specific range we can use IntRange:

age = click.prompt("What's your age?", type=click.IntRange(1, 120))
print(age)
What's your age?: 
 a
Error: a is not a valid integer
What's your age?: 
 0
Error: 0 is not in the valid range of 1 to 120.
What's your age?: 
 5
5

We can also specify just one of the limits, min or max:

age = click.prompt("What's your age?", type=click.IntRange(min=14))
print(age)
What's your age?: 
 0
Error: 0 is smaller than the minimum valid value 14.
What's your age?: 
 18
18

Membership testing:

Using click.Choice type. By default this check is case-sensitive.

choices = {'apple', 'orange', 'peach'}
choice = click.prompt('Provide a fruit', type=click.Choice(choices, case_sensitive=False))
print(choice)
Provide a fruit (apple, peach, orange): 
 banana
Error: invalid choice: banana. (choose from apple, peach, orange)
Provide a fruit (apple, peach, orange): 
 OrAnGe
orange

Working with paths and files:

Using a click.Path type we can check for existing paths and also resolve them:

path = click.prompt('Provide path', type=click.Path(exists=True, resolve_path=True))
print(path)
Provide path: 
 nonexistent
Error: Path "nonexistent" does not exist.
Provide path: 
 existing_folder
'/path/to/existing_folder

Reading and writing files can be done by click.File:

file = click.prompt('In which file to write data?', type=click.File('w'))
with file.open():
    file.write('Hello!')
# More info about `lazy=True` at:
# https://click.palletsprojects.com/en/7.x/arguments/#file-opening-safety
file = click.prompt('Which file you wanna read?', type=click.File(lazy=True))
with file.open():
    print(file.read())
In which file to write data?: 
         # <-- provided an empty string, which is an illegal name for a file
In which file to write data?: 
 some_file.txt
Which file you wanna read?: 
 nonexistent.txt
Error: Could not open file: nonexistent.txt: No such file or directory
Which file you wanna read?: 
 some_file.txt
Hello!

Other examples:

Password confirmation:

password = click.prompt('Enter password', hide_input=True, confirmation_prompt=True)
print(password)
Enter password: 
 ······
Repeat for confirmation: 
 ·
Error: the two entered values do not match
Enter password: 
 ······
Repeat for confirmation: 
 ······
qwerty

Default values:

In this case, simply pressing Enter (or whatever key you use) without entering a value, will give you a default one:

number = click.prompt('Please enter a number', type=int, default=42)
print(number)
Please enter a number [42]: 
 a
Error: a is not a valid integer
Please enter a number [42]: 

42

回答 6

def validate_age(age):
    if age >=0 :
        return True
    return False

while True:
    try:
        age = int(raw_input("Please enter your age:"))
        if validate_age(age): break
    except ValueError:
        print "Error: Invalid age."
def validate_age(age):
    if age >=0 :
        return True
    return False

while True:
    try:
        age = int(raw_input("Please enter your age:"))
        if validate_age(age): break
    except ValueError:
        print "Error: Invalid age."

回答 7

在Daniel Q和Patrick Artner的出色建议的基础上,这是一个更为通用的解决方案。

# Assuming Python3
import sys

class ValidationError(ValueError):  # thanks Patrick Artner
    pass

def validate_input(prompt, cast=str, cond=(lambda x: True), onerror=None):
    if onerror==None: onerror = {}
    while True:
        try:
            data = cast(input(prompt))
            if not cond(data): raise ValidationError
            return data
        except tuple(onerror.keys()) as e:  # thanks Daniel Q
            print(onerror[type(e)], file=sys.stderr)

我选择了显式ifraise语句而不是assert,因为断言检查可能已关闭,而验证应始终处于打开状态以提供鲁棒性。

这可用于获取具有不同验证条件的不同种类的输入。例如:

# No validation, equivalent to simple input:
anystr = validate_input("Enter any string: ")

# Get a string containing only letters:
letters = validate_input("Enter letters: ",
    cond=str.isalpha,
    onerror={ValidationError: "Only letters, please!"})

# Get a float in [0, 100]:
percentage = validate_input("Percentage? ",
    cast=float, cond=lambda x: 0.0<=x<=100.0,
    onerror={ValidationError: "Must be between 0 and 100!",
             ValueError: "Not a number!"})

或者,回答原始问题:

age = validate_input("Please enter your age: ",
        cast=int, cond=lambda a:0<=a<150,
        onerror={ValidationError: "Enter a plausible age, please!",
                 ValueError: "Enter an integer, please!"})
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Building upon Daniel Q’s and Patrick Artner’s excellent suggestions, here is an even more generalized solution.

# Assuming Python3
import sys

class ValidationError(ValueError):  # thanks Patrick Artner
    pass

def validate_input(prompt, cast=str, cond=(lambda x: True), onerror=None):
    if onerror==None: onerror = {}
    while True:
        try:
            data = cast(input(prompt))
            if not cond(data): raise ValidationError
            return data
        except tuple(onerror.keys()) as e:  # thanks Daniel Q
            print(onerror[type(e)], file=sys.stderr)

I opted for explicit if and raise statements instead of an assert, because assertion checking may be turned off, whereas validation should always be on to provide robustness.

This may be used to get different kinds of input, with different validation conditions. For example:

# No validation, equivalent to simple input:
anystr = validate_input("Enter any string: ")

# Get a string containing only letters:
letters = validate_input("Enter letters: ",
    cond=str.isalpha,
    onerror={ValidationError: "Only letters, please!"})

# Get a float in [0, 100]:
percentage = validate_input("Percentage? ",
    cast=float, cond=lambda x: 0.0<=x<=100.0,
    onerror={ValidationError: "Must be between 0 and 100!",
             ValueError: "Not a number!"})

Or, to answer the original question:

age = validate_input("Please enter your age: ",
        cast=int, cond=lambda a:0<=a<150,
        onerror={ValidationError: "Enter a plausible age, please!",
                 ValueError: "Enter an integer, please!"})
if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

回答 8

试试这个:

def takeInput(required):
  print 'ooo or OOO to exit'
  ans = raw_input('Enter: ')

  if not ans:
      print "You entered nothing...!"
      return takeInput(required) 

      ##  FOR Exit  ## 
  elif ans in ['ooo', 'OOO']:
    print "Closing instance."
    exit()

  else:
    if ans.isdigit():
      current = 'int'
    elif set('[~!@#$%^&*()_+{}":/\']+$').intersection(ans):
      current = 'other'
    elif isinstance(ans,basestring):
      current = 'str'        
    else:
      current = 'none'

  if required == current :
    return ans
  else:
    return takeInput(required)

## pass the value in which type you want [str/int/special character(as other )]
print "input: ", takeInput('str')

Try this one:-

def takeInput(required):
  print 'ooo or OOO to exit'
  ans = raw_input('Enter: ')

  if not ans:
      print "You entered nothing...!"
      return takeInput(required) 

      ##  FOR Exit  ## 
  elif ans in ['ooo', 'OOO']:
    print "Closing instance."
    exit()

  else:
    if ans.isdigit():
      current = 'int'
    elif set('[~!@#$%^&*()_+{}":/\']+$').intersection(ans):
      current = 'other'
    elif isinstance(ans,basestring):
      current = 'str'        
    else:
      current = 'none'

  if required == current :
    return ans
  else:
    return takeInput(required)

## pass the value in which type you want [str/int/special character(as other )]
print "input: ", takeInput('str')

回答 9

尽管try/ except块可以工作,但使用可以更快,更干净地完成此任务str.isdigit()

while True:
    age = input("Please enter your age: ")
    if age.isdigit():
        age = int(age)
        break
    else:
        print("Invalid number '{age}'. Try again.".format(age=age))

if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

While a try/except block will work, a much faster and cleaner way to accomplish this task would be to use str.isdigit().

while True:
    age = input("Please enter your age: ")
    if age.isdigit():
        age = int(age)
        break
    else:
        print("Invalid number '{age}'. Try again.".format(age=age))

if age >= 18: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

回答 10

好问题!您可以尝试以下代码。=)

此代码使用ast.literal_eval()找到输入的数据类型age)。然后遵循以下算法:

  1. 要求用户输入她/他的age

    1.1。如果agefloatint数据类型:

    • 检查是否age>=18。如果为age>=18,则输出适当的输出并退出。

    • 检查是否0<age<18。如果为0<age<18,则输出适当的输出并退出。

    • 如果为age<=0,则要求用户再次输入有效的年龄编号(返回步骤1)。

    1.2。如果age不是floatint数据类型,则要求用户再次输入他/他的年龄(返回步骤1)。

这是代码。

from ast import literal_eval

''' This function is used to identify the data type of input data.'''
def input_type(input_data):
    try:
        return type(literal_eval(input_data))
    except (ValueError, SyntaxError):
        return str

flag = True

while(flag):
    age = raw_input("Please enter your age: ")

    if input_type(age)==float or input_type(age)==int:
        if eval(age)>=18: 
            print("You are able to vote in the United States!") 
            flag = False 
        elif eval(age)>0 and eval(age)<18: 
            print("You are not able to vote in the United States.") 
            flag = False
        else: print("Please enter a valid number as your age.")

    else: print("Sorry, I didn't understand that.") 

Good question! You can try the following code for this. =)

This code uses ast.literal_eval() to find the data type of the input (age). Then it follows the following algorithm:

  1. Ask user to input her/his age.

    1.1. If age is float or int data type:

    • Check if age>=18. If age>=18, print appropriate output and exit.

    • Check if 0<age<18. If 0<age<18, print appropriate output and exit.

    • If age<=0, ask the user to input a valid number for age again, (i.e. go back to step 1.)

    1.2. If age is not float or int data type, then ask user to input her/his age again (i.e. go back to step 1.)

Here is the code.

from ast import literal_eval

''' This function is used to identify the data type of input data.'''
def input_type(input_data):
    try:
        return type(literal_eval(input_data))
    except (ValueError, SyntaxError):
        return str

flag = True

while(flag):
    age = raw_input("Please enter your age: ")

    if input_type(age)==float or input_type(age)==int:
        if eval(age)>=18: 
            print("You are able to vote in the United States!") 
            flag = False 
        elif eval(age)>0 and eval(age)<18: 
            print("You are not able to vote in the United States.") 
            flag = False
        else: print("Please enter a valid number as your age.")

    else: print("Sorry, I didn't understand that.") 

回答 11

您始终可以应用简单的if-else逻辑,并if在代码和for循环中添加一个或多个逻辑。

while True:
     age = int(input("Please enter your age: "))
     if (age >= 18)  : 
         print("You are able to vote in the United States!")
     if (age < 18) & (age > 0):
         print("You are not able to vote in the United States.")
     else:
         print("Wrong characters, the input must be numeric")
         continue

这将是一个无限的厕所,并且您将被要求无限期地输入年龄。

You can always apply simple if-else logic and add one more if logic to your code along with a for loop.

while True:
     age = int(input("Please enter your age: "))
     if (age >= 18)  : 
         print("You are able to vote in the United States!")
     if (age < 18) & (age > 0):
         print("You are not able to vote in the United States.")
     else:
         print("Wrong characters, the input must be numeric")
         continue

This will be an infinite loo and you would be asked to enter the age, indefinitely.


回答 12

您可以编写更通用的逻辑,以允许用户仅输入特定的次数,因为在许多实际应用程序中会出现相同的用例。

def getValidInt(iMaxAttemps = None):
  iCount = 0
  while True:
    # exit when maximum attempt limit has expired
    if iCount != None and iCount > iMaxAttemps:
       return 0     # return as default value

    i = raw_input("Enter no")
    try:
       i = int(i)
    except ValueError as e:
       print "Enter valid int value"
    else:
       break

    return i

age = getValidInt()
# do whatever you want to do.

You can write more general logic to allow user to enter only specific number of times, as the same use-case arises in many real-world applications.

def getValidInt(iMaxAttemps = None):
  iCount = 0
  while True:
    # exit when maximum attempt limit has expired
    if iCount != None and iCount > iMaxAttemps:
       return 0     # return as default value

    i = raw_input("Enter no")
    try:
       i = int(i)
    except ValueError as e:
       print "Enter valid int value"
    else:
       break

    return i

age = getValidInt()
# do whatever you want to do.

回答 13

您可以将输入语句设置为True循环,以便它反复询问用户输入,然后在用户输入您想要的响应时中断该循环。您可以使用try和except块来处理无效响应。

while True:

    var = True

    try:
        age = int(input("Please enter your age: "))

    except ValueError:
        print("Invalid input.")
        var = False

    if var == True:
        if age >= 18:
                print("You are able to vote in the United States.")
                break
        else:
            print("You are not able to vote in the United States.")

var变量只是这样,如果用户输入字符串而不是整数,程序将不会返回“您无法在美国投票”。

You can make the input statement a while True loop so it repeatedly asks for the users input and then break that loop if the user enters the response you would like. And you can use try and except blocks to handle invalid responses.

while True:

    var = True

    try:
        age = int(input("Please enter your age: "))

    except ValueError:
        print("Invalid input.")
        var = False

    if var == True:
        if age >= 18:
                print("You are able to vote in the United States.")
                break
        else:
            print("You are not able to vote in the United States.")

The var variable is just so that if the user enters a string instead of a integer the program wont return “You are not able to vote in the United States.”


回答 14

使用“ while”语句,直到用户输入一个真值,并且如果输入值不是数字或它是一个空值,请跳过该语句并尝试再次询问,依此类推。例如,我试图真正回答您的问题。如果我们认为年龄在1到150之间,则接受输入值,否则输入的值是错误的。对于终止程序,用户可以使用0键并将其作为值输入。

注意:阅读代码顶部的注释。

# If your input value is only a number then use "Value.isdigit() == False".
# If you need an input that is a text, you should remove "Value.isdigit() == False".
def Input(Message):
    Value = None
    while Value == None or Value.isdigit() == False:
        try:        
            Value = str(input(Message)).strip()
        except InputError:
            Value = None
    return Value

# Example:
age = 0
# If we suppose that our age is between 1 and 150 then input value accepted,
# else it's a wrong value.
while age <=0 or age >150:
    age = int(Input("Please enter your age: "))
    # For terminating program, the user can use 0 key and enter it as an a value.
    if age == 0:
        print("Terminating ...")
        exit(0)

if age >= 18 and age <=150: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

Use “while” statement till user enter a true value and if the input value is not a number or it’s a null value skip it and try to ask again and so on. In example I tried to answer truly your question. If we suppose that our age is between 1 and 150 then input value accepted, else it’s a wrong value. For terminating program, the user can use 0 key and enter it as a value.

Note: Read comments top of code.

# If your input value is only a number then use "Value.isdigit() == False".
# If you need an input that is a text, you should remove "Value.isdigit() == False".
def Input(Message):
    Value = None
    while Value == None or Value.isdigit() == False:
        try:        
            Value = str(input(Message)).strip()
        except InputError:
            Value = None
    return Value

# Example:
age = 0
# If we suppose that our age is between 1 and 150 then input value accepted,
# else it's a wrong value.
while age <=0 or age >150:
    age = int(Input("Please enter your age: "))
    # For terminating program, the user can use 0 key and enter it as an a value.
    if age == 0:
        print("Terminating ...")
        exit(0)

if age >= 18 and age <=150: 
    print("You are able to vote in the United States!")
else:
    print("You are not able to vote in the United States.")

回答 15

使用输入验证的另一种解决方案是ValidationError对整数输入使用定制的(可选)范围验证:

class ValidationError(ValueError): 
    """Special validation error - its message is supposed to be printed"""
    pass

def RangeValidator(text,num,r):
    """Generic validator - raises 'text' as ValidationError if 'num' not in range 'r'."""
    if num in r:
        return num
    raise ValidationError(text)

def ValidCol(c): 
    """Specialized column validator providing text and range."""
    return RangeValidator("Columns must be in the range of 0 to 3 (inclusive)", 
                          c, range(4))

def ValidRow(r): 
    """Specialized row validator providing text and range."""
    return RangeValidator("Rows must be in the range of 5 to 15(exclusive)",
                          r, range(5,15))

用法:

def GetInt(text, validator=None):
    """Aks user for integer input until a valid integer is given. If provided, 
    a 'validator' function takes the integer and either raises a 
    ValidationError to be printed or returns the valid number. 
    Non integers display a simple error message."""
    print()
    while True:
        n = input(text)
        try:
            n = int(n)

            return n if validator is None else validator(n)

        except ValueError as ve:
            # prints ValidationErrors directly - else generic message:
            if isinstance(ve, ValidationError):
                print(ve)
            else:
                print("Invalid input: ", n)


column = GetInt("Pleased enter column: ", ValidCol)
row = GetInt("Pleased enter row: ", ValidRow)
print( row, column)

输出:

Pleased enter column: 22
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: -2
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: 2
Pleased enter row: a
Invalid input:  a
Pleased enter row: 72
Rows must be in the range of 5 to 15(exclusive)
Pleased enter row: 9  

9, 2

One more solution for using input validation using a customized ValidationError and a (optional) range validation for integer inputs:

class ValidationError(ValueError): 
    """Special validation error - its message is supposed to be printed"""
    pass

def RangeValidator(text,num,r):
    """Generic validator - raises 'text' as ValidationError if 'num' not in range 'r'."""
    if num in r:
        return num
    raise ValidationError(text)

def ValidCol(c): 
    """Specialized column validator providing text and range."""
    return RangeValidator("Columns must be in the range of 0 to 3 (inclusive)", 
                          c, range(4))

def ValidRow(r): 
    """Specialized row validator providing text and range."""
    return RangeValidator("Rows must be in the range of 5 to 15(exclusive)",
                          r, range(5,15))

Usage:

def GetInt(text, validator=None):
    """Aks user for integer input until a valid integer is given. If provided, 
    a 'validator' function takes the integer and either raises a 
    ValidationError to be printed or returns the valid number. 
    Non integers display a simple error message."""
    print()
    while True:
        n = input(text)
        try:
            n = int(n)

            return n if validator is None else validator(n)

        except ValueError as ve:
            # prints ValidationErrors directly - else generic message:
            if isinstance(ve, ValidationError):
                print(ve)
            else:
                print("Invalid input: ", n)


column = GetInt("Pleased enter column: ", ValidCol)
row = GetInt("Pleased enter row: ", ValidRow)
print( row, column)

Output:

Pleased enter column: 22
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: -2
Columns must be in the range of 0 to 3 (inclusive)
Pleased enter column: 2
Pleased enter row: a
Invalid input:  a
Pleased enter row: 72
Rows must be in the range of 5 to 15(exclusive)
Pleased enter row: 9  

9, 2

回答 16

这是一个更干净,更通用的解决方案,避免了重复的if / else块:在字典中编写一个接受(错误,错误提示)对的函数,并使用断言进行所有值检查。

def validate_input(prompt, error_map):
    while True:
        try:
            data = int(input(prompt))
            # Insert your non-exception-throwing conditionals here
            assert data > 0
            return data
        # Print whatever text you want the user to see
        # depending on how they messed up
        except tuple(error_map.keys()) as e:
            print(error_map[type(e)])

用法:

d = {ValueError: 'Integers only', AssertionError: 'Positive numbers only', 
     KeyboardInterrupt: 'You can never leave'}
user_input = validate_input("Positive number: ", d)

Here’s a cleaner, more generalized solution that avoids repetitive if/else blocks: write a function that takes (Error, error prompt) pairs in a dictionary and do all your value-checking with assertions.

def validate_input(prompt, error_map):
    while True:
        try:
            data = int(input(prompt))
            # Insert your non-exception-throwing conditionals here
            assert data > 0
            return data
        # Print whatever text you want the user to see
        # depending on how they messed up
        except tuple(error_map.keys()) as e:
            print(error_map[type(e)])

Usage:

d = {ValueError: 'Integers only', AssertionError: 'Positive numbers only', 
     KeyboardInterrupt: 'You can never leave'}
user_input = validate_input("Positive number: ", d)

回答 17

使用递归功能的持久性用户输入:

def askName():
    return input("Write your name: ").strip() or askName()

name = askName()

整数

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

最后,问题要求:

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

responseAge = [
    "You are able to vote in the United States!",
    "You are not able to vote in the United States.",
][int(age < 18)]

print(responseAge)

Persistent user input using recursive function:

String

def askName():
    return input("Write your name: ").strip() or askName()

name = askName()

Integer

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

and finally, the question requirement:

def askAge():
    try: return int(input("Enter your age: "))
    except ValueError: return askAge()

age = askAge()

responseAge = [
    "You are able to vote in the United States!",
    "You are not able to vote in the United States.",
][int(age < 18)]

print(responseAge)

回答 18

简单的解决方案是:

while True:
    age = int(input("Please enter your age: "))

    if (age<=0) or (age>120):
        print('Sorry, I did not understand that.Please try again')
        continue
    else:

        if age>=18:
            print("You are able to vote in the United States!")
        else:
            print("You are not able to vote in the United States.")
        break

上面的代码说明: 为了使年龄有效,它应该是正数,并且不应超过正常的身体年龄,例如,最大年龄为120。

然后,我们可以询问用户年龄,如果年龄输入为负数或大于120,我们将其视为无效输入,然后要求用户重试。

输入有效输入后,我们将检查(使用嵌套的if-else语句)年龄是否大于等于18,反之亦然,并显示一条消息,说明用户是否有资格投票

The simple solution would be:

while True:
    age = int(input("Please enter your age: "))

    if (age<=0) or (age>120):
        print('Sorry, I did not understand that.Please try again')
        continue
    else:

        if age>=18:
            print("You are able to vote in the United States!")
        else:
            print("You are not able to vote in the United States.")
        break

Explanation of above code: In order for a valid age,it should be positive and should not be more than normal physical age,say for example maximum age is 120.

Then we can ask user for age and if age input is negative or more than 120,we consider it invalid input and ask the user to try again.

Once the valid input is entered, we perform a check (using nested if-else statement) whether the age is >=18 or vice versa and print a message whether the user is eligible to vote


回答 19

将输入作为字符串并使用isdigit()来检查输入是否只有数字,不能为空,不能为-ve

while(True):
   #take input as string
   name = input('Enter age : ')
   #check if valid age, only digits
   print( name.isdigit() ) 

run output : 
Enter age : 12
True
Enter age : 
False
Enter age : qwd
False
Enter age : dw3
False
Enter age : 21de
False
Enter age : 1
True
Enter age : -1
False

take input as string and use isdigit() to check input only has digits, not empty, cant be -ve

while(True):
   #take input as string
   name = input('Enter age : ')
   #check if valid age, only digits
   print( name.isdigit() ) 

run output : 
Enter age : 12
True
Enter age : 
False
Enter age : qwd
False
Enter age : dw3
False
Enter age : 21de
False
Enter age : 1
True
Enter age : -1
False