分类目录归档:知识问答

如何复制字典并仅编辑副本

问题:如何复制字典并仅编辑副本

有人可以向我解释一下吗?这对我来说毫无意义。

我将字典复制到另一个字典中,然后编辑第二个字典,并且两者都已更改。为什么会这样呢?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}

Can someone please explain this to me? This doesn’t make any sense to me.

I copy a dictionary into another and edit the second and both are changed. Why is this happening?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}

回答 0

Python 绝不会隐式复制对象。设置时dict2 = dict1,将使它们引用同一精确的dict对象,因此,在对它进行突变时,对其的所有引用都将始终引用该对象的当前状态。

如果要复制字典(这种情况很少见),则必须使用

dict2 = dict(dict1)

要么

dict2 = dict1.copy()

Python never implicitly copies objects. When you set dict2 = dict1, you are making them refer to the same exact dict object, so when you mutate it, all references to it keep referring to the object in its current state.

If you want to copy the dict (which is rare), you have to do so explicitly with

dict2 = dict(dict1)

or

dict2 = dict1.copy()

回答 1

分配时dict2 = dict1,您并没有复制该文件的副本dict1,导致dict2它只是它的另一个名称dict1

要复制字典等可变类型,请使用copy/ deepcopycopy模块。

import copy

dict2 = copy.deepcopy(dict1)

When you assign dict2 = dict1, you are not making a copy of dict1, it results in dict2 being just another name for dict1.

To copy the mutable types like dictionaries, use copy / deepcopy of the copy module.

import copy

dict2 = copy.deepcopy(dict1)

回答 2

虽然dict.copy()dict(dict1)生成副本,但它们只是浅表副本。如果要拷贝,copy.deepcopy(dict1)则是必需的。一个例子:

>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = x.copy()
>>> copy2 = dict(x)
>>> import copy
>>> copy3 = copy.deepcopy(x)
>>> source['a'] = 10  # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40  # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3  # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}

关于浅层副本与深层副本,来自Python copy模块docs

浅表复制和深度复制之间的区别仅与复合对象(包含其他对象的对象,如列表或类实例)有关:

  • 浅表副本构造一个新的复合对象,然后(在可能的范围内)将对原始对象中找到的对象的引用插入其中。
  • 深层副本将构造一个新的复合对象,然后递归地将原始对象中发现的对象的副本插入其中。

While dict.copy() and dict(dict1) generates a copy, they are only shallow copies. If you want a deep copy, copy.deepcopy(dict1) is required. An example:

>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = x.copy()
>>> copy2 = dict(x)
>>> import copy
>>> copy3 = copy.deepcopy(x)
>>> source['a'] = 10  # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40  # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3  # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}

Regarding shallow vs deep copies, from the Python copy module docs:

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

  • A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
  • A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

回答 3

在python 3.5+上,有一种更简单的方法可以通过使用**解包运算符来实现浅表副本。由Pep 448定义。

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}

**将字典解包为新字典,然后将其分配给dict2。

我们还可以确认每个词典都有不同的ID。

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

如果需要深层副本,那么仍然可以使用copy.deepcopy()

On python 3.5+ there is an easier way to achieve a shallow copy by using the ** unpackaging operator. Defined by Pep 448.

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}

** unpackages the dictionary into a new dictionary that is then assigned to dict2.

We can also confirm that each dictionary has a distinct id.

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

If a deep copy is needed then copy.deepcopy() is still the way to go.


回答 4

最好的和最简单的方法创建一个副本一个的字典中都Python的2.7和3是…

要创建简单(单级)字典的副本:

1.使用dict()方法,而不是生成指向现有dict的引用。

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2.使用python字典的内置update()方法。

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

要创建嵌套或复杂字典的副本:

使用内置的复制模块,该模块提供通用的浅层和深层复制操作。Python 2.7和3中都提供了此模块。*

import copy

my_dict2 = copy.deepcopy(my_dict1)

The best and the easiest ways to create a copy of a dict in both Python 2.7 and 3 are…

To create a copy of simple(single-level) dictionary:

1. Using dict() method, instead of generating a reference that points to the existing dict.

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2. Using the built-in update() method of python dictionary.

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

To create a copy of nested or complex dictionary:

Use the built-in copy module, which provides a generic shallow and deep copy operations. This module is present in both Python 2.7 and 3.*

import copy

my_dict2 = copy.deepcopy(my_dict1)

回答 5

您也可以使用字典理解功能来制作新字典。这样可以避免导入副本。

dout = dict((k,v) for k,v in mydict.items())

当然,在python> = 2.7中,您可以执行以下操作:

dout = {k:v for k,v in mydict.items()}

但是对于向后兼容,顶级方法更好。

You can also just make a new dictionary with a dictionary comprehension. This avoids importing copy.

dout = dict((k,v) for k,v in mydict.items())

Of course in python >= 2.7 you can do:

dout = {k:v for k,v in mydict.items()}

But for backwards compat., the top method is better.


回答 6

除了提供的其他解决方案外,您还可以**将字典集成到一个空字典中,例如,

shallow_copy_of_other_dict = {**other_dict}

现在,您将拥有的“浅”副本other_dict

应用于您的示例:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = {**dict1}
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>>

指针:浅拷贝和深拷贝之间的区别

In addition to the other provided solutions, you can use ** to integrate the dictionary into an empty dictionary, e.g.,

shallow_copy_of_other_dict = {**other_dict}.

Now you will have a “shallow” copy of other_dict.

Applied to your example:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = {**dict1}
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>>

Pointer: Difference between shallow and deep copys


回答 7

Python中的赋值语句不复制对象,它们在目标和对象之间创建绑定。

因此,dict2 = dict1它会在dict2dict1引用的对象之间产生另一个绑定。

如果要复制字典,可以使用copy module。复制模块有两个接口:

copy.copy(x)
Return a shallow copy of x.

copy.deepcopy(x)
Return a deep copy of x.

浅表复制和深度复制之间的区别仅与复合对象(包含其他对象的对象,如列表或类实例)有关:

浅拷贝构造新化合物对象,然后(在可能的范围)插入到它的对象引用原始发现。

深层副本构造新化合物的对象,然后,递归地,插入拷贝到它的目的在原始发现。

例如,在python 2.7.9中:

>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')

结果是:

>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]

Assignment statements in Python do not copy objects, they create bindings between a target and an object.

so, dict2 = dict1, it results another binding between dict2and the object that dict1 refer to.

if you want to copy a dict, you can use the copy module. The copy module has two interface:

copy.copy(x)
Return a shallow copy of x.

copy.deepcopy(x)
Return a deep copy of x.

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.

A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

For example, in python 2.7.9:

>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')

and the result is:

>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]

回答 8

您可以通过dict使用其他关键字参数调用构造函数来一次性复制和编辑新构造的副本:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}

You can copy and edit the newly constructed copy in one go by calling the dict constructor with additional keyword arguments:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}

回答 9

最初,这也使我感到困惑,因为我来自C语言。

在C语言中,变量是内存中定义类型的位置。分配给变量会将数据复制到变量的存储位置。

但是在Python中,变量的作用更像是指向对象的指针。因此,将一个变量分配给另一个变量不会产生副本,只会使该变量名称指向同一对象。

This confused me too, initially, because I was coming from a C background.

In C, a variable is a location in memory with a defined type. Assigning to a variable copies the data into the variable’s memory location.

But in Python, variables act more like pointers to objects. So assigning one variable to another doesn’t make a copy, it just makes that variable name point to the same object.


回答 10

python中的每个变量(类似于dict1str或的东西__builtins__都是指向机器内部某些隐藏的柏拉图“对象”的指针。

如果设置dict1 = dict2,则只需指向dict1与相同的对象(或内存位置,或类似的对象)dict2。现在,所引用的对象与所引用的对象dict1相同dict2

您可以检查:dict1 is dict2应该是True。另外,id(dict1)应与相同id(dict2)

您想要dict1 = copy(dict2)dict1 = deepcopy(dict2)

copy和之间的区别deepcopydeepcopy将确保dict2(您是否将其指向列表?)的元素也是副本。

我用的不是deepcopy很多-在我看来,编写需要它的代码通常是不明智的做法。

Every variable in python (stuff like dict1 or str or __builtins__ is a pointer to some hidden platonic “object” inside the machine.

If you set dict1 = dict2,you just point dict1 to the same object (or memory location, or whatever analogy you like) as dict2. Now, the object referenced by dict1 is the same object referenced by dict2.

You can check: dict1 is dict2 should be True. Also, id(dict1) should be the same as id(dict2).

You want dict1 = copy(dict2), or dict1 = deepcopy(dict2).

The difference between copy and deepcopy? deepcopy will make sure that the elements of dict2 (did you point it at a list?) are also copies.

I don’t use deepcopy much – it’s usually poor practice to write code that needs it (in my opinion).


回答 11

dict1是引用基础字典对象的符号。分配dict1dict2仅分配相同的参考。通过dict2符号更改键的值会更改基础对象,这也会影响dict1。这很混乱。

关于不可变值的推理要比引用容易得多,因此请尽可能制作副本:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

在语法上与以下内容相同:

one_year_later = dict(person, age=26)

dict1 is a symbol that references an underlying dictionary object. Assigning dict1 to dict2 merely assigns the same reference. Changing a key’s value via the dict2 symbol changes the underlying object, which also affects dict1. This is confusing.

It is far easier to reason about immutable values than references, so make copies whenever possible:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

This is syntactically the same as:

one_year_later = dict(person, age=26)

回答 12

dict2 = dict1不复制字典。它只是为程序员提供了第二种方法(dict2)来引用同一词典。

dict2 = dict1 does not copy the dictionary. It simply gives you the programmer a second way (dict2) to refer to the same dictionary.


回答 13

>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

复制Dict对象的方法很多,我只是简单地使用

dict_1 = {
           'a':1,
           'b':2
         }
dict_2 = {}
dict_2.update(dict_1)
>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

There are many ways to copy Dict object, I simply use

dict_1 = {
           'a':1,
           'b':2
         }
dict_2 = {}
dict_2.update(dict_1)

回答 14

正如其他人所解释的,内置dict功能无法满足您的需求。但是在Python2中(可能还有3个),您可以轻松地创建一个ValueDict用于复制的类,=因此可以确保原始版本不会更改。

class ValueDict(dict):

    def __ilshift__(self, args):
        result = ValueDict(self)
        if isinstance(args, dict):
            dict.update(result, args)
        else:
            dict.__setitem__(result, *args)
        return result # Pythonic LVALUE modification

    def __irshift__(self, args):
        result = ValueDict(self)
        dict.__delitem__(result, args)
        return result # Pythonic LVALUE modification

    def __setitem__(self, k, v):
        raise AttributeError, \
            "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)

    def __delitem__(self, k):
        raise AttributeError, \
            "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)

    def update(self, d2):
        raise AttributeError, \
            "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""


# test
d = ValueDict()

d <<='apples', 5
d <<='pears', 8
print "d =", d

e = d
e <<='bananas', 1
print "e =", e
print "d =", d

d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']


# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1

# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."

请参考此处讨论的左值修改模式:Python 2.7-左值修改的纯语法。关键的观察是,strint表现为在Python值(即使它们实际上是引擎盖下的不可变对象)。当您观察到这一点时,也请注意,关于str或,没有什么神奇的特别之处intdict可以以几乎相同的方式使用,我可以想到很多ValueDict有意义的情况。

As others have explained, the built-in dict does not do what you want. But in Python2 (and probably 3 too) you can easily create a ValueDict class that copies with = so you can be sure that the original will not change.

class ValueDict(dict):

    def __ilshift__(self, args):
        result = ValueDict(self)
        if isinstance(args, dict):
            dict.update(result, args)
        else:
            dict.__setitem__(result, *args)
        return result # Pythonic LVALUE modification

    def __irshift__(self, args):
        result = ValueDict(self)
        dict.__delitem__(result, args)
        return result # Pythonic LVALUE modification

    def __setitem__(self, k, v):
        raise AttributeError, \
            "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)

    def __delitem__(self, k):
        raise AttributeError, \
            "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)

    def update(self, d2):
        raise AttributeError, \
            "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""


# test
d = ValueDict()

d <<='apples', 5
d <<='pears', 8
print "d =", d

e = d
e <<='bananas', 1
print "e =", e
print "d =", d

d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']


# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1

# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."

Please refer to the lvalue modification pattern discussed here: Python 2.7 – clean syntax for lvalue modification. The key observation is that str and int behave as values in Python (even though they’re actually immutable objects under the hood). While you’re observing that, please also observe that nothing is magically special about str or int. dict can be used in much the same ways, and I can think of many cases where ValueDict makes sense.


回答 15

以下代码,是遵循json语法的字典的,比deepcopy快3倍以上

def CopyDict(dSrc):
    try:
        return json.loads(json.dumps(dSrc))
    except Exception as e:
        Logger.warning("Can't copy dict the preferred way:"+str(dSrc))
        return deepcopy(dSrc)

the following code, which is on dicts which follows json syntax more than 3 times faster than deepcopy

def CopyDict(dSrc):
    try:
        return json.loads(json.dumps(dSrc))
    except Exception as e:
        Logger.warning("Can't copy dict the preferred way:"+str(dSrc))
        return deepcopy(dSrc)

回答 16

尝试深复制类w / o将其分配给变量的字典属性时,遇到了一种特殊的行为

new = copy.deepcopy(my_class.a)不起作用,即修改new修改my_class.a

但是,如果您这样做old = my_class.a,那么new = copy.deepcopy(old)它会完美运行,即修改new不会影响my_class.a

我不确定为什么会发生这种情况,但希望它可以节省一些时间!:)

i ran into a peculiar behavior when trying to deep copy dictionary property of class w/o assigning it to variable

new = copy.deepcopy(my_class.a) doesn’t work i.e. modifying new modifies my_class.a

but if you do old = my_class.a and then new = copy.deepcopy(old) it works perfectly i.e. modifying new does not affect my_class.a

I am not sure why this happens, but hope it helps save some hours! :)


回答 17

因为dict2 = dict1,dict2保存了对dict1的引用。dict1和dict2都指向内存中的同一位置。这是在python中使用可变对象时的正常情况。使用python中的可变对象时,必须小心,因为它很难调试。如下面的例子。

 my_users = {
        'ids':[1,2],
        'blocked_ids':[5,6,7]
 }
 ids = my_users.get('ids')
 ids.extend(my_users.get('blocked_ids')) #all_ids
 print ids#output:[1, 2, 5, 6, 7]
 print my_users #output:{'blocked_ids': [5, 6, 7], 'ids': [1, 2, 5, 6, 7]}

此示例意图是获取所有用户ID,包括被阻止的ID。我们是从ids变量获得的,但是我们也无意间更新了my_users的值。当你扩展的IDSblocked_ids my_users得到了更新,因为IDS参考my_users

because, dict2 = dict1, dict2 holds the reference to dict1. Both dict1 and dict2 points to the same location in the memory. This is just a normal case while working with mutable objects in python. When you are working with mutable objects in python you must be careful as it is hard to debug. Such as the following example.

 my_users = {
        'ids':[1,2],
        'blocked_ids':[5,6,7]
 }
 ids = my_users.get('ids')
 ids.extend(my_users.get('blocked_ids')) #all_ids
 print ids#output:[1, 2, 5, 6, 7]
 print my_users #output:{'blocked_ids': [5, 6, 7], 'ids': [1, 2, 5, 6, 7]}

This example intention is to get all the user ids including blocked ids. That we got from ids variable but we also updated the value of my_users unintentionally. when you extended the ids with blocked_ids my_users got updated because ids refer to my_users.


回答 18

使用for循环进行复制:

orig = {"X2": 674.5, "X3": 245.0}

copy = {}
for key in orig:
    copy[key] = orig[key]

print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}

Copying by using a for loop:

orig = {"X2": 674.5, "X3": 245.0}

copy = {}
for key in orig:
    copy[key] = orig[key]

print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}

回答 19

您可以直接使用:

dict2 = eval(repr(dict1))

其中对象dict2是dict1的独立副本,因此您可以修改dict2而不会影响dict1。

这适用于任何类型的对象。

You can use directly:

dict2 = eval(repr(dict1))

where object dict2 is an independent copy of dict1, so you can modify dict2 without affecting dict1.

This works for any kind of object.


错误:找不到vcvarsall.bat

问题:错误:找不到vcvarsall.bat

我试图安装Python软件包dulwich

pip install dulwich

但是我收到了一个神秘的错误消息:

error: Unable to find vcvarsall.bat

如果我尝试手动安装软件包,也会发生相同的情况:

> python setup.py install
running build_ext
building 'dulwich._objects' extension
error: Unable to find vcvarsall.bat

I tried to install the Python package dulwich:

pip install dulwich

But I get a cryptic error message:

error: Unable to find vcvarsall.bat

The same happens if I try installing the package manually:

> python setup.py install
running build_ext
building 'dulwich._objects' extension
error: Unable to find vcvarsall.bat

回答 0

更新:评论指出此处的说明可能很危险。考虑使用Visual C ++ 2008 Express版或专用于Python的Microsoft Visual C ++编译器详细信息),而不要使用下面的原始答案。原始错误消息表示未安装所需的Visual C ++版本。


对于Windows安装:

在运行setup.py进行软件包安装时,Python 2.7搜索已安装的Visual Studio2008。您可以通过VS90COMNTOOLS在调用之前在环境变量中设置正确的路径来诱使Python使用更新的Visual Studio setup.py

根据安装的Visual Studio版本执行以下命令:

  • Visual Studio 2010(VS10): SET VS90COMNTOOLS=%VS100COMNTOOLS%
  • Visual Studio 2012(VS11): SET VS90COMNTOOLS=%VS110COMNTOOLS%
  • Visual Studio 2013(VS12): SET VS90COMNTOOLS=%VS120COMNTOOLS%
  • Visual Studio 2015(VS14): SET VS90COMNTOOLS=%VS140COMNTOOLS%

警告:如下所述,如果您尝试编译python模块,则此答案不太可能起作用。

有关详细信息,请参见在Windows上为Python 2.7构建lxml

Update: Comments point out that the instructions here may be dangerous. Consider using the Visual C++ 2008 Express edition or the purpose-built Microsoft Visual C++ Compiler for Python (details) and NOT using the original answer below. Original error message means the required version of Visual C++ is not installed.


For Windows installations:

While running setup.py for package installations, Python 2.7 searches for an installed Visual Studio 2008. You can trick Python to use a newer Visual Studio by setting the correct path in VS90COMNTOOLS environment variable before calling setup.py.

Execute the following command based on the version of Visual Studio installed:

  • Visual Studio 2010 (VS10): SET VS90COMNTOOLS=%VS100COMNTOOLS%
  • Visual Studio 2012 (VS11): SET VS90COMNTOOLS=%VS110COMNTOOLS%
  • Visual Studio 2013 (VS12): SET VS90COMNTOOLS=%VS120COMNTOOLS%
  • Visual Studio 2015 (VS14): SET VS90COMNTOOLS=%VS140COMNTOOLS%

WARNING: As noted below, this answer is unlikely to work if you are trying to compile python modules.

See Building lxml for Python 2.7 on Windows for details.


回答 1

我找到了解决方案。我安装了“ amara”时遇到了完全相同的问题,并且出现了错误。我安装了mingw32,但需要配置distutils。

  1. 我已经安装了Python 2.6。
  2. 我安装了mingw32 C:\programs\mingw\
  3. 将mingw32的bin目录添加到您的环境变量中:附加c:\programs\MinGW\bin;PATH
  4. 编辑位于以下位置的distutils.cfg文件(如果不存在则创建)C:\Python26\Lib\distutils\distutils.cfg

    [build]
    compiler=mingw32
  5. 现在运行easy_install.exe amara

确保通过打开新环境来设置环境cmd.exe

I found the solution. I had the exact same problem, and error, installing ‘amara’. I had mingw32 installed, but distutils needed to be configured.

  1. I have Python 2.6 that was already installed.
  2. I installed mingw32 to C:\programs\mingw\
  3. Add mingw32’s bin directory to your environment variable: append c:\programs\MinGW\bin; to the PATH
  4. Edit (create if not existing) distutils.cfg file located at C:\Python26\Lib\distutils\distutils.cfg to be:

    [build]
    compiler=mingw32
    
  5. Now run easy_install.exe amara.

Make sure environment is set by opening a new cmd.exe.


回答 2

您可以从http://www.lfd.uci.edu/~gohlke/pythonlibs/安装编译版本


回答 3

如果要使用Visual Studio C ++而不是mingw进行编译…

  1. 运行python.exe以显示使用哪个版本的VC ++(如下所示的示例)。

    它是重要的使用Visual C ++编译器的相应版本的Python用,因为编译distilutilsget_build_version防止混合版本(每彼得的警告)。

    • 黄色(顶部)是使用MSC v.1500(Visual Studio C ++ 2008)编译的Python 2.7。
    • 红色(底部)是使用MSC v.1600(Visual Studio C ++ 2010)编译的Python 3.4.1。

    命令行示例显示了用MSC v.1500编译的Python 2.7和用MSC v.1600编译的Python 3.4.1

  2. 使用下表[1]将内部VC ++版本与相应的Visual Studio版本进行匹配:

    MSC v.1000 -> Visual C++ 4.x        
    MSC v.1100 -> Visual C++ 5          
    MSC v.1200 -> Visual C++ 6          
    MSC v.1300 -> Visual C++ .NET       
    MSC v.1310 -> Visual C++ .NET 2003  
    MSC v.1400 -> Visual C++ 2005  (8.0)
    MSC v.1500 -> Visual C++ 2008  (9.0)
    MSC v.1600 -> Visual C++ 2010 (10.0)
    MSC v.1700 -> Visual C++ 2012 (11.0)
    MSC v.1800 -> Visual C++ 2013 (12.0)
    MSC v.1900 -> Visual C++ 2015 (14.0)
    MSC v.1910 -> Visual C++ 2017 (15.0)
    MSC v.1911 -> Visual C++ 2017 (15.3)
    MSC v.1912 -> Visual C++ 2017 (15.5)
    MSC v.1913 -> Visual C++ 2017 (15.6)
    MSC v.1914 -> Visual C++ 2017 (15.7)
    MSC v.1915 -> Visual C++ 2017 (15.8)
    MSC v.1916 -> Visual C++ 2017 (15.9)   
  3. 从上一步下载并安装相应版本的Visual Studio C ++。
    下面列出了特定版本VC ++的其他说明。

    Visual Studio C ++ 2008的注意事项

    对于只有 32位编译器,下载的Visual Studio C ++ 2008 Express版本

    对于64位编译器[2] [3],请下载Windows 7的Windows SDK和.NET Framework 3.5 SP1

    • 取消选中所有选项,Developer Tools >> Visual C++ Compilers以节省安装SDK工具所需的时间和磁盘空间,否则就不需要使用SDK工具。

    Visual Studio C ++ 2010的注意事项

    根据Microsoft的说法,如果安装了Visual Studio 2010 SP1,则可能已删除VC ++的编译器和库。
    如果是这种情况,请下载Visual C ++ 2010 SP1编译器更新

    Visual Studio C ++ 2015的注意事项

    如果不需要Visual Studio IDE,请下载Visual Studio C ++ 2015构建工具

    Visual Studio C ++ 2017的注意事项

    如果您不需要Visual Studio IDE,请下载Visual Studio 2017的构建工具

    建议:如果您同时安装了32位和64位Python,则可能还希望使用virtualenv创建单独的Python环境,以便一次可以使用一个或另一个,而无需弄乱选择要使用哪个Python版本的路径。采用。

根据@srodriguex的说法,您可以通过遵循以下答案,而不是将一些批处理文件复制到Python正在搜索的位置,从而跳过手动加载批处理文件的步骤(步骤4-6)。如果这不起作用,请执行以下最初对我有用的步骤。

  1. 开一个 cmd.exe

  2. 尝试安装需要C扩展的东西之前,请运行以下批处理文件以将VC ++编译器的环境加载到会话中(即环境变量,编译器的路径等)。

    执行:

    • 32位编译器:

      注意:32位Windows安装将仅C:\Program Files\符合预期

      "C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"

    • 64位编译器:

      "C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars64.bat"

      注意:是的,本机64位编译器位于中Program Files (x86)。不要问我为什么。
      此外,如果您想知道vcvars64.bat和之间的区别,vcvarsx86_amd64.bat或者更重要的是amd64和之间的区别x86_amd64,则前者用于本机64位编译器工具,而后者是可以在32位Windows安装上运行的64位交叉编译器。 。

    更新:
    如果由于某种原因你得到error: ... was unexpected at this time.其中的...一些一系列字符,那么你需要检查你的路径变量没有任何多余的字符,如额外的报价或杂散字符。如果批处理文件最初没有意义,则将无法更新您的会话路径。

  3. 如果一切顺利,则应根据以下版本的VC ++和运行的命令获得以下消息之一:

    对于32位编译器工具:
    Setting environment for using Microsoft Visual Studio 20xx x86 tools.

    对于64位编译器工具:
    Setting environment for using Microsoft Visual Studio 20xx x64 tools.

  4. 现在,通过python setup.py install或运行设置pip install pkg-name

  5. 希望并用手指指望行星正确对齐,以使VC ++能够合作。

If you want to compile with Visual Studio C++ instead of mingw…

  1. Run python.exe to display which version of VC++ it was compiled with (example shown below).

    It is important to use the corresponding version of the Visual C++ compiler that Python was compiled with since distilutils‘s get_build_version prevents mixing versions (per Piotr’s warning).

    • Yellow (top) is Python 2.7, compiled with MSC v.1500 (Visual Studio C++ 2008)
    • Red (bottom) is Python 3.4.1, compiled with MSC v.1600 (Visual Studio C++ 2010)

    Example from the command line showing Python 2.7 compiled with MSC v.1500 and Python 3.4.1 compiled with MSC v.1600

  2. Use the table below[1] to match the internal VC++ version with the corresponding Visual Studio release:

    MSC v.1000 -> Visual C++ 4.x        
    MSC v.1100 -> Visual C++ 5          
    MSC v.1200 -> Visual C++ 6          
    MSC v.1300 -> Visual C++ .NET       
    MSC v.1310 -> Visual C++ .NET 2003  
    MSC v.1400 -> Visual C++ 2005  (8.0)
    MSC v.1500 -> Visual C++ 2008  (9.0)
    MSC v.1600 -> Visual C++ 2010 (10.0)
    MSC v.1700 -> Visual C++ 2012 (11.0)
    MSC v.1800 -> Visual C++ 2013 (12.0)
    MSC v.1900 -> Visual C++ 2015 (14.0)
    MSC v.1910 -> Visual C++ 2017 (15.0)
    MSC v.1911 -> Visual C++ 2017 (15.3)
    MSC v.1912 -> Visual C++ 2017 (15.5)
    MSC v.1913 -> Visual C++ 2017 (15.6)
    MSC v.1914 -> Visual C++ 2017 (15.7)
    MSC v.1915 -> Visual C++ 2017 (15.8)
    MSC v.1916 -> Visual C++ 2017 (15.9)   
    
  3. Download and install the corresponding version of Visual Studio C++ from the previous step.
    Additional notes for specific versions of VC++ are listed below.

    Notes for Visual Studio C++ 2008

    For only the 32-bit compilers, download Visual Studio C++ 2008 Express Edition.

    For the 64-bit compilers[2][3], download Windows SDK for Windows 7 and .NET Framework 3.5 SP1.

    • Uncheck everything except Developer Tools >> Visual C++ Compilers to save time and disk space from installing SDK tools you otherwise don’t need.

    Notes for Visual Studio C++ 2010

    According to Microsoft, if you installed Visual Studio 2010 SP1, it may have removed the compilers and libraries for VC++.
    If that is the case, download Visual C++ 2010 SP1 Compiler Update.

    Notes for Visual Studio C++ 2015

    If you don’t need the Visual Studio IDE, download Visual Studio C++ 2015 Build Tools.

    Notes for Visual Studio C++ 2017

    If you don’t need the Visual Studio IDE, download Build Tools for Visual Studio 2017.

    Suggestion: If you have both a 32- and 64-bit Python installation, you may also want to use virtualenv to create separate Python environments so you can use one or the other at a time without messing with your path to choose which Python version to use.

