标签归档:Python

访问包子目录中的数据

问题:访问包子目录中的数据

我正在编写一个python软件包,其中包含需要在./data/子目录中打开数据文件的模块。现在,我已经将文件的路径硬编码到了我的类和函数中。我想编写更健壮的代码,无论子目录在用户系统上的安装位置如何,都可以访问该子目录。

我尝试了多种方法,但是到目前为止,我还没有运气。似乎大多数“当前目录”命令返回系统的python解释器的目录,而不是模块的目录。

看来这应该是一个微不足道的普遍问题。但是我似乎无法弄清楚。问题的部分原因是我的数据文件不是.py文件,因此我不能使用导入功能等。

有什么建议?

现在,我的包目录如下所示:

/
__init__.py
module1.py
module2.py
data/   
   data.txt

我试图访问data.txt距离module*.py

I am writing a python package with modules that need to open data files in a ./data/ subdirectory. Right now I have the paths to the files hardcoded into my classes and functions. I would like to write more robust code that can access the subdirectory regardless of where it is installed on the user’s system.

I’ve tried a variety of methods, but so far I have had no luck. It seems that most of the “current directory” commands return the directory of the system’s python interpreter, and not the directory of the module.

This seems like it ought to be a trivial, common problem. Yet I can’t seem to figure it out. Part of the problem is that my data files are not .py files, so I can’t use import functions and the like.

Any suggestions?

Right now my package directory looks like:

/
__init__.py
module1.py
module2.py
data/   
   data.txt

I am trying to access data.txt from module*.py!


回答 0

您可以使用__file__获取包的路径,如下所示:

import os
this_dir, this_filename = os.path.split(__file__)
DATA_PATH = os.path.join(this_dir, "data", "data.txt")
print open(DATA_PATH).read()

You can use __file__ to get the path to the package, like this:

import os
this_dir, this_filename = os.path.split(__file__)
DATA_PATH = os.path.join(this_dir, "data", "data.txt")
print open(DATA_PATH).read()

回答 1

执行此操作的标准方法是使用setuptools软件包和pkg_resources。

您可以按照以下层次结构布置软件包,并按照以下链接配置软件包设置文件以将其指向您的数据资源:

http://docs.python.org/distutils/setupscript.html#installing-package-data

然后,您可以按照以下链接使用pkg_resources重新查找和使用这些文件:

http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access

import pkg_resources

DATA_PATH = pkg_resources.resource_filename('<package name>', 'data/')
DB_FILE = pkg_resources.resource_filename('<package name>', 'data/sqlite.db')

The standard way to do this is with setuptools packages and pkg_resources.

You can lay out your package according to the following hierarchy, and configure the package setup file to point it your data resources, as per this link:

http://docs.python.org/distutils/setupscript.html#installing-package-data

You can then re-find and use those files using pkg_resources, as per this link:

http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access

import pkg_resources

DATA_PATH = pkg_resources.resource_filename('<package name>', 'data/')
DB_FILE = pkg_resources.resource_filename('<package name>', 'data/sqlite.db')

回答 2

提供今天可以使用的解决方案。绝对使用此API不会重塑所有这些轮子。

需要一个真实的文件系统文件名。压缩的鸡蛋将被提取到缓存目录中:

from pkg_resources import resource_filename, Requirement

