标签归档:python-3.x

Python3的“函数注释”有什么好的用处

问题:Python3的“函数注释”有什么好的用处

功能注释:PEP-3107

我碰到了一段代码,展示了Python3的功能注释。这个概念很简单,但是我想不起来为什么要用Python3来实现它们或对其有很好的用途。也许可以启发我吗?

这个怎么运作:

def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
    ... function body ...

在参数后冒号后面的所有内容均为“注释”,在后面的信息->为函数返回值的注释。

foo.func_annotations将返回一个字典:

{'a': 'x',
 'b': 11,
 'c': list,
 'return': 9}

拥有此功能有什么意义?

Function Annotations: PEP-3107

I ran across a snippet of code demonstrating Python3’s function annotations. The concept is simple but I can’t think of why these were implemented in Python3 or any good uses for them. Perhaps SO can enlighten me?

How it works:

def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
    ... function body ...

Everything following the colon after an argument is an ‘annotation’, and the information following the -> is an annotation for the function’s return value.

foo.func_annotations would return a dictionary:

{'a': 'x',
 'b': 11,
 'c': list,
 'return': 9}

What’s the significance of having this available?


回答 0

我认为这实际上很棒。

来自学术背景,我可以告诉您,注释已证明对启用像Java这样的语言的智能静态分析器非常有用。例如,您可以定义语义,例如状态限制,允许访问的线程,体系结构限制等,然后有很多工具可以读取这些内容并进行处理,以提供超出编译器的保证。您甚至可以编写检查前提条件/后置条件的东西。

我觉得这样的事情在Python中特别需要,因为它的输入较弱,但是实际上没有任何结构可以使它简单明了,并且成为正式语法的一部分。

注解还有其他用途,无法保证。我可以看到如何将基于Java的工具应用于Python。例如,我有一个工具,可让您为方法分配特殊警告,并在调用它们时向您提供指示,指示您应阅读其文档(例如,假设您有一个不能用负值调用的方法,但是从名称上不直观)。通过注释,我可以为Python技术性地编写类似的内容。同样,如果存在正式语法,则可以编写基于标签将大型方法组织起来的工具。

I think this is actually great.

Coming from an academic background, I can tell you that annotations have proved themselves invaluable for enabling smart static analyzers for languages like Java. For instance, you could define semantics like state restrictions, threads that are allowed to access, architecture limitations, etc., and there are quite a few tools that can then read these and process them to provide assurances beyond what you get from the compilers. You could even write things that check preconditions/postconditions.

I feel something like this is especially needed in Python because of its weaker typing, but there were really no constructs that made this straightforward and part of the official syntax.

There are other uses for annotations beyond assurance. I can see how I could apply my Java-based tools to Python. For instance, I have a tool that lets you assign special warnings to methods, and gives you indications when you call them that you should read their documentation (E.g., imagine you have a method that must not be invoked with a negative value, but it’s not intuitive from the name). With annotations, I could technicall write something like this for Python. Similarly, a tool that organizes methods in a large class based on tags can be written if there is an official syntax.


回答 1

函数批注就是您对它们所做的。

它们可以用于文档:

def kinetic_energy(mass: 'in kilograms', velocity: 'in meters per second'):
     ...

它们可用于前提条件检查:

def validate(func, locals):
    for var, test in func.__annotations__.items():
        value = locals[var]
        msg = 'Var: {0}\tValue: {1}\tTest: {2.__name__}'.format(var, value, test)
        assert test(value), msg


def is_int(x):
    return isinstance(x, int)

def between(lo, hi):
    def _between(x):
            return lo <= x <= hi
    return _between

def f(x: between(3, 10), y: is_int):
    validate(f, locals())
    print(x, y)


>>> f(0, 31.1)
Traceback (most recent call last):
   ... 
AssertionError: Var: y  Value: 31.1 Test: is_int

另请参阅http://www.python.org/dev/peps/pep-0362/了解实现类型检查的方法。

Function annotations are what you make of them.

They can be used for documentation:

def kinetic_energy(mass: 'in kilograms', velocity: 'in meters per second'):
     ...

They can be used for pre-condition checking:

def validate(func, locals):
    for var, test in func.__annotations__.items():
        value = locals[var]
        msg = 'Var: {0}\tValue: {1}\tTest: {2.__name__}'.format(var, value, test)
        assert test(value), msg


def is_int(x):
    return isinstance(x, int)

def between(lo, hi):
    def _between(x):
            return lo <= x <= hi
    return _between

def f(x: between(3, 10), y: is_int):
    validate(f, locals())
    print(x, y)


>>> f(0, 31.1)
Traceback (most recent call last):
   ... 
AssertionError: Var: y  Value: 31.1 Test: is_int

Also see http://www.python.org/dev/peps/pep-0362/ for a way to implement type checking.


回答 2

这是一个较晚的答案,但是AFAICT(当前对功能注释的最佳使用)是PEP-0484MyPy

Mypy是Python的可选静态类型检查器。您可以使用即将在Python 3.5 beta 1(PEP 484)中引入的类型注释标准,将类型提示添加到Python程序中,并使用mypy进行静态类型检查。

像这样使用:

from typing import Iterator

def fib(n: int) -> Iterator[int]:
    a, b = 0, 1
    while a < n:
        yield a
        a, b = b, a + b

This is a way late answer, but AFAICT, the best current use of function annotations is PEP-0484 and MyPy.

Mypy is an optional static type checker for Python. You can add type hints to your Python programs using the upcoming standard for type annotations introduced in Python 3.5 beta 1 (PEP 484), and use mypy to type check them statically.

Used like so:

from typing import Iterator

def fib(n: int) -> Iterator[int]:
    a, b = 0, 1
    while a < n:
        yield a
        a, b = b, a + b

回答 3

我想补充从我的回答很好地利用的一个具体的例子在这里,加上装饰可以做的多方法的简单机制。

# This is in the 'mm' module

registry = {}
import inspect

class MultiMethod(object):
    def __init__(self, name):
        self.name = name
        self.typemap = {}
    def __call__(self, *args):
        types = tuple(arg.__class__ for arg in args) # a generator expression!
        function = self.typemap.get(types)
        if function is None:
            raise TypeError("no match")
        return function(*args)
    def register(self, types, function):
        if types in self.typemap:
            raise TypeError("duplicate registration")
        self.typemap[types] = function

def multimethod(function):
    name = function.__name__
    mm = registry.get(name)
    if mm is None:
        mm = registry[name] = MultiMethod(name)
    spec = inspect.getfullargspec(function)
    types = tuple(spec.annotations[x] for x in spec.args)
    mm.register(types, function)
    return mm

以及使用示例:

from mm import multimethod

@multimethod
def foo(a: int):
    return "an int"

@multimethod
def foo(a: int, b: str):
    return "an int and a string"

if __name__ == '__main__':
    print("foo(1,'a') = {}".format(foo(1,'a')))
    print("foo(7) = {}".format(foo(7)))

可以通过将类型添加到装饰器上来完成,如Guido的原始文章所示,但是对参数本身进行注释会更好,因为这样可以避免错误地匹配参数和类型。

:在Python中,你可以访问注解function.__annotations__,而不是function.func_annotations因为func_*风格是关于Python 3去除。

Just to add a specific example of a good use from my answer here, coupled with decorators a simple mechanism for multimethods can be done.

# This is in the 'mm' module

registry = {}
import inspect

class MultiMethod(object):
    def __init__(self, name):
        self.name = name
        self.typemap = {}
    def __call__(self, *args):
        types = tuple(arg.__class__ for arg in args) # a generator expression!
        function = self.typemap.get(types)
        if function is None:
            raise TypeError("no match")
        return function(*args)
    def register(self, types, function):
        if types in self.typemap:
            raise TypeError("duplicate registration")
        self.typemap[types] = function

def multimethod(function):
    name = function.__name__
    mm = registry.get(name)
    if mm is None:
        mm = registry[name] = MultiMethod(name)
    spec = inspect.getfullargspec(function)
    types = tuple(spec.annotations[x] for x in spec.args)
    mm.register(types, function)
    return mm

and an example of use:

from mm import multimethod

@multimethod
def foo(a: int):
    return "an int"

@multimethod
def foo(a: int, b: str):
    return "an int and a string"

if __name__ == '__main__':
    print("foo(1,'a') = {}".format(foo(1,'a')))
    print("foo(7) = {}".format(foo(7)))

This can be done by adding the types to the decorator as Guido’s original post shows, but annotating the parameters themselves is better as it avoids the possibility of wrong matching of parameters and types.

Note: In Python you can access the annotations as function.__annotations__ rather than function.func_annotations as the func_* style was removed on Python 3.


回答 4

Uri已经给出了正确的答案,所以下面是一个不太严重的答案:这样您可以缩短文档字符串。

Uri has already given a proper answer, so here’s a less serious one: So you can make your docstrings shorter.


回答 5

第一次看到注释时,我以为“很棒!最后我可以选择进行类型检查!” 当然,我没有注意到注解实际上并没有执行。

因此,我决定编写一个简单的函数装饰器来实施它们

def ensure_annotations(f):
    from functools import wraps
    from inspect import getcallargs
    @wraps(f)
    def wrapper(*args, **kwargs):
        for arg, val in getcallargs(f, *args, **kwargs).items():
            if arg in f.__annotations__:
                templ = f.__annotations__[arg]
                msg = "Argument {arg} to {f} does not match annotation type {t}"
                Check(val).is_a(templ).or_raise(EnsureError, msg.format(arg=arg, f=f, t=templ))
        return_val = f(*args, **kwargs)
        if 'return' in f.__annotations__:
            templ = f.__annotations__['return']
            msg = "Return value of {f} does not match annotation type {t}"
            Check(return_val).is_a(templ).or_raise(EnsureError, msg.format(f=f, t=templ))
        return return_val
    return wrapper

@ensure_annotations
def f(x: int, y: float) -> float:
    return x+y

print(f(1, y=2.2))

>>> 3.2

print(f(1, y=2))

>>> ensure.EnsureError: Argument y to <function f at 0x109b7c710> does not match annotation type <class 'float'>

我已将其添加到“ 确保”库中。

The first time I saw annotations, I thought “great! Finally I can opt in to some type checking!” Of course, I hadn’t noticed that annotations are not actually enforced.

So I decided to write a simple function decorator to enforce them:

def ensure_annotations(f):
    from functools import wraps
    from inspect import getcallargs
    @wraps(f)
    def wrapper(*args, **kwargs):
        for arg, val in getcallargs(f, *args, **kwargs).items():
            if arg in f.__annotations__:
                templ = f.__annotations__[arg]
                msg = "Argument {arg} to {f} does not match annotation type {t}"
                Check(val).is_a(templ).or_raise(EnsureError, msg.format(arg=arg, f=f, t=templ))
        return_val = f(*args, **kwargs)
        if 'return' in f.__annotations__:
            templ = f.__annotations__['return']
            msg = "Return value of {f} does not match annotation type {t}"
            Check(return_val).is_a(templ).or_raise(EnsureError, msg.format(f=f, t=templ))
        return return_val
    return wrapper

@ensure_annotations
def f(x: int, y: float) -> float:
    return x+y

print(f(1, y=2.2))

>>> 3.2

print(f(1, y=2))

>>> ensure.EnsureError: Argument y to <function f at 0x109b7c710> does not match annotation type <class 'float'>

I added it to the Ensure library.


回答 6

自问起以来已经有很长时间了,但问题中给出的示例摘录(也如此处所述)来自PEP 3107,并且在thas PEP示例结尾处也给出了用例,它们可能会从PEP角度回答问题。查看;)

以下引自PEP3107

用例

在讨论注释的过程中,提出了许多用例。其中一些按其传达的信息进行分组。还包括可以利用注释的现有产品和包装的示例。

  • 提供打字信息
    • 类型检查([3],[4])
    • 让IDE显示函数期望和返回的类型([17])
    • 函数重载/泛型函数([22])
    • 外语桥梁([18],[19])
    • 改编([21],[20])
    • 谓词逻辑功能
    • 数据库查询映射
    • RPC参数封送([23])
  • 其他资讯
    • 参数和返回值的文档([24])

有关特定点(及其参考)的更多信息,请参见PEP