According to @srodriguex, you may be able to skip manually loading the batch file (Steps 4-6) by instead copying a few batch files to where Python is searching by following this answer. If that doesn’t work, here are the following steps that originally worked for me.

  1. Open up a cmd.exe

  2. Before you try installing something which requires C extensions, run the following batch file to load the VC++ compiler’s environment into the session (i.e. environment variables, the path to the compiler, etc).

    Execute:

    • 32-bit Compilers:

      Note: 32-bit Windows installs will only have C:\Program Files\ as expected

      "C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"

    • 64-bit Compilers:

      "C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars64.bat"

      Note: Yes, the native 64-bit compilers are in Program Files (x86). Don’t ask me why.
      Additionally, if you are wondering what the difference between vcvars64.bat and vcvarsx86_amd64.bat or more importantly the difference between amd64 and x86_amd64, the former are for the native 64-bit compiler tools and the latter are the 64-bit cross compilers that can run on a 32-bit Windows installation.

    Update:
    If for some reason you are getting error: ... was unexpected at this time. where the ... is some series of characters, then you need to check that you path variable does not have any extraneous characters like extra quotations or stray characters. The batch file is not going to be able to update your session path if it can’t make sense of it in the first place.

  3. If that went well, you should get one of the following messages depending on which version of VC++ and which command you ran:

    For the 32-bit compiler tools:
    Setting environment for using Microsoft Visual Studio 20xx x86 tools.

    For the 64-bit compiler tools:
    Setting environment for using Microsoft Visual Studio 20xx x64 tools.

  4. Now, run the setup via python setup.py install or pip install pkg-name

  5. Hope and cross your fingers that the planets are aligned correctly for VC++ to cooperate.


回答 4

这是怎么回事?Python模块可以用C或C ++编写(通常是为了提高速度)。如果尝试使用Pip(或setup.py)安装这样的软件包,则必须从源代码编译该C / C ++。开箱即用,Pip会大胆假设您已安装了Microsoft Visual C ++编译器。如果没有它,您将看到此错误消息“错误:无法找到vcvarsall.bat”。

规定的解决方案是安装C / C ++编译器,Microsoft Visual C ++或MinGW(一个开源项目)。但是,安装和配置任何一个都非常困难。(编辑2014:Microsoft已发布了用于Python 2.7 的特殊C ++编译器

最简单的解决方案是将Christoph Gohlke的Windows安装程序(.msi)用于流行的Python软件包。他为Python 2.x和3.x,32位和64位构建安装程序。您可以从http://www.lfd.uci.edu/~gohlke/pythonlibs/下载它们


如果您也认为“错误:无法找到vcvarsall.bat”是一个含糊不清和无用的消息,请在http://bugs.python.org/issue2943上对该错误进行评论,以更有用和更用户化的方式替换它。友好的消息。

为了进行比较,Ruby附带了软件包管理器Gem,并提供了一个准官方的C / C ++编译器DevKit。如果您尝试安装不带该软件包的软件包,则会看到此有用的友好有用消息:

请更新您的PATH以包含构建工具,或从http://rubyinstaller.org/downloads下载DevKit 并按照http://github.com/oneclick/rubyinstaller/wiki/Development-Kit上的说明进行操作

您可以在https://stackoverflow.com/a/13445719/284795上阅读有关Python打包的更长篇文章

What’s going on? Python modules can be part written in C or C++ (typically for speed). If you try to install such a package with Pip (or setup.py), it has to compile that C/C++ from source. Out the box, Pip will brazenly assume you the compiler Microsoft Visual C++ installed. If you don’t have it, you’ll see this cryptic error message “Error: Unable to find vcvarsall.bat”.

The prescribed solution is to install a C/C++ compiler, either Microsoft Visual C++, or MinGW (an open-source project). However, installing and configuring either is prohibitively difficult. (Edit 2014: Microsoft have published a special C++ compiler for Python 2.7)

The easiest solution is to use Christoph Gohlke’s Windows installers (.msi) for popular Python packages. He builds installers for Python 2.x and 3.x, 32 bit and 64 bit. You can download them from http://www.lfd.uci.edu/~gohlke/pythonlibs/


If you too think “Error: Unable to find vcvarsall.bat” is a ludicrously cryptic and unhelpful message, then please comment on the bug at http://bugs.python.org/issue2943 to replace it with a more helpful and user-friendly message.

For comparison, Ruby ships with a package manager Gem and offers a quasi-official C/C++ compiler, DevKit. If you try to install a package without it, you see this helpful friendly useful message:

Please update your PATH to include build tools or download the DevKit from http://rubyinstaller.org/downloads and follow the instructions at http://github.com/oneclick/rubyinstaller/wiki/Development-Kit

You can read a longer rant about Python packaging at https://stackoverflow.com/a/13445719/284795


回答 5

您需要安装与用于构建Python的编译器兼容的Microsoft编译器。这意味着您需要Visual C ++ 2008(或更高版本,需要进行一些调整)。

微软现在提供一个捆绑的编译器和头能够编译Python扩展,在好记的网址:

适用于Python 2.7的Microsoft Visual C ++编译器

http://aka.ms/vcpython27

这是一个相对较小的包装;下载85MB,无需管理员权限即可安装,无需重新启动。名称有点误导,该编译器适用于最初使用Visual C ++ 2008编译的任何Python版本,而不仅仅是Python 2.7。

如果您启动Python交互式提示或print sys.version,请查找MSC版本字符串;否则,请执行以下操作:如果是这样,MSC v.1500您可以使用此工具。

原始公告到distutils列表

微软已经发布了适用于Python 2.7的编译器软件包,以使人们可以更轻松地在Windows上构建和分发C扩展模块。可从以下网站获得用于Python 2.7的Microsoft Visual C ++编译器(aka VC9):http : //aka.ms/vcpython27

该软件包包含为32位和64位Python 2.7构建C扩展模块所需的所有工具和头文件(请注意,某些扩展模块需要第三方的依赖项,例如OpenSSL或libxml2,但不包括在内)。还支持使用Visual C ++ 2008构建的其他Python版本,因此“ Python 2.7”仅是广告-可以在2.6和3.2上正常工作。

请注意,您需要安装setuptools6.0或更高版本(在下载页面的系统要求中列出)。您正在安装的项目必须使用setuptools.setup(),而不是,distutils否则自动检测将不起作用。

Microsoft已声明他们希望保持URL稳定,以便自动脚本可以轻松引用它。

You’ll need to install a Microsoft compiler, compatible with the compiler used to build Python. This means you need Visual C++ 2008 (or newer, with some tweaking).

Microsoft now supplies a bundled compiler and headers just to be able to compile Python extensions, at the memorable URL:

Microsoft Visual C++ Compiler for Python 2.7

http://aka.ms/vcpython27

This is a relatively small package; 85MB to download, installable without admin privileges, no reboot required. The name is a little misleading, the compiler will work for any Python version originally compiled with Visual C++ 2008, not just Python 2.7.

If you start a Python interactive prompt or print sys.version, look for the MSC version string; if it is MSC v.1500 you can use this tool.

From the original announcement to the distutils list:

Microsoft has released a compiler package for Python 2.7 to make it easier for people to build and distribute their C extension modules on Windows. The Microsoft Visual C++ Compiler for Python 2.7 (a.k.a. VC9) is available from: http://aka.ms/vcpython27

This package contains all the tools and headers required to build C extension modules for Python 2.7 32-bit and 64-bit (note that some extension modules require 3rd party dependencies such as OpenSSL or libxml2 that are not included). Other versions of Python built with Visual C++ 2008 are also supported, so “Python 2.7” is just advertising – it’ll work fine with 2.6 and 3.2.

Note that you need to have setuptools 6.0 or newer installed (listed in the system requirements on the download page). The project you are installing must use setuptools.setup(), not distutils or the auto-detection won’t work.

Microsoft has stated that they want to keep the URL stable, so that automated scripts can reference it easily.


回答 6

我只是遇到了同样的问题,所以我在这里讲述我的故事,希望它可以帮助遇到同样问题的其他人,并为他们节省几个小时的时间:

我在Windows 7盒子中有mingw(g ++(GCC)4.6.1)和python 2.7.3,我正在尝试安装PyCrypto。

运行setup.py install时,所有错误均始于此错误:

error: Unable to find vcvarsall.bat

通过将mingw指定为选择的编译器,可以轻松地在搜索错误之后解决此问题:

setup.py install build --compiler=mingw32

问题是然后我得到了另一个错误:

configure: error: cannot run C compiled programs.

事实证明,我的防病毒软件阻止了新编译的.exe的执行。我只是禁用了防病毒“居民防护罩”,然后转到下一个错误:

cc1.exe: error: unrecognized command line option '-mno-cygwin' 
error: command 'gcc' failed with exit status 1

解决了它:“要么安装稍旧版本的MinGW,要么在您的Python目录中编辑distutils \ cygwinccompiler.py以删除-mno-cygwin的所有实例。” (从这里开始

现在,我终于可以开始工作了。

I just had this same problem, so I’ll tell my story here hoping it helps someone else with the same issues and save them the couple of hours I just spent:

I have mingw (g++ (GCC) 4.6.1) and python 2.7.3 in a windows 7 box and I’m trying to install PyCrypto.

It all started with this error when running setup.py install:

error: Unable to find vcvarsall.bat

Easily solved after googling the error by specifying mingw as the compiler of choice:

setup.py install build --compiler=mingw32

The problem is that then I got a different error:

configure: error: cannot run C compiled programs.

It turns out that my anti-virus was blocking the execution of a freshly compiled .exe. I just disabled the anti-virus “resident shield” and went to the next error:

cc1.exe: error: unrecognized command line option '-mno-cygwin' 
error: command 'gcc' failed with exit status 1

This solved it: “Either install a slightly older version of MinGW, or edit distutils\cygwinccompiler.py in your Python directory to remove all instances of -mno-cygwin.” (from here)

Now, I can finally start working.


回答 7

看起来它正在寻找VC编译器,因此您可以尝试使用来提及编译器类型-c mingw32,因为您拥有msys

python setup.py install -c mingw32

Looks like its looking for VC compilers, so you could try to mention compiler type with -c mingw32, since you have msys

python setup.py install -c mingw32

回答 8

我有python 2.73和Windows 7。对我有用的解决方案是:

  1. 新增的mingw32的bin目录到环境变量:追加PATHC:\programs\mingw\bin;
  2. 创建的distutils.cfg位于C:\Python27\Lib\distutils\distutils.cfg

    [build]
    compiler=mingw32

要处理MinGW不再识别-mno-cygwin标志的情况,请删除C:\ Python27 \ Lib \ distutils \ cygwincompiler.py第322行至326行中的标志,因此如下所示:

  self.set_executables(compiler='gcc -O -Wall',
                         compiler_so='gcc -mdll -O -Wall',
                         compiler_cxx='g++ -O -Wall',
                         linker_exe='gcc',
                         linker_so='%s %s %s'
                                    % (self.linker_dll, shared_option,
                                       entry_point))

I have python 2.73 and windows 7 .The solution that worked for me was:

  1. Added mingw32’s bin directory to environment variable: append PATH with C:\programs\mingw\bin;
  2. Created distutils.cfg located at C:\Python27\Lib\distutils\distutils.cfg containing:

    [build]
    compiler=mingw32
    

To deal with MinGW not recognizing the -mno-cygwin flag anymore, remove the flag in C:\Python27\Lib\distutils\cygwincompiler.py line 322 to 326, so it looks like this:

  self.set_executables(compiler='gcc -O -Wall',
                         compiler_so='gcc -mdll -O -Wall',
                         compiler_cxx='g++ -O -Wall',
                         linker_exe='gcc',
                         linker_so='%s %s %s'
                                    % (self.linker_dll, shared_option,
                                       entry_point))

回答 9

查看setup.py您要安装的软件包的文件。如果是较旧的软件包,则可能是导入distutils.core.setup()而不是setuptools.setup()

我在2015年遇到了以下这些因素:

  1. 来自http://aka.ms/vcpython27的适用于Python 2.7的Microsoft Visual C ++编译器

  2. 使用较旧的软件包 distutils.core.setup()

  3. 尝试做python setup.py build而不是使用pip

如果您使用的是最新版本的pip,则它将强制(monkeypatch)软件包使用setuptools,即使其setup.py对distutils的调用也是如此。但是,如果您不使用pip而是在做python setup.py build,则构建过程将使用distutils.core.setup(),而后者不知道编译器的安装位置。


步骤1:打开适当的Visual C ++ 2008命令提示符

打开“开始”菜单或“开始”屏幕,然后搜索“ Visual C ++ 2008 32位命令提示符”(如果您的Python是32位)或“ Visual C ++ 2008 64位命令提示符”(如果您的Python是64位) 。运行。命令提示符在标题栏中应显示Visual C ++ 2008…。

步骤2:设定环境变数

在刚打开的命令提示符中设置这些环境变量。

SET DISTUTILS_USE_SDK=1
SET MSSdk=1

参考http://bugs.python.org/issue23246

步骤3:建立并安装

cd到要构建并运行的包python setup.py build,然后python setup.py install。如果要安装到virtualenv,请在构建之前将其激活。

Look in the setup.py file of the package you are trying to install. If it is an older package it may be importing distutils.core.setup() rather than setuptools.setup().

I ran in to this (in 2015) with a combination of these factors:

  1. The Microsoft Visual C++ Compiler for Python 2.7 from http://aka.ms/vcpython27

  2. An older package that uses distutils.core.setup()

  3. Trying to do python setup.py build rather than using pip.

If you use a recent version of pip, it will force (monkeypatch) the package to use setuptools, even if its setup.py calls for distutils. However, if you are not using pip, and instead are just doing python setup.py build, the build process will use distutils.core.setup(), which does not know about the compiler install location.


Solution

Step 1: Open the appropriate Visual C++ 2008 Command Prompt

Open the Start menu or Start screen, and search for “Visual C++ 2008 32-bit Command Prompt” (if your python is 32-bit) or “Visual C++ 2008 64-bit Command Prompt” (if your python is 64-bit). Run it. The command prompt should say Visual C++ 2008 … in the title bar.

Step 2: Set environment variables

Set these environment variables in the command prompt you just opened.

SET DISTUTILS_USE_SDK=1
SET MSSdk=1

Reference http://bugs.python.org/issue23246

Step 3: Build and install

cd to the package you want to build, and run python setup.py build, then python setup.py install. If you want to install in to a virtualenv, activate it before you build.


回答 10

也许有人会感兴趣,以下对py2exe软件包有用。(我有Windows 7 64位和便携式python 2.7,带有适用于Windows 7和.NET Framework 4的Windows SDK的Visual Studio 2005 Express)

set VS90COMNTOOLS=%VS80COMNTOOLS%

然后:

python.exe setup.py install

Maybe somebody can be interested, the following worked for me for the py2exe package. (I have windows 7 64 bit and portable python 2.7, Visual Studio 2005 Express with Windows SDK for Windows 7 and .NET Framework 4)

set VS90COMNTOOLS=%VS80COMNTOOLS%

then:

python.exe setup.py install

回答 11

我花了将近2天的时间弄清楚如何在python 3.4 64位版本中解决此问题:Python 3.4.3(v3.4.3:9b73f1c3e601,Feb 24 2015,22:44:40)[MSC v.1600 64位(AMD64 )]在win32上

困难的解决方案1 ​​:(在阅读本文之前,请先阅读下面的解决方案2)最后,这对我有帮助:

  1. 安装Visual C ++ 2010 Express
  2. 为Windows 7安装Microsoft Windows SDK v7.1
  3. 手动创建文件vcvars64.batC:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64其中包含CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64或其他路径,具体取决于安装位置
  4. (这似乎是可选的)针对Windows SDK 7.1安装Microsoft Visual Studio 2010 Service Pack 1以及Microsoft Visual C ++ 2010 Service Pack 1编译器更新
  5. 之后,我尝试pip install numpy但收到以下错误:

    File "numpy\core\setup.py", line 686, in get_mathlib_info
    raise RuntimeError("Broken toolchain: cannot link a simple C program")
    RuntimeError: Broken toolchain: cannot link a simple C program

    我改mfinfoNoneC:\Python34\Lib\distutils\msvc9compiler.py每本https://stackoverflow.com/a/23099820/4383472

  6. 最终在pip install numpy命令后,我的avast防病毒软件试图干扰安装过程,但我很快将其禁用

花费了很长时间-numpy编译了几分钟,我什至以为出现了错误,但最终一切都OK。

解决方案2,简单:( 我知道这种方法已经在高度投票的答案中提到过,但是由于它确实更容易,所以让我重复一下)经过所有这些工作之后,我了解到对我来说最好的方法就是使用将来可从http://www.lfd.uci.edu/~gohlke/pythonlibs/预编译二进制文件。我极少需要此网站不包含的某些软件包(或软件包的版本)。这种方式的安装过程也更快。例如,安装numpy

  1. numpy‑1.9.2+mkl‑cp34‑none‑win_amd64.whl从该站点下载(如果您具有Python 3.4 64位)
  2. 在命令提示符或Powershell中使用pip安装pip install numpy‑1.9.2+mkl‑cp34‑none‑win_amd64.whl(或文件的完整路径,具体取决于打开命令提示符的方式)

I spent almost 2 days figuring out how to fix this problem in my python 3.4 64 bit version: Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64 bit (AMD64)] on win32

Solution 1, hard: (before reading this, read first Solution 2 below) Finally, this is what helped me:

  1. install Visual C++ 2010 Express
  2. install Microsoft Windows SDK v7.1 for Windows 7
  3. create manually file vcvars64.bat in C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64 which contains CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 or other path depending on where you have yours installed
  4. (this seems to be optional) install Microsoft Visual Studio 2010 Service Pack 1 together with Microsoft Visual C++ 2010 Service Pack 1 Compiler Update for the Windows SDK 7.1
  5. after that I tried to pip install numpy but received the following error:

    File "numpy\core\setup.py", line 686, in get_mathlib_info
    raise RuntimeError("Broken toolchain: cannot link a simple C program")
    RuntimeError: Broken toolchain: cannot link a simple C program
    

    I changed mfinfo to None in C:\Python34\Lib\distutils\msvc9compiler.py per this https://stackoverflow.com/a/23099820/4383472

  6. finally after pip install numpy command my avast antivirus tried to interfere into the installation process, but i quickly disabled it

It took very long – several minutes for numpy to compile, I even thought that there was an error, but finally everything was ok.

Solution 2, easy: (I know this approach has already been mentioned in a highly voted answer, but let me repeat since it really is easier) After going through all of this work I understood that the best way for me is just to use already precompiled binaries from http://www.lfd.uci.edu/~gohlke/pythonlibs/ in future. There is very small chance that I will ever need some package (or a version of a package) which this site doesn’t contain. The installation process is also much quicker this way. For example, to install numpy:

  1. donwload numpy‑1.9.2+mkl‑cp34‑none‑win_amd64.whl (if you have Python 3.4 64-bit) from that site
  2. in command prompt or powershell install it with pip pip install numpy‑1.9.2+mkl‑cp34‑none‑win_amd64.whl (or full path to the file depending how command prompt is opened)

回答 12

我想在Windows 10上的python 2.7下运行pysph并找不到vcvarsall.bat(来自distutils)

我的解决方案如下:

为Python 2.7安装Microsoft Visual C ++(建议@Michael)

在Windows 10上,它已安装到(我的用户名是Andreas):

C:\Users\Andreas\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0

设置环境变量VS90COMNTOOLS为Visual C ++ for Python 2.7的安装路径(请参见上面的路径)。

如果仍然无法使用,请在模块中进行修改

C:/Python27/lib/distutils

文件msvc9compiler.py。在其中找到功能find_vcvarsall并进行以下修改。

替换行:

productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")

productdir = os.path.join(toolsdir)

在我的情况下,这就是vcvarsall.bat所在的位置(请检查vcvarsall.bat在您的安装位置中)。

I wanted to run pysph on Windows 10 under Python 2.7 and got vcvarsall.bat was not found (from distutils)

My solution was the following:

Install Microsoft Visual C++ for Python 2.7 (like @Michael suggested)

On Windows 10 it was installed into (my username is Andreas):

C:\Users\Andreas\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0

Set environment variable VS90COMNTOOLS to the installation path of Visual C++ for Python 2.7 (see above path).

If it still doesn’t work, then modifiy in the module

C:/Python27/lib/distutils

the file msvc9compiler.py. Find in it the function find_vcvarsall and do following modification.

Replace the line:

productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")

with

productdir = os.path.join(toolsdir)

This is where vcvarsall.bat resides in my case (check, where vcvarsall.bat is in your installation).


回答 13

当我尝试在python 3.5上安装numpy库时遇到此问题。解决的办法是安装VS2015。我有VS2008、2012、2013,其中没有一个与python 3.5兼容。显然,较新版本的python依赖于较新版本的VS。

还要确保Visual Studio已安装C ++通用工具。

在此处输入图片说明

I encountered this issue when I tried to install numpy library on my python 3.5. The solution is to install VS2015. I had VS2008, 2012, 2013, none of which is compatible with python 3.5. Apparently newer version of python has dependency on newer versions of VS.

Also make sure C++ Common Tools are installed with Visual Studio.

enter image description here


回答 14

我尝试了上述所有答案,但发现它们都不起作用,这可能是我使用Windows 8并安装了Visual Studio2012。在这种情况下,这就是您要做的。

vcvarsall.bat文件位于此处: C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC

只需选择文件,然后将其复制。

然后转到此目录: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Tools

并粘贴文件。然后,一切都会好起来。

I tried all the above answers, and found all of them not to work, this was perhaps I was using Windows 8 and had installed Visual Studio 2012. In this case, this is what you do.

The vcvarsall.bat file is located here: C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC

Simply select the file, and copy it.

Then go to this directory: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\Tools

and paste the file. And then, all should be well.


回答 15

您可以从http://go.microsoft.com/?linkid=7729279下载免费的Visual C ++ 2008 Express Edition ,它将在安装过程中设置VS90COMNTOOLS环境变量,并因此使用兼容的编译器进行构建。

正如@PiotrDobrogost在评论中提到的那样,他对另一个问题的回答详细介绍了为什么要使用Visual C ++ 2008构建正确的东西,但是随着Windows的Python构建转移到更新版本的Visual Studio,这种情况可能会改变:构建lxml适用于Windows上的Python 2.7

You can download the free Visual C++ 2008 Express Edition from http://go.microsoft.com/?linkid=7729279, which will set the VS90COMNTOOLS environment variable during installation and therefore build with a compatible compiler.

As @PiotrDobrogost mentioned in a comment, his answer to this other question goes into details about why Visual C++ 2008 is the right thing to build with, but this can change as the Windows build of Python moves to newer versions of Visual Studio: Building lxml for Python 2.7 on Windows


回答 16

在Windows 7 x64上使用Python 3.4.1遇到了这个问题,不幸的是,我需要的软件包没有合适的exe或wheel可供使用。该系统需要一些“解决方法”,下面对此进行了详细说明(底部是TLDR)。

使用上面Jaxrtech的答案中的信息,我确定我需要Visual Studio C ++ 2010(sys.version返回MSC v.1600),因此我从他的答案中的链接http://go.microsoft安装了Visual C ++ 2010 Express。.com /?linkid = 9709949。我安装了所有带有更新的内容,但是正如您在下面看到的那样,这是一个错误。此时仅应安装Express的原始版本(不更新任何内容)。

vcvarsall.bat现在存在,但是在安装软件包时出现了新错误query_vcvarsall raise ValueError(str(list(result.keys())))ValueError: [u'path']。还有其他与此错误有关的stackoverflow问题,例如为Python 2.7构建/安装C模块时出现的错误

根据该答案,我确定2010 Express仅安装32位编译器。要获取64位(和其他)编译器,您需要安装Windows 7.1 SDK。请参阅http://msdn.microsoft.com/en-us/windowsserver/bb980924.aspx

但是,这不会为我安装,安装程序返回了错误installation failed with return code 5100。我在以下链接中找到了解决方案:http : //support.microsoft.com/kb/2717426。简而言之,如果安装了x86和x64 Microsoft Visual C ++ 2010 Redistributable的较新版本,它们将与SDK安装程序中的版本冲突,因此需要先进行卸载。

然后安装了SDK,但是我注意到vcvars64.bat仍然不存在C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin,也没有其子文件夹。vcvarsall.bat运行vcvars64批处理文件,因此如果没有该文件,python软件包仍将无法安装(我忘记了此时显示的错误)。

然后 ,我在这里找到了一些说明:http : //www.cryptohaze.com/wiki/index.php/Windows_7_Build_Setup#Download_VS_2010_and_Windows_SDK_7.1按照说明,我已经安装了Express和7.1 SDK,因此安装了SDK 7.1 SP1,并做了缺少头文件修复。然后,我使用content手动创建vcvars64.bat CALL setenv /x64。我将所有这些说明粘贴在这里,以免丢失。

步骤1是下载Visual Studio Express 2010。

http://www.microsoft.com/visualstudio/zh-cn/products/2010-editions/express 是一个不错的起点。下载安装程序,然后运行它(vc_web.exe)。您不需要SQL 2008的其他下载。

对于64位编译器,您还需要Windows SDK(当前为7.1)-除非您只想进行32位构建,否则将不完全支持…

http://www.microsoft.com/zh-cn/download/details.aspx?id=8279是下载此文件的好起点-下载后,您将要运行winsdk_web.exe!

这里的默认安装就可以了。

最后,下载并安装Windows SDK 7.1 SP1更新:http : //www.microsoft.com/zh-cn/download/details.aspx?id=4422

并且,要修复缺少的头文件,VS2010 SP1。 http://www.microsoft.com/downloads/zh-CN/confirmation.aspx?FamilyID=75568aa6-8107-475d-948a-ef22627e57a5

而且,该死的,为VS2010 Express修复丢失的批处理文件。这真是荒唐可笑。

在C:\ Program Files(x86)\ Microsoft Visual Studio 10.0 \ VC \ bin \ amd64中,使用以下命令创建“ vcvars64.bat”(您将需要以管理员身份运行):

呼叫setenv / x64

我的python软件包仍然没有安装(无法回忆起错误)。然后,我找到了一些使用特殊的SDK 7.1命令提示符的说明(在下面复制),请参阅:https : //mail.python.org/pipermail/distutils-sig/2012-February/018300.html

没关系,这个问题。此处有人在菜单上注意到此项目:开始->所有程序-> Microsoft Windows SDK v7.1-> Windows SDK 7.1命令提示符

这将运行一个批处理作业,该作业似乎为编译器设置了工作环境。在该提示下,您可以键入“ setup.py build”或“ setup.py install”。

我按照指示打开了Windows SDK 7.1命令提示符,并使用它在python软件包上运行easy_install。最后,成功!


TLDR ;

  1. 安装Visual Studio Express 2010(最好没有更新的可再发行文件或SQL Server)。
  2. 安装Windows 7.1 SDK
  3. Instal SDK 7.1 SP1更新和VS2010 SP1标头文件修复(可能不需要此步骤)。
  4. 手动创建C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64\vcvars64.bat内容CALL setenv /x64
  5. 开始->所有程序-> Microsoft Windows SDK v7.1-> Windows SDK 7.1命令提示符以打开特殊的x64命令提示符,然后可以将其与python / easy_install / pip / etc(包括virtual_envs中的命令)一起使用。

I had this problem using Python 3.4.1 on Windows 7 x64, and unfortunately the packages I needed didn’t have suitable exe or wheels that I could use. This system requires a few ‘workarounds’, which are detailed below (and TLDR at bottom).

Using the info in Jaxrtech’s answer above, I determined I needed Visual Studio C++ 2010 (sys.version return MSC v.1600), so I installed Visual C++ 2010 Express from the link in his answer, which is http://go.microsoft.com/?linkid=9709949. I installed everything with updates, but as you can read below, this was a mistake. Only the original version of Express should be installed at this time (no updated anything).

vcvarsall.bat was now present, but there was a new error when installing the package, query_vcvarsall raise ValueError(str(list(result.keys())))ValueError: [u'path']. There are other stackoverflow questions with this error, such as Errors while building/installing C module for Python 2.7

I determined from that answer that 2010 Express only installs 32-bit compilers. To get 64-bit (and other) compilers, you need to install Windows 7.1 SDK. See http://msdn.microsoft.com/en-us/windowsserver/bb980924.aspx

This would not install for me though, and the installer returned the error installation failed with return code 5100. I found the solution at the following link: http://support.microsoft.com/kb/2717426. In short, if newer versions of x86 and x64 Microsoft Visual C++ 2010 Redistributable’s are installed, they conflict with the ones in SDK installer, and need uninstalling first.

The SDK then installed, but I noticed vcvars64.bat still did not exist in C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin, nor its subfolders. vcvarsall.bat runs the vcvars64 batch file, so without it, the python package still wouldn’t install (I forgot the error that was shown at this time).

I then found some instructions here: http://www.cryptohaze.com/wiki/index.php/Windows_7_Build_Setup#Download_VS_2010_and_Windows_SDK_7.1 Following the instructions, I had already installed Express and 7.1 SDK, so installed SDK 7.1 SP1, and did the missing header file fix. I then manually created vcvars64.bat with the content CALL setenv /x64. I will paste all those instructions here, so they don’t get lost.

Step 1 is to download Visual Studio Express 2010.

http://www.microsoft.com/visualstudio/en-us/products/2010-editions/express is a good place to start. Download the installer, and run it (vc_web.exe). You don’t need the SQL 2008 additional download.

You’ll also need the Windows SDK (currently 7.1) for the 64-bit compilers – unless you want to do 32-bit only builds, which are not fully supported…

http://www.microsoft.com/en-us/download/details.aspx?id=8279 is a good starting point to download this – you’ll want to run winsdk_web.exe when downloaded!

The default install here is just fine.

Finally, download and install the Windows SDK 7.1 SP1 update: http://www.microsoft.com/en-us/download/details.aspx?id=4422

And, to fix missing header file, VS2010 SP1. http://www.microsoft.com/downloads/en/confirmation.aspx?FamilyID=75568aa6-8107-475d-948a-ef22627e57a5

And, bloody hell, fix the missing batch file for VS2010 Express. This is getting downright absurd.

In C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64, create “vcvars64.bat” with the following (you will need to be running as administrator):

CALL setenv /x64

My python package still did not install (can’t recall error). I then found some instructions (copied below) to use the special SDK 7.1 Command Prompt, see: https://mail.python.org/pipermail/distutils-sig/2012-February/018300.html

Never mind this question. Somebody here noticed this item on the menu: Start->All Programs->Microsoft Windows SDK v7.1 ->Windows SDK 7.1 Command Prompt

This runs a batch job that appears to set up a working environment for the compiler. From that prompt, you can type “setup.py build” or “setup.py install”.

I opened the Windows SDK 7.1 Command Prompt as instructed, and used it to run easy_install on the python package. And at last, success!


TLDR;

  1. Install Visual Studio Express 2010 (preferably without updated redistributables or SQL server).
  2. Install Windows 7.1 SDK
  3. Instal SDK 7.1 SP1 update, and VS2010 SP1 header file fix (this step may not be required).
  4. Manually create C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64\vcvars64.bat with content CALL setenv /x64
  5. Start->All Programs->Microsoft Windows SDK v7.1 ->Windows SDK 7.1 Command Prompt to open special x64 command prompt, which can then be used with python/easy_install/pip/etc (including those in virtual_envs).

回答 17

下面的步骤为我解决了这个问题,我试图用cython扩展创建安装程序。

  1. 安装适用于Python 2.7的Microsoft Visual C ++编译器
  2. 默认安装位置为@ C:\ Users \ PC-user \ AppData \ Local \ Programs \ Common \ Microsoft \ Visual C ++ for Python。这实际上可以解决此问题,请在继续操作之前进行一次测试。
  3. 如果失败,请检查VC ++中python vcvarsall.bat文件的位置。
  4. 在记事本中打开distutils软件包的msvc9compiler.py文件。
  5. 在我的框中,这是该文件中的@ C:\ Anaconda2 \ Lib \ distutils \ msvc9compiler.py find_vcvarsall函数,通过打印出版本参数来确定VC的版本。对于Python 2.7,可能是9.0
  6. 现在创建一个环境变量VS90COMNTOOLS,指向C:\ Users \ PC-user \ AppData \ Local \ Programs \ Common \ Microsoft \ Visual C ++ for Python \ 9.0 \ VC \ bin
  7. 由于某种原因,distutils期望vcvarsall.bat文件位于VC目录中,但是python工具的VC ++在9.0的根目录中有此文件。要解决此问题,请从path.join中删除“ VC”(大约在247行附近)

    #productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC") productdir = os.path.join(toolsdir, os.pardir, os.pardir)

上面的步骤为我解决了这个问题。

Below steps fixed this issue for me, I was trying to create setup with cython extension.

  1. Install Microsoft Visual C++ Compiler for Python 2.7
  2. The default install location would be @ C:\Users\PC-user\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python This might actually fix the issue, test once before proceeding.
  3. If it fails, Check where in VC++ for python vcvarsall.bat file is located
  4. Open the msvc9compiler.py file of distutils package in notepad.
  5. In my box this was @ C:\Anaconda2\Lib\distutils\msvc9compiler.py find_vcvarsall function in this file, determine the version of VC by printing out version argument. For Python 2.7 it’s likely to be 9.0
  6. Now create an environment variable VS90COMNTOOLS, Pointing to C:\Users\PC-user\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\bin
  7. For some reason distutils expects the vcvarsall.bat file to be within VC dir, but VC++ for python tools has it in the root of 9.0 To fix this, remove “VC” from the path.join (roughly around line 247)

    #productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC") productdir = os.path.join(toolsdir, os.pardir, os.pardir)

The above steps fixed the issue for me.


回答 18

我尝试了许多解决方案,但只有一种对我有用,即安装Microsoft Visual Studio 2008 Express C ++。

我用用C编写的Python 2.7模块(yEnc,MS VS还有其他问题)遇到了这个问题。请注意,Python 2.7是使用MS VS 2008版本而非2010构建的!

尽管它是免费的,但由于MS正在推广VS 2010,因此很难找到它。但是,MSDN官方非常直接的链接仍在起作用:请访问https://stackoverflow.com/a/15319069/2227298以获取下载链接。

I tried many solutions but only one worked for me, the install of Microsoft Visual Studio 2008 Express C++.

I got this issue with a Python 2.7 module written in C (yEnc, which has other issues with MS VS). Note that Python 2.7 is built with MS VS 2008 version, not 2010!

Despite the fact it’s free, it is quite hard to find since MS is promoting VS 2010. Still, the MSDN official very direct links are still working: check https://stackoverflow.com/a/15319069/2227298 for download links.


回答 19

如果您已安装mingw

pip install --global-option build_ext --global-option --compiler=mingw32 packagename

起作用,迫使pip使用mingw编译器而不是Microsoft的编译器进行构建。有关详细信息,请参见https://github.com/pypa/pip/issues/18(最新文章)。

If you have mingw installed

pip install --global-option build_ext --global-option --compiler=mingw32 packagename

works, forcing pip to build using the mingw compiler instead of Microsoft’s. See here https://github.com/pypa/pip/issues/18 for details (last post).


回答 20

http://www.microsoft.com/zh-cn/download/details.aspx?id=44266上的 Python 2.7版Microsoft Visual C ++编译器不是解决方案吗?

Is Microsoft Visual C++ Compiler for Python 2.7 at http://www.microsoft.com/en-us/download/details.aspx?id=44266 not a solution?


回答 21

在2016年解决此问题的最简单方法是先安装Chocolatey,然后再安装该 vcpython27软件包。打开Powershell:

> iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))
> choco install python2 -y
> choco install vcpython27 -y