path_to_vik_logo = resource_filename(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png")

返回指定资源的可读文件状对象;它可能是实际文件,StringIO或某些类似的对象。从某种意义上说,该流处于“二进制模式”,即资源中的任何字节都将按原样读取。

from pkg_resources import resource_stream, Requirement

vik_logo_as_stream = resource_stream(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png")

使用pkg_resources进行软件包发现和资源访问

To provide a solution working today. Definitely use this API to not reinvent all those wheels.

A true filesystem filename is needed. Zipped eggs will be extracted to a cache directory:

from pkg_resources import resource_filename, Requirement

path_to_vik_logo = resource_filename(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png")

Return a readable file-like object for the specified resource; it may be an actual file, a StringIO, or some similar object. The stream is in “binary mode”, in the sense that whatever bytes are in the resource will be read as-is.

from pkg_resources import resource_stream, Requirement

vik_logo_as_stream = resource_stream(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png")

Package Discovery and Resource Access using pkg_resources


回答 3

做出详细的代码无法按原样工作的答案通常是没有意义的,但是我认为这是一个exceptions。Python 3.7添加importlib.resources了应该替换的pkg_resources。它可以用于访问名称中没有斜杠的软件包中的文件,即

foo/
    __init__.py
    module1.py
    module2.py
    data/   
       data.txt
    data2.txt

即您可以使用例如访问data2.txt内部软件包foo

importlib.resources.open_binary('foo', 'data2.txt')

但是它会失败,但有一个exceptions

>>> importlib.resources.open_binary('foo', 'data/data.txt')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.7/importlib/resources.py", line 87, in open_binary
    resource = _normalize_path(resource)
  File "/usr/lib/python3.7/importlib/resources.py", line 61, in _normalize_path
    raise ValueError('{!r} must be only a file name'.format(path))
ValueError: 'data/data2.txt' must be only a file name

这不能被固定,除了通过将__init__.pydata再使用它作为一个包:

importlib.resources.open_binary('foo.data', 'data.txt')

这种行为的原因是“这是设计使然”;但是设计可能会改变

There is often not point in making an answer that details code that does not work as is, but I believe this to be an exception. Python 3.7 added importlib.resources that is supposed to replace pkg_resources. It would work for accessing files within packages that do not have slashes in their names, i.e.

foo/
    __init__.py
    module1.py
    module2.py
    data/   
       data.txt
    data2.txt

i.e. you could access data2.txt inside package foo with for example

importlib.resources.open_binary('foo', 'data2.txt')

but it would fail with an exception for

>>> importlib.resources.open_binary('foo', 'data/data.txt')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.7/importlib/resources.py", line 87, in open_binary
    resource = _normalize_path(resource)
  File "/usr/lib/python3.7/importlib/resources.py", line 61, in _normalize_path
    raise ValueError('{!r} must be only a file name'.format(path))
ValueError: 'data/data2.txt' must be only a file name

This cannot be fixed except by placing __init__.py in data and then using it as a package:

importlib.resources.open_binary('foo.data', 'data.txt')

The reason for this behaviour is “it is by design”; but the design might change


回答 4

您需要为整个模块命名,目录树没有列出详细信息,对我来说这是可行的:

import pkg_resources
print(    
    pkg_resources.resource_filename(__name__, 'data/data.txt')
)

值得注意的是,setuptools似乎无法基于与打包数据文件匹配的名称来解析文件,所以无论如何,您都必须data/几乎包含前缀。os.path.join('data', 'data.txt)如果需要备用目录分隔符,可以使用。通常,我发现硬编码的unix样式目录分隔符没有兼容性问题。

You need a name for your whole module, you’re given directory tree doesn’t list that detail, for me this worked:

import pkg_resources
print(    
    pkg_resources.resource_filename(__name__, 'data/data.txt')
)

Notibly setuptools does not appear to resolve files based on a name match with packed data files, soo you’re gunna have to include the data/ prefix pretty much no matter what. You can use os.path.join('data', 'data.txt) if you need alternate directory separators, Generally I find no compatibility problems with hard-coded unix style directory separators though.


回答 5

我想我找到了答案。

我创建一个模块data_path.py,将其导入其他包含以下内容的模块:

data_path = os.path.join(os.path.dirname(__file__),'data')

然后我用打开所有文件

open(os.path.join(data_path,'filename'), <param>)

I think I hunted down an answer.

I make a module data_path.py, which I import into my other modules containing:

data_path = os.path.join(os.path.dirname(__file__),'data')

And then I open all my files with

open(os.path.join(data_path,'filename'), <param>)

通过匹配字典的值来找到列表中字典的索引

问题:通过匹配字典的值来找到列表中字典的索引

我有一些字典:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'}]

如何通过匹配name =’Tom’来有效地找到索引位置[0],[1]或[2]?

如果这是一维列表,则可以执行list.index(),但是我不确定如何通过搜索列表中的dict的值来进行操作。

I have a list of dicts:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'}]

How can I efficiently find the index position [0],[1], or [2] by matching on name = ‘Tom’?

If this were a one-dimensional list I could do list.index() but I’m not sure how to proceed by searching the values of the dicts within the list.


回答 0

tom_index = next((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None)
# 1

如果需要从名称重复获取,则应按名称对它们进行索引(使用字典),这样get操作的时间为O(1)。一个想法:

def build_dict(seq, key):
    return dict((d[key], dict(d, index=index)) for (index, d) in enumerate(seq))

info_by_name = build_dict(lst, key="name")
tom_info = info_by_name.get("Tom")
# {'index': 1, 'id': '2345', 'name': 'Tom'}
lst = [{'id':'1234','name':'Jason'}, {'id':'2345','name':'Tom'}, {'id':'3456','name':'Art'}]

tom_index = next((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None)
# 1

If you need to fetch repeatedly from name, you should index them by name (using a dictionary), this way get operations would be O(1) time. An idea:

def build_dict(seq, key):
    return dict((d[key], dict(d, index=index)) for (index, d) in enumerate(seq))

info_by_name = build_dict(lst, key="name")
tom_info = info_by_name.get("Tom")
# {'index': 1, 'id': '2345', 'name': 'Tom'}

回答 1

一个简单的可读版本是

def find(lst, key, value):
    for i, dic in enumerate(lst):
        if dic[key] == value:
            return i
    return -1

A simple readable version is

def find(lst, key, value):
    for i, dic in enumerate(lst):
        if dic[key] == value:
            return i
    return -1

回答 2

效率不高,因为您需要遍历列表检查其中的每个项目(O(n))。如果要提高效率,可以使用dict of dicts。关于这个问题,这是找到它的一种可能方法(不过,如果您要坚持使用这种数据结构,实际上使用 Brent Newey在评论中所写的生成器会更有效;另请参阅tokland的答案):

>>> L = [{'id':'1234','name':'Jason'},
...         {'id':'2345','name':'Tom'},
...         {'id':'3456','name':'Art'}]
>>> [i for i,_ in enumerate(L) if _['name'] == 'Tom'][0]
1

It won’t be efficient, as you need to walk the list checking every item in it (O(n)). If you want efficiency, you can use dict of dicts. On the question, here’s one possible way to find it (though, if you want to stick to this data structure, it’s actually more efficient to use a generator as Brent Newey has written in the comments; see also tokland’s answer):

>>> L = [{'id':'1234','name':'Jason'},
...         {'id':'2345','name':'Tom'},
...         {'id':'3456','name':'Art'}]
>>> [i for i,_ in enumerate(L) if _['name'] == 'Tom'][0]
1

回答 3

这是一个查找字典索引位置(如果存在)的函数。

dicts = [{'id':'1234','name':'Jason'},
         {'id':'2345','name':'Tom'},
         {'id':'3456','name':'Art'}]

def find_index(dicts, key, value):
    class Null: pass
    for i, d in enumerate(dicts):
        if d.get(key, Null) == value:
            return i
    else:
        raise ValueError('no dict with the key and value combination found')

print find_index(dicts, 'name', 'Tom')
# 1
find_index(dicts, 'name', 'Ensnare')
# ValueError: no dict with the key and value combination found

Here’s a function that finds the dictionary’s index position if it exists.

dicts = [{'id':'1234','name':'Jason'},
         {'id':'2345','name':'Tom'},
         {'id':'3456','name':'Art'}]

def find_index(dicts, key, value):
    class Null: pass
    for i, d in enumerate(dicts):
        if d.get(key, Null) == value:
            return i
    else:
        raise ValueError('no dict with the key and value combination found')

print find_index(dicts, 'name', 'Tom')
# 1
find_index(dicts, 'name', 'Ensnare')
# ValueError: no dict with the key and value combination found

回答 4

似乎最合乎逻辑的是使用过滤器/索引组合:

names=[{}, {'name': 'Tom'},{'name': 'Tony'}]
names.index(filter(lambda n: n.get('name') == 'Tom', names)[0])
1

如果您认为可能存在多个匹配项:

[names.index(n) for item in filter(lambda n: n.get('name') == 'Tom', names)]
[1]

Seems most logical to use a filter/index combo:

names=[{}, {'name': 'Tom'},{'name': 'Tony'}]
names.index(filter(lambda n: n.get('name') == 'Tom', names)[0])
1

And if you think there could be multiple matches:

[names.index(n) for item in filter(lambda n: n.get('name') == 'Tom', names)]
[1]

回答 5

@faham提供的答案很不错,但是它不会将索引返回包含该值的字典。而是返回字典本身。这是一种简单的获取方法:如果有多个索引,则一个或多个索引列表;如果不存在,则为空列表:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'}]

[i for i, d in enumerate(list) if 'Tom' in d.values()]

输出:

>>> [1]

我喜欢这种方法的地方是,通过简单的编辑,您既可以将索引又将字典作为元组得到一个列表。这是我需要解决并找到这些答案的问题。在下面的代码中,我在另一个字典中添加了重复的值以显示其工作方式:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'},
        {'id':'4567','name':'Tom'}]

[(i, d) for i, d in enumerate(list) if 'Tom' in d.values()]

输出:

>>> [(1, {'id': '2345', 'name': 'Tom'}), (3, {'id': '4567', 'name': 'Tom'})]

该解决方案可查找所有值中包含“ Tom”的所有词典。

Answer offered by @faham is a nice one-liner, but it doesn’t return the index to the dictionary containing the value. Instead it returns the dictionary itself. Here is a simple way to get: A list of indexes one or more if there are more than one, or an empty list if there are none:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'}]

[i for i, d in enumerate(list) if 'Tom' in d.values()]

Output:

>>> [1]

What I like about this approach is that with a simple edit you can get a list of both the indexes and the dictionaries as tuples. This is the problem I needed to solve and found these answers. In the following, I added a duplicate value in a different dictionary to show how it works:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'},
        {'id':'4567','name':'Tom'}]

[(i, d) for i, d in enumerate(list) if 'Tom' in d.values()]

Output:

>>> [(1, {'id': '2345', 'name': 'Tom'}), (3, {'id': '4567', 'name': 'Tom'})]

This solution finds all dictionaries containing ‘Tom’ in any of their values.


回答 6

一行代码!!

elm = ([i for i in mylist if i['name'] == 'Tom'] or [None])[0]

One liner!?

elm = ([i for i in mylist if i['name'] == 'Tom'] or [None])[0]

回答 7

对于给定的可迭代项,more_itertools.locate产生满足谓词的项的位置。

import more_itertools as mit


iterable = [
    {"id": "1234", "name": "Jason"},
    {"id": "2345", "name": "Tom"},
    {"id": "3456", "name": "Art"}
]

list(mit.locate(iterable, pred=lambda d: d["name"] == "Tom"))
# [1]

more_itertools是在其他有用工具中实现itertools配方的第三方库。

For a given iterable, more_itertools.locate yields positions of items that satisfy a predicate.

import more_itertools as mit


iterable = [
    {"id": "1234", "name": "Jason"},
    {"id": "2345", "name": "Tom"},
    {"id": "3456", "name": "Art"}
]

list(mit.locate(iterable, pred=lambda d: d["name"] == "Tom"))
# [1]

more_itertools is a third-party library that implements itertools recipes among other useful tools.


回答 8

def search(itemID,list):
     return[i for i in list if i.itemID==itemID]
def search(itemID,list):
     return[i for i in list if i.itemID==itemID]

什么是无值?

问题:什么是无值?

我一直在研究Python,并且阅读了一章描述了它的None价值,但不幸的是,这本书在某些方面并不十分清楚。我认为,如果我在那分享我的问题,我会找到答案。

我想知道None价值什么,您将其用于什么?

而且,我没有得到本书的这一部分:

将值None赋给变量是将其重置为其原始的空状态的一种方法。

那是什么意思?

答案很棒,尽管由于我对计算机世界的了解不足(我还没有了解类,对象等),所以我对大多数答案都不了解。这句话是什么意思?

将值None赋给变量是将其重置为其原始的空状态的一种方法。

最后:

最后,我从寻找不同的答案中得到了答案。我必须感谢所有抽出宝贵时间来帮助我的人(尤其是Martijn Pieters和DSM),我希望我可以选择所有答案作为最佳答案,但是选择仅限于一个。所有的答案都很好。

I have been studying Python, and I read a chapter which describes the None value, but unfortunately this book isn’t very clear at some points. I thought that I would find the answer to my question, if I share it there.

I want to know what the None value is and what do you use it for?

And also, I don’t get this part of the book:

Assigning a value of None to a variable is one way to reset it to its original, empty state.

What does that mean?

The answers were great, although I didn’t understand most of answers due to my low knowledge of the computer world (I haven’t learned about classes, objects, etc.). What does this sentence mean?

Assigning a value of None to a variable is one way to reset it to its original, empty state.

Final:

Finally I’ve got my answer from looking to different answers. I must appreciate all the people who put their times to help me (especially Martijn Pieters and DSM), and I wish that I could choose all answers as the best, but the selection is limited to one. All of the answers were great.


回答 0

Martijn的答案解释了NonePython中的内容,并正确指出该书具有误导性。由于Python程序员通常不会说

将值None赋给变量是将其重置为其原始的空状态的一种方法。

很难以一种有意义的方式来解释布里格斯的意思,并解释为什么这里没有人对此感到满意。一个类推可能会有所帮助:

在Python中,变量名称就像贴在对象上的标签。每个标签上都有一个唯一的名称,并且一次只能在一个对象上,但是如果需要,您可以在同一对象上放置多个标签。当你写

F = "fork"

您将标签“ F”放在字符串对象上"fork"。如果你再写

F = None

您将标签移动到None对象。

Briggs想让您想象的是,您没有贴纸"F",但已经F贴纸上了None,您所做的就是其从None移到"fork"。因此F = None,如果我们决定将其None视为,则在键入时,您会将其“重置为原始的空状态” empty state

我可以看到他的意思,但这是一种不好的观察方式。如果启动Python并输入print(F),则会看到

>>> print(F)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'F' is not defined

NameError意味着Python无法识别这个名字F因为没有这样的标签。如果Briggs是正确的并且F = None重置F为原始状态,那么它应该现在在那里,并且我们应该看到

>>> print(F)
None

就像我们在键入F = None并贴上贴纸后所做的一样None


这就是所有的事情。实际上,Python附带了一些已经粘贴到对象上的标签(内置名称),但是其他一些标签则需要使用诸如F = "fork"and A = 2和这样的行来编写c17 = 3.14,然后再将其粘贴在其他对象上(例如F = 10or F = None;它们都是一样的) )

Briggs假装您可能要写的所有可能的贴纸均已粘贴到该None对象上。

Martijn’s answer explains what None is in Python, and correctly states that the book is misleading. Since Python programmers as a rule would never say

Assigning a value of None to a variable is one way to reset it to its original, empty state.

it’s hard to explain what Briggs means in a way which makes sense and explains why no one here seems happy with it. One analogy which may help:

In Python, variable names are like stickers put on objects. Every sticker has a unique name written on it, and it can only be on one object at a time, but you could put more than one sticker on the same object, if you wanted to. When you write

F = "fork"

you put the sticker “F” on a string object "fork". If you then write

F = None

you move the sticker to the None object.

What Briggs is asking you to imagine is that you didn’t write the sticker "F", there was already an F sticker on the None, and all you did was move it, from None to "fork". So when you type F = None, you’re “reset[ting] it to its original, empty state”, if we decided to treat None as meaning empty state.

I can see what he’s getting at, but that’s a bad way to look at it. If you start Python and type print(F), you see

>>> print(F)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'F' is not defined

and that NameError means Python doesn’t recognize the name F, because there is no such sticker. If Briggs were right and F = None resets F to its original state, then it should be there now, and we should see

>>> print(F)
None

like we do after we type F = None and put the sticker on None.


So that’s all that’s going on. In reality, Python comes with some stickers already attached to objects (built-in names), but others you have to write yourself with lines like F = "fork" and A = 2 and c17 = 3.14, and then you can stick them on other objects later (like F = 10 or F = None; it’s all the same.)

Briggs is pretending that all possible stickers you might want to write were already stuck to the None object.


回答 1

None只是通常用于表示“空”或“此处无值”的值。它是一个信号对象 ; 它仅具有含义,因为Python文档说明了它的含义。

在给定的Python解释器会话中,该对象只有一个副本。

例如,如果您编写一个函数,但该函数不使用显式return语句,None则返回该函数。这样,使用函数进行编程就大大简化了;一个函数总是返回某些东西,即使它只是那个None对象。

您可以明确地对其进行测试:

if foo is None:
    # foo is set to None

if bar is not None:
    # bar is set to something *other* than None

另一个用途是为函数提供可选参数,默认为“空”:

def spam(foo=None):
    if foo is not None:
        # foo was specified, do something clever!

该函数spam()有一个可选参数。如果在spam()未指定的情况下进行调用,则会为其指定默认值None,从而易于检测是否使用参数调用了该函数。

其他语言也有类似的概念。SQL有NULL; JavaScript具有undefined null,等等。

请注意,在Python中,变量通过使用而存在。您无需先声明变量,因此Python 中没有真正的变量。那么,将变量设置None为与将其设置为默认的空值是不同的。None也是一个值,尽管该值通常用于表示空白。您正在阅读的书在这一点上具有误导性。

None is just a value that commonly is used to signify ’empty’, or ‘no value here’. It is a signal object; it only has meaning because the Python documentation says it has that meaning.

There is only one copy of that object in a given Python interpreter session.

If you write a function, and that function doesn’t use an explicit return statement, None is returned instead, for example. That way, programming with functions is much simplified; a function always returns something, even if it is only that one None object.

You can test for it explicitly:

if foo is None:
    # foo is set to None

if bar is not None:
    # bar is set to something *other* than None

Another use is to give optional parameters to functions an ’empty’ default:

def spam(foo=None):
    if foo is not None:
        # foo was specified, do something clever!

The function spam() has a optional argument; if you call spam() without specifying it, the default value None is given to it, making it easy to detect if the function was called with an argument or not.

Other languages have similar concepts. SQL has NULL; JavaScript has undefined and null, etc.

Note that in Python, variables exist by virtue of being used. You don’t need to declare a variable first, so there are no really empty variables in Python. Setting a variable to None is then not the same thing as setting it to a default empty value; None is a value too, albeit one that is often used to signal emptyness. The book you are reading is misleading on that point.


回答 2

这就是Python文档必须说的None

types.NoneType的唯一值。当没有将默认参数传递给函数时,通常不使用None来表示缺少值。

在版本2.4中更改:分配为None是非法的,并引发SyntaxError。

注意不能重新分配名称None和debug(分配给它们,即使作为属性名称,也会引发SyntaxError),因此可以将它们视为“ true”常量。

  1. 让我们确认None第一个的类型

    print type(None)
    print None.__class__
    

    输出量

    <type 'NoneType'>
    <type 'NoneType'>
    

基本上,NoneType数据类型与intfloat等类似。您可以在8.15中查看Python中可用的默认类型列表types —内置类型的名称

  1. 并且,NoneNoneType类的实例。因此,我们可能要创建None自己的实例。让我们尝试一下

    print types.IntType()
    print types.NoneType()
    

    输出量

    0
    TypeError: cannot create 'NoneType' instances
    

很明显,无法创建NoneType实例。我们不必担心价值的独特性None

  1. 让我们检查一下我们是如何None内部实现的。

    print dir(None)

    输出量

    ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', 
     '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__',
     '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
    

除了__setattr__,所有其他均为只读属性。因此,我们无法更改的属性None

  1. 让我们尝试为添加新属性 None

    setattr(types.NoneType, 'somefield', 'somevalue')
    setattr(None, 'somefield', 'somevalue')
    None.somefield = 'somevalue'
    

    输出量

    TypeError: can't set attributes of built-in/extension type 'NoneType'
    AttributeError: 'NoneType' object has no attribute 'somefield'
    AttributeError: 'NoneType' object has no attribute 'somefield'
    

上面看到的语句分别产生这些错误消息。这意味着,我们不能在None实例上动态创建属性。

  1. 让我们检查一下分配东西时会发生什么None。根据文档,它应该抛出SyntaxError。这意味着,如果我们向分配了某些内容None,则该程序将根本不会执行。

    None = 1

    输出量

    SyntaxError: cannot assign to None

我们已经确定

  1. None 是…的实例 NoneType
  2. None 不能有新属性
  3. 的现有属性None无法更改。
  4. 我们无法创建的其他实例 NoneType
  5. 我们甚至不能通过None给它分配值来更改对它的引用。

因此,如文档中所述,None实际上可以将其视为true constant

很高兴知道None:)

This is what the Python documentation has got to say about None:

The sole value of types.NoneType. None is frequently used to represent the absence of a value, as when default arguments are not passed to a function.

Changed in version 2.4: Assignments to None are illegal and raise a SyntaxError.

Note The names None and debug cannot be reassigned (assignments to them, even as an attribute name, raise SyntaxError), so they can be considered “true” constants.

  1. Let’s confirm the type of None first

    print type(None)
    print None.__class__
    

    Output

    <type 'NoneType'>
    <type 'NoneType'>
    

Basically, NoneType is a data type just like int, float, etc. You can check out the list of default types available in Python in 8.15. types — Names for built-in types.

  1. And, None is an instance of NoneType class. So we might want to create instances of None ourselves. Let’s try that

    print types.IntType()
    print types.NoneType()
    

    Output

    0
    TypeError: cannot create 'NoneType' instances
    

So clearly, cannot create NoneType instances. We don’t have to worry about the uniqueness of the value None.

  1. Let’s check how we have implemented None internally.

    print dir(None)
    

    Output

    ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', 
     '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__',
     '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
    

Except __setattr__, all others are read-only attributes. So, there is no way we can alter the attributes of None.

  1. Let’s try and add new attributes to None

    setattr(types.NoneType, 'somefield', 'somevalue')
    setattr(None, 'somefield', 'somevalue')
    None.somefield = 'somevalue'
    

    Output

    TypeError: can't set attributes of built-in/extension type 'NoneType'
    AttributeError: 'NoneType' object has no attribute 'somefield'
    AttributeError: 'NoneType' object has no attribute 'somefield'
    

The above seen statements produce these error messages, respectively. It means that, we cannot create attributes dynamically on a None instance.

  1. Let us check what happens when we assign something None. As per the documentation, it should throw a SyntaxError. It means, if we assign something to None, the program will not be executed at all.

    None = 1
    

    Output

    SyntaxError: cannot assign to None
    

We have established that

  1. None is an instance of NoneType
  2. None cannot have new attributes
  3. Existing attributes of None cannot be changed.
  4. We cannot create other instances of NoneType
  5. We cannot even change the reference to None by assigning values to it.

So, as mentioned in the documentation, None can really be considered as a true constant.

Happy knowing None :)


回答 3

您所指的书显然是试图大大简化的含义None。Python的变量不具备初始,空状态- Python的变量绑定(只),他们定义的时候。如果不给它一个值,就不能创建一个Python变量。

>>> print(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> def test(x):
...   print(x)
... 
>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: test() takes exactly 1 argument (0 given)
>>> def test():
...   print(x)
... 
>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in test
NameError: global name 'x' is not defined

但是有时候您想让一个函数根据变量是否定义而具有不同的含义。您可以创建默认值为的参数None

>>> def test(x=None):
...   if x is None:
...     print('no x here')
...   else:
...     print(x)
... 
>>> test()
no x here
>>> test('x!')
x!

None在这种情况下,此值是特殊值并不十分重要。我可以使用任何默认值:

>>> def test(x=-1):
...   if x == -1:
...     print('no x here')
...   else:
...     print(x)
... 
>>> test()
no x here
>>> test('x!')
x!

…但是None到处都有给我们带来两个好处:

  1. 我们不必选择-1含义不明确的特殊值,并且
  2. 实际上,我们的函数可能需要-1作为普通输入处理。
>>> test(-1)
no x here

哎呀!

因此,这本书在使用“ 重设 ”一词时通常会产生一些误导–分配None名称是向程序员发出信号,表明该值未在使用中,或者该函数应以某种默认方式运行,但需要重设一个值要恢复其原始的未定义状态,您必须使用del关键字:

>>> x = 3
>>> x
3
>>> del x
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

The book you refer to is clearly trying to greatly simplify the meaning of None. Python variables don’t have an initial, empty state – Python variables are bound (only) when they’re defined. You can’t create a Python variable without giving it a value.

>>> print(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> def test(x):
...   print(x)
... 
>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: test() takes exactly 1 argument (0 given)
>>> def test():
...   print(x)
... 
>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in test
NameError: global name 'x' is not defined

but sometimes you want to make a function mean different things depending on whether a variable is defined or not. You can create an argument with a default value of None:

>>> def test(x=None):
...   if x is None:
...     print('no x here')
...   else:
...     print(x)
... 
>>> test()
no x here
>>> test('x!')
x!

The fact that this value is the special None value is not terribly important in this case. I could’ve used any default value:

>>> def test(x=-1):
...   if x == -1:
...     print('no x here')
...   else:
...     print(x)
... 
>>> test()
no x here
>>> test('x!')
x!

…but having None around gives us two benefits:

  1. We don’t have to pick a special value like -1 whose meaning is unclear, and
  2. Our function may actually need to handle -1 as a normal input.
>>> test(-1)
no x here

oops!

So the book is a little misleading mostly in its use of the word reset – assigning None to a name is a signal to a programmer that that value isn’t being used or that the function should behave in some default way, but to reset a value to its original, undefined state you must use the del keyword:

>>> x = 3
>>> x
3
>>> del x
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

回答 4

其他答案已经很好地解释了None的含义。但是,我仍然想通过一个例子对此进行更多说明。

例:

def extendList(val, list=[]):
    list.append(val)
    return list

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

现在尝试猜测上面列表的输出。好吧,答案令人惊讶地如下:

list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']

但为什么?

许多人会错误地期望list1等于[10]list3等于[‘a’],以为每次调用extendList时,list参数将被设置为其默认值[]

但是,实际发生的情况是,在定义函数时,仅会创建一次新的默认列表,然后在每次调用extendList且未指定list参数的情况下都使用同一列表。这是因为默认参数中的表达式是在定义函数时计算的,而不是在调用函数时计算的

因此,list1list3在同一默认列表上运行,而list2在它创建的单独列表上运行(通过传递其自己的空列表作为list参数的值)。


“无”救星:(修改上面的示例以产生所需的行为)

def extendList(val, list=None):
    if list is None:
       list = []
    list.append(val)
    return list

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

使用此修订的实现,输出将是:

list1 = [10]
list2 = [123]
list3 = ['a']

注意 -贷记至toptal.com的示例

Other answers have already explained meaning of None beautifully. However, I would still like to throw more light on this using an example.

Example:

def extendList(val, list=[]):
    list.append(val)
    return list

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

Now try to guess output of above list. Well, the answer is surprisingly as below:

list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']

But Why?

Many will mistakenly expect list1 to be equal to [10] and list3 to be equal to [‘a’], thinking that the list argument will be set to its default value of [] each time extendList is called.

However, what actually happens is that the new default list is created only once when the function is defined, and that same list is then used subsequently whenever extendList is invoked without a list argument being specified. This is because expressions in default arguments are calculated when the function is defined, not when it’s called.

list1 and list3 are therefore operating on the same default list, whereas list2 is operating on a separate list that it created (by passing its own empty list as the value for the list parameter).


‘None’ the savior: (Modify example above to produce desired behavior)

def extendList(val, list=None):
    if list is None:
       list = []
    list.append(val)
    return list

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

With this revised implementation, the output would be:

list1 = [10]
list2 = [123]
list3 = ['a']

Note – Example credit to toptal.com


回答 5

None是一个单例对象(意味着只有一个None),在语言和库中的许多地方都用于表示缺少其他值。


例如:
if d是一个字典,如果存在d.get(k)则返回d[k],但None如果d没有key 则返回k

从一个很棒的博客中阅读以下信息:http : //python-history.blogspot.in/

None is a singleton object (meaning there is only one None), used in many places in the language and library to represent the absence of some other value.


For example:
if d is a dictionary, d.get(k) will return d[k] if it exists, but None if d has no key k.

Read this info from a great blog: http://python-history.blogspot.in/


回答 6

所有这些都是很好的答案,但是我认为还有更多的原因可以解释None

想象一下,您在婚礼上收集了RSVP。您想记录每个人是否参加。如果他们正在参加,请设置person.attending = True。如果他们不参加,您设置person.attending = False。如果尚未收到任何RSVP,则person.attending = None。这样,您可以区分无信息None和否定答案。

All of these are good answers but I think there’s more to explain why None is useful.

Imagine you collecting RSVPs to a wedding. You want to record whether each person will attend. If they are attending, you set person.attending = True. If they are not attending you set person.attending = False. If you have not received any RSVP, then person.attending = None. That way you can distinguish between no information – None – and a negative answer.


回答 7

我喜欢代码示例(以及水果),所以让我告诉你

apple = "apple"
print(apple)
>>> apple
apple = None
print(apple)
>>> None

没有意味着什么,没有价值。

没有一个计算结果为False。

I love code examples (as well as fruit), so let me show you

apple = "apple"
print(apple)
>>> apple
apple = None
print(apple)
>>> None

None means nothing, it has no value.

None evaluates to False.


回答 8

largest=none
smallest =none 
While True :
          num =raw_input ('enter a number ') 
          if num =="done ": break 
          try :
           inp =int (inp) 
          except:
              Print'Invalid input' 
           if largest is none :
               largest=inp
           elif inp>largest:
                largest =none 
           print 'maximum', largest

          if smallest is none:
               smallest =none
          elif inp<smallest :
               smallest =inp
          print 'minimum', smallest 

print 'maximum, minimum, largest, smallest 
largest=none
smallest =none 
While True :
          num =raw_input ('enter a number ') 
          if num =="done ": break 
          try :
           inp =int (inp) 
          except:
              Print'Invalid input' 
           if largest is none :
               largest=inp
           elif inp>largest:
                largest =none 
           print 'maximum', largest

          if smallest is none:
               smallest =none
          elif inp<smallest :
               smallest =inp
          print 'minimum', smallest 

print 'maximum, minimum, largest, smallest 

Matplotlib:“未知投影’3d’”错误

问题:Matplotlib:“未知投影’3d’”错误

我刚安装了matplotlib,并尝试运行其中的示例脚本之一。但是我遇到了下面详述的错误。我究竟做错了什么?

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
cset = ax.contour(X, Y, Z, 16, extend3d=True)
ax.clabel(cset, fontsize=9, inline=1)

plt.show()

错误是

Traceback (most recent call last):
  File "<string>", line 245, in run_nodebug
  File "<module1>", line 5, in <module>
  File "C:\Python26\lib\site-packages\matplotlib\figure.py", line 945, in gca
    return self.add_subplot(111, **kwargs)
  File "C:\Python26\lib\site-packages\matplotlib\figure.py", line 677, in add_subplot
    projection_class = get_projection_class(projection)
  File "C:\Python26\lib\site-packages\matplotlib\projections\__init__.py", line 61, in get_projection_class
    raise ValueError("Unknown projection '%s'" % projection)
ValueError: Unknown projection '3d'

I just installed matplotlib and am trying to run one of there example scripts. However I run into the error detailed below. What am I doing wrong?

from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y, Z = axes3d.get_test_data(0.05)
cset = ax.contour(X, Y, Z, 16, extend3d=True)
ax.clabel(cset, fontsize=9, inline=1)

plt.show()

The error is

Traceback (most recent call last):
  File "<string>", line 245, in run_nodebug
  File "<module1>", line 5, in <module>
  File "C:\Python26\lib\site-packages\matplotlib\figure.py", line 945, in gca
    return self.add_subplot(111, **kwargs)
  File "C:\Python26\lib\site-packages\matplotlib\figure.py", line 677, in add_subplot
    projection_class = get_projection_class(projection)
  File "C:\Python26\lib\site-packages\matplotlib\projections\__init__.py", line 61, in get_projection_class
    raise ValueError("Unknown projection '%s'" % projection)
ValueError: Unknown projection '3d'

回答 0

首先,我认为版本的mplot3D工作方式与当前版本的有所不同。matplotlib0.99matplotlib

您正在使用哪个版本?(尝试运行:python -c 'import matplotlib; print matplotlib."__version__")

我猜您正在运行的是version 0.99,在这种情况下,您需要使用稍微不同的语法或更新到的最新版本matplotlib

如果您正在运行version 0.99,请尝试执行此操作,而不要使用projection关键字参数:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d, Axes3D #<-- Note the capitalization! 
fig = plt.figure()

ax = Axes3D(fig) #<-- Note the difference from your original code...

X, Y, Z = axes3d.get_test_data(0.05)
cset = ax.contour(X, Y, Z, 16, extend3d=True)
ax.clabel(cset, fontsize=9, inline=1)
plt.show()

这应该工作在matplotlib 1.0.x,还有,不只是0.99

First off, I think mplot3D worked a bit differently in matplotlib version 0.99 than it does in the current version of matplotlib.

Which version are you using? (Try running: python -c 'import matplotlib; print matplotlib."__version__")

I’m guessing you’re running version 0.99, in which case you’ll need to either use a slightly different syntax or update to a more recent version of matplotlib.

If you’re running version 0.99, try doing this instead of using using the projection keyword argument:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d, Axes3D #<-- Note the capitalization! 
fig = plt.figure()

ax = Axes3D(fig) #<-- Note the difference from your original code...

X, Y, Z = axes3d.get_test_data(0.05)
cset = ax.contour(X, Y, Z, 16, extend3d=True)
ax.clabel(cset, fontsize=9, inline=1)
plt.show()

This should work in matplotlib 1.0.x, as well, not just 0.99.


回答 1

只是为了增加Joe Kington的答案(没有足够的声誉来发表评论),在http://matplotlib.org/examples/mplot3d/mixed_subplots_demo.html的文档中有一个很好的混合2d和3d绘图的例子,其中显示projection =’ 3d’与Axes3D导入结合使用。

from mpl_toolkits.mplot3d import Axes3D
...
ax = fig.add_subplot(2, 1, 1)
...
ax = fig.add_subplot(2, 1, 2, projection='3d')

实际上,只要存在Axes3D导入,

from mpl_toolkits.mplot3d import Axes3D
...
ax = fig.gca(projection='3d')

OP所使用的也可以。(已使用matplotlib 1.3.1版检查)

Just to add to Joe Kington’s answer (not enough reputation for a comment) there is a good example of mixing 2d and 3d plots in the documentation at http://matplotlib.org/examples/mplot3d/mixed_subplots_demo.html which shows projection=’3d’ working in combination with the Axes3D import.

from mpl_toolkits.mplot3d import Axes3D
...
ax = fig.add_subplot(2, 1, 1)
...
ax = fig.add_subplot(2, 1, 2, projection='3d')

In fact as long as the Axes3D import is present the line

from mpl_toolkits.mplot3d import Axes3D
...
ax = fig.gca(projection='3d')

as used by the OP also works. (checked with matplotlib version 1.3.1)


回答 2

整个导入mplot3d以使用“ projection =’3d’”。

在脚本顶部插入以下命令。它应该运行良好。

从mpl_toolkits导入mplot3d

Import mplot3d whole to use “projection = ‘3d'”.

Insert the command below in top of your script. It should run fine.

from mpl_toolkits import mplot3d

回答 3

我遇到了同样的问题,@ Joe Kington和@bvanlew的答案解决了我的问题。

但是当您使用pycharm并启用时,我应该添加更多信息auto import

格式化代码时,代码from mpl_toolkits.mplot3d import Axes3D会被pycharm自动删除。

所以,我的解决方案是

from mpl_toolkits.mplot3d import Axes3D
Axes3D = Axes3D  # pycharm auto import
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

而且效果很好!

I encounter the same problem, and @Joe Kington and @bvanlew’s answer solve my problem.

but I should add more infomation when you use pycharm and enable auto import.

when you format the code, the code from mpl_toolkits.mplot3d import Axes3D will auto remove by pycharm.

so, my solution is

from mpl_toolkits.mplot3d import Axes3D
Axes3D = Axes3D  # pycharm auto import
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

and it works well!


回答 4

试试这个:

import matplotlib.pyplot as plt
import seaborn as sns
from mpl_toolkits.mplot3d import axes3d

fig=plt.figure(figsize=(16,12.5))
ax=fig.add_subplot(2,2,1,projection="3d")

a=ax.scatter(Dataframe['bedrooms'],Dataframe['bathrooms'],Dataframe['floors'])
plt.plot(a)

Try this:

import matplotlib.pyplot as plt
import seaborn as sns
from mpl_toolkits.mplot3d import axes3d

fig=plt.figure(figsize=(16,12.5))
ax=fig.add_subplot(2,2,1,projection="3d")

a=ax.scatter(Dataframe['bedrooms'],Dataframe['bathrooms'],Dataframe['floors'])
plt.plot(a)

如何使用Pipfile和Pipfile.lock?

问题:如何使用Pipfile和Pipfile.lock?

在Python封装的上下文中,似乎Pipfile / Pipfile.lock旨在替代Requirements.txt。但是,关于它们如何实际工作的文献很少。我在这里的Python网站的PyPi部分找到了对pipfile的不断发展的描述,但这很混乱,并且没有解释文件不同部分的语义。

关于如何理解这些文件的任何指示?

It seems that Pipfile/Pipfile.lock are intended to be replacements for requirements.txt, in the context of Python packaging. There isn’t much documentation out there on how these actually work, however. I found an evolving description of pipfile on the PyPi section of the Python website here but it’s pretty messy and doesn’t explain the semantics of the different sections of the file.

Any pointers on how to understand these files?


回答 0

如果您对Ruby的Bundler或Node的Npm有一定的了解,这些文件的概念很简单,并且与其他现有工具类似。Pipenv是使用Pipfile和Pipfile.lock文件实现这些目标的程序包和虚拟环境管理工具。

Pipenv以一种默认的标准方式为您处理虚拟环境(不再需要激活和停用)。下面是一些入门的基础知识,请在pipenv网站上查看更多信息

入门

在您的项目文件夹类型中,开始使用pipenv很容易。

$ pipenv install

…,如果已经有一个requirements.txt文件,它将生成一个Pipfile带有需求的文件和一个虚拟环境文件夹,否则,它将生成一个空Pipfile文件。如果您不喜欢或改变主意,请输入…

$ pipenv uninstall <package>

…而且您很高兴。要激活已生成pipenv的虚拟环境,请继续…

$ pipenv shell

…,您的虚拟环境将被激活。离开环境…

$ exit

…,您将回到原来的终端会话。

点文件

Pipfile文件旨在指定套餐要求为您的Python应用程序或库,既要发展和执行。您只需使用…即可安装软件包。

$ pipenv install flask

…并将其添加为部署和执行的依赖项或使用…

$ pipenv install --dev pytest

…,它将用作开发时间的依赖。文件语法非常简单,如下所示。

[[source]] # Here goes your package sources (where you are downloading your packages from).
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[packages] # Here goes your package requirements for running the application and its versions (which packages you will use when running the application).
requests = "*"
flask = "*"
pandas = "*"

[dev-packages] # Here goes your package requirements for developing the application and its versions (which packaes you will use when developing the application)
pylint = "*"
wheel = "*"

[requires] # Here goes your required Python version.
python_version = "3.6"

Pipfile.lock

Pipfile.lock是用来规定的基础上,目前在包装Pipfile,应使用哪个那些特定版本,避免自动升级依赖于对方的包和破坏你的项目的依赖关系树的风险。

您可以使用…锁定当前安装的软件包。

$ pipenv lock

…,然后该工具将根据当前安装的版本查找您的虚拟环境文件夹,以自动为您生成锁定文件。文件语法并不像Pipfile那样明显,因此为简洁起见,此处不会显示。

The concept behind these files is simple and analogue to other already existing tools, if you have some familiarity with Ruby’s Bundler or Node’s Npm. Pipenv is both a package and virtual environment management tool that uses the Pipfile and Pipfile.lock files to achieve these goals.

Pipenv handles the virtual environment for you in one default standard way (no more activate and deactivate required). Below, some basics to get you started, see more at pipenv website.

Getting Started

Start using pipenv is easy, in your project folder type…

$ pipenv install

… and if it already has a requirements.txt file, it will generate a Pipfile file with the requirements and a virtual environment folder, otherwise, it will generate an empty Pipfile file. If you disliked or changed your mind about something that you have installed, just type…

$ pipenv uninstall <package>

… and you’re good to go. To activate the virtual environment that pipenv already generated, go with…

$ pipenv shell

… and your virtual environment will be activated. To leave the environment…

$ exit

… and you will be back to your original terminal session.

Pipfile

The Pipfile file is intended to specify packages requirements for your Python application or library, both to development and execution. You can install a package by simply using…

$ pipenv install flask

… and it will be added as a dependency for deployment and execution or by using …

$ pipenv install --dev pytest

… and it will be used as a depencency for development time. The file syntax is pretty straight forward, as follows.

[[source]] # Here goes your package sources (where you are downloading your packages from).
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[packages] # Here goes your package requirements for running the application and its versions (which packages you will use when running the application).
requests = "*"
flask = "*"
pandas = "*"

[dev-packages] # Here goes your package requirements for developing the application and its versions (which packaes you will use when developing the application)
pylint = "*"
wheel = "*"

[requires] # Here goes your required Python version.
python_version = "3.6"

Pipfile.lock

The Pipfile.lock is intended to specify, based on the packages present in Pipfile, which specific version of those should be used, avoiding the risks of automatically upgrading packages that depend upon each other and breaking your project dependency tree.

You can lock your currently installed packages using…

$ pipenv lock

… and the tool will lookup your virtual environment folder to generate the lock file for you automatically, based on the currently installed versions. The file syntax is not as obvious as is for Pipfile , so for the sake of conciseness, it will not be displayed here.


如何复制virtualenv

问题:如何复制virtualenv

我有一个现有的virtualenv,其中包含很多软件包,但是旧版本的Django。

我想要做的就是复制此环境,因此我有另一个环境,它们的软件包完全相同,但是 Django的更新版本。我怎样才能做到这一点?

I have an existing virtualenv with a lot of packages but an old version of Django.

What I want to do is duplicate this environment so I have another environment with the exact same packages but a newer version of Django. How can I do this?


回答 0

最简单的方法是使用pip生成需求文件。需求文件基本上是一个文件,其中包含要安装(或在pip生成文件的情况下已经安装)所有python软件包的列表,以及它们的版本。

要生成需求文件,请进入原始的virtualenv,然后运行:

pip freeze > requirements.txt

这将为您生成requirements.txt文件。如果您在喜欢的文本编辑器中打开该文件,则会看到类似以下内容的内容:

Django==1.3
Fabric==1.0.1
etc...

现在,编辑这行Django==x.xDjango==1.3(或任何版本要在新的virtualenv安装)。

最后,激活新的 virtualenv并运行:

pip install -r requirements.txt

然后pip会自动下载并安装您requirements.txt文件中列出的所有python模块,无论您使用的是哪个版本!

The easiest way is to use pip to generate a requirements file. A requirements file is basically a file that contains a list of all the python packages you want to install (or have already installed in case of file generated by pip), and what versions they’re at.

To generate a requirements file, go into your original virtualenv, and run:

pip freeze > requirements.txt

This will generate the requirements.txt file for you. If you open that file up in your favorite text editor, you’ll see something like:

Django==1.3
Fabric==1.0.1
etc...

Now, edit the line that says Django==x.x to say Django==1.3 (or whatever version you want to install in your new virtualenv).

Lastly, activate your new virtualenv, and run:

pip install -r requirements.txt

And pip will automatically download and install all the python modules listed in your requirements.txt file, at whatever versions you specified!


回答 1

另一种选择是使用virtualenv-clone包:

用于克隆不可重定位的virtualenv的脚本。

Another option is to use virtualenv-clone package:

A script for cloning a non-relocatable virtualenv.


回答 2

virtualenvwrapper提供复制虚拟环境命令

cpvirtualenv ENVNAME [TARGETENVNAME]

virtualenvwrapper provides a command to duplicate virtualenv

cpvirtualenv ENVNAME [TARGETENVNAME]

回答 3

如果您正在使用Anaconda,则可以运行:

conda create --name myclone --clone myenv

这将复制myenv到名为的新创建的环境myclone

If you are using Anaconda you can just run:

conda create --name myclone --clone myenv

This will copy myenv to the newly created environment called myclone.


回答 4

最简单的选择是使用virtualenv-clone软件包。

要复制venv1venv2,请按照以下步骤操作:

  1. 安装virtualenv-clone在任一venv1或虚拟的虚拟环境venv_dummy。创建venv_dummy

    python -m virtualenv venv_dummy
    source venv_dummy/bin/activate
  2. 要安装virtualenv-clone

    (venv_dummy): pip install virtualenv-clone
  3. 复制venv1venv2

    (venv_dummy): virtualenv-clone venv1/ venv2/

Easiest option is using virtualenv-clone package.

To duplicate venv1 to venv2, follow these steps:

  1. Install virtualenv-clone in either venv1 or a dummy virtual environment venv_dummy. To create venv_dummy:

    python -m virtualenv venv_dummy
    source venv_dummy/bin/activate
    
  2. To install virtualenv-clone:

    (venv_dummy): pip install virtualenv-clone
    
  3. To duplicate venv1 to venv2:

    (venv_dummy): virtualenv-clone venv1/ venv2/
    

回答 5

您能不能简单地:

  • 将现有的虚拟环境目录复制到新目录
  • 更新到新的Django?

Can you not simply:

  • Copy the existing virtual env directory to a new one
  • Update to the new Django?

在Python中,如何将一个列表与另一个列表建立索引?

问题:在Python中,如何将一个列表与另一个列表建立索引?

我想用这样的另一个列表索引一个列表

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
T = L[ Idx ]

T应该最终是一个包含[‘a’,’d’,’h’]的列表。

有没有比这更好的方法

T = []
for i in Idx:
    T.append(L[i])

print T
# Gives result ['a', 'd', 'h']

I would like to index a list with another list like this

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
T = L[ Idx ]

and T should end up being a list containing [‘a’, ‘d’, ‘h’].

Is there a better way than

T = []
for i in Idx:
    T.append(L[i])

print T
# Gives result ['a', 'd', 'h']

回答 0

T = [L[i] for i in Idx]
T = [L[i] for i in Idx]

回答 1

如果您使用的是numpy,则可以执行如下扩展切片:

>>> import numpy
>>> a=numpy.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
>>> Idx = [0, 3, 7]
>>> a[Idx]
array(['a', 'd', 'h'], 
      dtype='|S1')

…并且可能要快得多(如果性能足以影响numpy导入)

If you are using numpy, you can perform extended slicing like that:

>>> import numpy
>>> a=numpy.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
>>> Idx = [0, 3, 7]
>>> a[Idx]
array(['a', 'd', 'h'], 
      dtype='|S1')

…and is probably much faster (if performance is enough of a concern to to bother with the numpy import)


回答 2

功能方法:

a = [1,"A", 34, -123, "Hello", 12]
b = [0, 2, 5]

from operator import itemgetter

print(list(itemgetter(*b)(a)))
[1, 34, 12]

A functional approach:

a = [1,"A", 34, -123, "Hello", 12]
b = [0, 2, 5]

from operator import itemgetter

print(list(itemgetter(*b)(a)))
[1, 34, 12]

回答 3

T = map(lambda i: L[i], Idx)
T = map(lambda i: L[i], Idx)

回答 4

我对这些方法都不满意,所以我想出了一个Flexlist类,它允许通过整数,切片或索引列表进行灵活的索引编制:

class Flexlist(list):
    def __getitem__(self, keys):
        if isinstance(keys, (int, slice)): return list.__getitem__(self, keys)
        return [self[k] for k in keys]

例如,您将其用作:

L = Flexlist(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
Idx = [0, 3, 7]
T = L[ Idx ]

print(T)  # ['a', 'd', 'h']

I wasn’t happy with any of these approaches, so I came up with a Flexlist class that allows for flexible indexing, either by integer, slice or index-list:

class Flexlist(list):
    def __getitem__(self, keys):
        if isinstance(keys, (int, slice)): return list.__getitem__(self, keys)
        return [self[k] for k in keys]

Which, for your example, you would use as:

L = Flexlist(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
Idx = [0, 3, 7]
T = L[ Idx ]

print(T)  # ['a', 'd', 'h']

回答 5

L= {'a':'a','d':'d', 'h':'h'}
index= ['a','d','h'] 
for keys in index:
    print(L[keys])

我会用一个Dict add想要keysindex

L= {'a':'a','d':'d', 'h':'h'}
index= ['a','d','h'] 
for keys in index:
    print(L[keys])

I would use a Dict add desired keys to index


回答 6

您也可以将__getitem__方法与map以下方法结合使用:

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
res = list(map(L.__getitem__, Idx))
print(res)
# ['a', 'd', 'h']

You could also use the __getitem__ method combined with map like the following:

L = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
Idx = [0, 3, 7]
res = list(map(L.__getitem__, Idx))
print(res)
# ['a', 'd', 'h']

检查密钥是否存在,并使用Python迭代JSON数组

问题:检查密钥是否存在,并使用Python迭代JSON数组

我从Facebook帖子中获得了一堆JSON数据,如下所示:

{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}

JSON数据是半结构化的,并且所有数据都不相同。下面是我的代码:

import json 

str = '{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}'
data = json.loads(str)

post_id = data['id']
post_type = data['type']
print(post_id)
print(post_type)

created_time = data['created_time']
updated_time = data['updated_time']
print(created_time)
print(updated_time)

if data.get('application'):
    app_id = data['application'].get('id', 0)
    print(app_id)
else:
    print('null')

#if data.get('to'):
#... This is the part I am not sure how to do
# Since it is in the form "to": {"data":[{"id":...}]}

我希望代码将to_id打印为1543,否则打印’null’

我不确定该怎么做。

I have a bunch of JSON data from Facebook posts like the one below:

{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}

The JSON data is semi-structured and all is not the same. Below is my code:

import json 

str = '{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}'
data = json.loads(str)

post_id = data['id']
post_type = data['type']
print(post_id)
print(post_type)

created_time = data['created_time']
updated_time = data['updated_time']
print(created_time)
print(updated_time)

if data.get('application'):
    app_id = data['application'].get('id', 0)
    print(app_id)
else:
    print('null')

#if data.get('to'):
#... This is the part I am not sure how to do
# Since it is in the form "to": {"data":[{"id":...}]}

I want the code to print the to_id as 1543 else print ‘null’

I am not sure how to do this.


回答 0

import json

jsonData = """{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}"""

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    if 'to' not in data:
        raise ValueError("No target in given data")
    if 'data' not in data['to']:
        raise ValueError("No data for target")

    for dest in data['to']['data']:
        if 'id' not in dest:
            continue
        targetId = dest['id']
        print("to_id:", targetId)

输出:

In [9]: getTargetIds(s)
to_id: 1543
import json

jsonData = """{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}"""

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    if 'to' not in data:
        raise ValueError("No target in given data")
    if 'data' not in data['to']:
        raise ValueError("No data for target")

    for dest in data['to']['data']:
        if 'id' not in dest:
            continue
        targetId = dest['id']
        print("to_id:", targetId)

Output:

In [9]: getTargetIds(s)
to_id: 1543

回答 1

如果您只想检查密钥是否存在

h = {'a': 1}
'b' in h # returns False

如果要检查是否有密钥值

h.get('b') # returns None

如果缺少实际值,则返回默认值

h.get('b', 'Default value')

If all you want is to check if key exists or not

h = {'a': 1}
'b' in h # returns False

If you want to check if there is a value for key

h.get('b') # returns None

Return a default value if actual value is missing

h.get('b', 'Default value')

回答 2

为此类事件创建助手实用程序方法是一个好习惯,这样,每当您需要更改属性验证的逻辑时,它就会放在一个位置,并且对于跟随者而言,代码将更具可读性。

例如,在以下位置创建一个辅助方法(或JsonUtils带有静态方法的类)json_utils.py

def get_attribute(data, attribute, default_value):
    return data.get(attribute) or default_value

然后在您的项目中使用它:

from json_utils import get_attribute

def my_cool_iteration_func(data):

    data_to = get_attribute(data, 'to', None)
    if not data_to:
        return

    data_to_data = get_attribute(data_to, 'data', [])
    for item in data_to_data:
        print('The id is: %s' % get_attribute(item, 'id', 'null'))

重要的提示:

我使用的原因data.get(attribute) or default_value不是简单的data.get(attribute, default_value)

{'my_key': None}.get('my_key', 'nothing') # returns None
{'my_key': None}.get('my_key') or 'nothing' # returns 'nothing'

在我的应用程序中,获取属性值为“ null”与根本不获取属性相同。如果您的用法不同,则需要进行更改。

It is a good practice to create helper utility methods for things like that so that whenever you need to change the logic of attribute validation it would be in one place, and the code will be more readable for the followers.

For example create a helper method (or class JsonUtils with static methods) in json_utils.py:

def get_attribute(data, attribute, default_value):
    return data.get(attribute) or default_value

and then use it in your project:

from json_utils import get_attribute

def my_cool_iteration_func(data):

    data_to = get_attribute(data, 'to', None)
    if not data_to:
        return

    data_to_data = get_attribute(data_to, 'data', [])
    for item in data_to_data:
        print('The id is: %s' % get_attribute(item, 'id', 'null'))

IMPORTANT NOTE:

There is a reason I am using data.get(attribute) or default_value instead of simply data.get(attribute, default_value):

{'my_key': None}.get('my_key', 'nothing') # returns None
{'my_key': None}.get('my_key') or 'nothing' # returns 'nothing'

In my applications getting attribute with value ‘null’ is the same as not getting the attribute at all. If your usage is different, you need to change this.


回答 3

jsonData = """{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}, {"name": "Joe Schmoe"}]}, "type": "status", "id": "id_7"}"""

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    for dest in data['to']['data']:
        print("to_id:", dest.get('id', 'null'))

试试吧:

>>> getTargetIds(jsonData)
to_id: 1543
to_id: null

或者,如果您只想跳过缺少ID的值,而不是打印'null'

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    for dest in data['to']['data']:
        if 'id' in to_id:
            print("to_id:", dest['id'])

所以:

>>> getTargetIds(jsonData)
to_id: 1543

当然,在现实生活中,您可能不想使用print每个id,而是要存储它们并对其进行操作,但这是另一个问题。

jsonData = """{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}, {"name": "Joe Schmoe"}]}, "type": "status", "id": "id_7"}"""

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    for dest in data['to']['data']:
        print("to_id:", dest.get('id', 'null'))

Try it:

>>> getTargetIds(jsonData)
to_id: 1543
to_id: null

Or, if you just want to skip over values missing ids instead of printing 'null':

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    for dest in data['to']['data']:
        if 'id' in to_id:
            print("to_id:", dest['id'])

So:

>>> getTargetIds(jsonData)
to_id: 1543

Of course in real life, you probably don’t want to print each id, but to store them and do something with them, but that’s another issue.


回答 4

if "my_data" in my_json_data:
         print json.dumps(my_json_data["my_data"])
if "my_data" in my_json_data:
         print json.dumps(my_json_data["my_data"])

回答 5

为此,我编写了一个小函数。随时调整用途,

def is_json_key_present(json, key):
    try:
        buf = json[key]
    except KeyError:
        return False

    return True

I wrote a tiny function for this purpose. Feel free to repurpose,

def is_json_key_present(json, key):
    try:
        buf = json[key]
    except KeyError:
        return False

    return True

如何在Tkinter中处理窗口关闭事件?

问题:如何在Tkinter中处理窗口关闭事件?

如何在Python Tkinter程序中处理窗口关闭事件(用户单击“ X”按钮)?

How do I handle the window close event (user clicking the ‘X’ button) in a Python Tkinter program?


回答 0

Tkinter支持一种称为协议处理程序的机制。在这里,术语协议是指应用程序和窗口管理器之间的交互。最常用的协议称为WM_DELETE_WINDOW,用于定义当用户使用窗口管理器显式关闭窗口时发生的情况。

您可以使用该protocol方法为该协议安装处理程序(窗口小部件必须是TkToplevel窗口小部件):

这里有一个具体的例子:

import tkinter as tk
from tkinter import messagebox

root = tk.Tk()

def on_closing():
    if messagebox.askokcancel("Quit", "Do you want to quit?"):
        root.destroy()

root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()

Tkinter supports a mechanism called protocol handlers. Here, the term protocol refers to the interaction between the application and the window manager. The most commonly used protocol is called WM_DELETE_WINDOW, and is used to define what happens when the user explicitly closes a window using the window manager.

You can use the protocol method to install a handler for this protocol (the widget must be a Tk or Toplevel widget):

Here you have a concrete example:

import tkinter as tk
from tkinter import messagebox

root = tk.Tk()

def on_closing():
    if messagebox.askokcancel("Quit", "Do you want to quit?"):
        root.destroy()

root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()

回答 1

马特展示了关闭按钮的一种经典修改。
另一种是使关闭按钮最小化窗口。
您可以通过将iconify方法
作为协议方法的第二个参数来重现此行为。

这是一个在Windows 7和10上测试过的有效示例:

# Python 3
import tkinter
import tkinter.scrolledtext as scrolledtext

root = tkinter.Tk()
# make the top right close button minimize (iconify) the main window
root.protocol("WM_DELETE_WINDOW", root.iconify)
# make Esc exit the program
root.bind('<Escape>', lambda e: root.destroy())

# create a menu bar with an Exit command
menubar = tkinter.Menu(root)
filemenu = tkinter.Menu(menubar, tearoff=0)
filemenu.add_command(label="Exit", command=root.destroy)
menubar.add_cascade(label="File", menu=filemenu)
root.config(menu=menubar)

# create a Text widget with a Scrollbar attached
txt = scrolledtext.ScrolledText(root, undo=True)
txt['font'] = ('consolas', '12')
txt.pack(expand=True, fill='both')

root.mainloop()

在此示例中,我们为用户提供了两个新的退出选项:
经典的File→Exit,以及Esc按钮。

Matt has shown one classic modification of the close button.
The other is to have the close button minimize the window.
You can reproduced this behavior by having the iconify method
be the protocol method’s second argument.

Here’s a working example, tested on Windows 7 & 10:

# Python 3
import tkinter
import tkinter.scrolledtext as scrolledtext

root = tkinter.Tk()
# make the top right close button minimize (iconify) the main window
root.protocol("WM_DELETE_WINDOW", root.iconify)
# make Esc exit the program
root.bind('<Escape>', lambda e: root.destroy())

# create a menu bar with an Exit command
menubar = tkinter.Menu(root)
filemenu = tkinter.Menu(menubar, tearoff=0)
filemenu.add_command(label="Exit", command=root.destroy)
menubar.add_cascade(label="File", menu=filemenu)
root.config(menu=menubar)

# create a Text widget with a Scrollbar attached
txt = scrolledtext.ScrolledText(root, undo=True)
txt['font'] = ('consolas', '12')
txt.pack(expand=True, fill='both')

root.mainloop()

In this example we give the user two new exit options:
the classic File → Exit, and also the Esc button.


回答 2

取决于Tkinter活动,尤其是在使用Tkinter.after时,使用destroy()-即使通过使用protocol(),按钮等停止该活动也会干扰该活动(“执行时出错”),而不仅仅是终止它。在几乎每种情况下,最好的解决方案是使用标志。这是一个简单,愚蠢的用法示例(尽管我敢肯定,你们大多数人都不需要它!

from Tkinter import *

def close_window():
  global running
  running = False  # turn off while loop
  print( "Window closed")

root = Tk()
root.protocol("WM_DELETE_WINDOW", close_window)
cv = Canvas(root, width=200, height=200)
cv.pack()

running = True;
# This is an endless loop stopped only by setting 'running' to 'False'
while running: 
  for i in range(200): 
    if not running: 
        break
    cv.create_oval(i, i, i+1, i+1)
    root.update() 

这样可以很好地终止图形活动。您只需要running在正确的位置检查即可。

Depending on the Tkinter activity, and especially when using Tkinter.after, stopping this activity with destroy() — even by using protocol(), a button, etc. — will disturb this activity (“while executing” error) rather than just terminate it. The best solution in almost every case is to use a flag. Here is a simple, silly example of how to use it (although I am certain that most of you don’t need it! :)

from Tkinter import *

def close_window():
  global running
  running = False  # turn off while loop
  print( "Window closed")

root = Tk()
root.protocol("WM_DELETE_WINDOW", close_window)
cv = Canvas(root, width=200, height=200)
cv.pack()

running = True;
# This is an endless loop stopped only by setting 'running' to 'False'
while running: 
  for i in range(200): 
    if not running: 
        break
    cv.create_oval(i, i, i+1, i+1)
    root.update() 

This terminates graphics activity nicely. You only need to check running at the right place(s).


回答 3

我要感谢Apostolos的回答,这一点引起了我的注意。这是2019年Python 3的更加详细的示例,带有更清晰的描述和示例代码。


注意以下事实destroy():(或完全没有自定义窗口关闭处理程序)将在用户关闭窗口时立即销毁窗口及其所有正在运行的回调

这可能对您不利,具体取决于您当前的Tkinter活动,尤其是在使用tkinter.after(定期回调)时。您可能正在使用处理一些数据并将其写入磁盘的回调…在这种情况下,您显然希望数据写入完成而不会被突然终止。

最好的解决方案是使用标志。因此,当用户请求关闭窗口时,可以将其标记为一个标志,然后对其进行响应。

(注意:我通常将GUI设计为封装良好的类和单独的工作线程,并且我绝对不使用“全局”(我改用类实例变量),但这只是一个简单的示例,用于演示当用户关闭窗口时,Tk如何突然终止您的定期回调…)

from tkinter import *
import time

# Try setting this to False and look at the printed numbers (1 to 10)
# during the work-loop, if you close the window while the periodic_call
# worker is busy working (printing). It will abruptly end the numbers,
# and kill the periodic callback! That's why you should design most
# applications with a safe closing callback as described in this demo.
safe_closing = True

# ---------

busy_processing = False
close_requested = False

def close_window():
    global close_requested
    close_requested = True
    print("User requested close at:", time.time(), "Was busy processing:", busy_processing)

root = Tk()
if safe_closing:
    root.protocol("WM_DELETE_WINDOW", close_window)
lbl = Label(root)
lbl.pack()

def periodic_call():
    global busy_processing

    if not close_requested:
        busy_processing = True
        for i in range(10):
            print((i+1), "of 10")
            time.sleep(0.2)
            lbl["text"] = str(time.time()) # Will error if force-closed.
            root.update() # Force redrawing since we change label multiple times in a row.
        busy_processing = False
        root.after(500, periodic_call)
    else:
        print("Destroying GUI at:", time.time())
        try: # "destroy()" can throw, so you should wrap it like this.
            root.destroy()
        except:
            # NOTE: In most code, you'll wanna force a close here via
            # "exit" if the window failed to destroy. Just ensure that
            # you have no code after your `mainloop()` call (at the
            # bottom of this file), since the exit call will cause the
            # process to terminate immediately without running any more
            # code. Of course, you should NEVER have code after your
            # `mainloop()` call in well-designed code anyway...
            # exit(0)
            pass

root.after_idle(periodic_call)
root.mainloop()

此代码将向您显示WM_DELETE_WINDOW即使在periodic_call()工作/循环中间我们的自定义繁忙时,处理程序也会运行!

我们使用一些相当夸张的.after()值:500毫秒。这只是为了使它很容易让你看到关闭的区别,而周期性呼叫占线,或不…如果关闭,而数字更新,你会看到WM_DELETE_WINDOW发生了,而你的定期电话“是忙处理:是”。如果您在数字暂停时关闭(这意味着此时不处理定期回调),则会看到关闭发生在“不忙”期间。

在实际使用中,您.after()将使用30到100毫秒左右的时间来获得响应式GUI。这只是一个演示,可以帮助您了解如何保护自己免受Tk的默认“关闭时立即中断所有工作”的行为。

总结:让WM_DELETE_WINDOW处理程序设置一个标志,然后.destroy()在安全的情况下(当您的应用程序完成所有工作时)定期并手动检查该标志。

PS:您还可以使用WM_DELETE_WINDOW询问用户是否真的要关闭的窗口; 如果他们回答“否”,则无需设置标志。非常简单 您只需要在自己的信箱中显示一个消息框,WM_DELETE_WINDOW然后根据用户的答案设置标志即可。

I’d like to thank the answer by Apostolos for bringing this to my attention. Here’s a much more detailed example for Python 3 in the year 2019, with a clearer description and example code.


Beware of the fact that destroy() (or not having a custom window closing handler at all) will destroy the window and all of its running callbacks instantly when the user closes it.

This can be bad for you, depending on your current Tkinter activity, and especially when using tkinter.after (periodic callbacks). You might be using a callback which processes some data and writes to disk… in that case, you obviously want the data writing to finish without being abruptly killed.

The best solution for that is to use a flag. So when the user requests window closing, you mark that as a flag, and then react to it.

(Note: I normally design GUIs as nicely encapsulated classes and separate worker threads, and I definitely don’t use “global” (I use class instance variables instead), but this is meant to be a simple, stripped-down example to demonstrate how Tk abruptly kills your periodic callbacks when the user closes the window…)

from tkinter import *
import time

# Try setting this to False and look at the printed numbers (1 to 10)
# during the work-loop, if you close the window while the periodic_call
# worker is busy working (printing). It will abruptly end the numbers,
# and kill the periodic callback! That's why you should design most
# applications with a safe closing callback as described in this demo.
safe_closing = True

# ---------

busy_processing = False
close_requested = False

def close_window():
    global close_requested
    close_requested = True
    print("User requested close at:", time.time(), "Was busy processing:", busy_processing)

root = Tk()
if safe_closing:
    root.protocol("WM_DELETE_WINDOW", close_window)
lbl = Label(root)
lbl.pack()

def periodic_call():
    global busy_processing

    if not close_requested:
        busy_processing = True
        for i in range(10):
            print((i+1), "of 10")
            time.sleep(0.2)
            lbl["text"] = str(time.time()) # Will error if force-closed.
            root.update() # Force redrawing since we change label multiple times in a row.
        busy_processing = False
        root.after(500, periodic_call)
    else:
        print("Destroying GUI at:", time.time())
        try: # "destroy()" can throw, so you should wrap it like this.
            root.destroy()
        except:
            # NOTE: In most code, you'll wanna force a close here via
            # "exit" if the window failed to destroy. Just ensure that
            # you have no code after your `mainloop()` call (at the
            # bottom of this file), since the exit call will cause the
            # process to terminate immediately without running any more
            # code. Of course, you should NEVER have code after your
            # `mainloop()` call in well-designed code anyway...
            # exit(0)
            pass

root.after_idle(periodic_call)
root.mainloop()

This code will show you that the WM_DELETE_WINDOW handler runs even while our custom periodic_call() is busy in the middle of work/loops!

We use some pretty exaggerated .after() values: 500 milliseconds. This is just meant to make it very easy for you to see the difference between closing while the periodic call is busy, or not… If you close while the numbers are updating, you will see that the WM_DELETE_WINDOW happened while your periodic call “was busy processing: True”. If you close while the numbers are paused (meaning that the periodic callback isn’t processing at that moment), you see that the close happened while it’s “not busy”.

In real-world usage, your .after() would use something like 30-100 milliseconds, to have a responsive GUI. This is just a demonstration to help you understand how to protect yourself against Tk’s default “instantly interrupt all work when closing” behavior.

In summary: Make the WM_DELETE_WINDOW handler set a flag, and then check that flag periodically and manually .destroy() the window when it’s safe (when your app is done with all work).

PS: You can also use WM_DELETE_WINDOW to ask the user if they REALLY want to close the window; and if they answer no, you don’t set the flag. It’s very simple. You just show a messagebox in your WM_DELETE_WINDOW and set the flag based on the user’s answer.


回答 4

尝试简单版本:

import tkinter

window = Tk()

closebutton = Button(window, text='X', command=window.destroy)
closebutton.pack()

window.mainloop()

或者,如果您想添加更多命令:

import tkinter

window = Tk()


def close():
    window.destroy()
    #More Functions


closebutton = Button(window, text='X', command=close)
closebutton.pack()

window.mainloop()

Try The Simple Version:

import tkinter

window = Tk()

closebutton = Button(window, text='X', command=window.destroy)
closebutton.pack()

window.mainloop()

Or If You Want To Add More Commands:

import tkinter

window = Tk()


def close():
    window.destroy()
    #More Functions


closebutton = Button(window, text='X', command=close)
closebutton.pack()

window.mainloop()

回答 5

from tkinter import*
root=Tk()
exit_button=Button(root,text="X",command=root.quit)
root.mainloop()
from tkinter import*
root=Tk()
exit_button=Button(root,text="X",command=root.quit)
root.mainloop()

将目录添加到sys.path / PYTHONPATH

问题:将目录添加到sys.path / PYTHONPATH

我正在尝试从特定目录导入模块。

问题是,如果我使用sys.path.append(mod_directory)追加路径然后打开python解释器,该目录mod_directory将添加到列表sys.path的末尾。如果我PYTHONPATH在打开python解释器之前导出变量,则目录将添加到列表的开头。在后一种情况下,我可以导入模块,但是在前一种情况下,我不能。

有人可以解释为什么会发生这种情况,并给我一个 python脚本中将其添加mod_directory到开始的解决方案吗?

I am trying to import a module from a particular directory.

The problem is that if I use sys.path.append(mod_directory) to append the path and then open the python interpreter, the directory mod_directory gets added to the end of the list sys.path. If I export the PYTHONPATH variable before opening the python interpreter, the directory gets added to the start of the list. In the latter case I can import the module but in the former, I cannot.

Can somebody explain why this is happening and give me a solution to add the mod_directory to the start, inside a python script ?


回答 0

如文档所述,这正在工作。PYTHONPATH文件中指定的所有路径通常在工作目录之后但在标准解释器提供的路径之前记录。 sys.path.append()追加到现有路径。看到这里这里。如果要让特定目录优先出现,只需将其插入sys.path的开头即可:

import sys
sys.path.insert(0,'/path/to/mod_directory')

就是说,通常有比直接使用PYTHONPATH或操纵更好的方法来管理进口sys.path。例如,请参阅此问题的答案。

This is working as documented. Any paths specified in PYTHONPATH are documented as normally coming after the working directory but before the standard interpreter-supplied paths. sys.path.append() appends to the existing path. See here and here. If you want a particular directory to come first, simply insert it at the head of sys.path:

import sys
sys.path.insert(0,'/path/to/mod_directory')

That said, there are usually better ways to manage imports than either using PYTHONPATH or manipulating sys.path directly. See, for example, the answers to this question.


回答 1

您可以使用:

import os
path = 'the path you want'
os.environ['PATH'] += ':'+path

You could use:

import os
path = 'the path you want'
os.environ['PATH'] += ':'+path

回答 2

对于我来说,我需要了解我的python路径。我可以将它的路径添加到该文件 /home/xy/.bashrc由add

export PYTHONPATH=/home/xy/caffe-master/python:$PYTHONPATH

到我的/home/xy/.bashrc文件。

但是当我使用pycharm时,路径仍然不在。

因此,我可以PYTHONPATH通过运行->编辑配置将路径添加到变量。

As to me, i need to caffe to my python path. I can add it’s path to the file /home/xy/.bashrc by add

export PYTHONPATH=/home/xy/caffe-master/python:$PYTHONPATH.

to my /home/xy/.bashrc file.

But when I use pycharm, the path is still not in.

So I can add path to PYTHONPATH variable, by run -> edit Configuration.


回答 3

临时更改目录可以很好地导入:

cwd = os.getcwd()
os.chdir(<module_path>)
import <module>
os.chdir(cwd)

Temporarily changing dirs works well for importing:

cwd = os.getcwd()
os.chdir(<module_path>)
import <module>
os.chdir(cwd)

回答 4

在Windows下从Powershell运行Python脚本时,这应该可以工作:

$pathToSourceRoot = "C:/Users/Steve/YourCode"
$env:PYTHONPATH = "$($pathToSourceRoot);$($pathToSourceRoot)/subdirs_if_required"

# Now run the actual script
python your_script.py

When running a Python script from Powershell under Windows, this should work:

$pathToSourceRoot = "C:/Users/Steve/YourCode"
$env:PYTHONPATH = "$($pathToSourceRoot);$($pathToSourceRoot)/subdirs_if_required"

# Now run the actual script
python your_script.py