It a long time since this was asked but the example snippet given in the question is (as stated there as well) from PEP 3107 and at the end of thas PEP example Use cases are also given which might answer the question from the PEPs point of view ;)

The following is quoted from PEP3107

Use Cases

In the course of discussing annotations, a number of use-cases have been raised. Some of these are presented here, grouped by what kind of information they convey. Also included are examples of existing products and packages that could make use of annotations.

  • Providing typing information
    • Type checking ([3], [4])
    • Let IDEs show what types a function expects and returns ([17])
    • Function overloading / generic functions ([22])
    • Foreign-language bridges ([18], [19])
    • Adaptation ([21], [20])
    • Predicate logic functions
    • Database query mapping
    • RPC parameter marshaling ([23])
  • Other information
    • Documentation for parameters and return values ([24])

See the PEP for more information on specific points (as well as their references)


回答 7

Python 3.X(仅)还泛化了函数定义,以允许将参数和返回值与对象值一起注释以 用于扩展

用其META数据进行解释,以更明确地了解函数值。

注释的编码方式是:value在参数名称之后,默认值之前以及->value在参数列表之后。

它们被收集到__annotations__函数的属性中,但Python本身并未将其视为特殊的:

>>> def f(a:99, b:'spam'=None) -> float:
... print(a, b)
...
>>> f(88)
88 None
>>> f.__annotations__
{'a': 99, 'b': 'spam', 'return': <class 'float'>}

来源:Python Pocket Reference,第五版

例:

typeannotations模块提供了一组用于Python代码的类型检查和类型推断的工具。它还提供了一组用于注释功能和对象的类型。

这些工具主要设计用于静态分析器,如linter,代码完成库和IDE。另外,提供了用于进行运行时检查的装饰器。在Python中,运行时类型检查并不总是一个好主意,但在某些情况下,它可能非常有用。

https://github.com/ceronman/typeannotations

键入如何帮助编写更好的代码

键入可以帮助您进行静态代码分析,以在将代码发送到生产环境之前捕获类型错误,并防止出现一些明显的错误。有些工具例如mypy,可以将其添加到工具箱中,作为软件生命周期的一部分。mypy可以通过部分或完全针对您的代码库运行来检查类型是否正确。mypy还可以帮助您检测错误,例如从函数返回值时检查None类型。键入有助于使代码更整洁。您可以在不增加性能成本的情况下使用类型,而不必使用注释在文档字符串中指定类型的方式来记录代码。

干净的Python:Python中的优雅编码ISBN:ISBN-13(pbk):978-1-4842-4877-5

PEP 526-变量注释的语法

https://www.python.org/dev/peps/pep-0526/

https://www.attrs.org/en/stable/types.html

Python 3.X (only) also generalizes function definition to allow arguments and return values to be annotated with object values for use in extensions.

Its META-data to explain, to be more explicit about the function values.

Annotations are coded as :value after the argument name and before a default, and as ->value after the argument list.

They are collected into an __annotations__ attribute of the function, but are not otherwise treated as special by Python itself:

>>> def f(a:99, b:'spam'=None) -> float:
... print(a, b)
...
>>> f(88)
88 None
>>> f.__annotations__
{'a': 99, 'b': 'spam', 'return': <class 'float'>}

Source: Python Pocket Reference, Fifth Edition

EXAMPLE:

The typeannotations module provides a set of tools for type checking and type inference of Python code. It also a provides a set of types useful for annotating functions and objects.

These tools are mainly designed to be used by static analyzers such as linters, code completion libraries and IDEs. Additionally, decorators for making run-time checks are provided. Run-time type checking is not always a good idea in Python, but in some cases it can be very useful.

https://github.com/ceronman/typeannotations

How Typing Helps to Write Better Code

Typing can help you do static code analysis to catch type errors before you send your code to production and prevent you from some obvious bugs. There are tools like mypy, which you can add to your toolbox as part of your software life cycle. mypy can check for correct types by running against your codebase partially or fully. mypy also helps you to detect bugs such as checking for the None type when the value is returned from a function. Typing helps to make your code cleaner. Instead of documenting your code using comments, where you specify types in a docstring, you can use types without any performance cost.

Clean Python: Elegant Coding in Python ISBN: ISBN-13 (pbk): 978-1-4842-4877-5

PEP 526 — Syntax for Variable Annotations

https://www.python.org/dev/peps/pep-0526/

https://www.attrs.org/en/stable/types.html


回答 8

尽管在此描述了所有用法,但注释的一种可执行且最有可能的强制使用将是类型提示

目前尚未以任何方式强制执行此操作,但从PEP 484判断,Python的未来版本将仅允许类型作为注释的值。

引用注释的现有用法如何?

我们确实希望类型提示最终将成为注释的唯一用法,但这在使用Python 3.5首次键入类型模块之后,将需要进行额外的讨论和弃用期。当前的PEP将具有临时状态(请参阅PEP 411),直到发布Python 3.6。最快的可能方案将在3.6中引入对非类型提示注释的静默弃用,在3.7中引入完全弃用,并将类型提示声明为Python 3.8中唯一允许使用的注释。

尽管我还没有在3.6中看到任何过时的贬值,但是很可能会升至3.7。

因此,即使可能还有其他一些很好的用例,如果您不想在将来有此限制的情况下四处更改所有内容,最好还是仅将它们保留为类型提示。

Despite all uses described here, the one enforceable and, most likely, enforced use of annotations will be for type hints.

This is currently not enforced in any way but, judging from PEP 484, future versions of Python will only allow types as the value for annotations.

Quoting What about existing uses of annotations?:

We do hope that type hints will eventually become the sole use for annotations, but this will require additional discussion and a deprecation period after the initial roll-out of the typing module with Python 3.5. The current PEP will have provisional status (see PEP 411 ) until Python 3.6 is released. The fastest conceivable scheme would introduce silent deprecation of non-type-hint annotations in 3.6, full deprecation in 3.7, and declare type hints as the only allowed use of annotations in Python 3.8.

Though I haven’t seen any silent deprecations in 3.6 yet, this could very well be bumped to 3.7, instead.

So, even though there might be some other good use-cases, it is best to keep them solely for type hinting if you don’t want to go around changing everything in a future where this restriction is in place.


回答 9

作为一个延迟回答的问题,我的一些软件包(marrow.script,WebCore等)也使用了注释来声明类型转换(即,转换来自Web的传入值,检测哪些参数是布尔开关等)。以执行其他参数标记。

Marrow Script可为任意函数和类构建完整的命令行界面,并允许通过注释定义文档,强制转换和回调派生的默认值,并带有装饰器以支持较早的运行时。我所有使用注释的库都支持以下形式:

any_string  # documentation
any_callable  # typecast / callback, not called if defaulting
(any_callable, any_string)  # combination
AnnotationClass()  # package-specific rich annotation object
[AnnotationClass(), AnnotationClass(), …]  # cooperative annotation

对文档字符串或类型转换功能的“裸露”支持可简化与其他可识别注释的库的混合。(即,有一个使用类型转换的Web控制器,它也恰巧作为命令行脚本公开。)

编辑添加:我还开始使用TypeGuard包,该包使用开发时断言进行验证。好处:在启用“优化”(-O/ PYTHONOPTIMIZEenv var)的情况下运行时,可能会很昂贵(例如,递归)的检查被省略,因为您已经在开发中正确测试了应用程序,因此在生产中不必要检查。

As a bit of a delayed answer, several of my packages (marrow.script, WebCore, etc.) use annotations where available to declare typecasting (i.e. transforming incoming values from the web, detecting which arguments are boolean switches, etc.) as well as to perform additional markup of arguments.

Marrow Script builds a complete command-line interface to arbitrary functions and classes and allows for defining documentation, casting, and callback-derived default values via annotations, with a decorator to support older runtimes. All of my libraries that use annotations support the forms:

any_string  # documentation
any_callable  # typecast / callback, not called if defaulting
(any_callable, any_string)  # combination
AnnotationClass()  # package-specific rich annotation object
[AnnotationClass(), AnnotationClass(), …]  # cooperative annotation

“Bare” support for docstrings or typecasting functions allows for easier mixing with other libraries that are annotation-aware. (I.e. have a web controller using typecasting that also happens to be exposed as a command-line script.)

Edited to add: I’ve also begun making use of the TypeGuard package using development-time assertions for validation. Benefit: when run with “optimizations” enabled (-O / PYTHONOPTIMIZE env var) the checks, which may be expensive (e.g. recursive) are omitted, with the idea that you’ve properly tested your app in development so the checks should be unnecessary in production.


回答 10

注释可用于轻松地模块化代码。例如,我要维护的程序模块可以只定义以下方法:

def run(param1: int):
    """
    Does things.

    :param param1: Needed for counting.
    """
    pass

我们可以要求用户输入一个名为“ param1”的东西,该东西“需要计数”并且应该是“ int”。最后,我们甚至可以将用户提供的字符串转换为所需的类型,以获取最轻松的体验。

请参阅我们的函数元数据对象以获取开放源代码类,该类对此有所帮助,并且可以自动检索所需的值并将其转换为任何所需的类型(因为注释是一种转换方法)。甚至IDE都显示正确的自动完成功能,并假定类型符合注释-非常合适。

Annotations can be used for easily modularizing code. E.g. a module for a program which I’m maintaining could just define a method like:

def run(param1: int):
    """
    Does things.

    :param param1: Needed for counting.
    """
    pass

and we could ask the user for a thing named “param1” which is “Needed for counting” and should be an “int”. In the end we can even convert the string given by the user to the desired type to get the most hassle free experience.

See our function metadata object for an open source class which helps with this and can automatically retrieve needed values and convert them to any desired type (because the annotation is a conversion method). Even IDEs show autocompletions right and assume that types are according to annotations – a perfect fit.


回答 11

如果您查看Cython的好处列表,那么主要的一项功能就是能够告诉编译器Python对象的类型。

我可以预见一个未来,Cython(或编译某些Python代码的类似工具)将使用注释语法来发挥作用。

If you look at the list of benefits of Cython, a major one is the ability to tell the compiler which type a Python object is.

I can envision a future where Cython (or similar tools that compile some of your Python code) will use the annotation syntax to do their magic.


为什么Python 3.x的super()有魔力?

问题:为什么Python 3.x的super()有魔力?

在Python 3.x中,super()可以不带参数调用:

class A(object):
    def x(self):
         print("Hey now")

class B(A):
    def x(self):
        super().x()
>>> B().x()
Hey now

为了完成这项工作,需要执行一些编译时的魔术,其结果是以下代码(重新绑定supersuper_)失败了:

super_ = super

class A(object):
    def x(self):
        print("No flipping")

class B(A):
    def x(self):
        super_().x()
>>> B().x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found

为什么super()在没有编译器帮助的情况下无法在运行时解析超类?在实际情况下,这种行为或其根本原因可能会咬一个粗心的程序员吗?

…,还有一个附带的问题:Python中是否还有其他函数,方法等示例,可以通过将它们重新绑定为其他名称来破坏它们吗?

In Python 3.x, super() can be called without arguments:

class A(object):
    def x(self):
         print("Hey now")

class B(A):
    def x(self):
        super().x()
>>> B().x()
Hey now

In order to make this work, some compile-time magic is performed, one consequence of which is that the following code (which rebinds super to super_) fails:

super_ = super

class A(object):
    def x(self):
        print("No flipping")

class B(A):
    def x(self):
        super_().x()
>>> B().x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
RuntimeError: super(): __class__ cell not found

Why is super() unable to resolve the superclass at runtime without assistance from the compiler? Are there practical situations in which this behaviour, or the underlying reason for it, could bite an unwary programmer?

… and, as a side question: are there any other examples in Python of functions, methods etc. which can be broken by rebinding them to a different name?


回答 0

super()添加了新的魔术行为,以避免违反DRY(请勿重复自己)原理,请参阅PEP 3135。必须通过将其引用为全局来显式地命名该类,这也容易产生与您自己发现的相同的重新绑定问题super()

class Foo(Bar):
    def baz(self):
        return super(Foo, self).baz() + 42

Spam = Foo
Foo = something_else()

Spam().baz()  # liable to blow up

对于使用类装饰器的情况也是如此,其中装饰器返回一个新对象,该对象重新绑定了类名:

@class_decorator_returning_new_class
class Foo(Bar):
    def baz(self):
        # Now `Foo` is a *different class*
        return super(Foo, self).baz() + 42

魔术 super() __class__单元使您可以访问原始类对象,从而很好地避开了这些问题。

PEP由Guido开始,他最初设想super成为关键字,并且使用单元格查找当前Class的想法也是他的想法。当然,使其成为关键字的想法是PEP初稿的一部分

但是,实际上是Guido自己才放弃了“太不可思议”的关键字想法,而是提出了当前的实现方式。他预计使用其他名称super()可能会出现问题

我的补丁使用了一种中间解决方案:假定您__class__ 每次使用名为的变量时都需要使用该解决方案'super'。因此,如果你(全局)重新命名super,以supper和使用supper,但不能super,也不会不带参数的工作(但它仍然可以工作,如果你通过它要么 __class__或实际的类对象); 如果您有一个名为的不相关变量super,那么一切都会起作用,但是该方法将使用稍慢一些的用于单元变量的调用路径。

因此,最终,Guido自己宣布使用super关键字感觉不正确,并且提供一个魔术__class__单元是可以接受的折衷方案。

我同意该实现的神奇的,隐式的行为有些令人惊讶,但它super()是该语言中使用最广泛的功能之一。只需看看 Internet上所有被误用super(type(self), self)super(self.__class__, self)调用的内容;如果从派生类调用了任何代码,最终都会遇到无限递归异常。至少super(),没有参数的简化调用避免了这种情况问题。

至于更名super_; 刚才提到__class__您的方法,以及它会重新工作。如果您在方法中引用super __class__名称,则会创建该单元格:

>>> super_ = super
>>> class A(object):
...     def x(self):
...         print("No flipping")
... 
>>> class B(A):
...     def x(self):
...         __class__  # just referencing it is enough
...         super_().x()
... 
>>> B().x()
No flipping

The new magic super() behaviour was added to avoid violating the D.R.Y. (Don’t Repeat Yourself) principle, see PEP 3135. Having to explicitly name the class by referencing it as a global is also prone to the same rebinding issues you discovered with super() itself:

class Foo(Bar):
    def baz(self):
        return super(Foo, self).baz() + 42

Spam = Foo
Foo = something_else()

Spam().baz()  # liable to blow up

The same applies to using class decorators where the decorator returns a new object, which rebinds the class name:

@class_decorator_returning_new_class
class Foo(Bar):
    def baz(self):
        # Now `Foo` is a *different class*
        return super(Foo, self).baz() + 42

The magic super() __class__ cell sidesteps these issues nicely by giving you access to the original class object.

The PEP was kicked off by Guido, who initially envisioned super becoming a keyword, and the idea of using a cell to look up the current class was also his. Certainly, the idea to make it a keyword was part of the first draft of the PEP.

However, it was in fact Guido himself who then stepped away from the keyword idea as ‘too magical’, proposing the current implementation instead. He anticipated that using a different name for super() could be a problem:

My patch uses an intermediate solution: it assumes you need __class__ whenever you use a variable named 'super'. Thus, if you (globally) rename super to supper and use supper but not super, it won’t work without arguments (but it will still work if you pass it either __class__ or the actual class object); if you have an unrelated variable named super, things will work but the method will use the slightly slower call path used for cell variables.

So, in the end, it was Guido himself that proclaimed that using a super keyword did not feel right, and that providing a magic __class__ cell was an acceptable compromise.

I agree that the magic, implicit behaviour of the implementation is somewhat surprising, but super() is one of the most mis-applied functions in the language. Just take a look at all the misapplied super(type(self), self) or super(self.__class__, self) invocations found on the Internet; if any of that code was ever called from a derived class you’d end up with an infinite recursion exception. At the very least the simplified super() call, without arguments, avoids that problem.

As for the renamed super_; just reference __class__ in your method as well and it’ll work again. The cell is created if you reference either the super or __class__ names in your method:

>>> super_ = super
>>> class A(object):
...     def x(self):
...         print("No flipping")
... 
>>> class B(A):
...     def x(self):
...         __class__  # just referencing it is enough
...         super_().x()
... 
>>> B().x()
No flipping

csv.Error:迭代器应返回字符串,而不是字节

问题:csv.Error:迭代器应返回字符串,而不是字节

Sample.csv包含以下内容:

NAME    Id   No  Dept
Tom     1    12   CS
Hendry  2    35   EC
Bahamas 3    21   IT
Frank   4    61   EE

Python文件包含以下代码:

import csv
ifile  = open('sample.csv', "rb")
read = csv.reader(ifile)
for row in read :
    print (row) 

当我在Python中运行上述代码时,出现以下异常:

文件“ csvformat.py”,第4行,在已读行中表示:_csv.Error:迭代器应返回字符串,而不是字节(您是否以文本模式打开文件?)

我该如何解决?

Sample.csv contains the following:

NAME    Id   No  Dept
Tom     1    12   CS
Hendry  2    35   EC
Bahamas 3    21   IT
Frank   4    61   EE

And the Python file contains the following code:

import csv
ifile  = open('sample.csv', "rb")
read = csv.reader(ifile)
for row in read :
    print (row) 

When I run the above code in Python, I get the following exception:

File “csvformat.py”, line 4, in for row in read : _csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)

How can I fix it?


回答 0

您以文本模式打开文件。

进一步来说:

ifile  = open('sample.csv', "rt", encoding=<theencodingofthefile>)

编码的不错猜测是“ ascii”和“ utf8”。您还可以关闭编码,它将使用系统默认编码,该编码通常为UTF8,但可能还有其他含义。

You open the file in text mode.

More specifically:

ifile  = open('sample.csv', "rt", encoding=<theencodingofthefile>)

Good guesses for encoding is “ascii” and “utf8”. You can also leave the encoding off, and it will use the system default encoding, which tends to be UTF8, but may be something else.


回答 1

我只是用我的代码解决了这个问题。引发该异常的原因是因为您有参数rb。更改为r

您的代码:

import csv
ifile  = open('sample.csv', "rb")
read = csv.reader(ifile)
for row in read :
    print (row) 

新代码:

import csv
ifile  = open('sample.csv', "r")
read = csv.reader(ifile)
for row in read :
    print (row)

The reason it is throwing that exception is because you have the argument rb, which opens the file in binary mode. Change that to r, which will by default open the file in text mode.

Your code:

import csv
ifile  = open('sample.csv', "rb")
read = csv.reader(ifile)
for row in read :
    print (row) 

New code:

import csv
ifile  = open('sample.csv', "r")
read = csv.reader(ifile)
for row in read :
    print (row)

回答 2

您的问题是您bopen标志中。该标志rt(读取,文本)是默认设置,因此,使用上下文管理器只需执行以下操作:

with open('sample.csv') as ifile:
    read = csv.reader(ifile) 
    for row in read:
        print (row)  

上下文管理器意味着您不需要常规的错误处理(如果没有这种处理,您可能会卡在打开文件中,尤其是在解释器中),因为它会在发生错误或退出上下文时自动关闭文件。

上面是一样的:

with open('sample.csv', 'r') as ifile:
    ...

要么

with open('sample.csv', 'rt') as ifile:
    ...

Your problem is you have the b in the open flag. The flag rt (read, text) is the default, so, using the context manager, simply do this:

with open('sample.csv') as ifile:
    read = csv.reader(ifile) 
    for row in read:
        print (row)  

The context manager means you don’t need generic error handling (without which you may get stuck with the file open, especially in an interpreter), because it will automatically close the file on an error, or on exiting the context.

The above is the same as:

with open('sample.csv', 'r') as ifile:
    ...

or

with open('sample.csv', 'rt') as ifile:
    ...

回答 3

csv.reader期望在Python3中,传递可迭代的返回字符串,而不是字节。这是使用codecs模块的另一解决方案:

import csv
import codecs
ifile  = open('sample.csv', "rb")
read = csv.reader(codecs.iterdecode(ifile, 'utf-8'))
for row in read :
    print (row) 

In Python3, csv.reader expects, that passed iterable returns strings, not bytes. Here is one more solution to this problem, that uses codecs module:

import csv
import codecs
ifile  = open('sample.csv', "rb")
read = csv.reader(codecs.iterdecode(ifile, 'utf-8'))
for row in read :
    print (row) 

回答 4

运行使用Python 2.6.4开发的旧python脚本时出现此错误

更新到3.6.2时,我必须从打开的调用中删除所有“ rb”参数,以修复此csv读取错误。

I had this error when running an old python script developped with Python 2.6.4

When updating to 3.6.2, I had to remove all ‘rb’ parameters from open calls in order to fix this csv reading error.


pythonw.exe还是python.exe?

问题:pythonw.exe还是python.exe?

长话短说:pythonw.exe什么都不做,python.exe什么也不接受(我应该使用哪一个?)

test.py:

print "a"

CMD窗口:

C:\path>pythonw.exe test.py
<BLANK LINE>
C:\path>

C:\path>python.exe test.py
  File "C:\path\test.py", line 7
    print "a"
            ^
SyntaxError: invalid syntax

C:\path>

请告诉我我在做错什么。

Long story short: pythonw.exe does nothing, python.exe accepts nothing (which one should I use?)

test.py:

print "a"

CMD window:

C:\path>pythonw.exe test.py
<BLANK LINE>
C:\path>

C:\path>python.exe test.py
  File "C:\path\test.py", line 7
    print "a"
            ^
SyntaxError: invalid syntax

C:\path>

Please tell me what I’m doing terrible wrong.


回答 0

如果您不希望在运行程序时弹出终端窗口,请使用pythonw.exe;
否则,使用python.exe

关于语法错误:print 现在是3.x中的函数,请
改用:

print("a")

If you don’t want a terminal window to pop up when you run your program, use pythonw.exe;
Otherwise, use python.exe

Regarding the syntax error: print is now a function in 3.x
So use instead:

print("a")

回答 1

总结和补充现有的答案:

  • python.exe用于启动CLI类型脚本的控制台(终端)应用程序。

    • 除非从现有控制台窗口运行,否则python.exe 将打开一个新的控制台窗口
    • 标准流 sys.stdinsys.stdout并且sys.stderr连接到控制台窗口
    • 从或PowerShell控制台窗口启动时,执行是同步的cmd.exe请参阅下面的eryksun的第一条评论。

      • 如果创建了新的控制台窗口,它将保持打开状态,直到脚本终止。
      • 从现有的控制台窗口中调用时,提示被阻止,直到脚本终止。
  • pythonw.exe是一个用于启动GUI /无UI脚本的GUI应用。

    • 没有打开控制台窗口
    • 执行是异步的
      • 从控制台窗口中调用时,无论脚本是否仍在运行,仅启动脚本并立即返回提示。
    • 标准流 sys.stdinsys.stdout并且sys.stderr不可用
      • 警告除非您采取额外的步骤否则可能会带来意想不到的副作用
        • 未处理的异常会导致脚本静默中止
        • 在Python 2.x中,仅尝试使用print()会导致这种情况发生(在3.x中,print()完全没有效果)。
        • 为了防止这种情况出现在您的脚本中,并要了解更多信息,请参阅我的答案
        • 临时的,您可以使用输出重定向谢谢,@ handle。
          pythonw.exe yourScript.pyw 1>stdout.txt 2>stderr.txt
          (来自PowerShell :)
          cmd /c pythonw.exe yourScript.pyw 1>stdout.txt 2>stderr.txt捕获文件中的 stdout和stderr输出。
          如果您确信使用的print()是你的脚本就会失败的唯一原因pythonw.exe,而你不是在标准输出输出,使用从注释兴趣@拉手的命令:
          pythonw.exe yourScript.pyw 1>NUL 2>&1
          买者:这个输出重定向技术确实调用工作时*.pyw脚本直接(而不是将脚本文件路径传递到pythonw.exe)。请参阅下面的eryksun的第二条评论及其后续意见。

通过选择正确的文件扩展名,您可以控制默认情况下哪个可执行文件运行您的脚本(例如从资源管理器打开时):

  • *.py 默认情况下,文件与以下文件关联(调用) python.exe
  • *.pyw 默认情况下,文件与以下文件关联(调用) pythonw.exe