The easiest way to solve this in 2016 is to install Chocolatey and then the vcpython27 package. Open Powershell:

> iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))
> choco install python2 -y
> choco install vcpython27 -y

回答 22

我不知道这是否是为时已晚,但我发现微软的Visual C ++编译器为Python 2.7读取

如果需要此编译器包,您将收到的典型错误消息是找不到vcvarsall.bat

希望这可以帮助!

I don’t know if it is too late, but I found Microsoft Visual C++ Compiler for Python 2.7 which reads

The typical error message you will receive if you need this compiler package is Unable to find vcvarsall.bat

Hope this helps!


回答 23

我遇到了同样的问题,目前已经解决了。

“ Google”告诉我,我需要安装“ Python 2.7的Microsoft Visual C ++编译器”。我不仅安装了该工具,还安装了Visual C ++ 2008 Reditributable,但这并没有帮助。然后,我尝试安装Visual C ++ 2008 Express Edition。问题已经解决了!

只需尝试安装Visual C ++ 2008 Express Edition!

I got the same problem and have solved it at the moment.

“Google” told me that I need to install “Microsoft Visual C++ Compiler for Python 2.7”. I install not only the tool, but also Visual C++ 2008 Reditributable, but it didn’t help. I then tried to install Visual C++ 2008 Express Edition. And the problem has gone!

Just try to install Visual C++ 2008 Express Edition!


回答 24

调用import setuptools将Monkey补丁distutils强制与Visual Studio兼容。vcvars32.bat手动调用将设置虚拟环境,并防止编译器引发其他常见错误。对于VS 2017,文件位于

“ C:\ Program Files(x86)\ Microsoft Visual Studio \ 2017 \ Community \ VC \ Auxiliary \ Build \ vcvars32.bat”

这是我用来快速将.pyx文件编译为.pyd的安装脚本:(注意:它使用第三方模块 send2trash

# cython_setup.py
import sys, os, time, platform, subprocess
from setuptools import setup, find_packages
from Cython.Build import cythonize
from traceback import format_exc

# USAGE:
#
#   from cython_setup import run
#   run(pyx_path)

# vcvars = r"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"

# NOTE: to use visual studio 2017 you must have setuptools version 34+
vcvars = r"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars32.bat"


def _build_ext():
    try:
        pyx_path = sys.argv.pop(-1)
        pyx_path = os.path.abspath(pyx_path)
        if not os.path.exists(pyx_path):
            raise FileNotFoundError(f"{pyx_path} does not exist")
        project_name = sys.argv.pop(-1)
        os.chdir(os.path.abspath(os.path.dirname(pyx_path)))

        print("cwd: %s" % os.getcwd())
        print(os.path.abspath("build"))
        setup(
            name=project_name,
            # cmdclass = {'build_ext': build_ext},
            packages=find_packages(),
            # ext_modules=cythonize(extensions)
            ext_modules=cythonize(pyx_path,
                                  compiler_directives={'language_level': 3, 'infer_types': True, 'binding': False},
                                  annotate=True),
            # include_dirs = [numpy.get_include()]
            build_dir=os.path.abspath("build")
        )
    except:
        input(format_exc())


def retry(func):
    def wrapper(*args, **kw):
        tries = 0
        while True:
            try:
                return func(*args, **kw)
            except Exception:
                tries += 1
                if tries > 4:
                    raise
                time.sleep(0.4)

    return wrapper


@retry
def cleanup(pyx_path):
    from send2trash import send2trash
    c_file = os.path.splitext(pyx_path)[0] + ".c"
    if os.path.exists(c_file):
        os.remove(c_file)

    if os.path.exists("build"):
        send2trash("build")


def move_pyd_files(pyx_path):
    pyx_dir = os.path.dirname(pyx_path)
    build_dir = os.path.join(pyx_dir, "build")
    if not os.path.exists(build_dir):
        raise RuntimeError(f"build_dir {build_dir} did not exist....")
    found_pyd = False
    for top, dirs, nondirs in os.walk(build_dir):
        for name in nondirs:
            if name.lower().endswith(".pyd") or name.lower().endswith(".so"):
                found_pyd = True
                old_path = os.path.join(top, name)
                new_path = os.path.join(pyx_dir, name)
                if os.path.exists(new_path):
                    print(f"removing {new_path}")
                    os.remove(new_path)
                print(f"file created at {new_path}")
                os.rename(old_path, new_path)
    if not found_pyd:
        raise RuntimeError("Never found .pyd file to move")

def run(pyx_path):
    """
    :param pyx_path:
    :type pyx_path:
    :return: this function creates the batch file, which in turn calls this module, which calls cythonize, once done
    the batch script deletes itself... I'm sure theres a less convoluted way of doing this, but it works
    :rtype:
    """
    try:
        project_name = os.path.splitext(os.path.basename(pyx_path))[0]
        run_script(project_name, os.path.abspath(pyx_path))
    except:
        input(format_exc())


def run_script(project_name, pyx_path):
    dirname = os.path.dirname(pyx_path)
    # ------------------------------
    os.chdir(dirname)
    if os.path.exists(vcvars):
        #  raise RuntimeError(
        # f"Could not find vcvars32.bat at {vcvars}\nis Visual Studio Installed?\nIs setuptools version > 34?")
        subprocess.check_call(f'call "{vcvars}"', shell=True)

    cmd = "python" if platform.system() == "Windows" else "python3"
    subprocess.check_call(f'{cmd} "{__file__}" build_ext "{project_name}" "{pyx_path}"', shell=True)
    move_pyd_files(pyx_path)
    cleanup(pyx_path)


if len(sys.argv) > 2:
    _build_ext()

calling import setuptools will monkey patch distutils to force compatibility with Visual Studio. Calling vcvars32.bat manually will setup the virtual environment and prevent other common errors the compiler will throw. For VS 2017 the file is located at

“C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat”

Here is the setup script I use to quickly compile .pyx files to .pyd: (Note: it uses the 3rd party module send2trash

# cython_setup.py
import sys, os, time, platform, subprocess
from setuptools import setup, find_packages
from Cython.Build import cythonize
from traceback import format_exc

# USAGE:
#
#   from cython_setup import run
#   run(pyx_path)

# vcvars = r"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"

# NOTE: to use visual studio 2017 you must have setuptools version 34+
vcvars = r"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars32.bat"


def _build_ext():
    try:
        pyx_path = sys.argv.pop(-1)
        pyx_path = os.path.abspath(pyx_path)
        if not os.path.exists(pyx_path):
            raise FileNotFoundError(f"{pyx_path} does not exist")
        project_name = sys.argv.pop(-1)
        os.chdir(os.path.abspath(os.path.dirname(pyx_path)))

        print("cwd: %s" % os.getcwd())
        print(os.path.abspath("build"))
        setup(
            name=project_name,
            # cmdclass = {'build_ext': build_ext},
            packages=find_packages(),
            # ext_modules=cythonize(extensions)
            ext_modules=cythonize(pyx_path,
                                  compiler_directives={'language_level': 3, 'infer_types': True, 'binding': False},
                                  annotate=True),
            # include_dirs = [numpy.get_include()]
            build_dir=os.path.abspath("build")
        )
    except:
        input(format_exc())


def retry(func):
    def wrapper(*args, **kw):
        tries = 0
        while True:
            try:
                return func(*args, **kw)
            except Exception:
                tries += 1
                if tries > 4:
                    raise
                time.sleep(0.4)

    return wrapper


@retry
def cleanup(pyx_path):
    from send2trash import send2trash
    c_file = os.path.splitext(pyx_path)[0] + ".c"
    if os.path.exists(c_file):
        os.remove(c_file)

    if os.path.exists("build"):
        send2trash("build")


def move_pyd_files(pyx_path):
    pyx_dir = os.path.dirname(pyx_path)
    build_dir = os.path.join(pyx_dir, "build")
    if not os.path.exists(build_dir):
        raise RuntimeError(f"build_dir {build_dir} did not exist....")
    found_pyd = False
    for top, dirs, nondirs in os.walk(build_dir):
        for name in nondirs:
            if name.lower().endswith(".pyd") or name.lower().endswith(".so"):
                found_pyd = True
                old_path = os.path.join(top, name)
                new_path = os.path.join(pyx_dir, name)
                if os.path.exists(new_path):
                    print(f"removing {new_path}")
                    os.remove(new_path)
                print(f"file created at {new_path}")
                os.rename(old_path, new_path)
    if not found_pyd:
        raise RuntimeError("Never found .pyd file to move")

def run(pyx_path):
    """
    :param pyx_path:
    :type pyx_path:
    :return: this function creates the batch file, which in turn calls this module, which calls cythonize, once done
    the batch script deletes itself... I'm sure theres a less convoluted way of doing this, but it works
    :rtype:
    """
    try:
        project_name = os.path.splitext(os.path.basename(pyx_path))[0]
        run_script(project_name, os.path.abspath(pyx_path))
    except:
        input(format_exc())


def run_script(project_name, pyx_path):
    dirname = os.path.dirname(pyx_path)
    # ------------------------------
    os.chdir(dirname)
    if os.path.exists(vcvars):
        #  raise RuntimeError(
        # f"Could not find vcvars32.bat at {vcvars}\nis Visual Studio Installed?\nIs setuptools version > 34?")
        subprocess.check_call(f'call "{vcvars}"', shell=True)

    cmd = "python" if platform.system() == "Windows" else "python3"
    subprocess.check_call(f'{cmd} "{__file__}" build_ext "{project_name}" "{pyx_path}"', shell=True)
    move_pyd_files(pyx_path)
    cleanup(pyx_path)


if len(sys.argv) > 2:
    _build_ext()

回答 25

使用此链接下载和安装Visual C ++ 2015生成工具。它会自动下载visualcppbuildtools_full.exe并安装Visual C ++ 14.0,而无需实际安装Visual Studio。安装完成后,重试pip安装,您将不会再次收到错误。

我已经在以下平台和版本上对其进行了测试:

Python 3.6 on Windows 7 64-bit
Python 3.7 on Windows Server 2016 (64-bit system)
Python 3.8 on Windows 10 64-bit

Use this link to download and install Visual C++ 2015 Build Tools. It will automatically download visualcppbuildtools_full.exe and install Visual C++ 14.0 without actually installing Visual Studio. After the installation completes, retry pip install and you won’t get the error again.

I have tested it on following platform and versions:

Python 3.6 on Windows 7 64-bit
Python 3.7 on Windows Server 2016 (64-bit system)
Python 3.8 on Windows 10 64-bit

回答 26

如果要在安装Visual Studio 的Windows机器上安装pyodbc,另一个选择是使用二进制发行版手动安装pyodbc。

如果您在使用的计算机上没有管理员特权并尝试设置virtualenv,则此功能特别有用

脚步:

  1. 此处下载最新的Windows安装程序(pyodbc-XXXwin-Y-py2.7.exe)
  2. 使用7-Zip(或WinRAR或其他工具)打开安装程序可执行文件
  3. 提取pyodbc.pyd和pyodbc-XXX-py2.7.egg-info并将它们放在 [python installation directory or virtualenv]\Lib\site-packages
  4. 没有步骤4 :)

If you’re looking to install pyodbc on a Windows box that doesn’t have Visual Studio installed another option is to manually install pyodbc using the binary distribution.

This is particularly useful if you do not have administrator privileges on the machine you’re working with and are trying to set up a virtualenv.

Steps:

  1. Download the latest Windows installer from here (pyodbc-X.X.X.win-Y-py2.7.exe)
  2. Open the installer executable using 7-Zip (or WinRAR or whatever)
  3. Extract pyodbc.pyd and pyodbc-X.X.X-py2.7.egg-info and place them in [python installation directory or virtualenv]\Lib\site-packages
  4. There is no step 4 :)

回答 27

使用Python 3.4,依赖关系依赖于Visual Studio2010。安装Visual C ++ 2010 Express对我来说解决了这个问题。

欺骗我使用我碰巧无法使用的VS 2008或2013安装。

With Python 3.4, the dependency is on Visual Studio 2010. Installing Visual C++ 2010 Express fixed the problem for me.

Tricking it into using the VS 2008 or 2013 installs that I happened to have didn’t work.


回答 28

您可以使用easy_install代替pip,它对我有用。

You can use easy_install instead of pip it works for me.


回答 29

@monkey给出的答案是正确的答案之一,但不完整。

如果您想使用MinGW,则应该选择C,C ++以及在MinGW安装过程中建议的其他开发工具,以获取“ make.exe”。

您还必须在环境中将路径设置为make.exe。

要完成他的回答,请按以下步骤操作:

  1. 将mingw32的bin目录添加到您的环境变量中
  2. 附加 C:\Programs\MinGW\bin;C:\Programs\MinGW\msys\1.0\bin;到PATH
  3. 编辑distutils.cfg位于以下位置的文件(如果不存在则创建)C:\Python26\Lib\distutils\distutils.cfg

    [build]
    compiler=mingw32

通过打开新的cmd.exe确保设置了环境变量。

The answer given by @monkey is one of the correct ones, but it is incomplete.

In case you’d like to use MinGW, you should select the C, C++ and also other development tools suggested during the MinGW installation process to also get “make.exe.”

You must also have the path set to make.exe in the env.

To complete his answer, here are the steps:

  1. Add mingw32’s bin directory to your environment variables
  2. Append C:\Programs\MinGW\bin;C:\Programs\MinGW\msys\1.0\bin; to the PATH
  3. Edit (create if it doesn’t exist) the distutils.cfg file located at C:\Python26\Lib\distutils\distutils.cfg to be:

    [build]
    compiler=mingw32
    

Make sure the environment variables is set by opening a new cmd.exe.


如何删除/删除不为空的文件夹?

问题:如何删除/删除不为空的文件夹?

尝试删除不为空的文件夹时,出现“访问被拒绝”错误。我尝试使用以下命令:os.remove("/folder_name")

删除/删除不为空的文件夹/目录的最有效方法是什么?

I am getting an ‘access is denied’ error when I attempt to delete a folder that is not empty. I used the following command in my attempt: os.remove("/folder_name").

What is the most effective way of removing/deleting a folder/directory that is not empty?


回答 0

import shutil

shutil.rmtree('/folder_name')

标准库参考:shutil.rmtree

根据设计,rmtree在包含只读文件的文件夹树上失败。如果要删除该文件夹而不管它是否包含只读文件,请使用

shutil.rmtree('/folder_name', ignore_errors=True)
import shutil

shutil.rmtree('/folder_name')

Standard Library Reference: shutil.rmtree.

By design, rmtree fails on folder trees containing read-only files. If you want the folder to be deleted regardless of whether it contains read-only files, then use

shutil.rmtree('/folder_name', ignore_errors=True)

回答 1

Python文档os.walk()

# Delete everything reachable from the directory named in 'top',
# assuming there are no symbolic links.
# CAUTION:  This is dangerous!  For example, if top == '/', it
# could delete all your disk files.
import os
for root, dirs, files in os.walk(top, topdown=False):
    for name in files:
        os.remove(os.path.join(root, name))
    for name in dirs:
        os.rmdir(os.path.join(root, name))

From the python docs on os.walk():

# Delete everything reachable from the directory named in 'top',
# assuming there are no symbolic links.
# CAUTION:  This is dangerous!  For example, if top == '/', it
# could delete all your disk files.
import os
for root, dirs, files in os.walk(top, topdown=False):
    for name in files:
        os.remove(os.path.join(root, name))
    for name in dirs:
        os.rmdir(os.path.join(root, name))

回答 2

import shutil
shutil.rmtree(dest, ignore_errors=True)
import shutil
shutil.rmtree(dest, ignore_errors=True)

回答 3

从python 3.4您可以使用:

import pathlib

def delete_folder(pth) :
    for sub in pth.iterdir() :
        if sub.is_dir() :
            delete_folder(sub)
        else :
            sub.unlink()
    pth.rmdir() # if you just want to delete dir content, remove this line

这里pth是一个pathlib.Path实例。不错,但可能不是最快的。

from python 3.4 you may use :

import pathlib

def delete_folder(pth) :
    for sub in pth.iterdir() :
        if sub.is_dir() :
            delete_folder(sub)
        else :
            sub.unlink()
    pth.rmdir() # if you just want to delete dir content, remove this line

where pth is a pathlib.Path instance. Nice, but may not be the fastest.


回答 4

来自docs.python.org

本示例说明如何在Windows上删除目录树,其中某些文件的只读位已设置。它使用onerror回调清除只读位并重新尝试删除。任何后续故障都将传播。

import os, stat
import shutil

def remove_readonly(func, path, _):
    "Clear the readonly bit and reattempt the removal"
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(directory, onerror=remove_readonly)

From docs.python.org:

This example shows how to remove a directory tree on Windows where some of the files have their read-only bit set. It uses the onerror callback to clear the readonly bit and reattempt the remove. Any subsequent failure will propagate.

import os, stat
import shutil

def remove_readonly(func, path, _):
    "Clear the readonly bit and reattempt the removal"
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(directory, onerror=remove_readonly)

回答 5

import os
import stat
import shutil

def errorRemoveReadonly(func, path, exc):
    excvalue = exc[1]
    if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
        # change the file to be readable,writable,executable: 0777
        os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  
        # retry
        func(path)
    else:
        # raiseenter code here

shutil.rmtree(path, ignore_errors=False, onerror=errorRemoveReadonly) 

如果设置了ignore_errors,错误将被忽略;否则,如果设置了onerror,则将使用参数(函数,路径,exc_info)来处理错误,其中func为os.listdir,os.remove或os.rmdir;path是导致该函数失败的参数。而exc_info是sys.exc_info()返回的元组。如果ignore_errors为false并且onerror为None,则会引发异常。在此处输入代码

import os
import stat
import shutil

def errorRemoveReadonly(func, path, exc):
    excvalue = exc[1]
    if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
        # change the file to be readable,writable,executable: 0777
        os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  
        # retry
        func(path)
    else:
        # raiseenter code here

shutil.rmtree(path, ignore_errors=False, onerror=errorRemoveReadonly) 

If ignore_errors is set, errors are ignored; otherwise, if onerror is set, it is called to handle the error with arguments (func, path, exc_info) where func is os.listdir, os.remove, or os.rmdir; path is the argument to that function that caused it to fail; and exc_info is a tuple returned by sys.exc_info(). If ignore_errors is false and onerror is None, an exception is raised.enter code here


回答 6

根据kkubasik的回答,删除之前检查文件夹是否存在,更可靠

import shutil
def remove_folder(path):
    # check if folder exists
    if os.path.exists(path):
         # remove if exists
         shutil.rmtree(path)
    else:
         # throw your exception to handle this special scenario
         raise XXError("your exception") 
remove_folder("/folder_name")

Base on kkubasik’s answer, check if folder exists before remove, more robust

import shutil
def remove_folder(path):
    # check if folder exists
    if os.path.exists(path):
         # remove if exists
         shutil.rmtree(path)
    else:
         # throw your exception to handle this special scenario
         raise XXError("your exception") 
remove_folder("/folder_name")

回答 7

如果您确定要删除整个目录树,并且不再对目录内容感兴趣,那么爬网整个目录树是愚蠢的……只需从python调用本机OS命令即可。它将更快,更有效且内存消耗更少。

RMDIR c:\blah /s /q 

或* nix

rm -rf /home/whatever 

在python中,代码看起来像..

import sys
import os

mswindows = (sys.platform == "win32")

def getstatusoutput(cmd):
    """Return (status, output) of executing cmd in a shell."""
    if not mswindows:
        return commands.getstatusoutput(cmd)
    pipe = os.popen(cmd + ' 2>&1', 'r')
    text = pipe.read()
    sts = pipe.close()
    if sts is None: sts = 0
    if text[-1:] == '\n': text = text[:-1]
    return sts, text


def deleteDir(path):
    """deletes the path entirely"""
    if mswindows: 
        cmd = "RMDIR "+ path +" /s /q"
    else:
        cmd = "rm -rf "+path
    result = getstatusoutput(cmd)
    if(result[0]!=0):
        raise RuntimeError(result[1])

if you are sure, that you want to delete the entire dir tree, and are no more interested in contents of dir, then crawling for entire dir tree is stupidness… just call native OS command from python to do that. It will be faster, efficient and less memory consuming.

RMDIR c:\blah /s /q 

or *nix

rm -rf /home/whatever 

In python, the code will look like..

import sys
import os

mswindows = (sys.platform == "win32")

def getstatusoutput(cmd):
    """Return (status, output) of executing cmd in a shell."""
    if not mswindows:
        return commands.getstatusoutput(cmd)
    pipe = os.popen(cmd + ' 2>&1', 'r')
    text = pipe.read()
    sts = pipe.close()
    if sts is None: sts = 0
    if text[-1:] == '\n': text = text[:-1]
    return sts, text


def deleteDir(path):
    """deletes the path entirely"""
    if mswindows: 
        cmd = "RMDIR "+ path +" /s /q"
    else:
        cmd = "rm -rf "+path
    result = getstatusoutput(cmd)
    if(result[0]!=0):
        raise RuntimeError(result[1])

回答 8

只需一些python 3.5选项即可完成上述答案。(我很想在这里找到他们)。

import os
import shutil
from send2trash import send2trash # (shutil delete permanently)

删除文件夹(如果为空)

root = r"C:\Users\Me\Desktop\test"   
for dir, subdirs, files in os.walk(root):   
    if subdirs == [] and files == []:
           send2trash(dir)
           print(dir, ": folder removed")

如果包含此文件的文件夹也删除

    elif subdirs == [] and len(files) == 1: # if contains no sub folder and only 1 file 
        if files[0]== "desktop.ini" or:  
            send2trash(dir)
            print(dir, ": folder removed")
        else:
            print(dir)

如果仅包含.srt或.txt文件,则删除文件夹

    elif subdirs == []: #if dir doesn’t contains subdirectory
        ext = (".srt", ".txt")
        contains_other_ext=0
        for file in files:
            if not file.endswith(ext):  
                contains_other_ext=True
        if contains_other_ext== 0:
                send2trash(dir)
                print(dir, ": dir deleted")

删除小于400kb的文件夹:

def get_tree_size(path):
    """Return total size of files in given path and subdirs."""
    total = 0
    for entry in os.scandir(path):
        if entry.is_dir(follow_symlinks=False):
            total += get_tree_size(entry.path)
        else:
            total += entry.stat(follow_symlinks=False).st_size
    return total


for dir, subdirs, files in os.walk(root):   
    If get_tree_size(dir) < 400000:  # ≈ 400kb
        send2trash(dir)
    print(dir, "dir deleted")

Just some python 3.5 options to complete the answers above. (I would have loved to find them here).

import os
import shutil
from send2trash import send2trash # (shutil delete permanently)

Delete folder if empty

root = r"C:\Users\Me\Desktop\test"   
for dir, subdirs, files in os.walk(root):   
    if subdirs == [] and files == []:
           send2trash(dir)
           print(dir, ": folder removed")

Delete also folder if it contains this file

    elif subdirs == [] and len(files) == 1: # if contains no sub folder and only 1 file 
        if files[0]== "desktop.ini" or:  
            send2trash(dir)
            print(dir, ": folder removed")
        else:
            print(dir)

delete folder if it contains only .srt or .txt file(s)

    elif subdirs == []: #if dir doesn’t contains subdirectory
        ext = (".srt", ".txt")
        contains_other_ext=0
        for file in files:
            if not file.endswith(ext):  
                contains_other_ext=True
        if contains_other_ext== 0:
                send2trash(dir)
                print(dir, ": dir deleted")

Delete folder if its size is less than 400kb :

def get_tree_size(path):
    """Return total size of files in given path and subdirs."""
    total = 0
    for entry in os.scandir(path):
        if entry.is_dir(follow_symlinks=False):
            total += get_tree_size(entry.path)
        else:
            total += entry.stat(follow_symlinks=False).st_size
    return total


for dir, subdirs, files in os.walk(root):   
    If get_tree_size(dir) < 400000:  # ≈ 400kb
        send2trash(dir)
    print(dir, "dir deleted")

回答 9

我想添加“纯路径库”方法:

from pathlib import Path
from typing import Union

def del_dir(target: Union[Path, str], only_if_empty: bool = False):
    target = Path(target).expanduser()
    assert target.is_dir()
    for p in sorted(target.glob('**/*'), reverse=True):
        if not p.exists():
            continue
        p.chmod(0o666)
        if p.is_dir():
            p.rmdir()
        else:
            if only_if_empty:
                raise RuntimeError(f'{p.parent} is not empty!')
            p.unlink()
    target.rmdir()

这取决于Path可排序的事实,较长的路径总是会在较短的路径之后排序,就像str。因此,目录将位于文件之前。如果我们反转排序,那么文件将位于它们各自的容器之前,因此我们可以简单地一遍一遍地取消链接/ rmdir文件。

优点:

  • 它不依赖于外部二进制文件:所有内容都使用Python的电池模块(Python> = 3.6)
  • 快速且内存高效:无需递归堆栈,无需启动子进程
  • 它是跨平台的(至少,这就是pathlibPython 3.6 中的承诺;上述所有操作都说不能在Windows上运行)
  • 如果需要,可以进行非常精细的日志记录,例如,记录每次删除的发生。

I’d like to add a “pure pathlib” approach:

from pathlib import Path
from typing import Union

def del_dir(target: Union[Path, str], only_if_empty: bool = False):
    target = Path(target).expanduser()
    assert target.is_dir()
    for p in sorted(target.glob('**/*'), reverse=True):
        if not p.exists():
            continue
        p.chmod(0o666)
        if p.is_dir():
            p.rmdir()
        else:
            if only_if_empty:
                raise RuntimeError(f'{p.parent} is not empty!')
            p.unlink()
    target.rmdir()

This relies on the fact that Path is orderable, and longer paths will always sort after shorter paths, just like str. Therefore, directories will come before files. If we reverse the sort, files will then come before their respective containers, so we can simply unlink/rmdir them one by one with one pass.

Benefits:

  • It’s NOT relying on external binaries: everything uses Python’s batteries-included modules (Python >= 3.6)
  • It’s fast and memory-efficient: No recursion stack, no need to start a subprocess
  • It’s cross-platform (at least, that’s what pathlib promises in Python 3.6; no operation above stated to not run on Windows)
  • If needed, one can do a very granular logging, e.g., log each deletion as it happens.

回答 10

def deleteDir(dirPath):
    deleteFiles = []
    deleteDirs = []
    for root, dirs, files in os.walk(dirPath):
        for f in files:
            deleteFiles.append(os.path.join(root, f))
        for d in dirs:
            deleteDirs.append(os.path.join(root, d))
    for f in deleteFiles:
        os.remove(f)
    for d in deleteDirs:
        os.rmdir(d)
    os.rmdir(dirPath)
def deleteDir(dirPath):
    deleteFiles = []
    deleteDirs = []
    for root, dirs, files in os.walk(dirPath):
        for f in files:
            deleteFiles.append(os.path.join(root, f))
        for d in dirs:
            deleteDirs.append(os.path.join(root, d))
    for f in deleteFiles:
        os.remove(f)
    for d in deleteDirs:
        os.rmdir(d)
    os.rmdir(dirPath)

回答 11

如果您不想使用该shutil模块,则可以使用该os模块。

from os import listdir, rmdir, remove
for i in listdir(directoryToRemove):
    os.remove(os.path.join(directoryToRemove, i))
rmdir(directoryToRemove) # Now the directory is empty of files

If you don’t want to use the shutil module you can just use the os module.

from os import listdir, rmdir, remove
for i in listdir(directoryToRemove):
    os.remove(os.path.join(directoryToRemove, i))
rmdir(directoryToRemove) # Now the directory is empty of files

回答 12

十年后,使用Python 3.7和Linux仍然有不同的方法:

import subprocess
from pathlib import Path

#using pathlib.Path
path = Path('/path/to/your/dir')
subprocess.run(["rm", "-rf", str(path)])

#using strings
path = "/path/to/your/dir"
subprocess.run(["rm", "-rf", path])

本质上,它是使用Python的子进程模块来运行bash脚本,$ rm -rf '/path/to/your/dir就像使用终端来完成相同的任务一样。它不是完全Python,但是可以完成。

我包含该pathlib.Path示例的原因是因为根据我的经验,在处理许多变化的路径时,它非常有用。导入pathlib.Path模块并将最终结果转换为字符串的额外步骤通常对我来说是较低的开发时间成本。如果Path.rmdir()带有arg选项来显式处理非空dirs ,将很方便。

Ten years later and using Python 3.7 and Linux there are still different ways to do this:

import subprocess
from pathlib import Path

#using pathlib.Path
path = Path('/path/to/your/dir')
subprocess.run(["rm", "-rf", str(path)])

#using strings
path = "/path/to/your/dir"
subprocess.run(["rm", "-rf", path])

Essentially it’s using Python’s subprocess module to run the bash script $ rm -rf '/path/to/your/dir as if you were using the terminal to accomplish the same task. It’s not fully Python, but it gets it done.

The reason I included the pathlib.Path example is because in my experience it’s very useful when dealing with many paths that change. The extra steps of importing the pathlib.Path module and converting the end results to strings is often a lower cost to me for development time. It would be convenient if Path.rmdir() came with an arg option to explicitly handle non-empty dirs.


回答 13

即使一个文件夹可能不存在,也要删除该文件夹(避免使用Charles Chow的竞价条件),但在其他情况出错(例如权限问题,磁盘读取错误,该文件不是目录)时仍然存在错误

对于Python 3.x:

import shutil

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, FileNotFoundError):
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

Python 2.7代码几乎相同:

import shutil
import errno

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, OSError) and \
        except_instance.errno == errno.ENOENT:
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

To delete a folder even if it might not exist (avoiding the race condition in Charles Chow’s answer) but still have errors when other things go wrong (e.g. permission problems, disk read error, the file isn’t a directory)

For Python 3.x:

import shutil

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, FileNotFoundError):
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

The Python 2.7 code is almost the same:

import shutil
import errno

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, OSError) and \
        except_instance.errno == errno.ENOENT:
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

回答 14

使用os.walk,我将提出包含3个单行Python调用的解决方案:

python -c "import sys; import os; [os.chmod(os.path.join(rs,d), 0o777) for rs,ds,fs in os.walk(_path_) for d in ds]"
python -c "import sys; import os; [os.chmod(os.path.join(rs,f), 0o777) for rs,ds,fs in os.walk(_path_) for f in fs]"
python -c "import os; import shutil; shutil.rmtree(_path_, ignore_errors=False)"

第一个脚本chmod的所有子目录,第二个脚本chmod的所有文件。然后,第三个脚本将无障碍地删除所有内容。

我已经在Jenkins作业中的“ Shell脚本”中对此进行了测试(我不想将新的Python脚本存储到SCM中,这就是为什么要搜索单行解决方案的原因),并且它适用于Linux和Windows。

With os.walk I would propose the solution which consists of 3 one-liner Python calls:

python -c "import sys; import os; [os.chmod(os.path.join(rs,d), 0o777) for rs,ds,fs in os.walk(_path_) for d in ds]"
python -c "import sys; import os; [os.chmod(os.path.join(rs,f), 0o777) for rs,ds,fs in os.walk(_path_) for f in fs]"
python -c "import os; import shutil; shutil.rmtree(_path_, ignore_errors=False)"

The first script chmod’s all sub-directories, the second script chmod’s all files. Then the third script removes everything with no impediments.

I have tested this from the “Shell Script” in a Jenkins job (I did not want to store a new Python script into SCM, that’s why searched for a one-line solution) and it worked for Linux and Windows.


回答 15

为了简单起见,可以使用os.system命令:

import os
os.system("rm -rf dirname")

显而易见,它实际上调用系统终端来完成此任务。

You can use os.system command for simplicity:

import os
os.system("rm -rf dirname")

As obvious, it actually invokes system terminal to accomplish this task.


回答 16

我发现一种非常简单的方法来删除WINDOWS OS上的任何文件夹(甚至不为空)或文件。

os.system('powershell.exe  rmdir -r D:\workspace\Branches\*%s* -Force' %CANDIDATE_BRANCH)

I have found a very easy way to Delete any folder(Even NOT Empty) or file on WINDOWS OS.

os.system('powershell.exe  rmdir -r D:\workspace\Branches\*%s* -Force' %CANDIDATE_BRANCH)

回答 17

对于Windows,如果目录不为空,并且您具有只读文件,或者出现诸如

  • Access is denied
  • The process cannot access the file because it is being used by another process

尝试这个, os.system('rmdir /S /Q "{}"'.format(directory))

rm -rf在Linux / Mac中等效。

For Windows, if directory is not empty, and you have read-only files or you get errors like

  • Access is denied
  • The process cannot access the file because it is being used by another process

Try this, os.system('rmdir /S /Q "{}"'.format(directory))

It’s equivalent for rm -rf in Linux/Mac.


为什么Python代码在函数中运行得更快?

问题:为什么Python代码在函数中运行得更快?

def main():
    for i in xrange(10**8):
        pass
main()

Python中的这段代码在其中运行(注意:计时是通过Linux中的BASH中的time函数完成的。)

real    0m1.841s
user    0m1.828s
sys     0m0.012s

但是,如果for循环未放在函数中,

for i in xrange(10**8):
    pass

那么它会运行更长的时间:

real    0m4.543s
user    0m4.524s
sys     0m0.012s

为什么是这样?

def main():
    for i in xrange(10**8):
        pass
main()

This piece of code in Python runs in (Note: The timing is done with the time function in BASH in Linux.)

real    0m1.841s
user    0m1.828s
sys     0m0.012s

However, if the for loop isn’t placed within a function,

for i in xrange(10**8):
    pass

then it runs for a much longer time:

real    0m4.543s
user    0m4.524s
sys     0m0.012s

Why is this?


回答 0

您可能会问为什么存储局部变量比全局变量更快。这是CPython实现的细节。

请记住,CPython被编译为字节码,解释器将运行该字节码。编译函数时,局部变量存储在固定大小的数组(不是 a dict)中,并且变量名称分配给索引。这是可能的,因为您不能将局部变量动态添加到函数中。然后检索一个本地变量实际上是对列表的指针查找,而对refcount的引用PyObject则是微不足道的。

将此与全局查找(LOAD_GLOBAL)进行对比,它是dict涉及哈希等的真实搜索。顺便说一句,这就是为什么需要指定global i是否要使其成为全局变量的原因:如果曾经在作用域内分配变量,则编译器将发出STORE_FASTs的访问权限,除非您告知不要这样做。

顺便说一句,全局查找仍然非常优化。属性查找foo.bar真的慢的!

这是关于局部变量效率的小插图

You might ask why it is faster to store local variables than globals. This is a CPython implementation detail.

Remember that CPython is compiled to bytecode, which the interpreter runs. When a function is compiled, the local variables are stored in a fixed-size array (not a dict) and variable names are assigned to indexes. This is possible because you can’t dynamically add local variables to a function. Then retrieving a local variable is literally a pointer lookup into the list and a refcount increase on the PyObject which is trivial.

Contrast this to a global lookup (LOAD_GLOBAL), which is a true dict search involving a hash and so on. Incidentally, this is why you need to specify global i if you want it to be global: if you ever assign to a variable inside a scope, the compiler will issue STORE_FASTs for its access unless you tell it not to.

By the way, global lookups are still pretty optimised. Attribute lookups foo.bar are the really slow ones!

Here is small illustration on local variable efficiency.


回答 1

在函数内部,字节码为:

  2           0 SETUP_LOOP              20 (to 23)
              3 LOAD_GLOBAL              0 (xrange)
              6 LOAD_CONST               3 (100000000)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                 6 (to 22)
             16 STORE_FAST               0 (i)

  3          19 JUMP_ABSOLUTE           13
        >>   22 POP_BLOCK           
        >>   23 LOAD_CONST               0 (None)
             26 RETURN_VALUE        

在顶层,字节码为:

  1           0 SETUP_LOOP              20 (to 23)
              3 LOAD_NAME                0 (xrange)
              6 LOAD_CONST               3 (100000000)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                 6 (to 22)
             16 STORE_NAME               1 (i)

  2          19 JUMP_ABSOLUTE           13
        >>   22 POP_BLOCK           
        >>   23 LOAD_CONST               2 (None)
             26 RETURN_VALUE        

区别在于STORE_FAST比()快STORE_NAME。这是因为在函数中,i它是局部的,但在顶层是全局的。

要检查字节码,请使用dis模块。我可以直接反汇编该函数,但是要反汇编顶层代码,我必须使用compile内置函数。

Inside a function, the bytecode is:

  2           0 SETUP_LOOP              20 (to 23)
              3 LOAD_GLOBAL              0 (xrange)
              6 LOAD_CONST               3 (100000000)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                 6 (to 22)
             16 STORE_FAST               0 (i)

  3          19 JUMP_ABSOLUTE           13
        >>   22 POP_BLOCK           
        >>   23 LOAD_CONST               0 (None)
             26 RETURN_VALUE        

At the top level, the bytecode is:

  1           0 SETUP_LOOP              20 (to 23)
              3 LOAD_NAME                0 (xrange)
              6 LOAD_CONST               3 (100000000)
              9 CALL_FUNCTION            1
             12 GET_ITER            
        >>   13 FOR_ITER                 6 (to 22)
             16 STORE_NAME               1 (i)

  2          19 JUMP_ABSOLUTE           13
        >>   22 POP_BLOCK           
        >>   23 LOAD_CONST               2 (None)
             26 RETURN_VALUE        

The difference is that STORE_FAST is faster (!) than STORE_NAME. This is because in a function, i is a local but at toplevel it is a global.

To examine bytecode, use the dis module. I was able to disassemble the function directly, but to disassemble the toplevel code I had to use the compile builtin.


回答 2

除了局部/全局变量存储时间外,操作码预测还使函数运行更快。

正如其他答案所解释的,该函数STORE_FAST在循环中使用操作码。这是函数循环的字节码:

    >>   13 FOR_ITER                 6 (to 22)   # get next value from iterator
         16 STORE_FAST               0 (x)       # set local variable
         19 JUMP_ABSOLUTE           13           # back to FOR_ITER

通常,在运行程序时,Python会依次执行每个操作码,跟踪堆栈并在执行每个操作码后对堆栈帧执行其他检查。操作码预测意味着在某些情况下,Python能够直接跳转到下一个操作码,从而避免了其中的一些开销。

在这种情况下,每当Python看到FOR_ITER(循环的顶部)时,它将“预测” STORE_FAST它必须执行的下一个操作码。然后,Python窥视下一个操作码,如果预测正确,它将直接跳转到STORE_FAST。这具有将两个操作码压缩为单个操作码的效果。

另一方面,STORE_NAME操作码在全局级别的循环中使用。看到此操作码时,Python *不会*做出类似的预测。相反,它必须返回到评估循环的顶部,该循环对循环的执行速度有明显的影响。

为了提供有关此优化的更多技术细节,以下是该ceval.c文件(Python虚拟机的“引擎”)的引文:

一些操作码往往成对出现,因此可以在运行第一个代码时预测第二个代码。例如, GET_ITER通常紧随其后FOR_ITER。并且FOR_ITER通常后跟STORE_FASTUNPACK_SEQUENCE

验证预测需要对寄存器变量进行一个针对常数的高速测试。如果配对良好,则处理器自己的内部分支谓词成功的可能性很高,从而导致到下一个操作码的开销几乎为零。成功的预测可以节省通过评估循环的旅程,该评估循环包括其两个不可预测的分支,HAS_ARG测试和开关情况。结合处理器的内部分支预测,成功PREDICT的结果是使两个操作码像合并了主体的单个新操作码一样运行。

我们可以在FOR_ITER操作码的源代码中看到准确的预测STORE_FAST位置:

case FOR_ITER:                         // the FOR_ITER opcode case
    v = TOP();
    x = (*v->ob_type->tp_iternext)(v); // x is the next value from iterator
    if (x != NULL) {                     
        PUSH(x);                       // put x on top of the stack
        PREDICT(STORE_FAST);           // predict STORE_FAST will follow - success!
        PREDICT(UNPACK_SEQUENCE);      // this and everything below is skipped
        continue;
    }
    // error-checking and more code for when the iterator ends normally                                     

PREDICT函数扩展为,if (*next_instr == op) goto PRED_##op即我们只是跳转到预测的操作码的开头。在这种情况下,我们跳到这里:

PREDICTED_WITH_ARG(STORE_FAST);
case STORE_FAST:
    v = POP();                     // pop x back off the stack
    SETLOCAL(oparg, v);            // set it as the new local variable
    goto fast_next_opcode;

现在设置了局部变量,下一个操作码可以执行了。Python继续执行迭代直到到达终点,每次都成功进行预测。

Python的wiki页面有大约CPython中的虚拟机是如何工作的更多信息。

Aside from local/global variable store times, opcode prediction makes the function faster.

As the other answers explain, the function uses the STORE_FAST opcode in the loop. Here’s the bytecode for the function’s loop:

    >>   13 FOR_ITER                 6 (to 22)   # get next value from iterator
         16 STORE_FAST               0 (x)       # set local variable
         19 JUMP_ABSOLUTE           13           # back to FOR_ITER

Normally when a program is run, Python executes each opcode one after the other, keeping track of the a stack and preforming other checks on the stack frame after each opcode is executed. Opcode prediction means that in certain cases Python is able to jump directly to the next opcode, thus avoiding some of this overhead.

In this case, every time Python sees FOR_ITER (the top of the loop), it will “predict” that STORE_FAST is the next opcode it has to execute. Python then peeks at the next opcode and, if the prediction was correct, it jumps straight to STORE_FAST. This has the effect of squeezing the two opcodes into a single opcode.

On the other hand, the STORE_NAME opcode is used in the loop at the global level. Python does *not* make similar predictions when it sees this opcode. Instead, it must go back to the top of the evaluation-loop which has obvious implications for the speed at which the loop is executed.

To give some more technical detail about this optimization, here’s a quote from the ceval.c file (the “engine” of Python’s virtual machine):

Some opcodes tend to come in pairs thus making it possible to predict the second code when the first is run. For example, GET_ITER is often followed by FOR_ITER. And FOR_ITER is often followed by STORE_FAST or UNPACK_SEQUENCE.

Verifying the prediction costs a single high-speed test of a register variable against a constant. If the pairing was good, then the processor’s own internal branch predication has a high likelihood of success, resulting in a nearly zero-overhead transition to the next opcode. A successful prediction saves a trip through the eval-loop including its two unpredictable branches, the HAS_ARG test and the switch-case. Combined with the processor’s internal branch prediction, a successful PREDICT has the effect of making the two opcodes run as if they were a single new opcode with the bodies combined.

We can see in the source code for the FOR_ITER opcode exactly where the prediction for STORE_FAST is made:

case FOR_ITER:                         // the FOR_ITER opcode case
    v = TOP();
    x = (*v->ob_type->tp_iternext)(v); // x is the next value from iterator
    if (x != NULL) {                     
        PUSH(x);                       // put x on top of the stack
        PREDICT(STORE_FAST);           // predict STORE_FAST will follow - success!
        PREDICT(UNPACK_SEQUENCE);      // this and everything below is skipped
        continue;
    }
    // error-checking and more code for when the iterator ends normally                                     

The PREDICT function expands to if (*next_instr == op) goto PRED_##op i.e. we just jump to the start of the predicted opcode. In this case, we jump here:

PREDICTED_WITH_ARG(STORE_FAST);
case STORE_FAST:
    v = POP();                     // pop x back off the stack
    SETLOCAL(oparg, v);            // set it as the new local variable
    goto fast_next_opcode;

The local variable is now set and the next opcode is up for execution. Python continues through the iterable until it reaches the end, making the successful prediction each time.

The Python wiki page has more information about how CPython’s virtual machine works.


如何使可序列化的JSON类

问题:如何使可序列化的JSON类

如何使Python类可序列化?

一个简单的类:

class FileItem:
    def __init__(self, fname):
        self.fname = fname