To summarize and complement the existing answers:

  • python.exe is a console (terminal) application for launching CLI-type scripts.

    • Unless run from an existing console window, python.exe opens a new console window.
    • Standard streams sys.stdin, sys.stdout and sys.stderr are connected to the console window.
    • Execution is synchronous when launched from a cmd.exe or PowerShell console window: See eryksun‘s 1st comment below.

      • If a new console window was created, it stays open until the script terminates.
      • When invoked from an existing console window, the prompt is blocked until the script terminates.
  • pythonw.exe is a GUI app for launching GUI/no-UI-at-all scripts.

    • NO console window is opened.
    • Execution is asynchronous:
      • When invoked from a console window, the script is merely launched and the prompt returns right away, whether the script is still running or not.
    • Standard streams sys.stdin, sys.stdout and sys.stderr are NOT available.
      • Caution: Unless you take extra steps, this has potentially unexpected side effects:
        • Unhandled exceptions cause the script to abort silently.
        • In Python 2.x, simply trying to use print() can cause that to happen (in 3.x, print() simply has no effect).
        • To prevent that from within your script, and to learn more, see this answer of mine.
        • Ad-hoc, you can use output redirection:Thanks, @handle.
          pythonw.exe yourScript.pyw 1>stdout.txt 2>stderr.txt
          (from PowerShell:
          cmd /c pythonw.exe yourScript.pyw 1>stdout.txt 2>stderr.txt) to capture stdout and stderr output in files.
          If you’re confident that use of print() is the only reason your script fails silently with pythonw.exe, and you’re not interested in stdout output, use @handle’s command from the comments:
          pythonw.exe yourScript.pyw 1>NUL 2>&1
          Caveat: This output redirection technique does not work when invoking *.pyw scripts directly (as opposed to by passing the script file path to pythonw.exe). See eryksun‘s 2nd comment and its follow-ups below.

You can control which of the executables runs your script by default – such as when opened from Explorer – by choosing the right filename extension:

  • *.py files are by default associated (invoked) with python.exe
  • *.pyw files are by default associated (invoked) with pythonw.exe

回答 2

参见此处:http : //docs.python.org/using/windows.html

pythonw.exe“这将在启动时禁止显示终端窗口。”

See here: http://docs.python.org/using/windows.html

pythonw.exe “This suppresses the terminal window on startup.”


回答 3

如果要从其他进程(例如,从命令行)调用python脚本,请使用pythonw.exe。否则,您的用户将不断看到cmd启动python进程的窗口。它仍将以相同的方式运行您的脚本,但不会影响用户体验。

例如发送电子邮件。python.exe将弹出一个CLI窗口,发送电子邮件,然后关闭该窗口。它会以快速闪烁的形式出现,并且可能会有些令人讨厌。pythonw.exe避免这种情况,但仍发送电子邮件。

If you’re going to call a python script from some other process (say, from the command line), use pythonw.exe. Otherwise, your user will continuously see a cmd window launching the python process. It’ll still run your script just the same, but it won’t intrude on the user experience.

An example might be sending an email; python.exe will pop up a CLI window, send the email, then close the window. It’ll appear as a quick flash, and can be considered somewhat annoying. pythonw.exe avoids this, but still sends the email.


回答 4

我正在努力使它工作一段时间。将扩展名更改为.pyw后,请确保打开文件的属性,并将“打开方式”路径定向到pythonw.exe。

I was struggling to get this to work for a while. Once you change the extension to .pyw, make sure that you open properties of the file and direct the “open with” path to pythonw.exe.


回答 5

以我的经验,至少使用pygame时pythonw.exe更快。

In my experience the pythonw.exe is faster at least with using pygame.


我可以在同一台Windows计算机上安装Python 3.x和2.x吗?

问题:我可以在同一台Windows计算机上安装Python 3.x和2.x吗?

我正在运行Windows,并且在命令行上运行程序时,shell / OS将根据注册表设置自动运行Python。如果我在同一台计算机上安装2.x和3.x版本的Python,这会中断吗?

我想玩Python 3,同时仍然能够在同一台机器上运行2.x脚本。

I’m running Windows and the shell/OS automatically runs Python based on the registry settings when you run a program on the command line. Will this break if I install a 2.x and 3.x version of Python on the same machine?

I want to play with Python 3 while still being able to run 2.x scripts on the same machine.


回答 0

共存的官方解决方案似乎是WindowsPython Launcher,PEP 397,它包含在Python 3.3.0中。将发行版转储文件py.exepyw.exe启动器安装到%SYSTEMROOT%C:\Windows)中,然后分别与pypyw脚本关联。

为了使用新启动器(无需手动设置自己的关联),请保持“注册扩展名”选项处于启用状态。我不太确定为什么,但是在我的机器上,它保留了Py 2.7作为(启动器的)“默认”值。

通过直接从命令行调用脚本来运行脚本,这些脚本将通过启动程序进行路由并解析shebang(如果存在)。您还可以显式调用启动器并使用开关:py -3 mypy2script.py

各种各样的shebangs似乎都可以工作

  • #!C:\Python33\python.exe
  • #!python3
  • #!/usr/bin/env python3

以及肆意滥用

  • #! notepad.exe

The official solution for coexistence seems to be the Python Launcher for Windows, PEP 397 which was included in Python 3.3.0. Installing the release dumps py.exe and pyw.exe launchers into %SYSTEMROOT% (C:\Windows) which is then associated with py and pyw scripts, respectively.

In order to use the new launcher (without manually setting up your own associations to it), leave the “Register Extensions” option enabled. I’m not quite sure why, but on my machine it left Py 2.7 as the “default” (of the launcher).

Running scripts by calling them directly from the command line will route them through the launcher and parse the shebang (if it exists). You can also explicitly call the launcher and use switches: py -3 mypy2script.py.

All manner of shebangs seem to work

  • #!C:\Python33\python.exe
  • #!python3
  • #!/usr/bin/env python3

as well as wanton abuses

  • #! notepad.exe

回答 1

这是我的设置:

  1. 使用Windows安装程序安装Python 2.7和3.4 。
  2. 转到C:\Python34(默认安装路径)并将python.exe更改为python3.exe
  3. 编辑 环境变量以包括C:\Python27\;C:\Python27\Scripts\;C:\Python34\;C:\Python34\Scripts\;

现在在命令行中,您可以使用python2.7和python33.4。

Here’s my setup:

  1. Install both Python 2.7 and 3.4 with the windows installers.
  2. Go to C:\Python34 (the default install path) and change python.exe to python3.exe
  3. Edit your environment variables to include C:\Python27\;C:\Python27\Scripts\;C:\Python34\;C:\Python34\Scripts\;

Now in command line you can use python for 2.7 and python3 for 3.4.


回答 2

您可以同时安装。

您应该在脚本之前编写以下代码:

#!/bin/env python2.7

或者,最终…

#!/bin/env python3.6

更新资料

Google上进行快速搜索后,我的解决方案与Unix完美搭配,这是Windows解决方案:

#!c:/Python/python3_6.exe -u

同样的事情:在脚本之前。

You can have both installed.

You should write this in front of your script:

#!/bin/env python2.7

or, eventually…

#!/bin/env python3.6

Update

My solution works perfectly with Unix, after a quick search on Google, here is the Windows solution:

#!c:/Python/python3_6.exe -u

Same thing: in front of your script.


回答 3

从3.3版开始,Python引入了适用于Windows的Launcher实用程序https://docs.python.org/3/using/windows.html#python-launcher-for-windows

为了能够使用多个版本的Python:

  1. 安装Python 2.x(x是您需要的任何版本)
  2. 安装Python 3.x(x是您需要的任何版本,您还必须拥有一个3.x> = 3.3的版本)
  3. 打开命令提示符
  4. 键入py -2.x以启动Python 2.x
  5. 键入py -3.x启动Python 3.x

From version 3.3 Python introduced Launcher for Windows utility https://docs.python.org/3/using/windows.html#python-launcher-for-windows.

So to be able to use multiple versions of Python:

  1. install Python 2.x (x is any version you need)
  2. install Python 3.x (x is any version you need also you have to have one version 3.x >= 3.3)
  3. open Command Prompt
  4. type py -2.x to launch Python 2.x
  5. type py -3.x to launch Python 3.x

回答 4

我从外壳程序中使用2.5、2.6和3.0,以及以下形式的一行批处理脚本:

:: The @ symbol at the start turns off the prompt from displaying the command.
:: The % represents an argument, while the * means all of them.
@c:\programs\pythonX.Y\python.exe %*

命名它们pythonX.Y.bat并将它们放在PATH中的某个位置。将首选的次要版本(即最新版本)的文件复制到pythonX.bat。(例如copy python2.6.bat python2.bat。)然后您可以python2 file.py在任何地方使用。

但是,这没有帮助甚至影响Windows文件关联的情况。为此,您需要一个启动器程序来读取该#!行,然后将其与.py和.pyw文件关联。

I’m using 2.5, 2.6, and 3.0 from the shell with one line batch scripts of the form:

:: The @ symbol at the start turns off the prompt from displaying the command.
:: The % represents an argument, while the * means all of them.
@c:\programs\pythonX.Y\python.exe %*

Name them pythonX.Y.bat and put them somewhere in your PATH. Copy the file for the preferred minor version (i.e. the latest) to pythonX.bat. (E.g. copy python2.6.bat python2.bat.) Then you can use python2 file.py from anywhere.

However, this doesn’t help or even affect the Windows file association situation. For that you’ll need a launcher program that reads the #! line, and then associate that with .py and .pyw files.


回答 5

将两者都添加到环境变量时,将发生冲突,因为两个可执行文件具有相同的名称:python.exe

只需重命名其中之一即可。就我而言,我将其重命名为python3.exe

因此,当我运行python它将执行python.exe2.7,而当我运行python3将执行python3.exe3.6

When you add both to environment variables there will a be a conflict because the two executable have the same name: python.exe.

Just rename one of them. In my case I renamed it to python3.exe.

So when I run python it will execute python.exe which is 2.7 and when I run python3 it will execute python3.exe which is 3.6


回答 6

干得好…

winpylaunch.py

#
# Looks for a directive in the form: #! C:\Python30\python.exe
# The directive must start with #! and contain ".exe".
# This will be assumed to be the correct python interpreter to
# use to run the script ON WINDOWS. If no interpreter is
# found then the script will be run with 'python.exe'.
# ie: whatever one is found on the path.
# For example, in a script which is saved as utf-8 and which
# runs on Linux and Windows and uses the Python 2.6 interpreter...
#
#    #!/usr/bin/python
#    #!C:\Python26\python.exe
#    # -*- coding: utf-8 -*-
#
# When run on Linux, Linux uses the /usr/bin/python. When run
# on Windows using winpylaunch.py it uses C:\Python26\python.exe.
#
# To set up the association add this to the registry...
#
#    HKEY_CLASSES_ROOT\Python.File\shell\open\command
#    (Default) REG_SZ = "C:\Python30\python.exe" S:\usr\bin\winpylaunch.py "%1" %*
#
# NOTE: winpylaunch.py itself works with either 2.6 and 3.0. Once
# this entry has been added python files can be run on the
# commandline and the use of winpylaunch.py will be transparent.
#

import subprocess
import sys

USAGE = """
USAGE: winpylaunch.py <script.py> [arg1] [arg2...]
"""

if __name__ == "__main__":
  if len(sys.argv) > 1:
    script = sys.argv[1]
    args   = sys.argv[2:]
    if script.endswith(".py"):
      interpreter = "python.exe" # Default to wherever it is found on the path.
      lines = open(script).readlines()
      for line in lines:
        if line.startswith("#!") and line.find(".exe") != -1:
          interpreter = line[2:].strip()
          break
      process = subprocess.Popen([interpreter] + [script] + args)
      process.wait()
      sys.exit()
  print(USAGE)

我刚刚在阅读此线程时就搞定了(因为这也是我所需要的)。我在Ubuntu和Windows上都有Python 2.6.1和3.0.1。如果对您不起作用,请在此处发布修复程序。

Here you go…

winpylaunch.py