我应该怎么做才能获得输出:

>>> import json

>>> my_file = FileItem('/foo/bar')
>>> json.dumps(my_file)
TypeError: Object of type 'FileItem' is not JSON serializable

没有错误

How to make a Python class serializable?

A simple class:

class FileItem:
    def __init__(self, fname):
        self.fname = fname

What should I do to be able to get output of:

>>> import json

>>> my_file = FileItem('/foo/bar')
>>> json.dumps(my_file)
TypeError: Object of type 'FileItem' is not JSON serializable

Without the error


回答 0

您对预期的输出有想法吗?例如这样做吗?

>>> f  = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'

在这种情况下,您只能调用json.dumps(f.__dict__)

如果您想要更多的自定义输出,则必须继承JSONEncoder并实现自己的自定义序列化。

有关一个简单的示例,请参见下文。

>>> from json import JSONEncoder
>>> class MyEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__    

>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'

然后,将该类json.dumps()作为clskwarg 传递给方法:

json.dumps(cls=MyEncoder)

如果你也想解码,那么你将有一个自定义供应object_hookJSONDecoder类。例如

>>> def from_json(json_object):
        if 'fname' in json_object:
            return FileItem(json_object['fname'])
>>> f = JSONDecoder(object_hook = from_json).decode('{"fname": "/foo/bar"}')
>>> f
<__main__.FileItem object at 0x9337fac>
>>> 

Do you have an idea about the expected output? For e.g. will this do?

>>> f  = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'

In that case you can merely call json.dumps(f.__dict__).

If you want more customized output then you will have to subclass JSONEncoder and implement your own custom serialization.

For a trivial example, see below.

>>> from json import JSONEncoder
>>> class MyEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__    

>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'

Then you pass this class into the json.dumps() method as cls kwarg:

json.dumps(cls=MyEncoder)

If you also want to decode then you’ll have to supply a custom object_hook to the JSONDecoder class. For e.g.

>>> def from_json(json_object):
        if 'fname' in json_object:
            return FileItem(json_object['fname'])
>>> f = JSONDecoder(object_hook = from_json).decode('{"fname": "/foo/bar"}')
>>> f
<__main__.FileItem object at 0x9337fac>
>>> 

回答 1

这是一个简单功能的简单解决方案:

.toJSON() 方法

代替JSON可序列化的类,实现一个序列化器方法:

import json

class Object:
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)

因此,您只需调用它即可序列化:

me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"

print(me.toJSON())

将输出:

{
    "age": 35,
    "dog": {
        "name": "Apollo"
    },
    "name": "Onur"
}

Here is a simple solution for a simple feature:

.toJSON() Method

Instead of a JSON serializable class, implement a serializer method:

import json

class Object:
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)

So you just call it to serialize:

me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"

print(me.toJSON())

will output:

{
    "age": 35,
    "dog": {
        "name": "Apollo"
    },
    "name": "Onur"
}

回答 2

对于更复杂的类,您可以考虑使用jsonpickle工具:

jsonpickle是一个Python库,用于将复杂的Python对象与JSON进行序列化和反序列化。

用于将Python编码为JSON的标准Python库(例如stdlib的json,simplejson和demjson)只能处理具有直接JSON等效项的Python原语(例如,字典,列表,字符串,整数等)。jsonpickle建立在这些库之上,并允许将更复杂的数据结构序列化为JSON。jsonpickle具有高度的可配置性和可扩展性,允许用户选择JSON后端并添加其他后端。

(链接到PyPi上的jsonpickle)

For more complex classes you could consider the tool jsonpickle:

jsonpickle is a Python library for serialization and deserialization of complex Python objects to and from JSON.

The standard Python libraries for encoding Python into JSON, such as the stdlib’s json, simplejson, and demjson, can only handle Python primitives that have a direct JSON equivalent (e.g. dicts, lists, strings, ints, etc.). jsonpickle builds on top of these libraries and allows more complex data structures to be serialized to JSON. jsonpickle is highly configurable and extendable–allowing the user to choose the JSON backend and add additional backends.

(link to jsonpickle on PyPi)


回答 3

大多数答案都涉及将对json.dumps()的调用更改为并非总是可能或不希望的(例如,它可能发生在框架组件内部)。

如果您希望能够原样调用 json.dumps(obj),那么一个简单的解决方案就是从dict继承:

class FileItem(dict):
    def __init__(self, fname):
        dict.__init__(self, fname=fname)

f = FileItem('tasks.txt')
json.dumps(f)  #No need to change anything here

如果您的类只是基本数据表示形式,则此方法有效,对于棘手的事情,您始终可以显式设置键。

Most of the answers involve changing the call to json.dumps(), which is not always possible or desirable (it may happen inside a framework component for example).

If you want to be able to call json.dumps(obj) as is, then a simple solution is inheriting from dict:

class FileItem(dict):
    def __init__(self, fname):
        dict.__init__(self, fname=fname)

f = FileItem('tasks.txt')
json.dumps(f)  #No need to change anything here

This works if your class is just basic data representation, for trickier things you can always set keys explicitly.


回答 4

我喜欢Onur的答案,但会扩展为包括一个可选toJSON()方法,以使对象自行序列化:

def dumper(obj):
    try:
        return obj.toJSON()
    except:
        return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)

I like Onur’s answer but would expand to include an optional toJSON() method for objects to serialize themselves:

def dumper(obj):
    try:
        return obj.toJSON()
    except:
        return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)

回答 5

另一个选择是将JSON转储包装在其自己的类中:

import json

class FileItem:
    def __init__(self, fname):
        self.fname = fname

    def __repr__(self):
        return json.dumps(self.__dict__)

或者,甚至更好的是,从类中继承FileItem JsonSerializable类:

import json

class JsonSerializable(object):
    def toJson(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.toJson()


class FileItem(JsonSerializable):
    def __init__(self, fname):
        self.fname = fname

测试:

>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'

Another option is to wrap JSON dumping in its own class:

import json

class FileItem:
    def __init__(self, fname):
        self.fname = fname

    def __repr__(self):
        return json.dumps(self.__dict__)

Or, even better, subclassing FileItem class from a JsonSerializable class:

import json

class JsonSerializable(object):
    def toJson(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.toJson()


class FileItem(JsonSerializable):
    def __init__(self, fname):
        self.fname = fname

Testing:

>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'

回答 6

只需将to_json方法添加到您的类中,如下所示:

def to_json(self):
  return self.message # or how you want it to be serialized

并将此代码(来自此答案添加到所有内容的顶部:

from json import JSONEncoder

def _default(self, obj):
    return getattr(obj.__class__, "to_json", _default.default)(obj)

_default.default = JSONEncoder().default
JSONEncoder.default = _default

导入时,它将对Monkeyjson模块进行Monkey补丁处理,因此JSONEncoder.default()自动检查特殊的“ to_json()”方法,并在找到后使用该方法对对象进行编码。

就像Onur所说的一样,但是这次您不必更新json.dumps()项目中的每个项目。

Just add to_json method to your class like this:

def to_json(self):
  return self.message # or how you want it to be serialized

And add this code (from this answer), to somewhere at the top of everything:

from json import JSONEncoder

def _default(self, obj):
    return getattr(obj.__class__, "to_json", _default.default)(obj)

_default.default = JSONEncoder().default
JSONEncoder.default = _default

This will monkey-patch json module when it’s imported so JSONEncoder.default() automatically checks for a special “to_json()” method and uses it to encode the object if found.

Just like Onur said, but this time you don’t have to update every json.dumps() in your project.


回答 7

前几天,我遇到了这个问题,并为Python对象实现了一个更通用的Encoder版本,可以处理嵌套对象继承的字段

import json
import inspect

class ObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, "to_json"):
            return self.default(obj.to_json())
        elif hasattr(obj, "__dict__"):
            d = dict(
                (key, value)
                for key, value in inspect.getmembers(obj)
                if not key.startswith("__")
                and not inspect.isabstract(value)
                and not inspect.isbuiltin(value)
                and not inspect.isfunction(value)
                and not inspect.isgenerator(value)
                and not inspect.isgeneratorfunction(value)
                and not inspect.ismethod(value)
                and not inspect.ismethoddescriptor(value)
                and not inspect.isroutine(value)
            )
            return self.default(d)
        return obj

例:

class C(object):
    c = "NO"
    def to_json(self):
        return {"c": "YES"}

class B(object):
    b = "B"
    i = "I"
    def __init__(self, y):
        self.y = y

    def f(self):
        print "f"

class A(B):
    a = "A"
    def __init__(self):
        self.b = [{"ab": B("y")}]
        self.c = C()

print json.dumps(A(), cls=ObjectEncoder, indent=2, sort_keys=True)

结果:

{
  "a": "A", 
  "b": [
    {
      "ab": {
        "b": "B", 
        "i": "I", 
        "y": "y"
      }
    }
  ], 
  "c": {
    "c": "YES"
  }, 
  "i": "I"
}

I came across this problem the other day and implemented a more general version of an Encoder for Python objects that can handle nested objects and inherited fields:

import json
import inspect

class ObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, "to_json"):
            return self.default(obj.to_json())
        elif hasattr(obj, "__dict__"):
            d = dict(
                (key, value)
                for key, value in inspect.getmembers(obj)
                if not key.startswith("__")
                and not inspect.isabstract(value)
                and not inspect.isbuiltin(value)
                and not inspect.isfunction(value)
                and not inspect.isgenerator(value)
                and not inspect.isgeneratorfunction(value)
                and not inspect.ismethod(value)
                and not inspect.ismethoddescriptor(value)
                and not inspect.isroutine(value)
            )
            return self.default(d)
        return obj

Example:

class C(object):
    c = "NO"
    def to_json(self):
        return {"c": "YES"}

class B(object):
    b = "B"
    i = "I"
    def __init__(self, y):
        self.y = y

    def f(self):
        print "f"

class A(B):
    a = "A"
    def __init__(self):
        self.b = [{"ab": B("y")}]
        self.c = C()

print json.dumps(A(), cls=ObjectEncoder, indent=2, sort_keys=True)

Result:

{
  "a": "A", 
  "b": [
    {
      "ab": {
        "b": "B", 
        "i": "I", 
        "y": "y"
      }
    }
  ], 
  "c": {
    "c": "YES"
  }, 
  "i": "I"
}

回答 8

如果您使用的是Python3.5 +,则可以使用jsons。它将把您的对象(及其所有属性递归地)转换成字典。

import jsons

a_dict = jsons.dump(your_object)

或者,如果您想要一个字符串:

a_str = jsons.dumps(your_object)

或者如果您的Class实施了jsons.JsonSerializable

a_dict = your_object.json

If you’re using Python3.5+, you could use jsons. It will convert your object (and all its attributes recursively) to a dict.

import jsons

a_dict = jsons.dump(your_object)

Or if you wanted a string:

a_str = jsons.dumps(your_object)

Or if your class implemented jsons.JsonSerializable:

a_dict = your_object.json

回答 9

import simplejson

class User(object):
    def __init__(self, name, mail):
        self.name = name
        self.mail = mail

    def _asdict(self):
        return self.__dict__

print(simplejson.dumps(User('alice', 'alice@mail.com')))

如果使用标准json,则需要定义一个default函数

import json
def default(o):
    return o._asdict()

print(json.dumps(User('alice', 'alice@mail.com'), default=default))
import simplejson

class User(object):
    def __init__(self, name, mail):
        self.name = name
        self.mail = mail

    def _asdict(self):
        return self.__dict__

print(simplejson.dumps(User('alice', 'alice@mail.com')))

if use standard json, u need to define a default function

import json
def default(o):
    return o._asdict()

print(json.dumps(User('alice', 'alice@mail.com'), default=default))

回答 10

json在可以打印的对象方面受到限制,并且jsonpickle(您可能需要pip install jsonpickle)在不能缩进文本方面受到限制。如果您想检查无法更改其类的对象的内容,我仍然找不到比以下方法更直接的方法:

 import json
 import jsonpickle
 ...
 print  json.dumps(json.loads(jsonpickle.encode(object)), indent=2)

注意:他们仍然无法打印对象方法。

json is limited in terms of objects it can print, and jsonpickle (you may need a pip install jsonpickle) is limited in terms it can’t indent text. If you would like to inspect the contents of an object whose class you can’t change, I still couldn’t find a straighter way than:

 import json
 import jsonpickle
 ...
 print  json.dumps(json.loads(jsonpickle.encode(object)), indent=2)

Note: that still they can’t print the object methods.


回答 11

此类可以解决问题,它将对象转换为标准json。

import json


class Serializer(object):
    @staticmethod
    def serialize(object):
        return json.dumps(object, default=lambda o: o.__dict__.values()[0])

用法:

Serializer.serialize(my_object)

python2.7和工作python3

This class can do the trick, it converts object to standard json .

import json


class Serializer(object):
    @staticmethod
    def serialize(object):
        return json.dumps(object, default=lambda o: o.__dict__.values()[0])

usage:

Serializer.serialize(my_object)

working in python2.7 and python3.


回答 12

import json

class Foo(object):
    def __init__(self):
        self.bar = 'baz'
        self._qux = 'flub'

    def somemethod(self):
        pass

def default(instance):
    return {k: v
            for k, v in vars(instance).items()
            if not str(k).startswith('_')}

json_foo = json.dumps(Foo(), default=default)
assert '{"bar": "baz"}' == json_foo

print(json_foo)
import json

class Foo(object):
    def __init__(self):
        self.bar = 'baz'
        self._qux = 'flub'

    def somemethod(self):
        pass

def default(instance):
    return {k: v
            for k, v in vars(instance).items()
            if not str(k).startswith('_')}

json_foo = json.dumps(Foo(), default=default)
assert '{"bar": "baz"}' == json_foo

print(json_foo)

回答 13

jaraco给出了一个非常简洁的答案。我需要修复一些小问题,但这可行:

# Your custom class
class MyCustom(object):
    def __json__(self):
        return {
            'a': self.a,
            'b': self.b,
            '__python__': 'mymodule.submodule:MyCustom.from_json',
        }

    to_json = __json__  # supported by simplejson

    @classmethod
    def from_json(cls, json):
        obj = cls()
        obj.a = json['a']
        obj.b = json['b']
        return obj

# Dumping and loading
import simplejson

obj = MyCustom()
obj.a = 3
obj.b = 4

json = simplejson.dumps(obj, for_json=True)

# Two-step loading
obj2_dict = simplejson.loads(json)
obj2 = MyCustom.from_json(obj2_dict)

# Make sure we have the correct thing
assert isinstance(obj2, MyCustom)
assert obj2.__dict__ == obj.__dict__

请注意,我们需要两个步骤进行加载。目前,该__python__属性尚未使用。

这有多普遍?

使用AlJohri的方法,我检查了方法的普及程度:

序列化(Python-> JSON):

反序列化(JSON-> Python):

jaraco gave a pretty neat answer. I needed to fix some minor things, but this works:

Code

# Your custom class
class MyCustom(object):
    def __json__(self):
        return {
            'a': self.a,
            'b': self.b,
            '__python__': 'mymodule.submodule:MyCustom.from_json',
        }

    to_json = __json__  # supported by simplejson

    @classmethod
    def from_json(cls, json):
        obj = cls()
        obj.a = json['a']
        obj.b = json['b']
        return obj

# Dumping and loading
import simplejson

obj = MyCustom()
obj.a = 3
obj.b = 4

json = simplejson.dumps(obj, for_json=True)

# Two-step loading
obj2_dict = simplejson.loads(json)
obj2 = MyCustom.from_json(obj2_dict)

# Make sure we have the correct thing
assert isinstance(obj2, MyCustom)
assert obj2.__dict__ == obj.__dict__

Note that we need two steps for loading. For now, the __python__ property is not used.

How common is this?

Using the method of AlJohri, I check popularity of approaches:

Serialization (Python -> JSON):

Deserialization (JSON -> Python):


回答 14

这对我来说效果很好:

class JsonSerializable(object):

    def serialize(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.serialize()

    @staticmethod
    def dumper(obj):
        if "serialize" in dir(obj):
            return obj.serialize()

        return obj.__dict__

然后

class FileItem(JsonSerializable):
    ...

log.debug(json.dumps(<my object>, default=JsonSerializable.dumper, indent=2))

This has worked well for me:

class JsonSerializable(object):

    def serialize(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.serialize()

    @staticmethod
    def dumper(obj):
        if "serialize" in dir(obj):
            return obj.serialize()

        return obj.__dict__

and then

class FileItem(JsonSerializable):
    ...

and

log.debug(json.dumps(<my object>, default=JsonSerializable.dumper, indent=2))

回答 15

如果您不介意为其安装软件包,则可以使用json-tricks

pip install json-tricks

在此之后,你只需要导入dump(s)json_tricks替代JSON,它通常会工作:

from json_tricks import dumps
json_str = dumps(cls_instance, indent=4)

这会给

{
        "__instance_type__": [
                "module_name.test_class",
                "MyTestCls"
        ],
        "attributes": {
                "attr": "val",
                "dct_attr": {
                        "hello": 42
                }
        }
}

基本上就是这样!


总的来说,这会很好。有一些exceptions,例如,如果发生了特殊情况__new__,或者发生了更多的元类魔术。

显然,加载也可以(否则有什么意义):

from json_tricks import loads
json_str = loads(json_str)

这确实假定module_name.test_class.MyTestCls可以导入并且没有以不兼容的方式进行更改。您将获得一个实例,而不是字典或其他内容,它应该与您转储的副本相同。

如果要自定义某些东西的序列化方法,可以向类中添加特殊方法,如下所示:

class CustomEncodeCls:
        def __init__(self):
                self.relevant = 42
                self.irrelevant = 37

        def __json_encode__(self):
                # should return primitive, serializable types like dict, list, int, string, float...
                return {'relevant': self.relevant}

        def __json_decode__(self, **attrs):
                # should initialize all properties; note that __init__ is not called implicitly
                self.relevant = attrs['relevant']
                self.irrelevant = 12

例如,它仅序列化部分属性参数。

作为免费赠品,您可以获得numpy数组(日期)的反序列化,日期和时间,有序映射以及在json中包含注释的功能。

免责声明:我创建了json_tricks,因为我和您有同样的问题。

If you don’t mind installing a package for it, you can use json-tricks:

pip install json-tricks

After that you just need to import dump(s) from json_tricks instead of json, and it’ll usually work:

from json_tricks import dumps
json_str = dumps(cls_instance, indent=4)

which’ll give

{
        "__instance_type__": [
                "module_name.test_class",
                "MyTestCls"
        ],
        "attributes": {
                "attr": "val",
                "dct_attr": {
                        "hello": 42
                }
        }
}

And that’s basically it!


This will work great in general. There are some exceptions, e.g. if special things happen in __new__, or more metaclass magic is going on.

Obviously loading also works (otherwise what’s the point):

from json_tricks import loads
json_str = loads(json_str)

This does assume that module_name.test_class.MyTestCls can be imported and hasn’t changed in non-compatible ways. You’ll get back an instance, not some dictionary or something, and it should be an identical copy to the one you dumped.

If you want to customize how something gets (de)serialized, you can add special methods to your class, like so:

class CustomEncodeCls:
        def __init__(self):
                self.relevant = 42
                self.irrelevant = 37

        def __json_encode__(self):
                # should return primitive, serializable types like dict, list, int, string, float...
                return {'relevant': self.relevant}

        def __json_decode__(self, **attrs):
                # should initialize all properties; note that __init__ is not called implicitly
                self.relevant = attrs['relevant']
                self.irrelevant = 12

which serializes only part of the attributes parameters, as an example.

And as a free bonus, you get (de)serialization of numpy arrays, date & times, ordered maps, as well as the ability to include comments in json.

Disclaimer: I created json_tricks, because I had the same problem as you.


回答 16

jsonweb似乎是对我最好的解决方案。参见http://www.jsonweb.info/en/latest/

from jsonweb.encode import to_object, dumper

@to_object()
class DataModel(object):
  def __init__(self, id, value):
   self.id = id
   self.value = value

>>> data = DataModel(5, "foo")
>>> dumper(data)
'{"__type__": "DataModel", "id": 5, "value": "foo"}'

jsonweb seems to be the best solution for me. See http://www.jsonweb.info/en/latest/

from jsonweb.encode import to_object, dumper

@to_object()
class DataModel(object):
  def __init__(self, id, value):
   self.id = id
   self.value = value

>>> data = DataModel(5, "foo")
>>> dumper(data)
'{"__type__": "DataModel", "id": 5, "value": "foo"}'

回答 17

这是我的3美分…
这演示了一个类似树的python对象的显式json序列化。
注意:如果您实际上想要这样的代码,则可以使用扭曲的FilePath类。

import json, sys, os

class File:
    def __init__(self, path):
        self.path = path

    def isdir(self):
        return os.path.isdir(self.path)

    def isfile(self):
        return os.path.isfile(self.path)

    def children(self):        
        return [File(os.path.join(self.path, f)) 
                for f in os.listdir(self.path)]

    def getsize(self):        
        return os.path.getsize(self.path)

    def getModificationTime(self):
        return os.path.getmtime(self.path)

def _default(o):
    d = {}
    d['path'] = o.path
    d['isFile'] = o.isfile()
    d['isDir'] = o.isdir()
    d['mtime'] = int(o.getModificationTime())
    d['size'] = o.getsize() if o.isfile() else 0
    if o.isdir(): d['children'] = o.children()
    return d

folder = os.path.abspath('.')
json.dump(File(folder), sys.stdout, default=_default)

Here is my 3 cents …
This demonstrates explicit json serialization for a tree-like python object.
Note: If you actually wanted some code like this you could use the twisted FilePath class.

import json, sys, os

class File:
    def __init__(self, path):
        self.path = path

    def isdir(self):
        return os.path.isdir(self.path)

    def isfile(self):
        return os.path.isfile(self.path)

    def children(self):        
        return [File(os.path.join(self.path, f)) 
                for f in os.listdir(self.path)]

    def getsize(self):        
        return os.path.getsize(self.path)

    def getModificationTime(self):
        return os.path.getmtime(self.path)

def _default(o):
    d = {}
    d['path'] = o.path
    d['isFile'] = o.isfile()
    d['isDir'] = o.isdir()
    d['mtime'] = int(o.getModificationTime())
    d['size'] = o.getsize() if o.isfile() else 0
    if o.isdir(): d['children'] = o.children()
    return d

folder = os.path.abspath('.')
json.dump(File(folder), sys.stdout, default=_default)

回答 18

当我尝试将Peewee的模型存储到PostgreSQL中时遇到了这个问题 JSONField

经过一段时间的努力,这是一般的解决方案。

我的解决方案的关键是浏览Python的源代码,并意识到代码文档(在此描述)已经解释了如何扩展现有的json.dumps以支持其他数据类型。

假设您当前有一个模型,其中包含一些无法序列化为JSON的字段,并且包含JSON字段的模型最初看起来像这样:

class SomeClass(Model):
    json_field = JSONField()

只需这样定义一个自定义JSONEncoder

class CustomJsonEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, SomeTypeUnsupportedByJsonDumps):
            return < whatever value you want >
        return json.JSONEncoder.default(self, obj)

    @staticmethod
    def json_dumper(obj):
        return json.dumps(obj, cls=CustomJsonEncoder)

然后JSONField像下面这样使用它:

class SomeClass(Model):
    json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)

关键是default(self, obj)上面的方法。对于... is not JSON serializable您从Python收到的每一个投诉,只需添加代码来处理从unserializable-to-JSON类型(例如Enumdatetime

例如,这是我如何支持从继承的类Enum

class TransactionType(Enum):
   CURRENT = 1
   STACKED = 2

   def default(self, obj):
       if isinstance(obj, TransactionType):
           return obj.value
       return json.JSONEncoder.default(self, obj)

最后,使用上述实现的代码,您可以将任何Peewee模型转换为JSON可序列化的对象,如下所示:

peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)

尽管上面的代码(某种程度上)特定于Peewee,但是我认为:

  1. 通常适用于其他ORM(例如Django等)
  2. 另外,如果您了解其json.dumps工作原理,那么该解决方案通常也适用于Python(无ORM)

如有任何疑问,请发表在评论部分。谢谢!

I ran into this problem when I tried to store Peewee’s model into PostgreSQL JSONField.

After struggling for a while, here’s the general solution.

The key to my solution is going through Python’s source code and realizing that the code documentation (described here) already explains how to extend the existing json.dumps to support other data types.

Suppose you current have a model that contains some fields that are not serializable to JSON and the model that contains the JSON field originally looks like this:

class SomeClass(Model):
    json_field = JSONField()

Just define a custom JSONEncoder like this:

class CustomJsonEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, SomeTypeUnsupportedByJsonDumps):
            return < whatever value you want >
        return json.JSONEncoder.default(self, obj)

    @staticmethod
    def json_dumper(obj):
        return json.dumps(obj, cls=CustomJsonEncoder)

And then just use it in your JSONField like below:

class SomeClass(Model):
    json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)

The key is the default(self, obj) method above. For every single ... is not JSON serializable complaint you receive from Python, just add code to handle the unserializable-to-JSON type (such as Enum or datetime)

For example, here’s how I support a class inheriting from Enum:

class TransactionType(Enum):
   CURRENT = 1
   STACKED = 2

   def default(self, obj):
       if isinstance(obj, TransactionType):
           return obj.value
       return json.JSONEncoder.default(self, obj)

Finally, with the code implemented like above, you can just convert any Peewee models to be a JSON-seriazable object like below:

peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)

Though the code above was (somewhat) specific to Peewee, but I think:

  1. It’s applicable to other ORMs (Django, etc) in general
  2. Also, if you understood how json.dumps works, this solution also works with Python (sans ORM) in general too

Any questions, please post in the comments section. Thanks!


回答 19

此函数使用递归遍历字典的每个部分,然后调用非内置类型的类的repr()方法。

def sterilize(obj):
    object_type = type(obj)
    if isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif object_type in (list, tuple):
        return [sterilize(v) for v in obj]
    elif object_type in (str, int, bool):
        return obj
    else:
        return obj.__repr__()

This function uses recursion to iterate over every part of the dictionary and then calls the repr() methods of classes that are not build-in types.

def sterilize(obj):
    object_type = type(obj)
    if isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif object_type in (list, tuple):
        return [sterilize(v) for v in obj]
    elif object_type in (str, int, bool):
        return obj
    else:
        return obj.__repr__()

回答 20

这是一个小型库,它将带有其所有子级的对象序列化为JSON并将其解析回:

https://github.com/Toubs/PyJSONSerialization/

This is a small library that serializes an object with all its children to JSON and also parses it back:

https://github.com/Toubs/PyJSONSerialization/


回答 21

我想出了自己的解决方案。使用此方法,传递任何文档(dictlistObjectId等)进行序列化。

def getSerializable(doc):
    # check if it's a list
    if isinstance(doc, list):
        for i, val in enumerate(doc):
            doc[i] = getSerializable(doc[i])
        return doc

    # check if it's a dict
    if isinstance(doc, dict):
        for key in doc.keys():
            doc[key] = getSerializable(doc[key])
        return doc

    # Process ObjectId
    if isinstance(doc, ObjectId):
        doc = str(doc)
        return doc

    # Use any other custom serializting stuff here...

    # For the rest of stuff
    return doc

I came up with my own solution. Use this method, pass any document (dict,list, ObjectId etc) to serialize.

def getSerializable(doc):
    # check if it's a list
    if isinstance(doc, list):
        for i, val in enumerate(doc):
            doc[i] = getSerializable(doc[i])
        return doc

    # check if it's a dict
    if isinstance(doc, dict):
        for key in doc.keys():
            doc[key] = getSerializable(doc[key])
        return doc

    # Process ObjectId
    if isinstance(doc, ObjectId):
        doc = str(doc)
        return doc

    # Use any other custom serializting stuff here...

    # For the rest of stuff
    return doc

回答 22

我选择使用装饰器解决datetime对象序列化问题。这是我的代码:

#myjson.py
#Author: jmooremcc 7/16/2017

import json
from datetime import datetime, date, time, timedelta
"""
This module uses decorators to serialize date objects using json
The filename is myjson.py
In another module you simply add the following import statement:
    from myjson import json

json.dumps and json.dump will then correctly serialize datetime and date 
objects
"""

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        serial = str(obj)
        return serial
    raise TypeError ("Type %s not serializable" % type(obj))


def FixDumps(fn):
    def hook(obj):
        return fn(obj, default=json_serial)

    return hook

def FixDump(fn):
    def hook(obj, fp):
        return fn(obj,fp, default=json_serial)

    return hook


json.dumps=FixDumps(json.dumps)
json.dump=FixDump(json.dump)


if __name__=="__main__":
    today=datetime.now()
    data={'atime':today, 'greet':'Hello'}
    str=json.dumps(data)
    print str

通过导入上述模块,我的其他模块以常规方式(不指定默认关键字)使用json来序列化包含日期时间对象的数据。datetime序列化程序代码会被json.dumps和json.dump自动调用。

I chose to use decorators to solve the datetime object serialization problem. Here is my code:

#myjson.py
#Author: jmooremcc 7/16/2017

import json
from datetime import datetime, date, time, timedelta
"""
This module uses decorators to serialize date objects using json
The filename is myjson.py
In another module you simply add the following import statement:
    from myjson import json

json.dumps and json.dump will then correctly serialize datetime and date 
objects
"""

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        serial = str(obj)
        return serial
    raise TypeError ("Type %s not serializable" % type(obj))


def FixDumps(fn):
    def hook(obj):
        return fn(obj, default=json_serial)

    return hook

def FixDump(fn):
    def hook(obj, fp):
        return fn(obj,fp, default=json_serial)

    return hook


json.dumps=FixDumps(json.dumps)
json.dump=FixDump(json.dump)


if __name__=="__main__":
    today=datetime.now()
    data={'atime':today, 'greet':'Hello'}
    str=json.dumps(data)
    print str

By importing the above module, my other modules use json in a normal way (without specifying the default keyword) to serialize data that contains date time objects. The datetime serializer code is automatically called for json.dumps and json.dump.


回答 23

我最喜欢Lost Koder的方法。尝试序列化其成员/方法无法序列化的更复杂对象时,我遇到了问题。这是适用于更多对象的实现:

class Serializer(object):
    @staticmethod
    def serialize(obj):
        def check(o):
            for k, v in o.__dict__.items():
                try:
                    _ = json.dumps(v)
                    o.__dict__[k] = v
                except TypeError:
                    o.__dict__[k] = str(v)
            return o
        return json.dumps(check(obj).__dict__, indent=2)

I liked Lost Koder’s method the most. I ran into issues when trying to serialize more complex objects whos members/methods aren’t serializable. Here’s my implementation that works on more objects:

class Serializer(object):
    @staticmethod
    def serialize(obj):
        def check(o):
            for k, v in o.__dict__.items():
                try:
                    _ = json.dumps(v)
                    o.__dict__[k] = v
                except TypeError:
                    o.__dict__[k] = str(v)
            return o
        return json.dumps(check(obj).__dict__, indent=2)

回答 24

如果您能够安装软件包,我建议您尝试dill,这对于我的项目来说效果很好。这个套件的优点是它具有与相同的介面pickle,因此,如果您已经pickle在专案中使用过,可以简单地以dill为该脚本并查看脚本是否在运行,而无需更改任何代码。因此,这是一个非常便宜的解决方案!

(完全反公开:我与Dill项目毫无关系,也从未参与过该项目。)

安装软件包:

pip install dill

然后,编辑要导入的代码,dill而不是pickle

# import pickle
import dill as pickle

运行您的脚本,看看它是否有效。(如果这样做,您可能需要清理代码,以使您不再隐藏pickle模块名称!)

dill项目页面可以和不能序列化的数据类型的一些细节:

dill 可以腌制以下标准类型:

无,类型,布尔值,整数,长整型,浮点型,复杂,str,unicode,元组,列表,字典,文件,缓冲区,内置,新旧样式类,新旧样式类实例,集合,frozenset,数组,功能,异常

dill 也可以腌制更多“异国”标准类型:

具有yields的函数,嵌套函数,lambdas,单元格,方法,unboundmethod,模块,代码,methodwrapper,dictproxy,methoddescriptor,getsetdescriptor,memberdescriptor,wrapperperscriptor,xrange,slice,未实现,省略号,退出

dill 尚不能腌制这些标准类型:

框架,发生器,回溯

If you are able to install a package, I’d recommend trying dill, which worked just fine for my project. A nice thing about this package is that it has the same interface as pickle, so if you have already been using pickle in your project you can simply substitute in dill and see if the script runs, without changing any code. So it is a very cheap solution to try!

(Full anti-disclosure: I am in no way affiliated with and have never contributed to the dill project.)

Install the package:

pip install dill

Then edit your code to import dill instead of pickle:

# import pickle
import dill as pickle

Run your script and see if it works. (If it does you may want to clean up your code so that you are no longer shadowing the pickle module name!)

Some specifics on datatypes that dill can and cannot serialize, from the project page:

dill can pickle the following standard types:

none, type, bool, int, long, float, complex, str, unicode, tuple, list, dict, file, buffer, builtin, both old and new style classes, instances of old and new style classes, set, frozenset, array, functions, exceptions

dill can also pickle more ‘exotic’ standard types:

functions with yields, nested functions, lambdas, cell, method, unboundmethod, module, code, methodwrapper, dictproxy, methoddescriptor, getsetdescriptor, memberdescriptor, wrapperdescriptor, xrange, slice, notimplemented, ellipsis, quit

dill cannot yet pickle these standard types:

frame, generator, traceback


回答 25

我在这里没有提到串行版本控制或反向兼容,因此我将发布已经使用了一段时间的解决方案。我可能有很多东西要学,特别是Java和Javascript在这里可能比我更成熟,但是这里

https://gist.github.com/andy-d/b7878d0044a4242c0498ed6d67fd50fe

I see no mention here of serial versioning or backcompat, so I will post my solution which I’ve been using for a bit. I probably have a lot more to learn from, specifically Java and Javascript are probably more mature than me here but here goes

https://gist.github.com/andy-d/b7878d0044a4242c0498ed6d67fd50fe


回答 26

要添加另一个选项:您可以使用attrs包和asdict方法。

class ObjectEncoder(JSONEncoder):
    def default(self, o):
        return attr.asdict(o)

json.dumps(objects, cls=ObjectEncoder)

并转换回来

def from_json(o):
    if '_obj_name' in o:
        type_ = o['_obj_name']
        del o['_obj_name']
        return globals()[type_](**o)
    else:
        return o

data = JSONDecoder(object_hook=from_json).decode(data)

类看起来像这样

@attr.s
class Foo(object):
    x = attr.ib()
    _obj_name = attr.ib(init=False, default='Foo')

To add another option: You can use the attrs package and the asdict method.

class ObjectEncoder(JSONEncoder):
    def default(self, o):
        return attr.asdict(o)

json.dumps(objects, cls=ObjectEncoder)

and to convert back

def from_json(o):
    if '_obj_name' in o:
        type_ = o['_obj_name']
        del o['_obj_name']
        return globals()[type_](**o)
    else:
        return o

data = JSONDecoder(object_hook=from_json).decode(data)

class looks like this

@attr.s
class Foo(object):
    x = attr.ib()
    _obj_name = attr.ib(init=False, default='Foo')

回答 27

除了Onur的答案外,您可能还想处理类似以下的datetime类型。
(为了处理:“ datetime.datetime”对象没有属性“ dict ”异常。)

def datetime_option(value):
    if isinstance(value, datetime.date):
        return value.timestamp()
    else:
        return value.__dict__

用法:

def toJSON(self):
    return json.dumps(self, default=datetime_option, sort_keys=True, indent=4)

In addition to the Onur’s answer, You possibly want to deal with datetime type like below.
(in order to handle: ‘datetime.datetime’ object has no attribute ‘dict‘ exception.)

def datetime_option(value):
    if isinstance(value, datetime.date):
        return value.timestamp()
    else:
        return value.__dict__

Usage:

def toJSON(self):
    return json.dumps(self, default=datetime_option, sort_keys=True, indent=4)

回答 28

首先,我们需要使对象符合JSON,因此可以使用标准JSON模块将其转储。我这样做是这样的:

def serialize(o):
    if isinstance(o, dict):
        return {k:serialize(v) for k,v in o.items()}
    if isinstance(o, list):
        return [serialize(e) for e in o]
    if isinstance(o, bytes):
        return o.decode("utf-8")
    return o

First we need to make our object JSON-compliant, so we can dump it using the standard JSON module. I did it this way:

def serialize(o):
    if isinstance(o, dict):
        return {k:serialize(v) for k,v in o.items()}
    if isinstance(o, list):
        return [serialize(e) for e in o]
    if isinstance(o, bytes):
        return o.decode("utf-8")
    return o

回答 29

基于Quinten Cabo答案

def sterilize(obj):
    if type(obj) in (str, float, int, bool, type(None)):
        return obj
    elif isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif hasattr(obj, '__iter__') and callable(obj.__iter__):
        return [sterilize(v) for v in obj]
    elif hasattr(obj, '__dict__'):
        return {k: sterilize(v) for k, v in obj.__dict__.items() if k not in ['__module__', '__dict__', '__weakref__', '__doc__']}
    else:
        return repr(obj)

区别是

  1. 适用于任何迭代而不是just listtuple(适用于NumPy数组等)
  2. 适用于动态类型(包含 __dict__)。
  3. 包括本机类型floatNone因此它们不会转换为字符串。

留给读者的练习是处理__slots__,这些类既可迭代且具有成员,这些类既是字典又具有成员,等等。

Building on Quinten Cabo‘s answer:

def sterilize(obj):
    if type(obj) in (str, float, int, bool, type(None)):
        return obj
    elif isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif hasattr(obj, '__iter__') and callable(obj.__iter__):
        return [sterilize(v) for v in obj]
    elif hasattr(obj, '__dict__'):
        return {k: sterilize(v) for k, v in obj.__dict__.items() if k not in ['__module__', '__dict__', '__weakref__', '__doc__']}
    else:
        return repr(obj)

The differences are

  1. Works for any iterable instead of just list and tuple (it works for NumPy arrays, etc.)
  2. Works for dynamic types (ones that contain a __dict__).
  3. Includes native types float and None so they don’t get converted to string.

Left as an exercise to the reader is to handle __slots__, classes that are both iterable and have members, classes that are dictionaries and also have members, etc.


字符串文字前的’b’字符做什么?

问题:字符串文字前的’b’字符做什么?

显然,以下是有效的语法:

my_string = b'The string'

我想知道:

  1. 这是什么b字在前面的字符串是什么意思?
  2. 使用它有什么作用?
  3. 在什么情况下可以使用它?

我在SO上找到了一个相关的问题,但是这个问题是关于PHP的,它指出b用来表示字符串是二进制的,与Unicode相反,Unicode是使PHP <6版本兼容的代码所必需的,当迁移到PHP 6时。我认为这不适用于Python。

我确实在Python站点上找到了有关使用相同语法的字符将字符串指定为Unicode的文档u。不幸的是,它在该文档的任何地方都没有提到b字符。

而且,只是出于好奇,有没有比多符号bu是做其他事情?

Apparently, the following is the valid syntax:

my_string = b'The string'

I would like to know:

  1. What does this b character in front of the string mean?
  2. What are the effects of using it?
  3. What are appropriate situations to use it?

I found a related question right here on SO, but that question is about PHP though, and it states the b is used to indicate the string is binary, as opposed to Unicode, which was needed for code to be compatible from version of PHP < 6, when migrating to PHP 6. I don’t think this applies to Python.

I did find this documentation on the Python site about using a u character in the same syntax to specify a string as Unicode. Unfortunately, it doesn’t mention the b character anywhere in that document.

Also, just out of curiosity, are there more symbols than the b and u that do other things?


回答 0

引用Python 2.x文档

在Python 2中,前缀’b’或’B’被忽略;它表示文字应在Python 3中变成字节文字(例如,当代码自动由2to3转换时)。前缀“ u”或“ b”后可以带有前缀“ r”。

Python 3中的文件状态:

字节字面量始终以“ b”或“ B”为前缀;它们产生字节类型的实例而不是str类型。它们只能包含ASCII字符;数值等于或大于128的字节必须用转义符表示。

To quote the Python 2.x documentation:

A prefix of ‘b’ or ‘B’ is ignored in Python 2; it indicates that the literal should become a bytes literal in Python 3 (e.g. when code is automatically converted with 2to3). A ‘u’ or ‘b’ prefix may be followed by an ‘r’ prefix.

The Python 3 documentation states:

Bytes literals are always prefixed with ‘b’ or ‘B’; they produce an instance of the bytes type instead of the str type. They may only contain ASCII characters; bytes with a numeric value of 128 or greater must be expressed with escapes.


回答 1

Python 3.x明确区分了以下类型:

  • str= '...'文字= Unicode字符序列(UTF-16或UTF-32,取决于Python的编译方式)
  • bytes= b'...'文字=八位字节序列(0到255之间的整数)

如果你熟悉Java或C#,想到strStringbytes作为byte[]。如果您熟悉SQL,请认为stras NVARCHARbytesas BINARYBLOB。如果你熟悉Windows注册表,想到strREG_SZbytes作为REG_BINARY。如果您熟悉C(++),请忘记学习的所有知识char和字符串,因为CHARACTER不是BYTE。这个想法早已过时。

您可以使用str,当你想要表达的文字。

print('שלום עולם')

您可以使用bytes,当你想表示相同结构的低级别的二进制数据。

NaN = struct.unpack('>d', b'\xff\xf8\x00\x00\x00\x00\x00\x00')[0]

您可以编码一个str到一个bytes对象。

>>> '\uFEFF'.encode('UTF-8')
b'\xef\xbb\xbf'

您可以将a解码bytesstr

>>> b'\xE2\x82\xAC'.decode('UTF-8')
'€'

但是您不能随意混合使用这两种类型。

>>> b'\xEF\xBB\xBF' + 'Text with a UTF-8 BOM'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str

这种b'...'表示法有些令人困惑,因为它允许使用ASCII字符而不是十六进制数字指定字节0x01-0x7F。

>>> b'A' == b'\x41'
True

但是我必须强调,字符不是字节

>>> 'A' == b'A'
False

在Python 2.x中

Python 3.0之前的版本在文本和二进制数据之间缺乏这种区别。相反,有:

  • unicode= u'...'文字= Unicode字符序列= 3.xstr
  • str= '...'文字=混杂字节/字符的序列
    • 通常为文本,以某种未指定的编码进行编码。
    • 而且还用来表示二进制数据,如struct.pack输出。

为了简化从2.x到3.x的过渡,b'...'将原义语法反向移植到Python 2.6,以便区分二进制字符串(应bytes在3.x中)和文本字符串(应str在3中) 。X)。该b前缀在2.x中不执行任何操作,但告诉2to3脚本不要在3.x中将其转换为Unicode字符串。

因此,是的,b'...'Python中的文字具有与PHP中相同的目的。

另外,出于好奇,还有比b和u更多的符号可以执行其他操作吗?

r前缀创建原始字符串(例如,r'\t'是反斜杠+ t,而不是一个选项卡),和三引号'''...'''"""..."""允许多行字符串文字。

Python 3.x makes a clear distinction between the types:

  • str = '...' literals = a sequence of Unicode characters (UTF-16 or UTF-32, depending on how Python was compiled)
  • bytes = b'...' literals = a sequence of octets (integers between 0 and 255)

If you’re familiar with Java or C#, think of str as String and bytes as byte[]. If you’re familiar with SQL, think of str as NVARCHAR and bytes as BINARY or BLOB. If you’re familiar with the Windows registry, think of str as REG_SZ and bytes as REG_BINARY. If you’re familiar with C(++), then forget everything you’ve learned about char and strings, because A CHARACTER IS NOT A BYTE. That idea is long obsolete.

You use str when you want to represent text.

print('שלום עולם')

You use bytes when you want to represent low-level binary data like structs.

NaN = struct.unpack('>d', b'\xff\xf8\x00\x00\x00\x00\x00\x00')[0]

You can encode a str to a bytes object.

>>> '\uFEFF'.encode('UTF-8')
b'\xef\xbb\xbf'

And you can decode a bytes into a str.

>>> b'\xE2\x82\xAC'.decode('UTF-8')
'€'

But you can’t freely mix the two types.

>>> b'\xEF\xBB\xBF' + 'Text with a UTF-8 BOM'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str

The b'...' notation is somewhat confusing in that it allows the bytes 0x01-0x7F to be specified with ASCII characters instead of hex numbers.

>>> b'A' == b'\x41'
True

But I must emphasize, a character is not a byte.

>>> 'A' == b'A'
False

In Python 2.x

Pre-3.0 versions of Python lacked this kind of distinction between text and binary data. Instead, there was:

  • unicode = u'...' literals = sequence of Unicode characters = 3.x str
  • str = '...' literals = sequences of confounded bytes/characters
    • Usually text, encoded in some unspecified encoding.
    • But also used to represent binary data like struct.pack output.

In order to ease the 2.x-to-3.x transition, the b'...' literal syntax was backported to Python 2.6, in order to allow distinguishing binary strings (which should be bytes in 3.x) from text strings (which should be str in 3.x). The b prefix does nothing in 2.x, but tells the 2to3 script not to convert it to a Unicode string in 3.x.

So yes, b'...' literals in Python have the same purpose that they do in PHP.

Also, just out of curiosity, are there more symbols than the b and u that do other things?

The r prefix creates a raw string (e.g., r'\t' is a backslash + t instead of a tab), and triple quotes '''...''' or """...""" allow multi-line string literals.


回答 2

b表示字节字符串。

字节是实际数据。字符串是一种抽象。

如果您有多个字符的字符串对象并且使用了一个字符,则该字符串将是一个字符串,并且根据编码的不同,大小可能会超过1个字节。

如果使用1个字节和一个字节字符串,则您将获得0-255之间的单个8位值,并且如果由于编码而导致的那些字符大于1个字节,则它可能不表示完整的字符。

TBH我将使用字符串,除非我有一些特定的低级原因要使用字节。

The b denotes a byte string.

Bytes are the actual data. Strings are an abstraction.

If you had multi-character string object and you took a single character, it would be a string, and it might be more than 1 byte in size depending on encoding.

If took 1 byte with a byte string, you’d get a single 8-bit value from 0-255 and it might not represent a complete character if those characters due to encoding were > 1 byte.

TBH I’d use strings unless I had some specific low level reason to use bytes.


回答 3

从服务器端,如果我们发送任何响应,它将以字节类型的形式发送,因此它将在客户端中显示为 b'Response from server'

为了摆脱,b'....'只需使用以下代码:

服务器文件:

stri="Response from server"    
c.send(stri.encode())

客户端文件:

print(s.recv(1024).decode())

然后它将打印 Response from server

From server side, if we send any response, it will be sent in the form of byte type, so it will appear in the client as b'Response from server'

In order get rid of b'....' simply use below code:

Server file:

stri="Response from server"    
c.send(stri.encode())

Client file:

print(s.recv(1024).decode())

then it will print Response from server


回答 4

这是一个示例,其中缺少bTypeError在Python 3.x中引发异常

>>> f=open("new", "wb")
>>> f.write("Hello Python!")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' does not support the buffer interface

添加b前缀将解决此问题。

Here’s an example where the absence of b would throw a TypeError exception in Python 3.x

>>> f=open("new", "wb")
>>> f.write("Hello Python!")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' does not support the buffer interface

Adding a b prefix would fix the problem.


回答 5

它将其转换为bytes文字(或str在2.x中),并且对于2.6+有效。

r前缀导致反斜杠需要“不解释”(不被忽略,差异确实物质)。

It turns it into a bytes literal (or str in 2.x), and is valid for 2.6+.

The r prefix causes backslashes to be “uninterpreted” (not ignored, and the difference does matter).


回答 6

除了其他人所说的以外,请注意unicode中的单个字符可以由多个字节组成

unicode的工作方式是采用旧的ASCII格式(7位代码,看起来像0xxx xxxx),并添加了多字节序列,其中所有字节均以1(1xxx xxxx)开头,以表示ASCII以外的字符,以便Unicode 向后-与ASCII 兼容

>>> len('Öl')  # German word for 'oil' with 2 characters
2
>>> 'Öl'.encode('UTF-8')  # convert str to bytes 
b'\xc3\x96l'
>>> len('Öl'.encode('UTF-8'))  # 3 bytes encode 2 characters !
3

In addition to what others have said, note that a single character in unicode can consist of multiple bytes.

The way unicode works is that it took the old ASCII format (7-bit code that looks like 0xxx xxxx) and added multi-bytes sequences where all bytes start with 1 (1xxx xxxx) to represent characters beyond ASCII so that Unicode would be backwards-compatible with ASCII.

>>> len('Öl')  # German word for 'oil' with 2 characters
2
>>> 'Öl'.encode('UTF-8')  # convert str to bytes 
b'\xc3\x96l'
>>> len('Öl'.encode('UTF-8'))  # 3 bytes encode 2 characters !
3

回答 7

您可以使用JSON将其转换为字典

import json
data = b'{"key":"value"}'
print(json.loads(data))

{“核心价值”}


烧瓶:

这是烧瓶的一个例子。在终端行上运行此命令:

import requests
requests.post(url='http://localhost(example)/',json={'key':'value'})

在flask / routes.py中

@app.route('/', methods=['POST'])
def api_script_add():
    print(request.data) # --> b'{"hi":"Hello"}'
    print(json.loads(request.data))
return json.loads(request.data)

{‘核心价值’}

You can use JSON to convert it to dictionary

import json
data = b'{"key":"value"}'
print(json.loads(data))

{“key”:”value”}


FLASK:

This is an example from flask. Run this on terminal line:

import requests
requests.post(url='http://localhost(example)/',json={'key':'value'})

In flask/routes.py

@app.route('/', methods=['POST'])
def api_script_add():
    print(request.data) # --> b'{"hi":"Hello"}'
    print(json.loads(request.data))
return json.loads(request.data)

{‘key’:’value’}


如何使IPython Notebook Matplotlib内联绘图

问题:如何使IPython Notebook Matplotlib内联绘图

我正在MacOS X上使用Python 2.7.2和IPython 1.1.0的情况下使用IPython Notebook。

我无法获得matplotlib图形来内联显示。

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline  

我也试过了%pylab inline和ipython命令行参数,--pylab=inline但这没什么区别。

x = np.linspace(0, 3*np.pi, 500)
plt.plot(x, np.sin(x**2))
plt.title('A simple chirp')
plt.show()

我得到的不是内联图形,而是:

<matplotlib.figure.Figure at 0x110b9c450>

matplotlib.get_backend()表明我有'module://IPython.kernel.zmq.pylab.backend_inline'后端。

I am trying to use IPython notebook on MacOS X with Python 2.7.2 and IPython 1.1.0.

I cannot get matplotlib graphics to show up inline.

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline  

I have also tried %pylab inline and the ipython command line arguments --pylab=inline but this makes no difference.

x = np.linspace(0, 3*np.pi, 500)
plt.plot(x, np.sin(x**2))
plt.title('A simple chirp')
plt.show()

Instead of inline graphics, I get this:

<matplotlib.figure.Figure at 0x110b9c450>

And matplotlib.get_backend() shows that I have the 'module://IPython.kernel.zmq.pylab.backend_inline' backend.


回答 0

%matplotlib inline在笔记本的第一个单元中使用了它,并且可以正常工作。我认为您应该尝试:

%matplotlib inline

import matplotlib
import numpy as np
import matplotlib.pyplot as plt

通过在配置文件中设置以下配置选项,默认情况下,您也始终可以始终默认以内联模式启动所有IPython内核:

c.IPKernelApp.matplotlib=<CaselessStrEnum>
  Default: None
  Choices: ['auto', 'gtk', 'gtk3', 'inline', 'nbagg', 'notebook', 'osx', 'qt', 'qt4', 'qt5', 'tk', 'wx']
  Configure matplotlib for interactive use with the default matplotlib backend.

I used %matplotlib inline in the first cell of the notebook and it works. I think you should try:

%matplotlib inline

import matplotlib
import numpy as np
import matplotlib.pyplot as plt

You can also always start all your IPython kernels in inline mode by default by setting the following config options in your config files:

c.IPKernelApp.matplotlib=<CaselessStrEnum>
  Default: None
  Choices: ['auto', 'gtk', 'gtk3', 'inline', 'nbagg', 'notebook', 'osx', 'qt', 'qt4', 'qt5', 'tk', 'wx']
  Configure matplotlib for interactive use with the default matplotlib backend.

回答 1

如果您的matplotlib版本高于1.4,则也可以使用

IPython 3.x及更高版本

%matplotlib notebook

import matplotlib.pyplot as plt

旧版本

%matplotlib nbagg

import matplotlib.pyplot as plt

两者都将激活nbagg后端,从而启用交互性。

使用nbagg后端的示例图

If your matplotlib version is above 1.4, it is also possible to use

IPython 3.x and above

%matplotlib notebook

import matplotlib.pyplot as plt

older versions

%matplotlib nbagg

import matplotlib.pyplot as plt

Both will activate the nbagg backend, which enables interactivity.

Example plot with the nbagg backend


回答 2

Ctrl + Enter

%matplotlib inline

魔线:D

请参阅:使用Matplotlib进行绘图

Ctrl + Enter

%matplotlib inline

Magic Line :D

See: Plotting with Matplotlib.


回答 3

使用%pylab inline魔术命令。

Use the %pylab inline magic command.


回答 4

要在Jupyter(IPython 3)中默认使matplotlib内联:

  1. 编辑档案 ~/.ipython/profile_default/ipython_config.py

  2. 加线 c.InteractiveShellApp.matplotlib = 'inline'

请注意,添加该行将ipython_notebook_config.py不起作用。否则,它可以与Jupyter和IPython 3.1.0一起使用