#
# Looks for a directive in the form: #! C:\Python30\python.exe
# The directive must start with #! and contain ".exe".
# This will be assumed to be the correct python interpreter to
# use to run the script ON WINDOWS. If no interpreter is
# found then the script will be run with 'python.exe'.
# ie: whatever one is found on the path.
# For example, in a script which is saved as utf-8 and which
# runs on Linux and Windows and uses the Python 2.6 interpreter...
#
#    #!/usr/bin/python
#    #!C:\Python26\python.exe
#    # -*- coding: utf-8 -*-
#
# When run on Linux, Linux uses the /usr/bin/python. When run
# on Windows using winpylaunch.py it uses C:\Python26\python.exe.
#
# To set up the association add this to the registry...
#
#    HKEY_CLASSES_ROOT\Python.File\shell\open\command
#    (Default) REG_SZ = "C:\Python30\python.exe" S:\usr\bin\winpylaunch.py "%1" %*
#
# NOTE: winpylaunch.py itself works with either 2.6 and 3.0. Once
# this entry has been added python files can be run on the
# commandline and the use of winpylaunch.py will be transparent.
#

import subprocess
import sys

USAGE = """
USAGE: winpylaunch.py <script.py> [arg1] [arg2...]
"""

if __name__ == "__main__":
  if len(sys.argv) > 1:
    script = sys.argv[1]
    args   = sys.argv[2:]
    if script.endswith(".py"):
      interpreter = "python.exe" # Default to wherever it is found on the path.
      lines = open(script).readlines()
      for line in lines:
        if line.startswith("#!") and line.find(".exe") != -1:
          interpreter = line[2:].strip()
          break
      process = subprocess.Popen([interpreter] + [script] + args)
      process.wait()
      sys.exit()
  print(USAGE)

I’ve just knocked this up on reading this thread (because it’s what I was needing too). I have Pythons 2.6.1 and 3.0.1 on both Ubuntu and Windows. If it doesn’t work for you post fixes here.


回答 7

据我所知,Python使用PATH变量而不是注册表设置来从命令行运行。

因此,如果您在PATH上指向正确的版本,则将使用该版本。请记住,重新启动命令提示符以使用新的PATH设置。

As far as I know Python runs off of the commandline using the PATH variable as opposed to a registry setting.

So if you point to the correct version on your PATH you will use that. Remember to restart your command prompt to use the new PATH settings.


回答 8

Python安装通常会将.py.pyw.pyc文件与Python解释器相关联。因此,您可以通过在资源管理器中双击Python脚本或在命令行窗口中键入其名称来运行Python脚本(这样就无需键入python scriptname.py,就scriptname.py可以了)。

如果要手动更改此关联,则可以在Windows注册表中编辑以下项:

HKEY_CLASSES_ROOT\Python.File\shell\open\command
HKEY_CLASSES_ROOT\Python.NoConFile\shell\open\command
HKEY_CLASSES_ROOT\Python.CompiledFile\shell\open\command

Python启动器

人们一直在研究Windows的Python启动器:与.py.pyw文件相关联的轻量级程序,它将在第一行中寻找“ shebang”行(类似于Linux等),并以2.x或3.x版本启动Python。需要。有关详细信息,请参见“适用于Windows的Python启动器”博客文章。

The Python installation normally associates .py, .pyw and .pyc files with the Python interpreter. So you can run a Python script either by double-clicking it in Explorer or by typing its name in a command-line window (so no need to type python scriptname.py, just scriptname.py will do).

If you want to manually change this association, you can edit these keys in the Windows registry:

HKEY_CLASSES_ROOT\Python.File\shell\open\command
HKEY_CLASSES_ROOT\Python.NoConFile\shell\open\command
HKEY_CLASSES_ROOT\Python.CompiledFile\shell\open\command

Python Launcher

People have been working on a Python launcher for Windows: a lightweight program associated with .py and .pyw files which would look for a “shebang” line (similar to Linux et al) on the first line, and launch Python 2.x or 3.x as required. See “A Python Launcher for Windows” blog post for details.


回答 9

尝试使用Anaconda。

假设使用Anaconda环境的概念,您需要Python 3来学习编程,但是您不想通过更新Python来消灭Python 2.7环境。您可以创建并激活名为“ snakes”(或所需的任何名称)的新环境,并按如下所示安装最新版本的Python 3:

conda create --name snakes python=3

它比听起来简单,请在此处查看介绍页面:Anaconda入门

然后要解决并排运行2.x和3.x版本的特定问题,请参阅:使用Anaconda管理Python版本

Try using Anaconda.

Using the concept of Anaconda environments, let’s say you need Python 3 to learn programming, but you don’t want to wipe out your Python 2.7 environment by updating Python. You can create and activate a new environment named “snakes” (or whatever you want), and install the latest version of Python 3 as follows:

conda create --name snakes python=3

Its simpler than it sounds, take a look at the intro page here: Getting Started with Anaconda

And then to handle your specific problem of having version 2.x and 3.x running side by side, see:


回答 10

这是在同一台机器上运行Python 2和3的方法

  1. 安装Python 2.x
  2. 安装Python 3.x
  3. 启动Powershell
  4. 输入Python -2以启动Python 2.x
  5. 输入Python -3启动Python 2.x

WindowsPython启动器自3.3版开始嵌入到Python中,正如2011年Stand Stand首次亮相时所承诺的那样:

适用于Windows的Python启动器

Here is how to run Python 2 and 3 on the same machine

  1. install Python 2.x
  2. install Python 3.x
  3. Start Powershell
  4. Type Python -2 to launch Python 2.x
  5. Type Python -3 to launch Python 2.x

The Python Launcher for Windows was embedded into Python since Version 3.3, as promised in 2011 when the Stand alone first made its debut:

Python Launcher for Windows


回答 11

这是在Windows上安装Python2和Python3的一种简洁方法。

https://datascience.com.co/how-to-install-python-2-7-and-3-6-in-windows-10-add-python-path-281e7eae62a

我的情况:我必须安装Apache cassandra。我已经在D:驱动器中安装了Python3 。随着大量开发工作的进行,我不想弄乱我的Python3安装。而且,我只需要Python2用于Apache cassandra。