To make matplotlib inline by default in Jupyter (IPython 3):

  1. Edit file ~/.ipython/profile_default/ipython_config.py

  2. Add line c.InteractiveShellApp.matplotlib = 'inline'

Please note that adding this line to ipython_notebook_config.py would not work. Otherwise it works well with Jupyter and IPython 3.1.0


回答 5

我必须同意foobarbecue(我的建议不足,无法简单地在他的帖子下插入评论):

--pylab根据Fernando Perez(ipythonnb的创建者)的说法,现在建议不要使用该参数启动python笔记本。%matplotlib inline应该是笔记本的初始命令。

看到这里:http : //nbviewer.ipython.org/github/ipython/ipython/blob/1.x/examples/notebooks/Part%203%20-%20Plotting%20with%20Matplotlib.ipynb

I have to agree with foobarbecue (I don’t have enough recs to be able to simply insert a comment under his post):

It’s now recommended that python notebook isn’t started wit the argument --pylab, and according to Fernando Perez (creator of ipythonnb) %matplotlib inline should be the initial notebook command.

See here: http://nbviewer.ipython.org/github/ipython/ipython/blob/1.x/examples/notebooks/Part%203%20-%20Plotting%20with%20Matplotlib.ipynb


回答 6

我找到了一种非常令人满意的解决方法。我安装了Anaconda Python,现在对我来说开箱即用。

I found a workaround that is quite satisfactory. I installed Anaconda Python and this now works out of the box for me.


回答 7

我做了anaconda安装,但是matplotlib没有绘制

当我这样做时它开始绘图

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline  

I did the anaconda install but matplotlib is not plotting

It starts plotting when i did this

import matplotlib
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline  

回答 8

您可以使用语法错误来模拟此问题,但是%matplotlib inline无法解决该问题。

首先是创建绘图的正确方法的示例。eNord9提供的导入内容和魔术可以使一切正常工作。

df_randNumbers1 = pd.DataFrame(np.random.randint(0,100,size=(100, 6)), columns=list('ABCDEF'))

df_randNumbers1.ix[:,["A","B"]].plot.kde()

但是,通过将()绘图类型的末尾保留为空白,您会收到含糊不清的非错误。

错误代码:

df_randNumbers1.ix[:,["A","B"]].plot.kde

错误示例:

<bound method FramePlotMethods.kde of <pandas.tools.plotting.FramePlotMethods object at 0x000001DDAF029588>>

除了这一行消息外,没有堆栈跟踪或其他明显的理由认为您犯了语法错误。该图不打印。

You can simulate this problem with a syntax mistake, however, %matplotlib inline won’t resolve the issue.

First an example of the right way to create a plot. Everything works as expected with the imports and magic that eNord9 supplied.

df_randNumbers1 = pd.DataFrame(np.random.randint(0,100,size=(100, 6)), columns=list('ABCDEF'))

df_randNumbers1.ix[:,["A","B"]].plot.kde()

However, by leaving the () off the end of the plot type you receive a somewhat ambiguous non-error.

Erronious code:

df_randNumbers1.ix[:,["A","B"]].plot.kde

Example error:

<bound method FramePlotMethods.kde of <pandas.tools.plotting.FramePlotMethods object at 0x000001DDAF029588>>

Other than this one line message, there is no stack trace or other obvious reason to think you made a syntax error. The plot doesn’t print.


回答 9

在Jupyter的单独单元中运行绘图命令时,我遇到了同样的问题:

In [1]:  %matplotlib inline
         import matplotlib
         import matplotlib.pyplot as plt
         import numpy as np
In [2]:  x = np.array([1, 3, 4])
         y = np.array([1, 5, 3])
In [3]:  fig = plt.figure()
         <Figure size 432x288 with 0 Axes>                      #this might be the problem
In [4]:  ax = fig.add_subplot(1, 1, 1)
In [5]:  ax.scatter(x, y)
Out[5]:  <matplotlib.collections.PathCollection at 0x12341234>  # CAN'T SEE ANY PLOT :(
In [6]:  plt.show()                                             # STILL CAN'T SEE IT :(

通过将绘图命令合并到单个单元格中解决了该问题:

In [1]:  %matplotlib inline
         import matplotlib
         import matplotlib.pyplot as plt
         import numpy as np
In [2]:  x = np.array([1, 3, 4])
         y = np.array([1, 5, 3])
In [3]:  fig = plt.figure()
         ax = fig.add_subplot(1, 1, 1)
         ax.scatter(x, y)
Out[3]:  <matplotlib.collections.PathCollection at 0x12341234>
         # AND HERE APPEARS THE PLOT AS DESIRED :)

I had the same problem when I was running the plotting commands in separate cells in Jupyter:

In [1]:  %matplotlib inline
         import matplotlib
         import matplotlib.pyplot as plt
         import numpy as np
In [2]:  x = np.array([1, 3, 4])
         y = np.array([1, 5, 3])
In [3]:  fig = plt.figure()
         <Figure size 432x288 with 0 Axes>                      #this might be the problem
In [4]:  ax = fig.add_subplot(1, 1, 1)
In [5]:  ax.scatter(x, y)
Out[5]:  <matplotlib.collections.PathCollection at 0x12341234>  # CAN'T SEE ANY PLOT :(
In [6]:  plt.show()                                             # STILL CAN'T SEE IT :(

The problem was solved by merging the plotting commands into a single cell:

In [1]:  %matplotlib inline
         import matplotlib
         import matplotlib.pyplot as plt
         import numpy as np
In [2]:  x = np.array([1, 3, 4])
         y = np.array([1, 5, 3])
In [3]:  fig = plt.figure()
         ax = fig.add_subplot(1, 1, 1)
         ax.scatter(x, y)
Out[3]:  <matplotlib.collections.PathCollection at 0x12341234>
         # AND HERE APPEARS THE PLOT AS DESIRED :)

在if语句中,Python等效于&&(逻辑与)

问题:在if语句中,Python等效于&&(逻辑与)

这是我的代码:

def front_back(a, b):
  # +++your code here+++
  if len(a) % 2 == 0 && len(b) % 2 == 0:
    return a[:(len(a)/2)] + b[:(len(b)/2)] + a[(len(a)/2):] + b[(len(b)/2):] 
  else:
    #todo! Not yet done. :P
  return

我在IF条件中遇到错误。
我究竟做错了什么?

Here’s my code:

def front_back(a, b):
  # +++your code here+++
  if len(a) % 2 == 0 && len(b) % 2 == 0:
    return a[:(len(a)/2)] + b[:(len(b)/2)] + a[(len(a)/2):] + b[(len(b)/2):] 
  else:
    #todo! Not yet done. :P
  return

I’m getting an error in the IF conditional.
What am I doing wrong?


回答 0

您可能想要and而不是&&

You would want and instead of &&.


回答 1

Python使用andor条件。

if foo == 'abc' and bar == 'bac' or zoo == '123':
  # do something

Python uses and and or conditionals.

i.e.

if foo == 'abc' and bar == 'bac' or zoo == '123':
  # do something

回答 2

我在IF条件中遇到错误。我究竟做错了什么?

得到a的原因SyntaxError&&Python中没有运算符。同样||!并且不是有效的 Python运算符。

您可能从其他语言中了解到的某些运算符在Python中使用不同的名称。逻辑运算符&&||实际上被称为andor。同样,逻辑否定运算符!称为not

所以你可以这样写:

if len(a) % 2 == 0 and len(b) % 2 == 0:

甚至:

if not (len(a) % 2 or len(b) % 2):

一些其他信息(可能会派上用场):

我在此表中总结了运算符“等效项”:

+------------------------------+---------------------+
|  Operator (other languages)  |  Operator (Python)  |
+==============================+=====================+
|              &&              |         and         |
+------------------------------+---------------------+
|              ||              |         or          |
+------------------------------+---------------------+
|              !               |         not         |
+------------------------------+---------------------+

另请参阅Python文档:6.11。布尔运算

除了逻辑运算符外,Python还具有按位/二进制运算符:

+--------------------+--------------------+
|  Logical operator  |  Bitwise operator  |
+====================+====================+
|        and         |         &          |
+--------------------+--------------------+
|         or         |         |          |
+--------------------+--------------------+

Python中没有按位取反(只是按位逆运算符~-但这并不等效于not)。

另见6.6。一元算术和按位/二进制运算6.7。二进制算术运算

逻辑运算符(像许多其他语言一样)具有使它们短路的优点。这意味着,如果第一个操作数已经定义了结果,则根本不会对第二个运算符求值。

为了说明这一点,我使用了一个简单地使用值的函数,将其打印并再次返回。方便查看由于print语句而实际评估的内容:

>>> def print_and_return(value):
...     print(value)
...     return value

>>> res = print_and_return(False) and print_and_return(True)
False

如您所见,仅执行了一个print语句,因此Python甚至没有查看正确的操作数。

对于二进制运算符,情况并非如此。那些总是评估两个操作数:

>>> res = print_and_return(False) & print_and_return(True);
False
True

但是,如果第一个操作数不够用,那么,当然会计算第二个运算符:

>>> res = print_and_return(True) and print_and_return(False);
True
False

总结一下,这是另一个表:

+-----------------+-------------------------+
|   Expression    |  Right side evaluated?  |
+=================+=========================+
| `True` and ...  |           Yes           |
+-----------------+-------------------------+
| `False` and ... |           No            |
+-----------------+-------------------------+
|  `True` or ...  |           No            |
+-----------------+-------------------------+
| `False` or ...  |           Yes           |
+-----------------+-------------------------+

TrueFalse代表什么bool(left-hand-side)回报,他们不必是TrueFalse,他们只需要返回TrueFalsebool被要求他们(1)。

因此,在Pseudo-Code(!)中,andand or函数的工作方式如下:

def and(expr1, expr2):
    left = evaluate(expr1)
    if bool(left):
        return evaluate(expr2)
    else:
        return left

def or(expr1, expr2):
    left = evaluate(expr1)
    if bool(left):
        return left
    else:
        return evaluate(expr2)

请注意,这是伪代码,而不是Python代码。在Python中,您无法创建称为and或的函数,or因为这些是关键字。另外,您永远不要使用“评估”或if bool(...)

自定义自己的类的行为

这隐含bool调用可用于自定义您的类的行为有andornot

为了说明如何进行自定义,我使用该类来再次print跟踪正在发生的事情:

class Test(object):
    def __init__(self, value):
        self.value = value

    def __bool__(self):
        print('__bool__ called on {!r}'.format(self))
        return bool(self.value)

    __nonzero__ = __bool__  # Python 2 compatibility

    def __repr__(self):
        return "{self.__class__.__name__}({self.value})".format(self=self)

因此,让我们看看与这些运算符结合使用该类会发生什么:

>>> if Test(True) and Test(False):
...     pass
__bool__ called on Test(True)
__bool__ called on Test(False)

>>> if Test(False) or Test(False):
...     pass
__bool__ called on Test(False)
__bool__ called on Test(False)

>>> if not Test(True):
...     pass
__bool__ called on Test(True)

如果您没有__bool__方法,Python还将检查对象是否具有__len__方法,以及它是否返回大于零的值。如果您创建了序列容器,可能会很有用。

另请参阅4.1。真值测试

NumPy数组和子类

可能超出了原始问题的范围,但是如果您要处理NumPy数组或子类(如Pandas Series或DataFrames),则隐式bool调用将引发可怕的问题ValueError

>>> import numpy as np
>>> arr = np.array([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

>>> import pandas as pd
>>> s = pd.Series([1,2,3])
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> s and s
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

在这些情况下,您可以使用NumPy中的逻辑和函数,该逻辑和函数执行逐个元素and(或or):

>>> np.logical_and(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([False, False,  True, False])
>>> np.logical_or(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([ True, False,  True,  True])

如果您只处理布尔数组,则还可以将二进制运算符与NumPy一起使用,它们确实会执行按元素进行比较(也可以是二进制)的比较:

>>> np.array([False,False,True,True]) & np.array([True, False, True, False])
array([False, False,  True, False])
>>> np.array([False,False,True,True]) | np.array([True, False, True, False])
array([ True, False,  True,  True])

(1)

bool对操作数调用必须返回True或者False是不完全正确的。它只是第一个需要在其__bool__方法中返回布尔值的操作数:

class Test(object):
    def __init__(self, value):
        self.value = value

    def __bool__(self):
        return self.value

    __nonzero__ = __bool__  # Python 2 compatibility

    def __repr__(self):
        return "{self.__class__.__name__}({self.value})".format(self=self)

>>> x = Test(10) and Test(10)
TypeError: __bool__ should return bool, returned int
>>> x1 = Test(True) and Test(10)
>>> x2 = Test(False) and Test(10)

这是因为,and如果第一个操作数求和False,则实际返回第一个操作数;如果求和,True则返回第二个操作数:

>>> x1
Test(10)
>>> x2
Test(False)

同样,or但相反:

>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)

但是,如果您在if语句中使用它们,if也会隐式调用bool结果。因此,这些要点可能与您无关。

I’m getting an error in the IF conditional. What am I doing wrong?

There reason that you get a SyntaxError is that there is no && operator in Python. Likewise || and ! are not valid Python operators.

Some of the operators you may know from other languages have a different name in Python. The logical operators && and || are actually called and and or. Likewise the logical negation operator ! is called not.

So you could just write:

if len(a) % 2 == 0 and len(b) % 2 == 0:

or even:

if not (len(a) % 2 or len(b) % 2):

Some additional information (that might come in handy):

I summarized the operator “equivalents” in this table:

+------------------------------+---------------------+
|  Operator (other languages)  |  Operator (Python)  |
+==============================+=====================+
|              &&              |         and         |
+------------------------------+---------------------+
|              ||              |         or          |
+------------------------------+---------------------+
|              !               |         not         |
+------------------------------+---------------------+

See also Python documentation: 6.11. Boolean operations.

Besides the logical operators Python also has bitwise/binary operators:

+--------------------+--------------------+
|  Logical operator  |  Bitwise operator  |
+====================+====================+
|        and         |         &          |
+--------------------+--------------------+
|         or         |         |          |
+--------------------+--------------------+

There is no bitwise negation in Python (just the bitwise inverse operator ~ – but that is not equivalent to not).

See also 6.6. Unary arithmetic and bitwise/binary operations and 6.7. Binary arithmetic operations.

The logical operators (like in many other languages) have the advantage that these are short-circuited. That means if the first operand already defines the result, then the second operator isn’t evaluated at all.

To show this I use a function that simply takes a value, prints it and returns it again. This is handy to see what is actually evaluated because of the print statements:

>>> def print_and_return(value):
...     print(value)
...     return value

>>> res = print_and_return(False) and print_and_return(True)
False

As you can see only one print statement is executed, so Python really didn’t even look at the right operand.

This is not the case for the binary operators. Those always evaluate both operands:

>>> res = print_and_return(False) & print_and_return(True);
False
True

But if the first operand isn’t enough then, of course, the second operator is evaluated:

>>> res = print_and_return(True) and print_and_return(False);
True
False

To summarize this here is another Table:

+-----------------+-------------------------+
|   Expression    |  Right side evaluated?  |
+=================+=========================+
| `True` and ...  |           Yes           |
+-----------------+-------------------------+
| `False` and ... |           No            |
+-----------------+-------------------------+
|  `True` or ...  |           No            |
+-----------------+-------------------------+
| `False` or ...  |           Yes           |
+-----------------+-------------------------+

The True and False represent what bool(left-hand-side) returns, they don’t have to be True or False, they just need to return True or False when bool is called on them (1).

So in Pseudo-Code(!) the and and or functions work like these:

def and(expr1, expr2):
    left = evaluate(expr1)
    if bool(left):
        return evaluate(expr2)
    else:
        return left

def or(expr1, expr2):
    left = evaluate(expr1)
    if bool(left):
        return left
    else:
        return evaluate(expr2)

Note that this is pseudo-code not Python code. In Python you cannot create functions called and or or because these are keywords. Also you should never use “evaluate” or if bool(...).

Customizing the behavior of your own classes

This implicit bool call can be used to customize how your classes behave with and, or and not.

To show how this can be customized I use this class which again prints something to track what is happening:

class Test(object):
    def __init__(self, value):
        self.value = value

    def __bool__(self):
        print('__bool__ called on {!r}'.format(self))
        return bool(self.value)

    __nonzero__ = __bool__  # Python 2 compatibility

    def __repr__(self):
        return "{self.__class__.__name__}({self.value})".format(self=self)

So let’s see what happens with that class in combination with these operators:

>>> if Test(True) and Test(False):
...     pass
__bool__ called on Test(True)
__bool__ called on Test(False)

>>> if Test(False) or Test(False):
...     pass
__bool__ called on Test(False)
__bool__ called on Test(False)

>>> if not Test(True):
...     pass
__bool__ called on Test(True)

If you don’t have a __bool__ method then Python also checks if the object has a __len__ method and if it returns a value greater than zero. That might be useful to know in case you create a sequence container.

See also 4.1. Truth Value Testing.

NumPy arrays and subclasses

Probably a bit beyond the scope of the original question but in case you’re dealing with NumPy arrays or subclasses (like Pandas Series or DataFrames) then the implicit bool call will raise the dreaded ValueError:

>>> import numpy as np
>>> arr = np.array([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

>>> import pandas as pd
>>> s = pd.Series([1,2,3])
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> s and s
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

In these cases you can use the logical and function from NumPy which performs an element-wise and (or or):

>>> np.logical_and(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([False, False,  True, False])
>>> np.logical_or(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([ True, False,  True,  True])

If you’re dealing just with boolean arrays you could also use the binary operators with NumPy, these do perform element-wise (but also binary) comparisons:

>>> np.array([False,False,True,True]) & np.array([True, False, True, False])
array([False, False,  True, False])
>>> np.array([False,False,True,True]) | np.array([True, False, True, False])
array([ True, False,  True,  True])

(1)

That the bool call on the operands has to return True or False isn’t completely correct. It’s just the first operand that needs to return a boolean in it’s __bool__ method:

class Test(object):
    def __init__(self, value):
        self.value = value

    def __bool__(self):
        return self.value

    __nonzero__ = __bool__  # Python 2 compatibility

    def __repr__(self):
        return "{self.__class__.__name__}({self.value})".format(self=self)

>>> x = Test(10) and Test(10)
TypeError: __bool__ should return bool, returned int
>>> x1 = Test(True) and Test(10)
>>> x2 = Test(False) and Test(10)

That’s because and actually returns the first operand if the first operand evaluates to False and if it evaluates to True then it returns the second operand:

>>> x1
Test(10)
>>> x2
Test(False)

Similarly for or but just the other way around:

>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)

However if you use them in an if statement the if will also implicitly call bool on the result. So these finer points may not be relevant for you.


回答 3

两条评论:

  • 在Python中使用andor进行逻辑操作。
  • 使用4个空格而不是2缩进。您稍后将感谢自己,因为您的代码看起来与其他人的代码几乎相同。有关更多详细信息,请参见PEP 8

Two comments:

  • Use and and or for logical operations in Python.
  • Use 4 spaces to indent instead of 2. You will thank yourself later because your code will look pretty much the same as everyone else’s code. See PEP 8 for more details.

回答 4

您可以使用andor执行类似C,C ++的逻辑操作。就像字面上的andis &&oris一样||


看看这个有趣的例子,

假设您要使用Python构建Logic Gate:

def AND(a,b):
    return (a and b) #using and operator

def OR(a,b):
    return (a or b)  #using or operator

现在尝试调用给他们:

print AND(False, False)
print OR(True, False)

这将输出:

False
True

希望这可以帮助!

You use and and or to perform logical operations like in C, C++. Like literally and is && and or is ||.


Take a look at this fun example,

Say you want to build Logic Gates in Python:

def AND(a,b):
    return (a and b) #using and operator

def OR(a,b):
    return (a or b)  #using or operator

Now try calling them:

print AND(False, False)
print OR(True, False)

This will output:

False
True

Hope this helps!


回答 5

我提出了一个纯粹的数学解决方案:

def front_back(a, b):
  return a[:(len(a)+1)//2]+b[:(len(b)+1)//2]+a[(len(a)+1)//2:]+b[(len(b)+1)//2:]

I went with a purlely mathematical solution:

def front_back(a, b):
  return a[:(len(a)+1)//2]+b[:(len(b)+1)//2]+a[(len(a)+1)//2:]+b[(len(b)+1)//2:]

回答 6

可能这不是执行此任务的最佳代码,但是可以正常工作-

def front_back(a, b):

 if len(a) % 2 == 0 and len(b) % 2 == 0:
    print a[:(len(a)/2)] + b[:(len(b)/2)] + a[(len(a)/2):] + b[(len(b)/2):]

 elif len(a) % 2 == 1 and len(b) % 2 == 0:
    print a[:(len(a)/2)+1] + b[:(len(b)/2)] + a[(len(a)/2)+1:] + b[(len(b)/2):] 

 elif len(a) % 2 == 0 and len(b) % 2 == 1:
     print a[:(len(a)/2)] + b[:(len(b)/2)+1] + a[(len(a)/2):] + b[(len(b)/2)+1:] 

 else :
     print a[:(len(a)/2)+1] + b[:(len(b)/2)+1] + a[(len(a)/2)+1:] + b[(len(b)/2)+1:]

Probably this is not best code for this task, but is working –

def front_back(a, b):

 if len(a) % 2 == 0 and len(b) % 2 == 0:
    print a[:(len(a)/2)] + b[:(len(b)/2)] + a[(len(a)/2):] + b[(len(b)/2):]

 elif len(a) % 2 == 1 and len(b) % 2 == 0:
    print a[:(len(a)/2)+1] + b[:(len(b)/2)] + a[(len(a)/2)+1:] + b[(len(b)/2):] 

 elif len(a) % 2 == 0 and len(b) % 2 == 1:
     print a[:(len(a)/2)] + b[:(len(b)/2)+1] + a[(len(a)/2):] + b[(len(b)/2)+1:] 

 else :
     print a[:(len(a)/2)+1] + b[:(len(b)/2)+1] + a[(len(a)/2)+1:] + b[(len(b)/2)+1:]

回答 7

一个&(而不是double &&)就足够了,或者作为最高答案建议您可以使用’and’。我也在大熊猫中发现了

cities['Is wide and has saint name'] = (cities['Population'] > 1000000) 
& cities['City name'].apply(lambda name: name.startswith('San'))

如果我们将“&”替换为“ and”,则将无法使用。

A single & (not double &&) is enough or as the top answer suggests you can use ‘and’. I also found this in pandas

cities['Is wide and has saint name'] = (cities['Population'] > 1000000) 
& cities['City name'].apply(lambda name: name.startswith('San'))

if we replace the “&” with “and”, it won’t work.


回答 8

也许用&代替%可以更快并保持可读性

其他测试奇数/奇数

x是偶数?x%2 == 0

x是奇数?不是x%2 == 0

也许按位和1更清楚

x是奇数?x&1

x是偶数?不是x&1(不奇怪)

def front_back(a, b):
    # +++your code here+++
    if not len(a) & 1 and not len(b) & 1:
        return a[:(len(a)/2)] + b[:(len(b)/2)] + a[(len(a)/2):] + b[(len(b)/2):] 
    else:
        #todo! Not yet done. :P
    return

maybe with & instead % is more fast and mantain readibility

other tests even/odd

x is even ? x % 2 == 0

x is odd ? not x % 2 == 0

maybe is more clear with bitwise and 1

x is odd ? x & 1

x is even ? not x & 1 (not odd)

def front_back(a, b):
    # +++your code here+++
    if not len(a) & 1 and not len(b) & 1:
        return a[:(len(a)/2)] + b[:(len(b)/2)] + a[(len(a)/2):] + b[(len(b)/2):] 
    else:
        #todo! Not yet done. :P
    return

回答 9

有条件地使用“和”。在Jupyter Notebook导入时,我经常使用此功能:

def find_local_py_scripts():
    import os # does not cost if already imported
    for entry in os.scandir('.'):
        # find files ending with .py
        if entry.is_file() and entry.name.endswith(".py") :
            print("- ", entry.name)
find_local_py_scripts()

-  googlenet_custom_layers.py
-  GoogLeNet_Inception_v1.py

Use of “and” in conditional. I often use this when importing in Jupyter Notebook:

def find_local_py_scripts():
    import os # does not cost if already imported
    for entry in os.scandir('.'):
        # find files ending with .py
        if entry.is_file() and entry.name.endswith(".py") :
            print("- ", entry.name)
find_local_py_scripts()

-  googlenet_custom_layers.py
-  GoogLeNet_Inception_v1.py

我应该放#!(shebang)在Python脚本中,它应该采用什么形式?

问题:我应该放#!(shebang)在Python脚本中,它应该采用什么形式?

我应该把shebang放到我的Python脚本中吗?以什么形式?

#!/usr/bin/env python 

要么

#!/usr/local/bin/python

这些同样便携吗?最常用哪种形式?

注:龙卷风项目采用的家当。另一方面, Django项目没有。

Should I put the shebang in my Python scripts? In what form?

#!/usr/bin/env python 

or

#!/usr/local/bin/python

Are these equally portable? Which form is used most?

Note: the tornado project uses the shebang. On the other hand the Django project doesn’t.


回答 0

任何脚本中的shebang行都决定了脚本的执行能力,就像独立的可执行文件一样,无需python事先在终端中键入或在文件管理器中双击(正确配置时)。不必要,但通常放在那里,因此当有人看到在编辑器中打开文件时,他们会立即知道他们在看什么。但是,您使用的家当线IS重要。

Python 3脚本的正确用法是:

#!/usr/bin/env python3

默认为版本3.latest。对于Python 2.7.latest python2代替python3

不应使用以下内容(除了极少数情况下,您正在编写与Python 2.x和3.x兼容的代码):

#!/usr/bin/env python

中给出的原因是这些建议,PEP 394,是python可以指到python2python3在不同的系统。目前,它python2在大多数发行版中都涉及,但是在某些时候可能会改变。

另外,请勿使用:

#!/usr/local/bin/python

“在这种情况下,python可能安装在/ usr / bin / python或/ bin / python上,上述#!将失败。”

“#!/ usr / bin / env python”与“#!/ usr / local / bin / python”

The shebang line in any script determines the script’s ability to be executed like a standalone executable without typing python beforehand in the terminal or when double clicking it in a file manager (when configured properly). It isn’t necessary but generally put there so when someone sees the file opened in an editor, they immediately know what they’re looking at. However, which shebang line you use IS important.

Correct usage for Python 3 scripts is:

#!/usr/bin/env python3

This defaults to version 3.latest. For Python 2.7.latest use python2 in place of python3.

The following should NOT be used (except for the rare case that you are writing code which is compatible with both Python 2.x and 3.x):

#!/usr/bin/env python

The reason for these recommendations, given in PEP 394, is that python can refer either to python2 or python3 on different systems. It currently refers to python2 on most distributions, but that is likely to change at some point.

Also, DO NOT Use:

#!/usr/local/bin/python

“python may be installed at /usr/bin/python or /bin/python in those cases, the above #! will fail.”

“#!/usr/bin/env python” vs “#!/usr/local/bin/python”


回答 1

这实际上只是一个品味问题。添加shebang意味着人们可以根据需要直接调用脚本(假设它被标记为可执行文件);省略它只是意味着python必须手动调用。

无论哪种方式,运行该程序的最终结果都不会受到影响。这只是手段的选择。

It’s really just a matter of taste. Adding the shebang means people can invoke the script directly if they want (assuming it’s marked as executable); omitting it just means python has to be invoked manually.

The end result of running the program isn’t affected either way; it’s just options of the means.


回答 2

我应该把shebang放到我的Python脚本中吗?

将shebang放入Python脚本中以指示:

  • 该模块可以作为脚本运行
  • 它只能在python2,python3上运行还是与Python 2/3兼容?
  • 在POSIX上,如果要直接运行脚本而不python显式调用可执行文件,则很有必要

这些同样便携吗?最常用哪种形式?

如果您手动编写shebang ,请始终使用,#!/usr/bin/env python除非有特殊原因不使用它。即使在Windows(Python启动器)上也可以理解这种形式。

注意:已安装的脚本应使用特定的python可执行文件,例如/usr/bin/python/home/me/.virtualenvs/project/bin/python。如果您在Shell中激活virtualenv,如果某些工具损坏了,那就很糟糕。幸运的是,在大多数情况下,正确的shebang是由setuptools您或您的分发包工具自动创建的(在Windows上,setuptools可以.exe自动生成包装器脚本)。

换句话说,如果脚本在源签出中,则可能会看到#!/usr/bin/env python。如果已安装,则shebang是特定python可执行文件的路径,例如#!/usr/local/bin/python (注意:您不应手动编写来自后一类别的路径)。

要选择是否应该使用pythonpython2python3在家当,见PEP 394 -在类Unix系统中的“Python”命令

  • python应该仅在shebang行中用于与Python 2和3源兼容的脚本。

  • 为了最终更改Python的默认版本,应仅将Python 2脚本更新为与Python 3源兼容,或者python2在shebang行中使用。

Should I put the shebang in my Python scripts?

Put a shebang into a Python script to indicate:

  • this module can be run as a script
  • whether it can be run only on python2, python3 or is it Python 2/3 compatible
  • on POSIX, it is necessary if you want to run the script directly without invoking python executable explicitly

Are these equally portable? Which form is used most?

If you write a shebang manually then always use #!/usr/bin/env python unless you have a specific reason not to use it. This form is understood even on Windows (Python launcher).

Note: installed scripts should use a specific python executable e.g., /usr/bin/python or /home/me/.virtualenvs/project/bin/python. It is bad if some tool breaks if you activate a virtualenv in your shell. Luckily, the correct shebang is created automatically in most cases by setuptools or your distribution package tools (on Windows, setuptools can generate wrapper .exe scripts automatically).

In other words, if the script is in a source checkout then you will probably see #!/usr/bin/env python. If it is installed then the shebang is a path to a specific python executable such as #!/usr/local/bin/python (NOTE: you should not write the paths from the latter category manually).

To choose whether you should use python, python2, or python3 in the shebang, see PEP 394 – The “python” Command on Unix-Like Systems:

  • python should be used in the shebang line only for scripts that are source compatible with both Python 2 and 3.

  • in preparation for an eventual change in the default version of Python, Python 2 only scripts should either be updated to be source compatible with Python 3 or else to use python2 in the shebang line.


回答 3

如果您有多个版本的Python,并且脚本需要在特定版本下运行,那么在直接执行脚本时,she-bang可以确保使用正确的版本,例如:

#!/usr/bin/python2.7

请注意,脚本仍然可以通过完整的Python命令行或通过import运行,在这种情况下,she-bang会被忽略。但是对于直接运行的脚本,这是使用she-bang的一个不错的理由。

#!/usr/bin/env python 通常是更好的方法,但这在特殊情况下会有所帮助。

通常,最好建立一个Python虚拟环境,在这种情况下,泛型#!/usr/bin/env python将为virtualenv标识正确的Python实例。

If you have more than one version of Python and the script needs to run under a specific version, the she-bang can ensure the right one is used when the script is executed directly, for example:

#!/usr/bin/python2.7

Note the script could still be run via a complete Python command line, or via import, in which case the she-bang is ignored. But for scripts run directly, this is a decent reason to use the she-bang.

#!/usr/bin/env python is generally the better approach, but this helps with special cases.

Usually it would be better to establish a Python virtual environment, in which case the generic #!/usr/bin/env python would identify the correct instance of Python for the virtualenv.


回答 4

如果脚本旨在可执行,则应添加shebang。您还应该使用可将shebang修改为正确的安装软件来安装脚本,以使其可以在目标平台上运行。例如distutils和Distribute。

You should add a shebang if the script is intended to be executable. You should also install the script with an installing software that modifies the shebang to something correct so it will work on the target platform. Examples of this is distutils and Distribute.


回答 5

shebang的目的是让脚本在您要从外壳执行脚本时识别解释器类型。通常,并非总是如此,您可以通过从外部提供解释器来执行脚本。用法示例:python-x.x script.py

即使您没有shebang声明符,这也将起作用。

为什么第一个更“便携”的原因是因为它/usr/bin/env包含了PATH声明,该声明说明了系统可执行文件所在的所有目标。

注意:Tornado严格不使用shebang,而Django严格不使用。它随您执行应用程序主要功能的方式而异。

还:它与Python并没有变化。

The purpose of shebang is for the script to recognize the interpreter type when you want to execute the script from the shell. Mostly, and not always, you execute scripts by supplying the interpreter externally. Example usage: python-x.x script.py

This will work even if you don’t have a shebang declarator.

Why first one is more “portable” is because, /usr/bin/env contains your PATH declaration which accounts for all the destinations where your system executables reside.

NOTE: Tornado doesn’t strictly use shebangs, and Django strictly doesn’t. It varies with how you are executing your application’s main function.

ALSO: It doesn’t vary with Python.


回答 6

有时,如果答案不是很清楚(我的意思是,你不能,如果是或否决定),那么它没有太大的关系,直到答案,你可以忽略的问题清楚的。

#!唯一目的是为了启动脚本。Django会自行加载并使用源。不需要决定使用哪种解释器。这样,#!这里实际上没有任何意义。

通常,如果它是一个模块并且不能用作脚本,则无需使用#!。另一方面,模块源通常包含if __name__ == '__main__': ...至少一些琐碎的功能测试。然后#!再次有意义。

使用的一个好理由#!是当您同时使用Python 2和Python 3脚本时-它们必须由不同版本的Python解释。这样,您必须记住python手动启动脚本时必须使用的内容(无#!内部内容)。如果混合使用这些脚本,则最好使用#!内部脚本,使其成为可执行文件,然后将其作为可执行文件启动(chmod …)。

使用MS-Windows时,#!直到最近才有意义。Python 3.3引入了Windows Python启动器(py.exe和pyw.exe),该启动器读取#!行,检测已安装的Python版本并使用正确或明确需要的Python版本。由于扩展可以与程序相关联,因此在Windows中可以获得与基于Unix的系统中的execute标志类似的行为。

Sometimes, if the answer is not very clear (I mean you cannot decide if yes or no), then it does not matter too much, and you can ignore the problem until the answer is clear.

The #! only purpose is for launching the script. Django loads the sources on its own and uses them. It never needs to decide what interpreter should be used. This way, the #! actually makes no sense here.

Generally, if it is a module and cannot be used as a script, there is no need for using the #!. On the other hand, a module source often contains if __name__ == '__main__': ... with at least some trivial testing of the functionality. Then the #! makes sense again.

One good reason for using #! is when you use both Python 2 and Python 3 scripts — they must be interpreted by different versions of Python. This way, you have to remember what python must be used when launching the script manually (without the #! inside). If you have a mixture of such scripts, it is a good idea to use the #! inside, make them executable, and launch them as executables (chmod …).

When using MS-Windows, the #! had no sense — until recently. Python 3.3 introduces a Windows Python Launcher (py.exe and pyw.exe) that reads the #! line, detects the installed versions of Python, and uses the correct or explicitly wanted version of Python. As the extension can be associated with a program, you can get similar behaviour in Windows as with execute flag in Unix-based systems.


回答 7

当我最近在Windows 7上安装Python 3.6.1时,它还安装了Windows的Python启动器,该应用程序应该可以处理shebang行。但是,我发现Python Launcher并没有做到这一点:shebang行被忽略,并且始终使用Python 2.7.13(除非我使用py -3执行脚本)。

要解决此问题,我必须编辑Windows注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.File\shell\open\command。这仍然有价值

"C:\Python27\python.exe" "%1" %*

从我以前的Python 2.7安装中获取。我将此注册表项值修改为

"C:\Windows\py.exe" "%1" %*

并且Python Launcher shebang行处理如上所述。

When I installed Python 3.6.1 on Windows 7 recently, it also installed the Python Launcher for Windows, which is supposed to handle the shebang line. However, I found that the Python Launcher did not do this: the shebang line was ignored and Python 2.7.13 was always used (unless I executed the script using py -3).

To fix this, I had to edit the Windows registry key HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.File\shell\open\command. This still had the value

"C:\Python27\python.exe" "%1" %*

from my earlier Python 2.7 installation. I modified this registry key value to

"C:\Windows\py.exe" "%1" %*

and the Python Launcher shebang line processing worked as described above.


回答 8

如果您安装了不同的模块,并且需要使用特定的python安装,那么shebang似乎一开始受到限制。但是,您可以执行以下操作,使shebang首先作为shell脚本被调用,然后选择python。这是非常灵活的imo:

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $PREFERRED_PYTHON
    exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())

或许更好的办法是,促进跨多个python脚本的代码重用:

#!/bin/bash
"true" '''\'; source $(cd $(dirname ${BASH_SOURCE[@]}) &>/dev/null && pwd)/select.sh; exec $CHOSEN_PYTHON "$0" "$@"; exit 127; '''

然后select.sh具有:

PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    CHOSEN_PYTHON=$PREFERRED_PYTHON
elif [ -x $ALTERNATIVE_PYTHON ]; then
    CHOSEN_PYTHON=$ALTERNATIVE_PYTHON
else
    CHOSEN_PYTHON=$FALLBACK_PYTHON
fi

If you have different modules installed and need to use a specific python install, then shebang appears to be limited at first. However, you can do tricks like the below to allow the shebang to be invoked first as a shell script and then choose python. This is very flexible imo:

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $PREFERRED_PYTHON
    exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())

Or better yet, perhaps, to facilitate code reuse across multiple python scripts:

#!/bin/bash
"true" '''\'; source $(cd $(dirname ${BASH_SOURCE[@]}) &>/dev/null && pwd)/select.sh; exec $CHOSEN_PYTHON "$0" "$@"; exit 127; '''

and then select.sh has:

PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    CHOSEN_PYTHON=$PREFERRED_PYTHON
elif [ -x $ALTERNATIVE_PYTHON ]; then
    CHOSEN_PYTHON=$ALTERNATIVE_PYTHON
else
    CHOSEN_PYTHON=$FALLBACK_PYTHON
fi

回答 9

答:仅当您计划使其成为命令行可执行脚本时。

步骤如下:

首先,验证要使用的适当的shebang字符串:

which python

从中获取输出,并在第一行中将其添加(带有shebang#!)。

在我的系统上,它的响应如下:

$which python
/usr/bin/python

因此,您的shebang将如下所示:

#!/usr/bin/python

保存后,它仍将像以前一样运行,因为python会将第一行视为注释。

python filename.py

要使其成为命令,请将其复制以删除.py扩展名。

cp filename.py filename

告诉文件系统这将是可执行的:

chmod +x filename

要测试它,请使用:

./filename

最佳实践是将其移动到$ PATH中的某个位置,因此只需键入文件名即可。

sudo cp filename /usr/sbin

这样,它将可以在任何地方使用(文件名前没有./)

Answer: Only if you plan to make it a command-line executable script.

Here is the procedure:

Start off by verifying the proper shebang string to use:

which python

Take the output from that and add it (with the shebang #!) in the first line.

On my system it responds like so:

$which python
/usr/bin/python

So your shebang will look like:

#!/usr/bin/python

After saving, it will still run as before since python will see that first line as a comment.

python filename.py

To make it a command, copy it to drop the .py extension.

cp filename.py filename

Tell the file system that this will be executable:

chmod +x filename

To test it, use:

./filename

Best practice is to move it somewhere in your $PATH so all you need to type is the filename itself.

sudo cp filename /usr/sbin

That way it will work everywhere (without the ./ before the filename)


回答 10

绝对路径与逻辑路径:

关于可移植性,这实际上是一个关于Python解释器的路径是绝对路径还是Logical/usr/bin/env)的问题。

遇到这个和谈论这个问题在一般的方式,而不支持其他证明堆栈网站其他的答案,我已经进行了一些真的,真的在上过这个问题,颗粒测试和分析unix.stackexchange.com。与其在此处粘贴答案,不如将那些对比较分析感兴趣的人指向该答案:

https://unix.stackexchange.com/a/566019/334294

作为一名Linux工程师,我的目标始终是为我的开发人员客户端提供最合适的,优化的主机,因此,我确实需要一个可靠的解决方案来解决Python环境问题。测试后,我的观点是,在(2)选项中,she-bang 中的逻辑路径更好。

Absolute vs Logical Path:

This is really a question about whether the path to the Python interpreter should be absolute or Logical (/usr/bin/env) in respect to portability.

Encountering other answers on this and other Stack sites which talked about the issue in a general way without supporting proofs, I’ve performed some really, REALLY, granular testing & analysis on this very question on the unix.stackexchange.com. Rather than paste that answer here, I’ll point those interested to the comparative analysis to that answer:

https://unix.stackexchange.com/a/566019/334294

Being a Linux Engineer, my goal is always to provide the most suitable, optimized hosts for my developer clients, so the issue of Python environments was something I really needed a solid answer to. My view after the testing was that the logical path in the she-bang was the better of the (2) options.


回答 11

首先使用

which python

这将给出输出作为我的python解释器(二进制)所在的位置。

此输出可以是任何这样的

/usr/bin/python

要么

/bin/python

现在,适当选择shebang行并使用它。

概括地说,我们可以使用:

#!/usr/bin/env

要么

#!/bin/env

Use first

which python

This will give the output as the location where my python interpreter (binary) is present.

This output could be any such as

/usr/bin/python

or

/bin/python

Now appropriately select the shebang line and use it.

To generalize we can use:

#!/usr/bin/env

or

#!/bin/env

将Unix时间戳字符串转换为可读日期

问题:将Unix时间戳字符串转换为可读日期

我有一个表示Python中的unix时间戳的字符串(即“ 1284101485”),我想将其转换为可读的日期。使用时time.strftime,我得到TypeError

>>>import time
>>>print time.strftime("%B %d %Y", "1284101485")

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: argument must be 9-item sequence, not str

I have a string representing a unix timestamp (i.e. “1284101485”) in Python, and I’d like to convert it to a readable date. When I use time.strftime, I get a TypeError:

>>>import time
>>>print time.strftime("%B %d %Y", "1284101485")

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: argument must be 9-item sequence, not str

回答 0

使用datetime模块:

from datetime import datetime
ts = int("1284101485")

# if you encounter a "year is out of range" error the timestamp
# may be in milliseconds, try `ts /= 1000` in that case
print(datetime.utcfromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S'))

Use datetime module:

from datetime import datetime
ts = int("1284101485")

# if you encounter a "year is out of range" error the timestamp
# may be in milliseconds, try `ts /= 1000` in that case
print(datetime.utcfromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S'))

回答 1

>>> from datetime import datetime
>>> datetime.fromtimestamp(1172969203.1)
datetime.datetime(2007, 3, 4, 0, 46, 43, 100000)

取自http://seehuhn.de/pages/pdate

>>> from datetime import datetime
>>> datetime.fromtimestamp(1172969203.1)
datetime.datetime(2007, 3, 4, 0, 46, 43, 100000)

Taken from http://seehuhn.de/pages/pdate


回答 2

投票最多的答案建议使用fromtimestamp,因为它使用本地时区,因此容易出错。为了避免出现问题,更好的方法是使用UTC:

datetime.datetime.utcfromtimestamp(posix_time).strftime('%Y-%m-%dT%H:%M:%SZ')

其中posix_time是要转换的Posix纪元时间

The most voted answer suggests using fromtimestamp which is error prone since it uses the local timezone. To avoid issues a better approach is to use UTC:

datetime.datetime.utcfromtimestamp(posix_time).strftime('%Y-%m-%dT%H:%M:%SZ')

Where posix_time is the Posix epoch time you want to convert


回答 3

>>> import time
>>> time.ctime(int("1284101485"))
'Fri Sep 10 16:51:25 2010'
>>> time.strftime("%D %H:%M", time.localtime(int("1284101485")))
'09/10/10 16:51'
>>> import time
>>> time.ctime(int("1284101485"))
'Fri Sep 10 16:51:25 2010'
>>> time.strftime("%D %H:%M", time.localtime(int("1284101485")))
'09/10/10 16:51'

回答 4

有两个部分:

  1. 将Unix时间戳(“自纪元以来的秒数”)转换为本地时间
  2. 以所需格式显示当地时间。

即使本地时区过去有不同的utc偏移并且python无法访问tz数据库,获取本地时间有效的一种便携式方法是使用pytz时区:

#!/usr/bin/env python
from datetime import datetime
import tzlocal  # $ pip install tzlocal

unix_timestamp = float("1284101485")
local_timezone = tzlocal.get_localzone() # get pytz timezone
local_time = datetime.fromtimestamp(unix_timestamp, local_timezone)

要显示它,您可以使用系统支持的任何时间格式,例如:

print(local_time.strftime("%Y-%m-%d %H:%M:%S.%f%z (%Z)"))
print(local_time.strftime("%B %d %Y"))  # print date in your format

如果您不需要当地时间,请改为获取可读的UTC时间:

utc_time = datetime.utcfromtimestamp(unix_timestamp)
print(utc_time.strftime("%Y-%m-%d %H:%M:%S.%f+00:00 (UTC)"))

如果您不关心可能影响返回日期的时区问题,或者python是否有权访问系统上的tz数据库:

local_time = datetime.fromtimestamp(unix_timestamp)
print(local_time.strftime("%Y-%m-%d %H:%M:%S.%f"))

在Python 3上,您可以仅使用stdlib获得时区感知日期时间(如果python无法访问系统上的tz数据库,例如Windows上的UTC偏移量可能是错误的):

#!/usr/bin/env python3
from datetime import datetime, timezone

utc_time = datetime.fromtimestamp(unix_timestamp, timezone.utc)
local_time = utc_time.astimezone()
print(local_time.strftime("%Y-%m-%d %H:%M:%S.%f%z (%Z)"))

time模块中的函数是对应C API的薄包装,因此它们可能比对应datetime方法的可移植性差,否则您也可以使用它们:

#!/usr/bin/env python
import time

unix_timestamp  = int("1284101485")
utc_time = time.gmtime(unix_timestamp)
local_time = time.localtime(unix_timestamp)
print(time.strftime("%Y-%m-%d %H:%M:%S", local_time)) 
print(time.strftime("%Y-%m-%d %H:%M:%S+00:00 (UTC)", utc_time))  

There are two parts:

  1. Convert the unix timestamp (“seconds since epoch”) to the local time
  2. Display the local time in the desired format.

A portable way to get the local time that works even if the local time zone had a different utc offset in the past and python has no access to the tz database is to use a pytz timezone:

#!/usr/bin/env python
from datetime import datetime
import tzlocal  # $ pip install tzlocal

unix_timestamp = float("1284101485")
local_timezone = tzlocal.get_localzone() # get pytz timezone
local_time = datetime.fromtimestamp(unix_timestamp, local_timezone)

To display it, you could use any time format that is supported by your system e.g.:

print(local_time.strftime("%Y-%m-%d %H:%M:%S.%f%z (%Z)"))
print(local_time.strftime("%B %d %Y"))  # print date in your format

If you do not need a local time, to get a readable UTC time instead:

utc_time = datetime.utcfromtimestamp(unix_timestamp)
print(utc_time.strftime("%Y-%m-%d %H:%M:%S.%f+00:00 (UTC)"))

If you don’t care about the timezone issues that might affect what date is returned or if python has access to the tz database on your system:

local_time = datetime.fromtimestamp(unix_timestamp)
print(local_time.strftime("%Y-%m-%d %H:%M:%S.%f"))

On Python 3, you could get a timezone-aware datetime using only stdlib (the UTC offset may be wrong if python has no access to the tz database on your system e.g., on Windows):

#!/usr/bin/env python3
from datetime import datetime, timezone

utc_time = datetime.fromtimestamp(unix_timestamp, timezone.utc)
local_time = utc_time.astimezone()
print(local_time.strftime("%Y-%m-%d %H:%M:%S.%f%z (%Z)"))

Functions from the time module are thin wrappers around the corresponding C API and therefore they may be less portable than the corresponding datetime methods otherwise you could use them too:

#!/usr/bin/env python
import time

unix_timestamp  = int("1284101485")
utc_time = time.gmtime(unix_timestamp)
local_time = time.localtime(unix_timestamp)
print(time.strftime("%Y-%m-%d %H:%M:%S", local_time)) 
print(time.strftime("%Y-%m-%d %H:%M:%S+00:00 (UTC)", utc_time))  

回答 5

为了使UNIX时间戳易于理解,我以前在脚本中使用过它:

import os, datetime

datetime.datetime.fromtimestamp(float(os.path.getmtime("FILE"))).strftime("%B %d, %Y")

输出:

‘2012年12月26日’

For a human readable timestamp from a UNIX timestamp, I have used this in scripts before:

import os, datetime

datetime.datetime.fromtimestamp(float(os.path.getmtime("FILE"))).strftime("%B %d, %Y")

Output:

‘December 26, 2012’


回答 6

您可以像这样转换当前时间

t=datetime.fromtimestamp(time.time())
t.strftime('%Y-%m-%d')
'2012-03-07'

将字符串中的日期转换为其他格式。

import datetime,time

def createDateObject(str_date,strFormat="%Y-%m-%d"):    
    timeStamp = time.mktime(time.strptime(str_date,strFormat))
    return datetime.datetime.fromtimestamp(timeStamp)

def FormatDate(objectDate,strFormat="%Y-%m-%d"):
    return objectDate.strftime(strFormat)

Usage
=====
o=createDateObject('2013-03-03')
print FormatDate(o,'%d-%m-%Y')

Output 03-03-2013

You can convert the current time like this

t=datetime.fromtimestamp(time.time())
t.strftime('%Y-%m-%d')
'2012-03-07'

To convert a date in string to different formats.

import datetime,time

def createDateObject(str_date,strFormat="%Y-%m-%d"):    
    timeStamp = time.mktime(time.strptime(str_date,strFormat))
    return datetime.datetime.fromtimestamp(timeStamp)

def FormatDate(objectDate,strFormat="%Y-%m-%d"):
    return objectDate.strftime(strFormat)

Usage
=====
o=createDateObject('2013-03-03')
print FormatDate(o,'%d-%m-%Y')

Output 03-03-2013

回答 7

除了使用time / datetime包之外,pandas还可以用于解决相同的问题。这是我们可以使用pandas时间戳转换为可读日期的方法

时间戳可以有两种格式:

  1. 13位数字(毫秒)-要将毫秒转换日期,请使用:

    import pandas
    result_ms=pandas.to_datetime('1493530261000',unit='ms')
    str(result_ms)
    
    Output: '2017-04-30 05:31:01'
  2. 10位(秒)-要将转换为日期,请使用:

    import pandas
    result_s=pandas.to_datetime('1493530261',unit='s')
    str(result_s)
    
    Output: '2017-04-30 05:31:01'

Other than using time/datetime package, pandas can also be used to solve the same problem.Here is how we can use pandas to convert timestamp to readable date:

Timestamps can be in two formats:

  1. 13 digits(milliseconds) – To convert milliseconds to date, use:

    import pandas
    result_ms=pandas.to_datetime('1493530261000',unit='ms')
    str(result_ms)
    
    Output: '2017-04-30 05:31:01'
    
  2. 10 digits(seconds) – To convert seconds to date, use:

    import pandas
    result_s=pandas.to_datetime('1493530261',unit='s')
    str(result_s)
    
    Output: '2017-04-30 05:31:01'
    

回答 8

timestamp ="124542124"
value = datetime.datetime.fromtimestamp(timestamp)
exct_time = value.strftime('%d %B %Y %H:%M:%S')

您还可以从时间戳获取带有时间的可读日期,也可以更改日期格式。

timestamp ="124542124"
value = datetime.datetime.fromtimestamp(timestamp)
exct_time = value.strftime('%d %B %Y %H:%M:%S')

Get the readable date from timestamp with time also, also you can change the format of the date.


回答 9

在Python 3.6+中:

import datetime

timestamp = 1579117901
value = datetime.datetime.fromtimestamp(timestamp)
print(f"{value:%Y-%m-%d %H:%M:%S}")

输出:

2020-01-15 19:51:41

说明:

In Python 3.6+:

import datetime

timestamp = 1579117901
value = datetime.datetime.fromtimestamp(timestamp)
print(f"{value:%Y-%m-%d %H:%M:%S}")

Output:

2020-01-15 19:51:41

Explanation:


回答 10

import datetime
temp = datetime.datetime.fromtimestamp(1386181800).strftime('%Y-%m-%d %H:%M:%S')
print temp
import datetime
temp = datetime.datetime.fromtimestamp(1386181800).strftime('%Y-%m-%d %H:%M:%S')
print temp

回答 11

可以使用gmtime和format函数完成此操作的另一种方法;

from time import gmtime
print('{}-{}-{} {}:{}:{}'.format(*gmtime(1538654264.703337)))

输出: 2018-10-4 11:57:44

Another way that this can be done using gmtime and format function;

from time import gmtime
print('{}-{}-{} {}:{}:{}'.format(*gmtime(1538654264.703337)))

Output: 2018-10-4 11:57:44


回答 12

我刚刚成功使用过:

>>> type(tstamp)
pandas.tslib.Timestamp
>>> newDt = tstamp.date()
>>> type(newDt)
datetime.date

i just successfully used:

>>> type(tstamp)
pandas.tslib.Timestamp
>>> newDt = tstamp.date()
>>> type(newDt)
datetime.date

回答 13

快速又脏的一个衬里:

'-'.join(str(x) for x in list(tuple(datetime.datetime.now().timetuple())[:6]))

‘2013-5-5-1-9-43’

quick and dirty one liner:

'-'.join(str(x) for x in list(tuple(datetime.datetime.now().timetuple())[:6]))

‘2013-5-5-1-9-43’


回答 14

您可以使用easy_date使其变得容易:

import date_converter
my_date_string = date_converter.timestamp_to_string(1284101485, "%B %d, %Y")

You can use easy_date to make it easy:

import date_converter
my_date_string = date_converter.timestamp_to_string(1284101485, "%B %d, %Y")