所以我采取了以下步骤:

  1. 下载并安装了Python2。
  2. 已将Python2条目添加到类路径(C:\Python27;C:\Python27\Scripts
  3. python.exe修改为python2.exe(如下图所示)

  1. 现在我可以同时运行两者。适用于Python 2(python2 --version)和Python 3(python --version)。

因此,我的Python3安装保持不变。

Here is a neat and clean way to install Python2 & Python3 on windows.

https://datascience.com.co/how-to-install-python-2-7-and-3-6-in-windows-10-add-python-path-281e7eae62a

My case: I had to install Apache cassandra. I already had Python3 installed in my D: drive. With loads of development work under process i didn’t wanted to mess my Python3 installation. And, i needed Python2 only for Apache cassandra.

So i took following steps:

  1. Downloaded & Installed Python2.
  2. Added Python2 entries to classpath (C:\Python27;C:\Python27\Scripts)
  3. Modified python.exe to python2.exe (as shown in image below)

  1. Now i am able to run both. For Python 2(python2 --version) & Python 3 (python --version).

So, my Python3 installation remained intact.


回答 12

我认为可以在安装程序中为.py文件设置Windows文件关联。取消选中它就可以了。

如果没有,您可以轻松地将.py文件与以前的版本重新关联。最简单的方法是右键单击.py文件,选择“打开方式” /“选择程序”。在出现的对话框中,选择或浏览到默认情况下要使用的python版本,然后选中“始终使用此程序打开这种文件”复选框。

I think there is an option to setup the windows file association for .py files in the installer. Uncheck it and you should be fine.

If not, you can easily re-associate .py files with the previous version. The simplest way is to right click on a .py file, select “open with” / “choose program”. On the dialog that appears, select or browse to the version of python you want to use by default, and check the “always use this program to open this kind of file” checkbox.


回答 13

您应该确保PATH环境变量不包含两个python.exe文件(添加您当前用于每天运行脚本的文件),或按照批处理文件的建议进行操作。除此之外,我不明白为什么不这样。

PS:我安装了2.6作为“主要” python,安装了3.0作为“ play” python。2.6包含在PATH中。一切正常。

You should make sure that the PATH environment variable doesn’t contain both python.exe files ( add the one you’re currently using to run scripts on a day to day basis ) , or do as Kniht suggested with the batch files . Aside from that , I don’t see why not .

P.S : I have 2.6 installed as my “primary” python and 3.0 as my “play” python . The 2.6 is included in the PATH . Everything works fine .


回答 14

在我勇敢地同时安装两者之前,我有很多问题。如果我给python,我要py2时会转到py3吗?pip / virtualenv是否会在py2 / 3下发生?

现在看来非常简单。

只需盲目安装它们。确保您获得正确的类型(x64 / x32)。在安装时/安装后,请确保添加到环境变量的路径。

[ENVIRONMENT]::SETENVIRONMENTVARIABLE("PATH", "$ENV:PATH;C:\PYTHONx", "USER")

替换上面命令中的x以设置路径。

然后转到两个文件夹。

导航

python3.6/Scripts/

并将pip重命名为pip3。

如果pip3已经存在,请删除该pip。这将确保just pip将在python2下运行。您可以通过以下方式进行验证:

pip --version

如果您想在python3中使用pip,请使用

pip3 install 

您可以类似地对python文件和其他文件执行相同的操作。

干杯!

Before I courageously installed both simultaneously, I had so many questions. If I give python will it go to py3 when i want py2? pip/virtualenv will happen under py2/3?

It seems to be very simple now.

Just blindly install both of them. Make sure you get the right type(x64/x32). While/after installing make sure you add to the path to your environment variables.

[ENVIRONMENT]::SETENVIRONMENTVARIABLE("PATH", "$ENV:PATH;C:\PYTHONx", "USER")

Replace the x in the command above to set the path.

Then go to both the folders.

Navigate to

python3.6/Scripts/

and rename pip to pip3.

If pip3 already exists delete the pip. This will make sure that just pip will run under python2. You can verify by:

pip --version

In case you want to use pip with python3 then just use

pip3 install 

You can similarly do the same to python file and others.

Cheers!


回答 15

Easy-peasy,在安装了两个python版本之后,将路径添加到环境变量;请参阅。然后转到python 2和python 3文件夹,分别将它们重命名为python2和python3,如图和所示。现在在cmd中键入python2或python3以使用所需的版本,请参见

Easy-peasy ,after installing both the python versions add the paths to the environment variables ;see. Then go to python 2 and python 3 folders and rename them to python2 and python3 respectively as shown and . Now in cmd type python2 or python3 to use your required version see .


回答 16

我假设是这样,我在同一台计算机上并排安装了Python 2.4、2.5和2.6。

I would assume so, I have Python 2.4, 2.5 and 2.6 installed side-by-side on the same computer.


回答 17

我现在刚开始使用python。我正在阅读Zed Shaw的书“以困难的方式学习Python”,该书需要python 2.x版本,但同时也要学习一个需要python 3.x的类。

这就是我所做的。

  1. 下载python 2.7
  2. 运行电源外壳(应该已经在Windows上安装)
  3. 在POWERSHELL中运行python(如果无法识别,请转到步骤4)
  4. 仅当powershell无法识别python 2.7时,才输入以下内容:

“ [[环境] :: SETENVIRONMENTVARIABLE(“ PATH”,“ $ ENV:PATH; C:\ PYTHON27”,“ USER”)“(无外部引号)

  1. 现在键入python,您应该看到它说python 2.7等等等等

现在适用于python 3.x

简单,适用于Windows应用程序的python 3.x下载带有python。因此,只需将适用于Windows的Python应用程序固定到任务栏,或创建桌面快捷方式即可完成!

打开适用于Windows的3.x版Python

打开适用于python 2.x的Powershell

我希望这有帮助!

I am just starting out with python now. I’m reading Zed Shaw’s book “Learn Python the Hard Way” which requires python version 2.x but am also taking a class that requires python 3.x

So here is what I did.

  1. Download python 2.7
  2. run power shell (should already be installed on windows)
  3. run python IN POWERSHELL (if it doesn’t recognize then go to step 4)
  4. Only if powershell doesn’t recognize python 2.7 type in the following:

“[ENVIRONMENT]::SETENVIRONMENTVARIABLE(“PATH”, “$ENV:PATH;C:\PYTHON27”, “USER”)” (no outside quotes)

  1. Now type python and you should see it say python 2.7 blah blah blah

NOW for python 3.x

Simple, python 3.x download comes with python for windows app. SO simply pin the Python for Windows app to your task bar, or create shortcut to the desktop and you are done!

Open Python for Windows for 3.x

Open Powershell for python 2.x

I hope this helps!


回答 18

嗯..我现在通过在https://www.python.org/downloads/release/python-365/下载适用于Windows的Python 3.6.5来做到这一点,并确保将安装启动器。然后,我按照使用python 2和python 3的说明进行操作。重新启动命令提示符,然后使用py -2.7来使用Python 2和pypy -3.6来使用Python3。您还可以将其pip2用于Python 2 pippipPython 3 pip

Hmm..I did this right now by just downloading Python 3.6.5 for Windows at https://www.python.org/downloads/release/python-365/ and made sure that the launcher would be installed. Then, I followed the instructions for using python 2 and python 3. Restart the command prompt and then use py -2.7 to use Python 2 and py or py -3.6 to use Python 3. You can also use pip2 for Python 2’s pip and pip for Python 3’s pip.


回答 19

我在要使用python3进行大多数工作时遇到了同样的问题,但是IDA pro需要python2。所以,这就是我所做的。

我首先在用户环境变量中创建了3个变量,如下所示:

  1. PYTHON_ACTIVE:最初为空
  2. HOME_PYTHON27:具有安装Python 2的文件夹的路径。例如。“; /脚本;”
  3. HOME_PYTHON38:类似于python 2,此变量包含python 3文件夹的路径。

现在我加了

%PYTHON_ACTIVE%

到PATH变量。因此,基本上说这个“ PYTHON_ACTIVE”包含的内容就是活动的python。我们以编程方式更改“ PYTHON_ACTIVE”的包含内容以切换python版本。

这是示例脚本:

:: This batch file is used to switch between python 2 and 3.
@ECHO OFF

set /p choice= "Please enter '27' for python 2.7 , '38' for python 3.8 : "

IF %choice%==27 (
setx PYTHON_ACTIVE %HOME_PYTHON27%
)

IF %choice%==38 (
setx PYTHON_ACTIVE %HOME_PYTHON38%
)


PAUSE

该脚本将python版本作为输入,并因此将HOME_PYTHON27或HOME_PYTHON38复制到PYTHON_ACTIVE。从而更改了全局Python版本。

I had the same problem where I wanted to use python3 for most work but IDA pro required python2. SO, here’s what I did.

I first created 3 variables in the user environment variable as follows:

  1. PYTHON_ACTIVE : This is initially empty
  2. HOME_PYTHON27 : Has a path to a folder where Python 2 is installed. Eg. “;/scripts;”
  3. HOME_PYTHON38 : Similar to python 2, this variable contains a path to python 3 folders.

Now I added

%PYTHON_ACTIVE%

to PATH variable. So, basically saying that whatever this “PYTHON_ACTIVE” contains is the active python. We programmatically change the contains of “PYTHON_ACTIVE” to switch python version.

Here is the example script:

:: This batch file is used to switch between python 2 and 3.
@ECHO OFF

set /p choice= "Please enter '27' for python 2.7 , '38' for python 3.8 : "

IF %choice%==27 (
setx PYTHON_ACTIVE %HOME_PYTHON27%
)

IF %choice%==38 (
setx PYTHON_ACTIVE %HOME_PYTHON38%
)


PAUSE

This script takes python version as input and accordingly copies HOME_PYTHON27 or HOME_PYTHON38 to PYTHON_ACTIVE. Thus changing the global Python version.


适用于Python 3的图片库

问题:适用于Python 3的图片库

什么是python-3而不是PIL来处理图像?

What is python-3 using instead of PIL for manipulating Images?


回答 0

“友好的PIL叉子” 枕头可在Python 2和3上使用。请查看Github项目以获取支持矩阵等。

The “friendly PIL fork” Pillow works on Python 2 and 3. Check out the Github project for support matrix and so on.


回答 1

Christoph Gohlke设法为高达3.3的python版本构建了PIL(仅适用于Windows):http ://www.lfd.uci.edu/~gohlke/pythonlibs/

我用Python 3.2尝试了他的PIL版本,并且图像打开/创建/像素操作/保存了所有工作。

Christoph Gohlke managed to build PIL (for Windows only) for python versions up to 3.3: http://www.lfd.uci.edu/~gohlke/pythonlibs/

I tried his version of PIL with Python 3.2, and image open/create/pixel manipulation/save all work.


回答 2

Qt与图形效果很好。在我看来,它比PIL更通用。

您可以获得图形处理所需的所有功能,但也有矢量图形,甚至支持实际打印机。而所有这些都在一个统一的API中QPainter

要使用Qt,您需要一个Python绑定:PySidePyQt4
它们都支持Python 3。

这是一个简单的示例,该示例加载JPG图像,在坐标(20,20)处绘制半径为10的抗锯齿圆,并使用这些坐标处的像素颜色,并将修改后的图像另存为PNG文件:

from PySide.QtCore import *
from PySide.QtGui import *

app = QCoreApplication([])

img = QImage('input.jpg')

g = QPainter(img)
g.setRenderHint(QPainter.Antialiasing)
g.setBrush(QColor(img.pixel(20, 20)))
g.drawEllipse(QPoint(20, 20), 10, 10)
g.end()

img.save('output.png')

但是请注意,此解决方案是“重量级”的,因为Qt是用于制作GUI应用程序的大型框架。

Qt works very well with graphics. In my opinion it is more versatile than PIL.

You get all the features you want for graphics manipulation, but there’s also vector graphics and even support for real printers. And all of that in one uniform API, QPainter.

To use Qt you need a Python binding for it: PySide or PyQt4.
They both support Python 3.

Here is a simple example that loads a JPG image, draws an antialiased circle of radius 10 at coordinates (20, 20) with the color of the pixel that was at those coordinates and saves the modified image as a PNG file:

from PySide.QtCore import *
from PySide.QtGui import *

app = QCoreApplication([])

img = QImage('input.jpg')

g = QPainter(img)
g.setRenderHint(QPainter.Antialiasing)
g.setBrush(QColor(img.pixel(20, 20)))
g.drawEllipse(QPoint(20, 20), 10, 10)
g.end()

img.save('output.png')

But please note that this solution is quite ‘heavyweight’, because Qt is a large framework for making GUI applications.


回答 3

截至2012年3月30日,我尝试并未能在GitHub上使用sloonz fork打开图像。我把它编译好了,但是实际上没有用。我还尝试构建gohlke的库,它也进行了编译,但是无法打开任何图像。有人在上面提到过PythonMagick,但它只能在Windows上编译。请参阅wxPython Wiki上的PythonMagick

PIL的最新更新是在2009年,虽然它的网站说他们正在使用Python 3端口,但是已经过去了3年,并且邮件列表变得越来越冷。

为了解决我的Python 3图像处理问题,我正在使用subprocess.call()执行ImageMagick shell命令。此方法有效。

请参阅子流程模块文档

As of March 30, 2012, I have tried and failed to get the sloonz fork on GitHub to open images. I got it to compile ok, but it didn’t actually work. I also tried building gohlke’s library, and it compiled also but failed to open any images. Someone mentioned PythonMagick above, but it only compiles on Windows. See PythonMagick on the wxPython wiki.

PIL was last updated in 2009, and while it’s website says they are working on a Python 3 port, it’s been 3 years, and the mailing list has gone cold.

To solve my Python 3 image manipulation problem, I am using subprocess.call() to execute ImageMagick shell commands. This method works.

See the subprocess module documentation.


回答 4

您可以在Python 3上使用我的软件包mahotas。它是基于numpy的,而不是基于PIL的。

You can use my package mahotas on Python 3. It is numpy-based rather than PIL based.


回答 5

您需要Pillow,这是在Python 3上安装它的方法:

pip3 install Pillow

如果那对您不起作用(应该),请尝试normal pip

pip install Pillow

You want the Pillow library, here is how to install it on Python 3:

pip3 install Pillow

If that does not work for you (it should), try normal pip:

pip install Pillow

回答 6

根据需要,scikit-image可能是最佳选择,其处理方式已经超越了PIL和当前版本的Pillow。保养得很好,至少和枕头一样多。而且,底层的数据结构来自Numpy和Scipy,这使其代码具有令人难以置信的互操作性。枕头无法处理的示例:

您可以在图库中看到其力量。 本文提供了一个很好的介绍。祝好运!

Depending on what is needed, scikit-image may be the best choice, with manipulations going way beyond PIL and the current version of Pillow. Very well-maintained, at least as much as Pillow. Also, the underlying data structures are from Numpy and Scipy, which makes its code incredibly interoperable. Examples that pillow can’t handle:

You can see its power in the gallery. This paper provides a great intro to it. Good luck!


回答 7

如果您使用的是Python3,还可以使用库PILasOPENCV,该库可在Python 2和3中使用。函数api调用与PIL或pillow中的函数相同,但在内部它与OpenCV和numpy一起加载,保存和操作图像。看看https://github.com/bunkahle/PILasOPENCV或使用pip install PILasOPENCV进行安装。并非所有PIL功能都已被模拟,但是最常用的功能都可以工作。

If you are on Python3 you can also use the library PILasOPENCV which works in Python 2 and 3. Function api calls are the same as in PIL or pillow but internally it works with OpenCV and numpy to load, save and manipulate images. Have a look at https://github.com/bunkahle/PILasOPENCV or install it with pip install PILasOPENCV. Not all PIL functions have been simulated but the most common functions work.


列表是线程安全的吗?

问题:列表是线程安全的吗?

我注意到经常建议使用具有多个线程的队列,而不是列表和.pop()。这是因为列表不是线程安全的,还是出于其他原因?

I notice that it is often suggested to use queues with multiple threads, instead of lists and .pop(). Is this because lists are not thread-safe, or for some other reason?


回答 0

列表本身是线程安全的。在CPython中,GIL防止对它们的并发访问,而其他实现则要小心地为它们的列表实现使用细粒度锁或同步数据类型。但是,虽然列表本身不会因尝试并发访问而损坏,但是列表的数据不受保护。例如:

L[0] += 1

如果另一个线程做同样的事情,则不能保证实际上将L [0]增加一,因为 +=这不是原子操作。(实际上,Python中很少有原子操作的操作,因为它们中的大多数操作都会导致调用任意Python代码。)您应该使用Queues,因为如果您仅使用不受保护的列表,则可能由于种族而获得或删除了错误的项目条件。

Lists themselves are thread-safe. In CPython the GIL protects against concurrent accesses to them, and other implementations take care to use a fine-grained lock or a synchronized datatype for their list implementations. However, while lists themselves can’t go corrupt by attempts to concurrently access, the lists’s data is not protected. For example:

L[0] += 1

is not guaranteed to actually increase L[0] by one if another thread does the same thing, because += is not an atomic operation. (Very, very few operations in Python are actually atomic, because most of them can cause arbitrary Python code to be called.) You should use Queues because if you just use an unprotected list, you may get or delete the wrong item because of race conditions.


回答 1

为了澄清托马斯出色答案的观点,应该提到的append() 线程安全的。

这是因为不必担心一旦我们去写入数据,读取的数据就会位于同一位置。该操作不读取数据,仅将数据写入列表。append()

To clarify a point in Thomas’ excellent answer, it should be mentioned that append() is thread safe.

This is because there is no concern that data being read will be in the same place once we go to write to it. The append() operation does not read data, it only writes data to the list.


回答 2

list操作示例以及它们是否线程安全的完整但不详尽的列表。希望能得到关于答案obj in a_list的语言结构在这里

Here’s a comprehensive yet non-exhaustive list of examples of list operations and whether or not they are thread safe. Hoping to get an answer regarding the obj in a_list language construct here.


回答 3

我最近遇到过这种情况,我需要在一个线程中连续地追加到列表,循环遍历这些项目,并检查该项目是否准备就绪,在我的情况下,它是一个AsyncResult,只有在准备就绪时才将其从列表中删除。我找不到任何示例可以清楚地说明我的问题。这是一个示例,该示例演示了在一个线程中连续添加到列表,并在另一个线程中连续从同一列表中删除该有缺陷的版本很容易在较小的数字上运行,但保持足够大的数字并运行一个几次,你会看到错误

FLAWED版本

import threading
import time

# Change this number as you please, bigger numbers will get the error quickly
count = 1000
l = []

def add():
    for i in range(count):
        l.append(i)
        time.sleep(0.0001)

def remove():
    for i in range(count):
        l.remove(i)
        time.sleep(0.0001)


t1 = threading.Thread(target=add)
t2 = threading.Thread(target=remove)
t1.start()
t2.start()
t1.join()
t2.join()

print(l)

错误时输出

Exception in thread Thread-63:
Traceback (most recent call last):
  File "/Users/zup/.pyenv/versions/3.6.8/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/Users/zup/.pyenv/versions/3.6.8/lib/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "<ipython-input-30-ecfbac1c776f>", line 13, in remove
    l.remove(i)
ValueError: list.remove(x): x not in list

使用锁的版本

import threading
import time
count = 1000
l = []
lock = threading.RLock()
def add():
    with lock:
        for i in range(count):
            l.append(i)
            time.sleep(0.0001)

def remove():
    with lock:
        for i in range(count):
            l.remove(i)
            time.sleep(0.0001)


t1 = threading.Thread(target=add)
t2 = threading.Thread(target=remove)
t1.start()
t2.start()
t1.join()
t2.join()

print(l)

输出量

[] # Empty list

结论

如前面的回答中所述,虽然从列表本身追加或弹出元素的行为是线程安全的,但当您在一个线程中追加并在另一个线程中弹出时,不是线程安全的

I recently had this case where I needed to append to a list continuously in one thread, loop through the items and check if the item was ready, it was an AsyncResult in my case and remove it from the list only if it was ready. I could not find any examples that demonstrated my problem clearly Here is an example demonstrating adding to list in one thread continuously and removing from the same list in another thread continuously The flawed version runs easily on smaller numbers but keep the numbers big enough and run a few times and you will see the error

The FLAWED version

import threading
import time

# Change this number as you please, bigger numbers will get the error quickly
count = 1000
l = []

def add():
    for i in range(count):
        l.append(i)
        time.sleep(0.0001)

def remove():
    for i in range(count):
        l.remove(i)
        time.sleep(0.0001)


t1 = threading.Thread(target=add)
t2 = threading.Thread(target=remove)
t1.start()
t2.start()
t1.join()
t2.join()

print(l)

Output when ERROR

Exception in thread Thread-63:
Traceback (most recent call last):
  File "/Users/zup/.pyenv/versions/3.6.8/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/Users/zup/.pyenv/versions/3.6.8/lib/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "<ipython-input-30-ecfbac1c776f>", line 13, in remove
    l.remove(i)
ValueError: list.remove(x): x not in list

Version that uses locks

import threading
import time
count = 1000
l = []
lock = threading.RLock()
def add():
    with lock:
        for i in range(count):
            l.append(i)
            time.sleep(0.0001)

def remove():
    with lock:
        for i in range(count):
            l.remove(i)
            time.sleep(0.0001)


t1 = threading.Thread(target=add)
t2 = threading.Thread(target=remove)
t1.start()
t2.start()
t1.join()
t2.join()

print(l)

Output

[] # Empty list

Conclusion

As mentioned in the earlier answers while the act of appending or popping elements from the list itself is thread safe, what is not thread safe is when you append in one thread and pop in another


什么时候应使用iteritems()代替items()?

问题:什么时候应使用iteritems()代替items()?

items()代替iteritems()在所有地方使用是否合法?为什么iteritems()从Python 3 中删除?似乎是一种了不起的,有用的方法。它背后的原因是什么?

编辑:为澄清起见,我想知道以类似于生成器的方式(一次将一项,而不是全部都存储到内存中)以与Python 2和Python 3兼容的方式遍历字典的正确习惯是什么。 ?

Is it legitimate to use items() instead of iteritems() in all places? Why was iteritems() removed from Python 3? Seems like a terrific and useful method. What’s the reasoning behind it?

Edit: To clarify, I want to know what is the correct idiom for iterating over a dictionary in a generator-like way (one item at a time, not all into memory) in a way that is compatible with both Python 2 and Python 3?


回答 0

在Python 2.x中- .items()返回(键,值)对的列表。在Python 3.x中,.items()现在是一个itemview对象,它的行为有所不同-因此必须对其进行迭代或实例化…因此,list(dict.items())对于dict.items()Python 2.x中的对象来说,这是必需的。

Python 2.7版也有一个有点背口密钥处理的,在你有viewkeysviewitems而且viewvalues方法,最有用的存在viewkeys,其表现更像是一个set(你想从预期dict)。

简单的例子:

common_keys = list(dict_a.viewkeys() & dict_b.viewkeys())

会为您提供常见键的列表,但是同样,在Python 3.x中-只需使用即可.keys()

通常使Python 3.x更加“懒惰”-即map现在有效itertools.imapzipis itertools.izip等等。

In Python 2.x – .items() returned a list of (key, value) pairs. In Python 3.x, .items() is now an itemview object, which behaves different – so it has to be iterated over, or materialised… So, list(dict.items()) is required for what was dict.items() in Python 2.x.

Python 2.7 also has a bit of a back-port for key handling, in that you have viewkeys, viewitems and viewvalues methods, the most useful being viewkeys which behaves more like a set (which you’d expect from a dict).

Simple example:

common_keys = list(dict_a.viewkeys() & dict_b.viewkeys())

Will give you a list of the common keys, but again, in Python 3.x – just use .keys() instead.

Python 3.x has generally been made to be more “lazy” – i.e. map is now effectively itertools.imap, zip is itertools.izip, etc.


回答 1

dict.iteritems之所以被删除是因为dict.items现在它dict.iteritems在python 2.x中做了,甚至通过将它变成了itemview

dict.iteritems was removed because dict.items now does the thing dict.iteritems did in python 2.x and even improved it a bit by making it an itemview.


回答 2

六个库有助于编写与python 2.5+和python 3兼容的代码。它具有iteritems方法,可在python 2和3中使用。示例:

import six

d = dict( foo=1, bar=2 )

for k, v in six.iteritems(d):
    print(k, v)

The six library helps with writing code that is compatible with both python 2.5+ and python 3. It has an iteritems method that will work in both python 2 and 3. Example:

import six

d = dict( foo=1, bar=2 )

for k, v in six.iteritems(d):
    print(k, v)

回答 3

就像python 2python 3的字典文档会告诉您的那样,在python 2中items返回一个列表,而iteritems返回一个迭代器。

在python 3中,items返回view,它与迭代器几乎相同。

如果您使用的是python 2,则可能需要iteritems使用大型字典,而您要做的就是遍历所有项目(不必将它们复制到列表中)

As the dictionary documentation for python 2 and python 3 would tell you, in python 2 items returns a list, while iteritems returns a iterator.

In python 3, items returns a view, which is pretty much the same as an iterator.

If you are using python 2, you may want to user iteritems if you are dealing with large dictionaries and all you want to do is iterate over the items (not necessarily copy them to a list)


回答 4

正如@Wessie指出的,dict.iteritemsdict.iterkeysdict.itervalues(它返回一个迭代中Python2.x)以及dict.viewitemsdict.viewkeysdict.viewvalues(其返回查看对象中Python2.x)均在Python3.x除去

dict.itemsdict.keys并且dict.values曾经用于在Python2.x中返回字典列表的副本,现在返回了Python3.x中的视图对象但是它们仍然与iterator并不相同。

如果要在Python3.x中返回迭代器,请使用iter(dictview)

$ python3.3

>>> d = {'one':'1', 'two':'2'}
>>> type(d.items())
<class 'dict_items'>
>>>
>>> type(d.keys())
<class 'dict_keys'>
>>>
>>>
>>> ii = iter(d.items())
>>> type(ii)
<class 'dict_itemiterator'>
>>>
>>> ik = iter(d.keys())
>>> type(ik)
<class 'dict_keyiterator'>

Just as @Wessie noted, dict.iteritems, dict.iterkeys and dict.itervalues (which return an iterator in Python2.x) as well as dict.viewitems, dict.viewkeys and dict.viewvalues (which return view objects in Python2.x) were all removed in Python3.x

And dict.items, dict.keys and dict.values used to return a copy of the dictionary’s list in Python2.x now return view objects in Python3.x, but they are still not the same as iterator.

If you want to return an iterator in Python3.x, use iter(dictview) :

$ python3.3

>>> d = {'one':'1', 'two':'2'}
>>> type(d.items())
<class 'dict_items'>
>>>
>>> type(d.keys())
<class 'dict_keys'>
>>>
>>>
>>> ii = iter(d.items())
>>> type(ii)
<class 'dict_itemiterator'>
>>>
>>> ik = iter(d.keys())
>>> type(ik)
<class 'dict_keyiterator'>

回答 5

不能使用items,而不是iteritems在所有的Python的地方。例如,以下代码:

class C:
  def __init__(self, a):
    self.a = a
  def __iter__(self):
    return self.a.iteritems()

>>> c = C(dict(a=1, b=2, c=3))
>>> [v for v in c]
[('a', 1), ('c', 3), ('b', 2)]

如果使用,将中断items

class D:
  def __init__(self, a):
    self.a = a
  def __iter__(self):
    return self.a.items()

>>> d = D(dict(a=1, b=2, c=3))
>>> [v for v in d]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __iter__ returned non-iterator of type 'list'

viewitems也是如此,这在Python 3中可用。

同样,由于返回字典对列表的副本(key, value),因此效率较低,除非您仍然要创建副本。

在Python 2中,最好iteritems用于迭代。如果您决定升级到Python 3,2to3可以用该工具替换items

You cannot use items instead iteritems in all places in Python. For example, the following code:

class C:
  def __init__(self, a):
    self.a = a
  def __iter__(self):
    return self.a.iteritems()

>>> c = C(dict(a=1, b=2, c=3))
>>> [v for v in c]
[('a', 1), ('c', 3), ('b', 2)]

will break if you use items:

class D:
  def __init__(self, a):
    self.a = a
  def __iter__(self):
    return self.a.items()

>>> d = D(dict(a=1, b=2, c=3))
>>> [v for v in d]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __iter__ returned non-iterator of type 'list'

The same is true for viewitems, which is available in Python 3.

Also, since items returns a copy of the dictionary’s list of (key, value) pairs, it is less efficient, unless you want to create a copy anyway.

In Python 2, it is best to use iteritems for iteration. The 2to3 tool can replace it with items if you ever decide to upgrade to Python 3.


回答 6

future.utils允许python 2和3兼容性

# Python 2 and 3: option 3
from future.utils import iteritems
heights = {'man': 185,'lady': 165}
for (key, value) in iteritems(heights):
    print(key,value)

>>> ('lady', 165)
>>> ('man', 185)

https://python-future.org/compatible_idioms.html

future.utils allows for python 2 and 3 compatibility

# Python 2 and 3: option 3
from future.utils import iteritems
heights = {'man': 185,'lady': 165}
for (key, value) in iteritems(heights):
    print(key,value)

>>> ('lady', 165)
>>> ('man', 185)

https://python-future.org/compatible_idioms.html


向后移植将Python 3 open(encoding =“ utf-8”)移植到Python 2

问题:向后移植将Python 3 open(encoding =“ utf-8”)移植到Python 2

我有一个为Python 3构建的Python代码库,它使用带有编码参数的Python 3样式的open():

https://github.com/miohtama/vvv/blob/master/vvv/textlineplugin.py#L47

    with open(fname, "rt", encoding="utf-8") as f:

现在,我想将此代码反向移植到Python 2.x,这样我将拥有一个可用于Python 2和Python 3的代码库。

建议的解决方法是什么 open()差异和缺乏编码参数的什么?

我可以使用Python 3 open()样式的文件处理程序来流字节字符串,以便像Python 2那样工作open()吗?

I have a Python codebase, built for Python 3, which uses Python 3 style open() with encoding parameter:

https://github.com/miohtama/vvv/blob/master/vvv/textlineplugin.py#L47

    with open(fname, "rt", encoding="utf-8") as f:

Now I’d like to backport this code to Python 2.x, so that I would have a codebase which works with Python 2 and Python 3.

What’s the recommended strategy to work around open() differences and lack of encoding parameter?

Could I have a Python 3 open() style file handler which streams bytestrings, so it would act like Python 2 open()?


回答 0

1.在Python 2中获取编码参数:

如果您只需要支持Python 2.6和2.7,则可以使用io.open代替openio是Python 3的新io子系统,它也存在于Python 2,6 ans 2.7中。请注意,在Python 2.6(以及3.0)中,它是完全在python中实现的,并且运行速度非常慢,因此,如果您需要快速读取文件,则不是一个好的选择。

如果需要速度,并且需要支持Python 2.6或更早版本,则可以codecs.open改用。它也有一个编码参数,io.open除了它以不同的方式处理行尾之外,它与之非常相似。

2.要获取open()可流字节串的Python 3 样式文件处理程序,请执行以下操作:

open(filename, 'rb')

注意“ b”,意思是“二进制”。

1. To get an encoding parameter in Python 2:

If you only need to support Python 2.6 and 2.7 you can use io.open instead of open. io is the new io subsystem for Python 3, and it exists in Python 2,6 ans 2.7 as well. Please be aware that in Python 2.6 (as well as 3.0) it’s implemented purely in python and very slow, so if you need speed in reading files, it’s not a good option.

If you need speed, and you need to support Python 2.6 or earlier, you can use codecs.open instead. It also has an encoding parameter, and is quite similar to io.open except it handles line-endings differently.

2. To get a Python 3 open() style file handler which streams bytestrings:

open(filename, 'rb')

Note the ‘b’, meaning ‘binary’.


回答 1

我认为

from io import open

应该做。

I think

from io import open

should do.


回答 2

这是一种方法:

with open("filename.txt", "rb") as f:
    contents = f.read().decode("UTF-8")

Here’s one way:

with open("filename.txt", "rb") as f:
    contents = f.read().decode("UTF-8")

回答 3

这可能会达到目的:

import sys
if sys.version_info[0] > 2:
    # py3k
    pass
else:
    # py2
    import codecs
    import warnings
    def open(file, mode='r', buffering=-1, encoding=None,
             errors=None, newline=None, closefd=True, opener=None):
        if newline is not None:
            warnings.warn('newline is not supported in py2')
        if not closefd:
            warnings.warn('closefd is not supported in py2')
        if opener is not None:
            warnings.warn('opener is not supported in py2')
        return codecs.open(filename=file, mode=mode, encoding=encoding,
                    errors=errors, buffering=buffering)

然后,您可以使用python3方式保留代码。

请注意,一些API一样newlineclosefdopener不工作

This may do the trick:

import sys
if sys.version_info[0] > 2:
    # py3k
    pass
else:
    # py2
    import codecs
    import warnings
    def open(file, mode='r', buffering=-1, encoding=None,
             errors=None, newline=None, closefd=True, opener=None):
        if newline is not None:
            warnings.warn('newline is not supported in py2')
        if not closefd:
            warnings.warn('closefd is not supported in py2')
        if opener is not None:
            warnings.warn('opener is not supported in py2')
        return codecs.open(filename=file, mode=mode, encoding=encoding,
                    errors=errors, buffering=buffering)

Then you can keep you code in the python3 way.

Note that some APIs like newline, closefd, opener do not work


回答 4

如果您使用six,则可以尝试使用最新的Python 3 API并可以在Python 2/3中运行:

import six

if six.PY2:
    # FileNotFoundError is only available since Python 3.3
    FileNotFoundError = IOError
    from io import open

fname = 'index.rst'
try:
    with open(fname, "rt", encoding="utf-8") as f:
        pass
        # do_something_with_f ...
except FileNotFoundError:
    print('Oops.')

而且,放弃Python 2支持只是删除与相关的所有内容six

If you are using six, you can try this, by which utilizing the latest Python 3 API and can run in both Python 2/3:

import six

if six.PY2:
    # FileNotFoundError is only available since Python 3.3
    FileNotFoundError = IOError
    from io import open

fname = 'index.rst'
try:
    with open(fname, "rt", encoding="utf-8") as f:
        pass
        # do_something_with_f ...
except FileNotFoundError:
    print('Oops.')

And, Python 2 support abandon is just deleting everything related to six.


如何在Mac上安装pip3?

问题:如何在Mac上安装pip3?

我正在尝试安装pip3,但没有任何运气。此外,我尝试了sudo install,但没有成功。如何在Mac上安装pip3?

sudo easy_install pip3
Password:
Searching for pip3
Reading https://pypi.python.org/simple/pip3/
Couldn't find index page for 'pip3' (maybe misspelled?)
Scanning index of all packages (this may take a while)
Reading https://pypi.python.org/simple/

No local packages or download links found for pip3
error: Could not find suitable distribution for Requirement.parse('pip3')

I’m trying to install pip3, but I’m not having any luck. Also, I tried sudo install and it did not work. How could I install pip3 on my Mac?

sudo easy_install pip3
Password:
Searching for pip3
Reading https://pypi.python.org/simple/pip3/
Couldn't find index page for 'pip3' (maybe misspelled?)
Scanning index of all packages (this may take a while)
Reading https://pypi.python.org/simple/

No local packages or download links found for pip3
error: Could not find suitable distribution for Requirement.parse('pip3')

回答 0

更新-1.5之后的自制版本

根据官方的Homebrew页面

在2018年3月1日,python公式将升级到Python 3.x,并且将添加python @ 2公式以安装Python 2.7(尽管这仅是小桶,因此默认情况下python和python2都不会添加到PATH中,而无需手动冲泡链接–force)。我们将维护python2,python3和python @ 3别名。

因此,要安装Python 3,请运行以下命令:

brew install python3

然后,pippip3会自动安装,您可以通过安装任何软件包pip install <package>


旧版本的Homebrew

不仅brew install python3而且brew postinstall python3

因此,您必须运行:

brew install python3
brew postinstall python3

请注意,您应该检查控制台,因为它可能会导致您出错,并且在这种情况下,pip3不会安装。

UPDATED – Homebrew version after 1.5

According to the official Homebrew page:

On 1st March 2018 the python formula will be upgraded to Python 3.x and a python@2 formula will be added for installing Python 2.7 (although this will be keg-only so neither python nor python2 will be added to the PATH by default without a manual brew link –force). We will maintain python2, python3 and python@3 aliases.

So to install Python 3, run the following command:

brew install python3

Then, the pip or pip3 is installed automatically, and you can install any package by pip install <package>.


The older version of Homebrew

Not only brew install python3 but also brew postinstall python3

So you must run:

brew install python3
brew postinstall python3

Note that you should check the console, as it might get you errors and in that case, the pip3 is NOT installed.


回答 1

你可以用 自制的

然后运行:

brew install python3

You could use home-brew

Then just run:

brew install python3

回答 2

我用以下命令解决了相同的问题:

curl -O https://bootstrap.pypa.io/get-pip.py
sudo python3 get-pip.py

I solved the same problem with these commands:

curl -O https://bootstrap.pypa.io/get-pip.py
sudo python3 get-pip.py

回答 3

对我来说brew postinstall python3没用。在GitHub自制问题页面上找到了此解决方案:

$ brew rm python 
$ rm -rf /usr/local/opt/python
$ brew cleanup 
$ brew install python3

For me brew postinstall python3 didn’t work. Found this solution on GitHub homebrew issues page:

$ brew rm python 
$ rm -rf /usr/local/opt/python
$ brew cleanup 
$ brew install python3

回答 4

Python3成功运行,但没有pip3。尝试了许多来自stackoverflow,quora等的建议。(大量安装和卸载)

Python3总是很好,但是没有pip3。最后,我从以下网址下载了Python3:https://www.python.org/downloads/

只需单击鼠标,一切(Python3 + pip3)现在都可以正常工作。

Python3 was working successfully but without pip3. Tried many advises from stackoverflow, quora and others. (numerous installs and uninstalls)

Python3 was always fine but without pip3. Finally I downloaded Python3 from: https://www.python.org/downloads/

By simple mouse clicks and everything (Python3 + pip3) is working fine now.


回答 5

要安装或升级pip,官方网站下载get-pip.py。然后运行以下命令:

sudo python get-pip.py 

它将安装pip为您的运行脚本的python版本。

To install or upgrade pip, download get-pip.py from the official site. Then run the following command:

sudo python get-pip.py 

and it will install pip for your python version which runs the script.


回答 6

类似于Oksana,但添加了python3

$ brew rm python 
$ brew rm python3 
$ rm -rf /usr/local/opt/python
$ rm -rf /usr/local/opt/python3
$ brew prune 
$ brew install python3
$ brew postinstall python3

似乎现在适用于Mac OS X 10.13.3 Xcode 9.2的pip3

Similar to Oksana but add python3

$ brew rm python 
$ brew rm python3 
$ rm -rf /usr/local/opt/python
$ rm -rf /usr/local/opt/python3
$ brew prune 
$ brew install python3
$ brew postinstall python3

Seem now work for pip3 under mac os x 10.13.3 Xcode 9.2


回答 7

我在目录中运行以下<user>:<group><user>:<group>其他文件匹配的其他文件/usr/local/lib/python3.7/site-packages/

sudo chown -R <user>:<group> /usr/local/lib/python3.7/site-packages/pip*
brew postinstall python3

I ran the below where <user>:<group> matched the other <user>:<group> for other files in the /usr/local/lib/python3.7/site-packages/ directory:

sudo chown -R <user>:<group> /usr/local/lib/python3.7/site-packages/pip*
brew postinstall python3

回答 8

我也遇到了同样的问题,但brew install python3无法正常安装pip3

布雷会发出警告The post-install step did not complete successfully

它与自制有关,没有许可 /usr/local

创建目录(如果不存在)

sudo mkdir lib 
sudo mkdir Frameworks

在内部/usr/local授予自制权限,以便可以访问它们:

sudo chown -R $(whoami) $(brew --prefix)/*

现在ostinstall python3

brew postinstall python3

这将为您成功安装

I also encountered the same problem but brew install python3 does not work properly to install pip3.

brre will throw the warning The post-install step did not complete successfully.

It has to do with homebrew does not have permission to /usr/local

Create the directory if not exist

sudo mkdir lib 
sudo mkdir Frameworks

Give the permissions inside /usr/local to homebrew so it can access them:

sudo chown -R $(whoami) $(brew --prefix)/*

Now ostinstall python3

brew postinstall python3

This will give you a successful installation


回答 9

升级到Mac OS Catalina之后,并升级了所有vEnv模块,pip3停止工作(产生错误:“ TypeError:’模块’对象不可调用”)。

找到问题58386953,导致这里出现问题并解决。

  1. 从vEnv退出(我启动了新的Shell)
  2. sudo python3 -m pip uninstall pip (这是必要的,但没有解决问题,因为它删除了基本的Python点子,但没有碰到我的vEnv点子)
  3. sudo easy_install pip (在基本Python中而不是vEnv中重新安装pip)
  4. cd到您的计算机上,vEnv/bin然后键入“ source activate”进入vEnv
  5. rm pip pip3 pip3.6 (似乎是摆脱vEnv中虚假点的唯一方法)
  6. 现在pip已从vEnv中消失,我们可以在基本Python中使用一个(我无法在删除后将pip成功安装到vEnv中)

After upgrading to Mac OS Catalina, and upgrading all my vEnv modules, pip3 stopped working (gave error: “TypeError: ‘module’ object is not callable”).

Found question 58386953 which led to here and solution.

  1. Exit from vEnv (I started fresh shell)
  2. sudo python3 -m pip uninstall pip (this is necessary, but did not fix problem, because it removed the base Python pip, but didn’t touch my vEnv pip)
  3. sudo easy_install pip (reinstalling pip in base Python, not in vEnv)
  4. cd to your vEnv/bin and type “source activate” to get into vEnv
  5. rm pip pip3 pip3.6 (seems to be the only way to get rid of the bogus pip’s in vEnv)
  6. Now pip is gone from vEnv, and we can use the one in the base Python (I wasn’t able to successfully install pip into vEnv after deleting)

回答 10

如果您使用的是python3,请执行python3 get-pip.py。只是一个简单的命令。

if you’re using python3 just execute python3 get-pip.py . Just a simple command.