如何使用PIL裁剪图像?

问题:如何使用PIL裁剪图像?

我想通过从给定图像中删除前30行和后30行来裁剪图像。我已经搜索过,但没有得到确切的解决方案。有人有建议吗?

I want to crop image in the way by removing first 30 rows and last 30 rows from the given image. I have searched but did not get the exact solution. Does somebody have some suggestions?


回答 0

有一种crop()方法:

w, h = yourImage.size
yourImage.crop((0, 30, w, h-30)).save(...)

There is a crop() method:

w, h = yourImage.size
yourImage.crop((0, 30, w, h-30)).save(...)

回答 1

您需要为此导入PIL(枕头)。假设您的图像尺寸为1200、1600。我们会将图像从400、400裁剪为800、800

from PIL import Image
img = Image.open("ImageName.jpg")
area = (400, 400, 800, 800)
cropped_img = img.crop(area)
cropped_img.show()

You need to import PIL (Pillow) for this. Suppose you have an image of size 1200, 1600. We will crop image from 400, 400 to 800, 800

from PIL import Image
img = Image.open("ImageName.jpg")
area = (400, 400, 800, 800)
cropped_img = img.crop(area)
cropped_img.show()

回答 2

(左,上,右,下)表示两个点,

  1. (左上)
  2. (右下)

对于800×600像素的图像,图像的左上点是(0,0),右下点是(800,600)。

因此,为了将图像减半:

from PIL import Image
img = Image.open("ImageName.jpg")

img_left_area = (0, 0, 400, 600)
img_right_area = (400, 0, 800, 600)

img_left = img.crop(img_left_area)
img_right = img.crop(img_right_area)

img_left.show()
img_right.show()

坐标系

Python Imaging Library使用笛卡尔像素坐标系,左上角为(0,0)。注意,坐标指的是隐含的像素角。寻址为(0,0)的像素的中心实际上位于(0.5,0.5)。

坐标通常以2元组(x,y)的形式传递给库。矩形用4元组表示,左上角在前。例如,将覆盖所有800×600像素图像的矩形写为(0,0,800,600)。

(left, upper, right, lower) means two points,

  1. (left, upper)
  2. (right, lower)

with an 800×600 pixel image, the image’s left upper point is (0, 0), the right lower point is (800, 600).

So, for cutting the image half:

from PIL import Image
img = Image.open("ImageName.jpg")

img_left_area = (0, 0, 400, 600)
img_right_area = (400, 0, 800, 600)

img_left = img.crop(img_left_area)
img_right = img.crop(img_right_area)

img_left.show()
img_right.show()

Coordinate System

The Python Imaging Library uses a Cartesian pixel coordinate system, with (0,0) in the upper left corner. Note that the coordinates refer to the implied pixel corners; the centre of a pixel addressed as (0, 0) actually lies at (0.5, 0.5).

Coordinates are usually passed to the library as 2-tuples (x, y). Rectangles are represented as 4-tuples, with the upper left corner given first. For example, a rectangle covering all of an 800×600 pixel image is written as (0, 0, 800, 600).


回答 3

一种更简单的方法是使用ImageOps中的作物。您可以从每一侧输入要裁剪的像素数。

from PIL import ImageOps

border = (0, 30, 0, 30) # left, up, right, bottom
ImageOps.crop(img, border)

An easier way to do this is using crop from ImageOps. You can feed the number of pixels you want to crop from each side.

from PIL import ImageOps

border = (0, 30, 0, 30) # left, up, right, bottom
ImageOps.crop(img, border)

AttributeError(“’str’对象没有属性’read’”)

问题:AttributeError(“’str’对象没有属性’read’”)

在Python中,我得到一个错误:

Exception:  (<type 'exceptions.AttributeError'>,
AttributeError("'str' object has no attribute 'read'",), <traceback object at 0x1543ab8>)

给定python代码:

def getEntries (self, sub):
    url = 'http://www.reddit.com/'
    if (sub != ''):
        url += 'r/' + sub

    request = urllib2.Request (url + 
        '.json', None, {'User-Agent' : 'Reddit desktop client by /user/RobinJ1995/'})
    response = urllib2.urlopen (request)
    jsonofabitch = response.read ()

    return json.load (jsonofabitch)['data']['children']

此错误是什么意思,我怎么做导致此错误?

In Python I’m getting an error:

Exception:  (<type 'exceptions.AttributeError'>,
AttributeError("'str' object has no attribute 'read'",), <traceback object at 0x1543ab8>)

Given python code:

def getEntries (self, sub):
    url = 'http://www.reddit.com/'
    if (sub != ''):
        url += 'r/' + sub

    request = urllib2.Request (url + 
        '.json', None, {'User-Agent' : 'Reddit desktop client by /user/RobinJ1995/'})
    response = urllib2.urlopen (request)
    jsonofabitch = response.read ()

    return json.load (jsonofabitch)['data']['children']

What does this error mean and what did I do to cause it?


回答 0

问题在于,对于json.load您,应该传递带有已read定义函数的对象之类的文件。因此,您可以使用json.load(response)json.loads(response.read())

The problem is that for json.load you should pass a file like object with a read function defined. So either you use json.load(response) or json.loads(response.read()).


回答 1

AttributeError("'str' object has no attribute 'read'",)

这就是说的意思:有人试图.read在给它的对象上找到一个属性,然后给它一个类型的对象str(即,给它一个字符串)。

错误发生在这里:

json.load (jsonofabitch)['data']['children']

好吧,您不在read任何地方寻找,因此它必须在json.load您调用的函数中发生(如完整的回溯所示)。这是因为json.load正在尝试提供给.read您的东西,但是却给了它jsonofabitch,该东西当前命名为字符串(通过调用.read来创建response)。

解决方案:不要.read自欺欺人。函数将执行此操作,并希望您response直接给它以使其可以执行操作。

您也可以通过阅读功能的内置Python文档(try help(json.load)或整个模块(try help(json))),或通过查看http://docs.python.org上这些功能的文档来解决此问题。

AttributeError("'str' object has no attribute 'read'",)

This means exactly what it says: something tried to find a .read attribute on the object that you gave it, and you gave it an object of type str (i.e., you gave it a string).

The error occurred here:

json.load (jsonofabitch)['data']['children']

Well, you aren’t looking for read anywhere, so it must happen in the json.load function that you called (as indicated by the full traceback). That is because json.load is trying to .read the thing that you gave it, but you gave it jsonofabitch, which currently names a string (which you created by calling .read on the response).

Solution: don’t call .read yourself; the function will do this, and is expecting you to give it the response directly so that it can do so.

You could also have figured this out by reading the built-in Python documentation for the function (try help(json.load), or for the entire module (try help(json)), or by checking the documentation for those functions on http://docs.python.org .


回答 2

如果收到这样的python错误:

AttributeError: 'str' object has no attribute 'some_method'

您可能通过用字符串覆盖对象意外地中毒了对象。

如何用几行代码在python中重现此错误:

#!/usr/bin/env python
import json
def foobar(json):
    msg = json.loads(json)

foobar('{"batman": "yes"}')

运行它,打印:

AttributeError: 'str' object has no attribute 'loads'

但是更改变量名的名称,它可以正常工作:

#!/usr/bin/env python
import json
def foobar(jsonstring):
    msg = json.loads(jsonstring)

foobar('{"batman": "yes"}')

当您尝试在字符串中运行方法时,导致此错误。字符串有几种方法,但是您没有调用。因此,停止尝试调用String未定义的方法,并开始寻找在何处毒害了对象。

If you get a python error like this:

AttributeError: 'str' object has no attribute 'some_method'

You probably poisoned your object accidentally by overwriting your object with a string.

How to reproduce this error in python with a few lines of code:

#!/usr/bin/env python
import json
def foobar(json):
    msg = json.loads(json)

foobar('{"batman": "yes"}')

Run it, which prints:

AttributeError: 'str' object has no attribute 'loads'

But change the name of the variablename, and it works fine:

#!/usr/bin/env python
import json
def foobar(jsonstring):
    msg = json.loads(jsonstring)

foobar('{"batman": "yes"}')

This error is caused when you tried to run a method within a string. String has a few methods, but not the one you are invoking. So stop trying to invoke a method which String does not define and start looking for where you poisoned your object.


回答 3

好的,这是旧线程了。我有一个相同的问题,我的问题是我用了json.load而不是json.loads

这样,json加载任何类型的字典都没有问题。

官方文件

json.load-使用此转换表将fp(支持.read()的文本文件或包含JSON文档的二进制文件)反序列化为Python对象。

json.loads-使用此转换表将s(包含JSON文档的str,字节或字节数组实例)反序列化为Python对象。

Ok, this is an old thread but. I had a same issue, my problem was I used json.load instead of json.loads

This way, json has no problem with loading any kind of dictionary.

Official documentation

json.load – Deserialize fp (a .read()-supporting text file or binary file containing a JSON document) to a Python object using this conversion table.

json.loads – Deserialize s (a str, bytes or bytearray instance containing a JSON document) to a Python object using this conversion table.


回答 4

您需要先打开文件。这不起作用:

json_file = json.load('test.json')

但这有效:

f = open('test.json')
json_file = json.load(f)

You need to open the file first. This doesn’t work:

json_file = json.load('test.json')

But this works:

f = open('test.json')
json_file = json.load(f)

Cython:“严重错误:numpy / arrayobject.h:没有此类文件或目录”

问题:Cython:“严重错误:numpy / arrayobject.h:没有此类文件或目录”

我试图加快答案在这里使用用Cython。我尝试编译代码(在完成此处cygwinccompiler.py介绍的hack 之后),但出现错误。谁能告诉我我的代码是否有问题,或者Cython有点神秘?fatal error: numpy/arrayobject.h: No such file or directory...compilation terminated

下面是我的代码。

import numpy as np
import scipy as sp
cimport numpy as np
cimport cython

cdef inline np.ndarray[np.int, ndim=1] fbincount(np.ndarray[np.int_t, ndim=1] x):
    cdef int m = np.amax(x)+1
    cdef int n = x.size
    cdef unsigned int i
    cdef np.ndarray[np.int_t, ndim=1] c = np.zeros(m, dtype=np.int)

    for i in xrange(n):
        c[<unsigned int>x[i]] += 1

    return c

cdef packed struct Point:
    np.float64_t f0, f1

@cython.boundscheck(False)
def sparsemaker(np.ndarray[np.float_t, ndim=2] X not None,
                np.ndarray[np.float_t, ndim=2] Y not None,
                np.ndarray[np.float_t, ndim=2] Z not None):

    cdef np.ndarray[np.float64_t, ndim=1] counts, factor
    cdef np.ndarray[np.int_t, ndim=1] row, col, repeats
    cdef np.ndarray[Point] indices

    cdef int x_, y_

    _, row = np.unique(X, return_inverse=True); x_ = _.size
    _, col = np.unique(Y, return_inverse=True); y_ = _.size
    indices = np.rec.fromarrays([row,col])
    _, repeats = np.unique(indices, return_inverse=True)
    counts = 1. / fbincount(repeats)
    Z.flat *= counts.take(repeats)

    return sp.sparse.csr_matrix((Z.flat,(row,col)), shape=(x_, y_)).toarray()

I’m trying to speed up the answer here using Cython. I try to compile the code (after doing the cygwinccompiler.py hack explained here), but get a fatal error: numpy/arrayobject.h: No such file or directory...compilation terminated error. Can anyone tell me if it’s a problem with my code, or some esoteric subtlety with Cython?

Below is my code.

import numpy as np
import scipy as sp
cimport numpy as np
cimport cython

cdef inline np.ndarray[np.int, ndim=1] fbincount(np.ndarray[np.int_t, ndim=1] x):
    cdef int m = np.amax(x)+1
    cdef int n = x.size
    cdef unsigned int i
    cdef np.ndarray[np.int_t, ndim=1] c = np.zeros(m, dtype=np.int)

    for i in xrange(n):
        c[<unsigned int>x[i]] += 1

    return c

cdef packed struct Point:
    np.float64_t f0, f1

@cython.boundscheck(False)
def sparsemaker(np.ndarray[np.float_t, ndim=2] X not None,
                np.ndarray[np.float_t, ndim=2] Y not None,
                np.ndarray[np.float_t, ndim=2] Z not None):

    cdef np.ndarray[np.float64_t, ndim=1] counts, factor
    cdef np.ndarray[np.int_t, ndim=1] row, col, repeats
    cdef np.ndarray[Point] indices

    cdef int x_, y_

    _, row = np.unique(X, return_inverse=True); x_ = _.size
    _, col = np.unique(Y, return_inverse=True); y_ = _.size
    indices = np.rec.fromarrays([row,col])
    _, repeats = np.unique(indices, return_inverse=True)
    counts = 1. / fbincount(repeats)
    Z.flat *= counts.take(repeats)

    return sp.sparse.csr_matrix((Z.flat,(row,col)), shape=(x_, y_)).toarray()

回答 0

在你里面setup.pyExtension应该有论据include_dirs=[numpy.get_include()]

另外,您np.import_array()的代码中缺少您。

示例setup.py:

from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy

setup(
    ext_modules=[
        Extension("my_module", ["my_module.c"],
                  include_dirs=[numpy.get_include()]),
    ],
)

# Or, if you use cythonize() to make the ext_modules list,
# include_dirs can be passed to setup()

setup(
    ext_modules=cythonize("my_module.pyx"),
    include_dirs=[numpy.get_include()]
)    

In your setup.py, the Extension should have the argument include_dirs=[numpy.get_include()].

Also, you are missing np.import_array() in your code.

Example setup.py:

from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy

setup(
    ext_modules=[
        Extension("my_module", ["my_module.c"],
                  include_dirs=[numpy.get_include()]),
    ],
)

# Or, if you use cythonize() to make the ext_modules list,
# include_dirs can be passed to setup()

setup(
    ext_modules=cythonize("my_module.pyx"),
    include_dirs=[numpy.get_include()]
)    

回答 1

对于像您这样的单文件项目,另一种选择是使用pyximportsetup.py如果使用IPython,则无需创建… …甚至无需打开命令行…都非常方便。您可以尝试在IPython或普通的Python脚本中运行以下命令:

import numpy
import pyximport
pyximport.install(setup_args={"script_args":["--compiler=mingw32"],
                              "include_dirs":numpy.get_include()},
                  reload_support=True)

import my_pyx_module

print my_pyx_module.some_function(...)
...

当然,您可能需要编辑编译器。这使得导入和重新加载对.pyx文件的作用与对文件的作用相同.py

资料来源:http : //wiki.cython.org/InstallingOnWindows

For a one-file project like yours, another alternative is to use pyximport. You don’t need to create a setup.py … you don’t need to even open a command line if you use IPython … it’s all very convenient. In your case, try running these commands in IPython or in a normal Python script:

import numpy
import pyximport
pyximport.install(setup_args={"script_args":["--compiler=mingw32"],
                              "include_dirs":numpy.get_include()},
                  reload_support=True)

import my_pyx_module

print my_pyx_module.some_function(...)
...

You may need to edit the compiler of course. This makes import and reload work the same for .pyx files as they work for .py files.

Source: http://wiki.cython.org/InstallingOnWindows


回答 2

该错误意味着在编译过程中找不到numpy头文件。

尝试这样做export CFLAGS=-I/usr/lib/python2.7/site-packages/numpy/core/include/,然后进行编译。这是几个不同软件包的问题。在ArchLinux中,存在针对同一问题的错误: https //bugs.archlinux.org/task/22326

The error means that a numpy header file isn’t being found during compilation.

Try doing export CFLAGS=-I/usr/lib/python2.7/site-packages/numpy/core/include/, and then compiling. This is a problem with a few different packages. There’s a bug filed in ArchLinux for the same issue: https://bugs.archlinux.org/task/22326


回答 3

简单的答案

一种更简单的方法是将路径添加到文件中distutils.cfg。默认情况下,它代表Windows 7的路径C:\Python27\Lib\distutils\。您只需声明以下内容即可解决:

[build_ext]
include_dirs= C:\Python27\Lib\site-packages\numpy\core\include

整个配置文件

为了给您一个示例,配置文件的外观,我的整个文件显示为:

[build]
compiler = mingw32

[build_ext]
include_dirs= C:\Python27\Lib\site-packages\numpy\core\include
compiler = mingw32

Simple answer

A way simpler way is to add the path to your file distutils.cfg. It’s path behalf of Windows 7 is by default C:\Python27\Lib\distutils\. You just assert the following contents and it should work out:

[build_ext]
include_dirs= C:\Python27\Lib\site-packages\numpy\core\include

Entire config file

To give you an example how the config file could look like, my entire file reads:

[build]
compiler = mingw32

[build_ext]
include_dirs= C:\Python27\Lib\site-packages\numpy\core\include
compiler = mingw32

回答 4

它应该能够在此处cythonize()提到的函数中执行此操作,但是由于存在已知问题,因此它不起作用

It should be able to do it within cythonize() function as mentioned here, but it doesn’t work beacuse there is a known issue


回答 5

如果您懒得编写设置文件并弄清楚包含目录的路径,请尝试cyper。它可以编译您的Cython代码并进行设置include_dirs自动为Numpy。

将您的代码加载到字符串中,然后简单地运行cymodule = cyper.inline(code_string),然后您的函数cymodule.sparsemaker即刻可用。像这样

code = open(your_pyx_file).read()
cymodule = cyper.inline(code)

cymodule.sparsemaker(...)
# do what you want with your function

您可以通过安装cyper pip install cyper

If you are too lazy to write setup files and figure out the path for include directories, try cyper. It can compile your Cython code and set include_dirs for Numpy automatically.

Load your code into a string, then simply run cymodule = cyper.inline(code_string), then your function is available as cymodule.sparsemaker instantaneously. Something like this

code = open(your_pyx_file).read()
cymodule = cyper.inline(code)

cymodule.sparsemaker(...)
# do what you want with your function

You can install cyper via pip install cyper.


如何在matplotlib中删除上轴和右轴?

问题:如何在matplotlib中删除上轴和右轴?

而不是默认的“装箱”轴样式,我只希望有左轴和底轴,即:

+------+         |
|      |         |
|      |   --->  |
|      |         |
+------+         +-------

这应该很容易,但是我在文档中找不到必要的选项。

Instead of the default “boxed” axis style I want to have only the left and bottom axis, i.e.:

+------+         |
|      |         |
|      |   --->  |
|      |         |
+------+         +-------

This should be easy, but I can’t find the necessary options in the docs.


回答 0

这是官方网站HERE推荐的Matplotlib 3解决方案:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)

ax = plt.subplot(111)
ax.plot(x, y)

# Hide the right and top spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

# Only show ticks on the left and bottom spines
ax.yaxis.set_ticks_position('left')
ax.xaxis.set_ticks_position('bottom')

plt.show()

This is the suggested Matplotlib 3 solution from the official website HERE:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)

ax = plt.subplot(111)
ax.plot(x, y)

# Hide the right and top spines
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)

# Only show ticks on the left and bottom spines
ax.yaxis.set_ticks_position('left')
ax.xaxis.set_ticks_position('bottom')

plt.show()


回答 1

或者,这

def simpleaxis(ax):
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()

似乎在轴上实现了相同的效果,而不会丢失旋转的标签支撑。

(Matplotlib 1.0.1;溶液的启发)。

Alternatively, this

def simpleaxis(ax):
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()

seems to achieve the same effect on an axis without losing rotated label support.

(Matplotlib 1.0.1; solution inspired by this).


回答 2

[edit] matplotlib现已发布(2013-10),版本为1.3.0,其中包括

该功能实际上只是添加的,您需要使用Subversion版本。您可以在此处查看示例代码。

我只是想说现在在线上有一个更好的例子。尽管仍然需要Subversion版本,但尚未发布。

[编辑] Matplotlib 0.99.0 RC1刚刚发布,并包含此功能。

[edit] matplotlib in now (2013-10) on version 1.3.0 which includes this

That ability was actually just added, and you need the Subversion version for it. You can see the example code here.

I am just updating to say that there’s a better example online now. Still need the Subversion version though, there hasn’t been a release with this yet.

[edit] Matplotlib 0.99.0 RC1 was just released, and includes this capability.


回答 3

(除了此处的全面答案之外,这更多是扩展注释。)


请注意,我们可以彼此独立地隐藏这三个元素中的每个元素:

  • 隐藏边框(又称“脊椎”):ax.set_frame_on(False)ax.spines['top'].set_visible(False)

  • 隐藏刻度线: ax.tick_params(top=False)

  • 隐藏标签: ax.tick_params(labeltop=False)

(This is more of an extension comment, in addition to the comprehensive answers here.)


Note that we can hide each of these three elements independently of each other:

  • To hide the border (aka “spine”): ax.set_frame_on(False) or ax.spines['top'].set_visible(False)

  • To hide the ticks: ax.tick_params(top=False)

  • To hide the labels: ax.tick_params(labeltop=False)


回答 4

如果不需要刻度线(例如用于绘制定性插图),则也可以使用以下快速解决方法:

使轴不可见(例如使用plt.gca().axison = False),然后使用手动绘制它们plt.arrow

If you don’t need ticks and such (e.g. for plotting qualitative illustrations) you could also use this quick workaround:

Make the axis invisible (e.g. with plt.gca().axison = False) and then draw them manually with plt.arrow.


回答 5

图书馆Seaborn具有内置的函数despine()。

只需添加:

import seaborn as sns

现在创建图形。并在末尾添加:

sns.despine()

如果查看该函数的某些默认参数值,它将删除顶部和右侧的书脊,并保留底部和左侧的书脊:

sns.despine(top=True, right=True, left=False, bottom=False)

在此处查看更多文档:https : //seaborn.pydata.org/generation/seaborn.despine.html

Library Seaborn has this built in with function despine().

Just add:

import seaborn as sns

Now create your graph. And add at the end:

sns.despine()

If you look at some of the default parameter values of the function it removes the top and right spine and keeps the bottom and left spine:

sns.despine(top=True, right=True, left=False, bottom=False)

Check out further documentation here: https://seaborn.pydata.org/generated/seaborn.despine.html


回答 6

如果需要从所有绘图中删除它,则可以在样式设置(样式表或rcParams)中删除刺。例如:

import matplotlib as mpl

mpl.rcParams['axes.spines.right'] = False
mpl.rcParams['axes.spines.top'] = False

如果要删除所有刺:

mpl.rcParams['axes.spines.left'] = False
mpl.rcParams['axes.spines.right'] = False
mpl.rcParams['axes.spines.top'] = False
mpl.rcParams['axes.spines.bottom'] = False

If you need to remove it from all your plots, you can remove spines in style settings (style sheet or rcParams). E.g:

import matplotlib as mpl

mpl.rcParams['axes.spines.right'] = False
mpl.rcParams['axes.spines.top'] = False

If you want to remove all spines:

mpl.rcParams['axes.spines.left'] = False
mpl.rcParams['axes.spines.right'] = False
mpl.rcParams['axes.spines.top'] = False
mpl.rcParams['axes.spines.bottom'] = False

查询sqlite数据库时为什么需要创建游标?

问题:查询sqlite数据库时为什么需要创建游标?

我对Python的sqlite3模块(以及与此相关的SQL)完全陌生,这完全让我感到困惑。对cursor对象的大量描述不足(而是其必要性)似乎也很奇怪。

此代码段是首选的处理方式:

import sqlite3
conn = sqlite3.connect("db.sqlite")
c = conn.cursor()
c.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()
c.close()

即使它工作得很好,并且没有(似乎毫无意义),它也不是这样cursor

import sqlite3
conn = sqlite3.connect("db.sqlite")
conn.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()

谁能告诉我为什么我需要一个cursor
似乎没有意义的开销。对于脚本中访问数据库的每个方法,都应该创建并销毁一个cursor
为什么不只是使用connection对象?

I’m completely new to Python’s sqlite3 module (and SQL in general for that matter), and this just completely stumps me. The abundant lack of descriptions of cursor objects (rather, their necessity) also seems odd.

This snippet of code is the preferred way of doing things:

import sqlite3
conn = sqlite3.connect("db.sqlite")
c = conn.cursor()
c.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()
c.close()

This one isn’t, even though it works just as well and without the (seemingly pointless) cursor:

import sqlite3
conn = sqlite3.connect("db.sqlite")
conn.execute('''insert into table "users" values ("Jack Bauer", "555-555-5555")''')
conn.commit()

Can anyone tell me why I need a cursor?
It just seems like pointless overhead. For every method in my script that accesses a database, I’m supposed to create and destroy a cursor?
Why not just use the connection object?


回答 0

在我看来,这只是一个错误应用的抽象。数据库游标是一种抽象,用于遍历数据集。

维基百科有关主题的文章

在计算机科学和技术中,数据库游标是一种控制结构,可以遍历数据库中的记录。游标有助于与遍历一起进行的后续处理,例如数据库记录的检索,添加和删除。数据库游标的遍历特性使游标类似于迭代器的编程语言概念。

和:

游标不仅可以用于将数据从DBMS提取到应用程序中,还可以标识表中要更新或删除的行。为此,SQL:2003标准定义了定位更新和定位删除SQL语句。这样的语句不使用带谓词的常规WHERE子句。而是用光标标识该行。游标必须已打开,并且已经通过FETCH语句定位在一行上。

如果查看Python sqlite模块上文档,您会发现cursor即使是一条CREATE TABLE语句也需要一个python模块,因此它用于仅一个connection对象就足够的情况-正如OP正确指出的那样。这种抽象与人们理解db游标的方式不同,因此与用户的困惑/挫败感不同。无论效率如何,这只是概念上的开销。如果在文档中指出python模块cursor与SQL和数据库中的游标有点不同,那将是很好的。

Just a misapplied abstraction it seems to me. A db cursor is an abstraction, meant for data set traversal.

From Wikipedia article on subject:

In computer science and technology, a database cursor is a control structure that enables traversal over the records in a database. Cursors facilitate subsequent processing in conjunction with the traversal, such as retrieval, addition and removal of database records. The database cursor characteristic of traversal makes cursors akin to the programming language concept of iterator.

And:

Cursors can not only be used to fetch data from the DBMS into an application but also to identify a row in a table to be updated or deleted. The SQL:2003 standard defines positioned update and positioned delete SQL statements for that purpose. Such statements do not use a regular WHERE clause with predicates. Instead, a cursor identifies the row. The cursor must be opened and already positioned on a row by means of FETCH statement.

If you check the docs on Python sqlite module, you can see that a python module cursor is needed even for a CREATE TABLE statement, so it’s used for cases where a mere connection object should suffice – as correctly pointed out by the OP. Such abstraction is different from what people understand a db cursor to be and hence, the confusion/frustration on the part of users. Regardless of efficiency, it’s just a conceptual overhead. Would be nice if it was pointed out in the docs that the python module cursor is bit different than what a cursor is in SQL and databases.


回答 1

您需要一个游标对象来获取结果。您的示例可以正常运行,因为它是一个INSERT,因此您没有尝试从中获取任何行,但是如果您查看sqlite3docs,则会注意到.fetchXXXX连接对象上没有任何方法,因此,如果您尝试这样做如果SELECT没有光标,您将无法获取结果数据。

游标对象使您可以跟踪哪个结果集是哪个结果集,因为可以在获取第一个结果之前运行多个查询。

You need a cursor object to fetch results. Your example works because it’s an INSERT and thus you aren’t trying to get any rows back from it, but if you look at the sqlite3 docs, you’ll notice that there aren’t any .fetchXXXX methods on connection objects, so if you tried to do a SELECT without a cursor, you’d have no way to get the resulting data.

Cursor objects allow you to keep track of which result set is which, since it’s possible to run multiple queries before you’re done fetching the results of the first.


回答 2

根据官方文档,这 connection.execute()是一个创建中间光标对象的非标准快捷方式

Connection.execute
这是一个非标准的快捷方式,它通过调用cursor()方法创建游标对象,使用给定的参数调用游标的execute()方法,然后返回游标。

According to the official docs connection.execute() is a nonstandard shortcut that creates an intermediate cursor object:

Connection.execute
This is a nonstandard shortcut that creates a cursor object by calling the cursor() method, calls the cursor’s execute() method with the parameters given, and returns the cursor.


回答 3

12.6.8。使用sqlite3的高效 LY

12.6.8.1。使用快捷方式

使用非标准的 execute()executemany()并且executescript()Connection对象的方法,您可以编写代码更简洁 LY,因为你没有创建(通常是多余的)光标明确对象。而是,隐式创建Cursor对象,并且这些快捷方式方法返回游标对象。这样,您可以执行SELECT语句并直接使用Connection对象上的单个调用直接对其进行迭代。

sqlite3文档;重点是我的。)

为什么不只使用连接对象?

因为连接对象的那些方法是非标准的,即它们不是Python数据库API规范v2.0(PEP 249)的一部分。

只要您使用Cursor对象的标准方法,就可以确保如果切换到遵循上述规范的另一个数据库实现,您的代码将完全可移植。也许您只需要更改import行。

但是,如果您使用connection.execute,切换的可能性将不会那么简单。这就是您可能要使用的主要原因cursor.execute

但是,如果您确定不打算切换,那么我想选择connection.execute快捷方式并“高效” 是完全可以的。

12.6.8. Using sqlite3 efficiently

12.6.8.1. Using shortcut methods

Using the nonstandard execute(), executemany() and executescript() methods of the Connection object, your code can be written more concisely because you don’t have to create the (often superfluous) Cursor objects explicitly. Instead, the Cursor objects are created implicitly and these shortcut methods return the cursor objects. This way, you can execute a SELECT statement and iterate over it directly using only a single call on the Connection object.

(sqlite3 documentation; emphasis mine.)

Why not just use the connection object?

Because those methods of the connection object are nonstandard, i.e. they are not part of Python Database API Specification v2.0 (PEP 249).

As long as you use the standard methods of the Cursor object, you can be sure that if you switch to another database implementation that follows the above specification, your code will be fully portable. Perhaps you will only need to change the import line.

But if you use the connection.execute there is a chance that switching won’t be that straightforward. That’s the main reason you might want to use cursor.execute instead.

However if you are certain that you’re not going to switch, I’d say it’s completely OK to take the connection.execute shortcut and be “efficient”.


回答 4

它使我们能够通过与数据库的同一连接来拥有多个单独的工作环境。

It gives us the ability to have multiple separate working environments through the same connection to the database.


如何在两个Django应用之间移动模型(Django 1.7)

问题:如何在两个Django应用之间移动模型(Django 1.7)

因此,大约一年前,我开始了一个项目,像所有新开发人员一样,我并没有真正专注于结构,但是现在我与Django一起走得更远,它开始似乎表明我的项目布局主要是我的模型在结构上很糟糕。

我的模型主要保存在单个应用程序中,实际上这些模型中的大多数应该放在自己的单个应用程序中,我确实尝试解决了此问题并将其向南移动,但是由于外键等原因,我发现它很棘手,而且确实很困难。

但是,由于Django 1.7并内置了对迁移的支持,现在有更好的方法吗?

So about a year ago I started a project and like all new developers I didn’t really focus too much on the structure, however now I am further along with Django it has started to appear that my project layout mainly my models are horrible in structure.

I have models mainly held in a single app and really most of these models should be in their own individual apps, I did try and resolve this and move them with south however I found it tricky and really difficult due to foreign keys ect.

However due to Django 1.7 and built in support for migrations is there a better way to do this now?


回答 0

我正在删除旧答案,因为这可能会导致数据丢失。如ozan所述,我们可以在每个应用中创建2个迁移。这篇文章下面的评论指的是我的旧答案。

第一次迁移以从第一个应用中删除模型。

$ python manage.py makemigrations old_app --empty

编辑迁移文件以包括这些操作。

class Migration(migrations.Migration):

    database_operations = [migrations.AlterModelTable('TheModel', 'newapp_themodel')]

    state_operations = [migrations.DeleteModel('TheModel')]

    operations = [
      migrations.SeparateDatabaseAndState(
        database_operations=database_operations,
        state_operations=state_operations)
    ]

第二次迁移取决于第一次迁移并在第二个应用程序中创建新表。将模型代码移至第二个应用程序后

$ python manage.py makemigrations new_app 

然后将迁移文件编辑为类似的内容。

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

I am removing the old answer as may result in data loss. As ozan mentioned, we can create 2 migrations one in each app. The comments below this post refer to my old answer.

First migration to remove model from 1st app.

$ python manage.py makemigrations old_app --empty

Edit migration file to include these operations.

class Migration(migrations.Migration):

    database_operations = [migrations.AlterModelTable('TheModel', 'newapp_themodel')]

    state_operations = [migrations.DeleteModel('TheModel')]

    operations = [
      migrations.SeparateDatabaseAndState(
        database_operations=database_operations,
        state_operations=state_operations)
    ]

Second migration which depends on first migration and create the new table in 2nd app. After moving model code to 2nd app

$ python manage.py makemigrations new_app 

and edit migration file to something like this.

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

回答 1

使用可以很容易地做到这一点migrations.SeparateDatabaseAndState。基本上,我们使用数据库操作来同时重命名表,同时使用两个状态操作从一个应用程序的历史记录中删除模型并在另一个应用程序的历史记录中创建模型。

从旧应用中删除

python manage.py makemigrations old_app --empty

在迁移中:

class Migration(migrations.Migration):

    dependencies = []

    database_operations = [
        migrations.AlterModelTable('TheModel', 'newapp_themodel')
    ]

    state_operations = [
        migrations.DeleteModel('TheModel')
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations)
    ]

添加到新应用

首先,将模型复制到新应用的model.py中,然后:

python manage.py makemigrations new_app

这将生成一个迁移CreateModel操作,其中天真的操作是唯一的操作。将其包装在一个SeparateDatabaseAndState操作中,这样我们就不会尝试重新创建表。还包括先前的迁移作为依赖项:

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

This can be done fairly easily using migrations.SeparateDatabaseAndState. Basically, we use a database operation to rename the table concurrently with two state operations to remove the model from one app’s history and create it in another’s.

Remove from old app

python manage.py makemigrations old_app --empty

In the migration:

class Migration(migrations.Migration):

    dependencies = []

    database_operations = [
        migrations.AlterModelTable('TheModel', 'newapp_themodel')
    ]

    state_operations = [
        migrations.DeleteModel('TheModel')
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations)
    ]

Add to new app

First, copy the model to the new app’s model.py, then:

python manage.py makemigrations new_app

This will generate a migration with a naive CreateModel operation as the sole operation. Wrap that in a SeparateDatabaseAndState operation such that we don’t try to recreate the table. Also include the prior migration as a dependency:

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

回答 2

我遇到了同样的问题。 奥赞的回答对我有很大帮助,但不幸的是还不够。确实,我有几个ForeignKey链接到我想移动的模型。经过一番头痛之后,我发现了解决方案,因此决定发布该解决方案以解决人们的时间问题。

您还需要2个步骤:

  1. 在执行任何操作之前,请将所有ForeignKey链接更改TheModelIntegerfield。然后跑python manage.py makemigrations
  2. 完成Ozan的步骤后,请重新转换外键:放回ForeignKey(TheModel)而不是IntegerField()。然后再次进行迁移(python manage.py makemigrations)。然后,您可以迁移,它应该可以工作(python manage.py migrate

希望能帮助到你。当然,在尝试生产之前,请先在本地进行测试,以避免出现意外情况:)

I encountered the same problem. Ozan’s answer helped me a lot but unfortunately was not enough. Indeed I had several ForeignKey linking to the model I wanted to move. After some headache I found the solution so decided to post it to solve people time.

You need 2 more steps:

  1. Before doing anything, change all your ForeignKey linking to TheModel into Integerfield. Then run python manage.py makemigrations
  2. After doing Ozan’s steps, re-convert your foreign keys: put back ForeignKey(TheModel)instead of IntegerField(). Then make the migrations again (python manage.py makemigrations). You can then migrate and it should work (python manage.py migrate)

Hope it helps. Of course test it in local before trying in production to avoid bad suprises :)


回答 3

我是如何做到的(在PostgreSQL == 1.8上进行了测试,使用postgres,可能也是1.7)

情况

app1.YourModel

但您希望它转到: app2.YourModel

  1. 将YourModel(代码)从app1复制到app2。
  2. 将此添加到app2.YourModel:

    Class Meta:
        db_table = 'app1_yourmodel'
  3. $ python manage.py makemigrations app2

  4. 使用migrations.CreateModel()语句在app2中进行了新的迁移(例如0009_auto_something.py),将该语句移至app2的初始迁移(例如0001_initial.py)(就像它一直在那儿一样)。现在删除创建的迁移= 0009_auto_something.py

  5. 就像您执行操作一样,就像app2.YourModel一直存在一样,现在从迁移中删除app1.YourModel的存在。含义:注释掉CreateModel语句,以及之后使用的所有调整或数据迁移。

  6. 当然,必须在您的项目中将对app1.YourModel的每个引用都更改为app2.YourModel。另外,不要忘记迁移中所有可能的app1.YourModel外键都必须更改为app2.YourModel。

  7. 现在,如果您执行$ python manage.py迁移,则什么都没有改变,同样,当您执行$ python manage.py makemigrations时,也不会检测到新的东西。

  8. 现在画龙点睛:从app2.YourModel中删除Class Meta并执行$ python manage.py makemigrations app2 && python manage.py migration app2(如果您研究此迁移,您将看到类似以下的内容:)

        migrations.AlterModelTable(
        name='yourmodel',
        table=None,
    ),

table = None,表示它将采用默认的表名,在这种情况下为app2_yourmodel。

  1. 完成,保存数据。

PS在迁移期间,它将看到content_type app1.yourmodel已被删除并且可以删除。您可以对此说是,但前提是您不使用它。如果您非常依赖它来使该内容类型的FK保持完整,则不要回答yes或no,而是手动进入该时间的db,并删除co​​ntentype app2.yourmodel,然后重命名contenttype app1。 yourmodel到app2.yourmodel,然后继续回答否。

How I did it (tested on Django==1.8, with postgres, so probably also 1.7)

Situation

app1.YourModel

but you want it to go to: app2.YourModel

  1. Copy YourModel (the code) from app1 to app2.
  2. add this to app2.YourModel:

    Class Meta:
        db_table = 'app1_yourmodel'
    
  3. $ python manage.py makemigrations app2

  4. A new migration (e.g. 0009_auto_something.py) is made in app2 with a migrations.CreateModel() statement, move this statement to the initial migration of app2 (e.g. 0001_initial.py) (it will be just like it always have been there). And now remove the created migration = 0009_auto_something.py

  5. Just as you act, like app2.YourModel always has been there, now remove the existence of app1.YourModel from your migrations. Meaning: comment out the CreateModel statements, and every adjustment or datamigration you used after that.

  6. And of course, every reference to app1.YourModel has to be changed to app2.YourModel through your project. Also, don’t forget that all possible foreign keys to app1.YourModel in migrations have to be changed to app2.YourModel

  7. Now if you do $ python manage.py migrate, nothing has changed, also when you do $ python manage.py makemigrations, nothing new has been detected.

  8. Now the finishing touch: remove the Class Meta from app2.YourModel and do $ python manage.py makemigrations app2 && python manage.py migrate app2 (if you look into this migration you’ll see something like this:)

        migrations.AlterModelTable(
        name='yourmodel',
        table=None,
    ),
    

table=None, means it will take the default table-name, which in this case will be app2_yourmodel.

  1. DONE, with data saved.

P.S during the migration it will see that that content_type app1.yourmodel has been removed and can be deleted. You can say yes to that but only if you don’t use it. In case you heavily depend on it to have FKs to that content-type be intact, don’t answer yes or no yet, but go into the db that time manually, and remove the contentype app2.yourmodel, and rename the contenttype app1.yourmodel to app2.yourmodel, and then continue by answering no.


回答 4

我会感到紧张的手工编码迁移(这是Ozan的回答所要求),因此以下内容结合了Ozan和Michael的策略以最大程度地减少所需的手工编码量:

  1. 在移动任何模型之前,请通过运行确保使用干净的基线makemigrations
  2. 将模型的代码从app1移至app2
  3. 按照@Michael的建议,我们使用db_table“新”模型上的Meta选项将新模型指向旧数据库表:

    class Meta:
        db_table = 'app1_yourmodel'
  4. 运行makemigrations。这将CreateModelapp2DeleteModel中生成app1。从技术上讲,这些迁移将引用完全相同的表,并且将删除(包括所有数据)并重新创建表。

  5. 实际上,我们不希望(或不需要)对表做任何事情。我们只需要Django相信所做的更改即可。根据@Ozan的回答,中的state_operations标志将SeparateDatabaseAndState执行此操作。因此,我们使用来将所有migrations条目包装在两个迁移文件SeparateDatabaseAndState(state_operations=[...])。例如,

    operations = [
        ...
        migrations.DeleteModel(
            name='YourModel',
        ),
        ...
    ]

    变成

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=[
            ...
            migrations.DeleteModel(
                name='YourModel',
            ),
            ...
        ])
    ]
  6. 您还需要确保新的“虚拟” CreateModel迁移取决于实际创建或更改原始表的任何迁移。例如,如果您的新迁移是app2.migrations.0004_auto_<date>(针对Create)和app1.migrations.0007_auto_<date>(针对Delete),则最简单的操作是:

    • 打开app1.migrations.0007_auto_<date>并复制其app1依赖项(例如 ('app1', '0006...'),)。这是“立即优先”的迁移app1,应该包括对所有实际模型构建逻辑的依赖。
    • 打开 app2.migrations.0004_auto_<date>并将刚刚复制的依赖项添加到其dependencies列表中。

如果您ForeignKey与要移动的模型有关系,则上述方法可能无效。发生这种情况是因为:

  • 不会自动为ForeignKey更改创建依赖关系
  • 我们不想包装这些ForeignKey更改,state_operations因此我们需要确保它们与表操作是分开的。

注意:Django 2.2添加了一个警告(models.E028),它破坏了此方法。您也许可以解决该问题,managed=False但我尚未对其进行测试。

“最小”操作集因情况而异,但是以下过程应适用于大多数/所有ForeignKey迁移:

  1. app1复制模型app2,设置db_table,但不要更改任何FK引用。
  2. 运行makemigrations并包装所有app2迁移state_operations(请参见上文)
    • 如上所述,将依赖项添加app2 CreateTable到最新的app1迁移中
  3. 将所有FK参考指向新模型。如果您不使用字符串引用,请将旧模型移到models.py(不要删除它)的底部,这样它就不会与导入的类竞争。
  4. 运行,makemigrations但不要包装任何内容state_operations(实际上应该发生FK更改)。将所有ForeignKey迁移(即AlterField)中的依赖项添加到其中的CreateTable迁移中app2(下一步将需要此列表,因此请对其进行跟踪)。例如:

    • 找到包含迁移CreateModelapp2.migrations.0002_auto_<date>和复制迁移的名称。
    • 查找所有具有该模型的ForeignKey的迁移(例如,通过搜索app2.YourModel找到类似以下的迁移:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
          ]
      
          operations = [
              migrations.AlterField(
                  model_name='relatedmodel',
                  name='fieldname',
                  field=models.ForeignKey(... to='app2.YourModel'),
              ),
          ]
    • CreateModel迁移作为依赖项添加:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
              ('app2', '0002_auto_<date>'),
          ]  
  5. 从中删除模型 app1

  6. 运行迁移makemigrations并将其包装在app1state_operations
    • 为上一步的所有ForeignKey迁移(即AlterField)添加一个依赖项(可能包括app1和中的迁移app2)。
    • 当我构建这些迁移时,DeleteTable已经依赖于AlterField迁移了,因此我不需要手动执行它(即Alterbefore Delete)。

在这一点上,Django是个不错的选择。新模型指向旧表,并且Django的迁移使它确信所有内容都已适当地重新放置。最大的警告(来自@Michael的答案)是ContentType为新模型创建了一个新模型。如果您链接(例如通过ForeignKey)到内容类型,则需要创建一个迁移来更新ContentType表。

我想自己清理一下(元选项和表名),所以我使用了以下过程(来自@Michael):

  1. 删除db_table元条目
  2. makemigrations再次运行以生成数据库重命名
  3. 编辑此最后的迁移,并确保它取决于DeleteTable迁移。似乎没有必要,因为它应该Delete纯粹是逻辑上的,但是app1_yourmodel如果我不这样做,就会遇到错误(例如,不存在)。

I get nervous hand-coding migrations (as is required by Ozan’s answer) so the following combines Ozan’s and Michael’s strategies to minimize the amount of hand-coding required:

  1. Before moving any models, make sure you’re working with a clean baseline by running makemigrations.
  2. Move the code for the Model from app1 to app2
  3. As recommended by @Michael, we point the new model to the old database table using the db_table Meta option on the “new” model:

    class Meta:
        db_table = 'app1_yourmodel'
    
  4. Run makemigrations. This will generate CreateModel in app2 and DeleteModel in app1. Technically, these migrations refer to the exact same table and would remove (including all data) and re-create the table.

  5. In reality, we don’t want (or need) to do anything to the table. We just need Django to believe that the change has been made. Per @Ozan’s answer, the state_operations flag in SeparateDatabaseAndState does this. So we wrap all of the migrations entries IN BOTH MIGRATIONS FILES with SeparateDatabaseAndState(state_operations=[...]). For example,

    operations = [
        ...
        migrations.DeleteModel(
            name='YourModel',
        ),
        ...
    ]
    

    becomes

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=[
            ...
            migrations.DeleteModel(
                name='YourModel',
            ),
            ...
        ])
    ]
    
  6. You also need to make sure the new “virtual” CreateModel migration depends on any migration that actually created or altered the original table. For example, if your new migrations are app2.migrations.0004_auto_<date> (for the Create) and app1.migrations.0007_auto_<date> (for the Delete), the simplest thing to do is:

    • Open app1.migrations.0007_auto_<date> and copy its app1 dependency (e.g. ('app1', '0006...'),). This is the “immediately prior” migration in app1 and should include dependencies on all of the actual model building logic.
    • Open app2.migrations.0004_auto_<date> and add the dependency you just copied to its dependencies list.

If you have ForeignKey relationship(s) to the model you’re moving, the above may not work. This happens because:

  • Dependencies are not automatically created for the ForeignKey changes
  • We do not want to wrap the ForeignKey changes in state_operations so we need to ensure they are separate from the table operations.

NOTE: Django 2.2 added a warning (models.E028) that breaks this method. You may be able to work around it with managed=False but I have not tested it.

The “minimum” set of operations differ depending on the situation, but the following procedure should work for most/all ForeignKey migrations:

  1. COPY the model from app1 to app2, set db_table, but DON’T change any FK references.
  2. Run makemigrations and wrap all app2 migration in state_operations (see above)
    • As above, add a dependency in the app2 CreateTable to the latest app1 migration
  3. Point all of the FK references to the new model. If you aren’t using string references, move the old model to the bottom of models.py (DON’T remove it) so it doesn’t compete with the imported class.
  4. Run makemigrations but DON’T wrap anything in state_operations (the FK changes should actually happen). Add a dependency in all the ForeignKey migrations (i.e. AlterField) to the CreateTable migration in app2 (you’ll need this list for the next step so keep track of them). For example:

    • Find the migration that includes the CreateModel e.g. app2.migrations.0002_auto_<date> and copy the name of that migration.
    • Find all migrations that have a ForeignKey to that model (e.g. by searching app2.YourModel to find migrations like:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
          ]
      
          operations = [
              migrations.AlterField(
                  model_name='relatedmodel',
                  name='fieldname',
                  field=models.ForeignKey(... to='app2.YourModel'),
              ),
          ]
      
    • Add the CreateModel migration as as a dependency:

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
              ('app2', '0002_auto_<date>'),
          ]  
      
  5. Remove the models from app1

  6. Run makemigrations and wrap the app1 migration in state_operations.
    • Add a dependency to all of the ForeignKey migrations (i.e. AlterField) from the previous step (may include migrations in app1 and app2).
    • When I built these migrations, the DeleteTable already depended on the AlterField migrations so I didn’t need to manually enforce it (i.e. Alter before Delete).

At this point, Django is good to go. The new model points to the old table and Django’s migrations have convinced it that everything has been relocated appropriately. The big caveat (from @Michael’s answer) is that a new ContentType is created for the new model. If you link (e.g. by ForeignKey) to content types, you’ll need to create a migration to update the ContentType table.

I wanted to cleanup after myself (Meta options and table names) so I used the following procedure (from @Michael):

  1. Remove the db_table Meta entry
  2. Run makemigrations again to generate the database rename
  3. Edit this last migration and make sure it depends on the DeleteTable migration. It doesn’t seem like it should be necessary as the Delete should be purely logical, but I’ve run into errors (e.g. app1_yourmodel doesn’t exist) if I don’t.

回答 5

如果数据不是很大或太复杂,但仍然很重要,则另一种骇人听闻的选择是:

  • 使用manage.py dumpdata获取数据固定装置
  • 继续正确建模更改和迁移,而不涉及更改
  • 全局将设备从旧型号和应用名称替换为新的
  • 使用manage.py loaddata加载数据

Another hacky alternative if the data is not big or too complicated, but still important to maintain, is to:

  • Get data fixtures using manage.py dumpdata
  • Proceed to model changes and migrations properly, without relating the changes
  • Global replace the fixtures from the old model and app names to the new
  • Load data using manage.py loaddata

回答 6

从我在https://stackoverflow.com/a/47392970/8971048的回答中复制

万一您需要移动模型而又无权访问该应用程序(或者您不想访问该应用程序),则可以创建一个新的Operation并考虑仅在迁移的模型不具有该模型的情况下创建一个新模型存在。

在此示例中,我将“ MyModel”从old_app传递到myapp。

class MigrateOrCreateTable(migrations.CreateModel):
    def __init__(self, source_table, dst_table, *args, **kwargs):
        super(MigrateOrCreateTable, self).__init__(*args, **kwargs)
        self.source_table = source_table
        self.dst_table = dst_table

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        table_exists = self.source_table in schema_editor.connection.introspection.table_names()
        if table_exists:
            with schema_editor.connection.cursor() as cursor:
                cursor.execute("RENAME TABLE {} TO {};".format(self.source_table, self.dst_table))
        else:
            return super(MigrateOrCreateTable, self).database_forwards(app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_some_migration'),
    ]

    operations = [
        MigrateOrCreateTable(
            source_table='old_app_mymodel',
            dst_table='myapp_mymodel',
            name='MyModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=18))
            ],
        ),
    ]

Copied from my answer at https://stackoverflow.com/a/47392970/8971048

In case you need to move the model and you don’t have access to the app anymore (or you don’t want the access), you can create a new Operation and consider to create a new model only if the migrated model does not exist.

In this example I am passing ‘MyModel’ from old_app to myapp.

class MigrateOrCreateTable(migrations.CreateModel):
    def __init__(self, source_table, dst_table, *args, **kwargs):
        super(MigrateOrCreateTable, self).__init__(*args, **kwargs)
        self.source_table = source_table
        self.dst_table = dst_table

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        table_exists = self.source_table in schema_editor.connection.introspection.table_names()
        if table_exists:
            with schema_editor.connection.cursor() as cursor:
                cursor.execute("RENAME TABLE {} TO {};".format(self.source_table, self.dst_table))
        else:
            return super(MigrateOrCreateTable, self).database_forwards(app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_some_migration'),
    ]

    operations = [
        MigrateOrCreateTable(
            source_table='old_app_mymodel',
            dst_table='myapp_mymodel',
            name='MyModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=18))
            ],
        ),
    ]

回答 7

这是经过粗略测试的,所以不要忘记备份数据库!!!

例如,有两个应用程序:src_appdst_app,我们希望将模型MoveMesrc_app移至dst_app

为两个应用程序创建空迁移:

python manage.py makemigrations --empty src_app
python manage.py makemigrations --empty dst_app

让我们假设,新的迁移是XXX1_src_app_newXXX1_dst_app_new,之前的主要迁移是XXX0_src_app_oldXXX0_dst_app_old

添加一个操作,该操作重命名MoveMe模型的表,并将其在ProjectState中的app_label重命名为XXX1_dst_app_new。不要忘记增加对XXX0_src_app_old迁移的依赖。产生的XXX1_dst_app_new迁移是:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

# this operations is almost the same as RenameModel
# https://github.com/django/django/blob/1.7/django/db/migrations/operations/models.py#L104
class MoveModelFromOtherApp(migrations.operations.base.Operation):

    def __init__(self, name, old_app_label):
        self.name = name
        self.old_app_label = old_app_label

    def state_forwards(self, app_label, state):

        # Get all of the related objects we need to repoint
        apps = state.render(skip_cache=True)
        model = apps.get_model(self.old_app_label, self.name)
        related_objects = model._meta.get_all_related_objects()
        related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
        # Rename the model
        state.models[app_label, self.name.lower()] = state.models.pop(
            (self.old_app_label, self.name.lower())
        )
        state.models[app_label, self.name.lower()].app_label = app_label
        for model_state in state.models.values():
            try:
                i = model_state.bases.index("%s.%s" % (self.old_app_label, self.name.lower()))
                model_state.bases = model_state.bases[:i] + ("%s.%s" % (app_label, self.name.lower()),) + model_state.bases[i+1:]
            except ValueError:
                pass
        # Repoint the FKs and M2Ms pointing to us
        for related_object in (related_objects + related_m2m_objects):
            # Use the new related key for self referential related objects.
            if related_object.model == model:
                related_key = (app_label, self.name.lower())
            else:
                related_key = (
                    related_object.model._meta.app_label,
                    related_object.model._meta.object_name.lower(),
                )
            new_fields = []
            for name, field in state.models[related_key].fields:
                if name == related_object.field.name:
                    field = field.clone()
                    field.rel.to = "%s.%s" % (app_label, self.name)
                new_fields.append((name, field))
            state.models[related_key].fields = new_fields

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        old_apps = from_state.render()
        new_apps = to_state.render()
        old_model = old_apps.get_model(self.old_app_label, self.name)
        new_model = new_apps.get_model(app_label, self.name)
        if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
            # Move the main table
            schema_editor.alter_db_table(
                new_model,
                old_model._meta.db_table,
                new_model._meta.db_table,
            )
            # Alter the fields pointing to us
            related_objects = old_model._meta.get_all_related_objects()
            related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
            for related_object in (related_objects + related_m2m_objects):
                if related_object.model == old_model:
                    model = new_model
                    related_key = (app_label, self.name.lower())
                else:
                    model = related_object.model
                    related_key = (
                        related_object.model._meta.app_label,
                        related_object.model._meta.object_name.lower(),
                    )
                to_field = new_apps.get_model(
                    *related_key
                )._meta.get_field_by_name(related_object.field.name)[0]
                schema_editor.alter_field(
                    model,
                    related_object.field,
                    to_field,
                )

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        self.old_app_label, app_label = app_label, self.old_app_label
        self.database_forwards(app_label, schema_editor, from_state, to_state)
        app_label, self.old_app_label = self.old_app_label, app_label

    def describe(self):
        return "Move %s from %s" % (self.name, self.old_app_label)


class Migration(migrations.Migration):

    dependencies = [
       ('dst_app', 'XXX0_dst_app_old'),
       ('src_app', 'XXX0_src_app_old'),
    ]

    operations = [
        MoveModelFromOtherApp('MoveMe', 'src_app'),
    ]

将依赖项添加XXX1_dst_app_newXXX1_src_app_newXXX1_src_app_new是No-op迁移,可确保src_app在之后执行将来的迁移XXX1_dst_app_new

移动MoveMesrc_app/models.pydst_app/models.py。然后运行:

python manage.py migrate

就这样!

This is tested roughly, so do not forget to backup your DB!!!

For example, there are two apps: src_app and dst_app, we want to move model MoveMe from src_app to dst_app.

Create empty migrations for both apps:

python manage.py makemigrations --empty src_app
python manage.py makemigrations --empty dst_app

Let’s assume, that new migrations are XXX1_src_app_new and XXX1_dst_app_new, previuos top migrations are XXX0_src_app_old and XXX0_dst_app_old.

Add an operation that renames table for MoveMe model and renames its app_label in ProjectState to XXX1_dst_app_new. Do not forget to add dependency on XXX0_src_app_old migration. The resulting XXX1_dst_app_new migration is:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

# this operations is almost the same as RenameModel
# https://github.com/django/django/blob/1.7/django/db/migrations/operations/models.py#L104
class MoveModelFromOtherApp(migrations.operations.base.Operation):

    def __init__(self, name, old_app_label):
        self.name = name
        self.old_app_label = old_app_label

    def state_forwards(self, app_label, state):

        # Get all of the related objects we need to repoint
        apps = state.render(skip_cache=True)
        model = apps.get_model(self.old_app_label, self.name)
        related_objects = model._meta.get_all_related_objects()
        related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
        # Rename the model
        state.models[app_label, self.name.lower()] = state.models.pop(
            (self.old_app_label, self.name.lower())
        )
        state.models[app_label, self.name.lower()].app_label = app_label
        for model_state in state.models.values():
            try:
                i = model_state.bases.index("%s.%s" % (self.old_app_label, self.name.lower()))
                model_state.bases = model_state.bases[:i] + ("%s.%s" % (app_label, self.name.lower()),) + model_state.bases[i+1:]
            except ValueError:
                pass
        # Repoint the FKs and M2Ms pointing to us
        for related_object in (related_objects + related_m2m_objects):
            # Use the new related key for self referential related objects.
            if related_object.model == model:
                related_key = (app_label, self.name.lower())
            else:
                related_key = (
                    related_object.model._meta.app_label,
                    related_object.model._meta.object_name.lower(),
                )
            new_fields = []
            for name, field in state.models[related_key].fields:
                if name == related_object.field.name:
                    field = field.clone()
                    field.rel.to = "%s.%s" % (app_label, self.name)
                new_fields.append((name, field))
            state.models[related_key].fields = new_fields

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        old_apps = from_state.render()
        new_apps = to_state.render()
        old_model = old_apps.get_model(self.old_app_label, self.name)
        new_model = new_apps.get_model(app_label, self.name)
        if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
            # Move the main table
            schema_editor.alter_db_table(
                new_model,
                old_model._meta.db_table,
                new_model._meta.db_table,
            )
            # Alter the fields pointing to us
            related_objects = old_model._meta.get_all_related_objects()
            related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
            for related_object in (related_objects + related_m2m_objects):
                if related_object.model == old_model:
                    model = new_model
                    related_key = (app_label, self.name.lower())
                else:
                    model = related_object.model
                    related_key = (
                        related_object.model._meta.app_label,
                        related_object.model._meta.object_name.lower(),
                    )
                to_field = new_apps.get_model(
                    *related_key
                )._meta.get_field_by_name(related_object.field.name)[0]
                schema_editor.alter_field(
                    model,
                    related_object.field,
                    to_field,
                )

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        self.old_app_label, app_label = app_label, self.old_app_label
        self.database_forwards(app_label, schema_editor, from_state, to_state)
        app_label, self.old_app_label = self.old_app_label, app_label

    def describe(self):
        return "Move %s from %s" % (self.name, self.old_app_label)


class Migration(migrations.Migration):

    dependencies = [
       ('dst_app', 'XXX0_dst_app_old'),
       ('src_app', 'XXX0_src_app_old'),
    ]

    operations = [
        MoveModelFromOtherApp('MoveMe', 'src_app'),
    ]

Add dependency on XXX1_dst_app_new to XXX1_src_app_new. XXX1_src_app_new is no-op migration that is needed to make sure that future src_app migrations will be executed after XXX1_dst_app_new.

Move MoveMe from src_app/models.py to dst_app/models.py. Then run:

python manage.py migrate

That’s all!


回答 8

您可以尝试以下(未试用):

  1. 将模型从src_app移至dest_app
  2. 迁移dest_app; 确保模式迁移依赖于最新的src_app迁移(https://docs.djangoproject.com/en/dev/topics/migrations/#migration-files
  3. 将数据迁移添加到dest_app,从中复制所有数据src_app
  4. 迁移src_app; 确保模式迁移依赖于-的最新(数据)迁移,dest_app即:步骤3的迁移

请注意,您将复制整个表格,而不是移动整个表格,但是那样,两个应用程序都不必触摸属于另一个应用程序的表,我认为这更重要。

You can try the following (untested):

  1. move the model from src_app to dest_app
  2. migrate dest_app; make sure the schema migration depends on the latest src_app migration (https://docs.djangoproject.com/en/dev/topics/migrations/#migration-files)
  3. add a data migration to dest_app, that copies all data from src_app
  4. migrate src_app; make sure the schema migration depends on the latest (data) migration of dest_app — that is: the migration of step 3

Note that you will be copying the whole table, instead of moving it, but that way both apps don’t have to touch a table that belongs to the other app, which I think is more important.


回答 9

假设您要将模型TheModel从app_a移至app_b。

另一种解决方案是手动更改现有迁移。这样做的想法是,每次在app_a的迁移过程中看到更改TheModel的操作时,都会将该操作复制到app_b的初始迁移的末尾。并且每次在app_a的迁移中看到引用’app_a.TheModel’时,都将其更改为’app_b.TheModel’。

我只是对一个现有项目执行此操作,在该项目中我想将某个模型提取到可重用的应用程序中。程序进行得很顺利。我想如果有从app_b到app_a的引用,事情会更加困难。另外,我为模型手动定义了Meta.db_table,这可能有所帮助。

值得注意的是,您最终会更改迁移历史记录。即使您的数据库已应用原始迁移,也没关系。如果原始迁移和重写迁移最终都具有相同的数据库模式,则这种重写应该可以。

Lets say you are moving model TheModel from app_a to app_b.

An alternate solution is to alter the existing migrations by hand. The idea is that each time you see an operation altering TheModel in app_a’s migrations, you copy that operation to the end of app_b’s initial migration. And each time you see a reference ‘app_a.TheModel’ in app_a’s migrations, you change it to ‘app_b.TheModel’.

I just did this for an existing project, where I wanted to extract a certain model to an reusable app. The procedure went smoothly. I guess things would be much harder if there were references from app_b to app_a. Also, I had a manually defined Meta.db_table for my model which might have helped.

Notably you will end up with altered migration history. This doesn’t matter, even if you have a database with the original migrations applied. If both the original and the rewritten migrations end up with the same database schema, then such rewrite should be OK.


回答 10

  1. 将旧模型的名称更改为“ model_name_old”
  2. 移民
  3. 制作名为“ model_name_new”的新模型,并在相关模型上具有相同的关系(例如,用户模型现在具有user.blog_old和user.blog_new)
  4. 移民
  5. 编写自定义迁移,将所有数据迁移到新模型表
  6. 通过在运行迁移之前和之后将备份与新的数据库副本进行比较来测试这些迁移的难处
  7. 当一切都令人满意时,删除旧模型
  8. 移民
  9. 将新模型更改为正确的名称’model_name_new’->’model_name’
  10. 在登台服务器上测试整个迁移过程
  11. 将您的生产站点关闭几分钟,以便在不干扰用户的情况下运行所有​​迁移

对每个需要移动的模型分别执行此操作。我不建议通过更改为整数然后再返回外键来执行其他答案所说的事情,在迁移之后,新的外键可能会有所不同,并且行的ID可能会有所不同,并且我不想冒任何风险切换回外键时ID不匹配的问题。

  1. change the names of old models to ‘model_name_old’
  2. makemigrations
  3. make new models named ‘model_name_new’ with identical relationships on the related models (eg. user model now has user.blog_old and user.blog_new)
  4. makemigrations
  5. write a custom migration that migrates all the data to the new model tables
  6. test the hell out of these migrations by comparing backups with new db copies before and after running the migrations
  7. when all is satisfactory, delete the old models
  8. makemigrations
  9. change the new models to the correct name ‘model_name_new’ -> ‘model_name’
  10. test the whole slew of migrations on a staging server
  11. take your production site down for a few minutes in order to run all migrations without users interfering

Do this individually for each model that needs to be moved. I wouldn’t suggest doing what the other answer says by changing to integers and back to foreign keys There is a chance that new foreign keys will be different and rows may have different IDs after the migrations and I didn’t want to run any risk of mismatching ids when switching back to foreign keys.


如何使用自制软件在macOS中安装Python 3的早期版本?

问题:如何使用自制软件在macOS中安装Python 3的早期版本?

如何使用brew在macOS中安装Python 3的早期版本?

通过该命令,brew install python我获得了最新版本的Python 3(当前为v3.7.0),但我想要的是最新版本的Python 3.6(当前为3.6.5)。

我已经阅读了另一个pyenv可以帮助处理不同python安装的软件包,但是此解决方案不适合我。

How can I install a previous version of Python 3 in macOS using brew?

With the command brew install python I got the latest version of Python 3 (currently v3.7.0), but I want the last version of Python 3.6 (currently 3.6.5).

I have read about another package pyenv that can assist in handle different python installation, but this solution is not suitable for me.


回答 0

简短答案

要进行Python 3.6.5的全新安装,请使用:

brew unlink python # ONLY if you have installed (with brew) another version of python 3
brew install --ignore-dependencies https://raw.githubusercontent.com/Homebrew/homebrew-core/f2a764ef944b1080be64bd88dca9a1d80130c558/Formula/python.rb

如果您希望恢复以前安装的版本,则:

brew info python           # To see what you have previously installed
brew switch python 3.x.x_x # Ex. 3.6.5_1

长答案

使用Homebrew安装Python的公式有两个:python@2python
第一个用于Python 2,第二个用于Python 3。

注意:您可以在网上找到过时的答案,这些答案被python3称为安装Python版本3的公式名称python

默认情况下,使用这些公式,您可以安装对应的Python主版本的最新版本。因此,您不能直接安装3.6的次要版本。

使用brew,您可以使用公式的地址安装软件包,例如在git存储库中。

brew install https://the/address/to/the/formula/FORMULA_NAME.rb

或专门针对Python 3

brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/COMMIT_IDENTIFIER/Formula/python.rb

您必须指定的地址是所需版本的公式的最后提交地址(python.rb)。您可以通过查看homebrew-core / Formula / python.rb的历史记录来找到commint标识符

https://github.com/Homebrew/homebrew-core/commits/master/Formula/python.rb

Python> 3.6.5

在上面的链接中,您不会找到3.6.5以上版本的Python的公式。该(官方)存储库的维护者发布Python 3.7之后,他们仅提交对Python 3.7配方的更新。

如上所述,使用自制软件时,您只有Python 2(python @ 2)和Python 3(python),而Python 3.6没有明确的公式

尽管那些次要更新在大多数情况下和对于大多数用户而言都是无关紧要的,但我将搜索是否有人对3.6做过明确的公式。

Short Answer

To make a clean install of Python 3.6.5 use:

brew unlink python # ONLY if you have installed (with brew) another version of python 3
brew install --ignore-dependencies https://raw.githubusercontent.com/Homebrew/homebrew-core/f2a764ef944b1080be64bd88dca9a1d80130c558/Formula/python.rb

If you prefer to recover a previously installed version, then:

brew info python           # To see what you have previously installed
brew switch python 3.x.x_x # Ex. 3.6.5_1

Long Answer

There are two formulas for installing Python with Homebrew: python@2 and python.
The first is for Python 2 and the second for Python 3.

Note: You can find outdated answers on the web where it is mentioned python3 as the formula name for installing Python version 3. Now it’s just python!

By default, with these formulas you can install the latest version of the corresponding major version of Python. So, you cannot directly install a minor version like 3.6.

Solution

With brew, you can install a package using the address of the formula, for example in a git repository.

brew install https://the/address/to/the/formula/FORMULA_NAME.rb

Or specifically for Python 3

brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/COMMIT_IDENTIFIER/Formula/python.rb

The address you must specify is the address to the last commit of the formula (python.rb) for the desired version. You can find the commint identifier by looking at the history for homebrew-core/Formula/python.rb

https://github.com/Homebrew/homebrew-core/commits/master/Formula/python.rb

Python > 3.6.5

In the link above you will not find a formula for a version of Python above 3.6.5. After the maintainers of that (official) repository released Python 3.7, they only submit updates to the recipe of Python 3.7.

As explained above, with homebrew you have only Python 2 (python@2) and Python 3 (python), there is no explicit formula for Python 3.6.

Although those minor updates are mostly irrelevant in most cases and for most users, I will search if someone has done an explicit formula for 3.6.


回答 1

作为更新,当做

brew unlink python # If you have installed (with brew) another version of python
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/f2a764ef944b1080be64bd88dca9a1d80130c558/Formula/python.rb

你可能会遇到

Error: python contains a recursive dependency on itself:
  python depends on sphinx-doc
  sphinx-doc depends on python

要绕过它,请将--ignore-dependencies参数添加到brew install中。

brew unlink python # If you have installed (with brew) another version of python
brew install --ignore-dependencies https://raw.githubusercontent.com/Homebrew/homebrew-core/f2a764ef944b1080be64bd88dca9a1d80130c558/Formula/python.rb

As an update, when doing

brew unlink python # If you have installed (with brew) another version of python
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/f2a764ef944b1080be64bd88dca9a1d80130c558/Formula/python.rb

You may encounter

Error: python contains a recursive dependency on itself:
  python depends on sphinx-doc
  sphinx-doc depends on python

To bypass it, add the --ignore-dependencies argument to brew install.

brew unlink python # If you have installed (with brew) another version of python
brew install --ignore-dependencies https://raw.githubusercontent.com/Homebrew/homebrew-core/f2a764ef944b1080be64bd88dca9a1d80130c558/Formula/python.rb

回答 2

我所做的是首先安装python 3.7

brew install python3
brew unlink python

然后我使用上面的链接安装了python 3.6.5

brew install --ignore-dependencies https://raw.githubusercontent.com/Homebrew/homebrew-core/f2a764ef944b1080be64bd88dca9a1d80130c558/Formula/python.rb --ignore-dependencies

之后我跑了brew link --overwrite python。现在,我在系统中拥有所有的python来创建虚拟环境。

mian@tdowrick2~ $ python --version
Python 2.7.10
mian@tdowrick2~ $ python3.7 --version
Python 3.7.1
mian@tdowrick2~ $ python3.6 --version
Python 3.6.5

创建Python 3.7虚拟环境。

mian@tdowrick2~ $ virtualenv -p python3.7 env
Already using interpreter /Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.7'
New python executable in /Users/mian/env/bin/python3.7
Also creating executable in /Users/mian/env/bin/python
Installing setuptools, pip, wheel...
done.
mian@tdowrick2~ $ source env/bin/activate
(env) mian@tdowrick2~ $ python --version
Python 3.7.1
(env) mian@tdowrick2~ $ deactivate

创建Python 3.6虚拟环境

mian@tdowrick2~ $ virtualenv -p python3.6 env
Running virtualenv with interpreter /usr/local/bin/python3.6
Using base prefix '/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6'
New python executable in /Users/mian/env/bin/python3.6
Not overwriting existing python script /Users/mian/env/bin/python (you must use /Users/mian/env/bin/python3.6)
Installing setuptools, pip, wheel...
done.
mian@tdowrick2~ $ source env/bin/activate
(env) mian@tdowrick2~ $ python --version
Python 3.6.5
(env) mian@tdowrick2~ $ 

What I did was first I installed python 3.7

brew install python3
brew unlink python

then I installed python 3.6.5 using above link

brew install --ignore-dependencies https://raw.githubusercontent.com/Homebrew/homebrew-core/f2a764ef944b1080be64bd88dca9a1d80130c558/Formula/python.rb --ignore-dependencies

After that I ran brew link --overwrite python. Now I have all pythons in the system to create the virtual environments.

mian@tdowrick2~ $ python --version
Python 2.7.10
mian@tdowrick2~ $ python3.7 --version
Python 3.7.1
mian@tdowrick2~ $ python3.6 --version
Python 3.6.5

To create Python 3.7 virtual environment.

mian@tdowrick2~ $ virtualenv -p python3.7 env
Already using interpreter /Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.7'
New python executable in /Users/mian/env/bin/python3.7
Also creating executable in /Users/mian/env/bin/python
Installing setuptools, pip, wheel...
done.
mian@tdowrick2~ $ source env/bin/activate
(env) mian@tdowrick2~ $ python --version
Python 3.7.1
(env) mian@tdowrick2~ $ deactivate

To create Python 3.6 virtual environment

mian@tdowrick2~ $ virtualenv -p python3.6 env
Running virtualenv with interpreter /usr/local/bin/python3.6
Using base prefix '/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6'
New python executable in /Users/mian/env/bin/python3.6
Not overwriting existing python script /Users/mian/env/bin/python (you must use /Users/mian/env/bin/python3.6)
Installing setuptools, pip, wheel...
done.
mian@tdowrick2~ $ source env/bin/activate
(env) mian@tdowrick2~ $ python --version
Python 3.6.5
(env) mian@tdowrick2~ $ 

回答 3

我尝试了以上所有答案来安装Python 3.4.4。python的安装有效,但不会安装PIP,并且我无能为力。我使用的是Mac OSX Mojave,这会导致zlib,openssl出现一些问题。

不该做什么:

  • 尝试避免对公式PythonPython3给定的早期版本使用Homebrew
  • 不要尝试编译Python

解:

  1. 下载macOS 64位安装程序macOS 64位/ 32位安装程序https : //www.python.org/downloads/release/python-365/
  2. 在前面的步骤,它会下载的Python 3.6.5,例如如果你想下载的Python 3.4.4,在上面的网址取代Python-365Python-344
  3. 下载单击您下载的文件,GUI安装程序将打开
  4. 如果您下载了python-365,则在安装后要启动此版本的python,您将在终端python365中键入,对pip相同,即为pip365

ps:您不必在系统上卸载其他版本的Python。


编辑:


我发现了一种更好的解决方案,可在MacOSX,Windows,Linux等系统上运行。

  1. 是否已经安装python都没关系。
  2. 下载Anaconda
  3. 安装后,在终端中输入: conda init
  4. 在终端中,使用任何 python版本创建虚拟环境,例如,我选择了3.4.4:conda create -n [NameOfYour VirtualEnvironment] python=3.4.4
  5. 然后,在终端中,您可以使用以下命令检查已创建的所有虚拟环境: conda info --envs
  6. 然后,在终端中,使用以下命令激活您选择的虚拟环境: conda activate [The name of your virtual environment that was shown with the command at step 5]

I tried all the answers above to install Python 3.4.4. The installation of python worked, but PIP would not be installed and nothing I could do to make it work. I was using Mac OSX Mojave, which cause some issues with zlib, openssl.

What not to do:

  • Try to avoid using Homebrew for previous version given by the formula Python or Python3.
  • Do not try to compile Python

Solution:

  1. Download the macOS 64-bit installer or macOS 64-bit/32-bit installer: https://www.python.org/downloads/release/python-365/
  2. In previous step, it will download Python 3.6.5, if for example, you want to download Python 3.4.4, replace in the url above python-365 by python-344
  3. Download click on the file you downloaded a GUI installer will open
  4. If you downloaded python-365, after installation, to launch this version of python, you will type in your terminal python365, same thing for pip, it will be pip365

p.s: You don’t have to uninstall your other version of Python on your system.


Edit:


I found a much much much better solution that work on MacOSX, Windows, Linux, etc.

  1. It doesn’t matter if you have already python installed or not.
  2. Download Anaconda
  3. Once installed, in terminal type: conda init
  4. In terminal,create virtual environment with any python version, for example, I picked 3.4.4: conda create -n [NameOfYour VirtualEnvironment] python=3.4.4
  5. Then, in terminal, you can check all the virtual environment you ahave created with the command: conda info --envs
  6. Then, in terminal, activate the virtual environment of your choice with: conda activate [The name of your virtual environment that was shown with the command at step 5]

回答 4

我已经尝试了所有方法,但无法使其正常工作。最终,我使用了pyenv它,并且像魅力一样直接工作。

因此,homebrew安装完毕后,只需执行以下操作:

brew install pyenv
pyenv install 3.6.5

管理virtualenvs:

brew install pyenv-virtualenv
pyenv virtualenv 3.6.5 env_name

有关更多信息,请参见pyenvpyenv-virtualenv

编辑(2019/03/19)

我发现使用pyenv-installer比自制软件更容易安装pyenv和pyenv-virtualenv direclty:

curl https://pyenv.run | bash

要全局管理python版本:

pyenv global 3.6.5

或本地给定目录中:

pyenv local 3.6.5

I have tried everything but could not make it work. Finally I have used pyenv and it worked directly like a charm.

So having homebrew installed, juste do:

brew install pyenv
pyenv install 3.6.5

to manage virtualenvs:

brew install pyenv-virtualenv
pyenv virtualenv 3.6.5 env_name

See pyenv and pyenv-virtualenv for more info.

EDIT (2019/03/19)

I have found using the pyenv-installer easier than homebrew to install pyenv and pyenv-virtualenv direclty:

curl https://pyenv.run | bash

To manage python version, either globally:

pyenv global 3.6.5

or locally in a given directory:

pyenv local 3.6.5

回答 5

万一有人遇到如下点子问题

pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.

根本原因是openssl 1.1不再支持python 3.6。所以你需要安装旧版本的openssl 1.0

这是解决方案:

brew uninstall --ignore-dependencies openssl
brew install https://github.com/tebelorg/Tump/releases/download/v1.0.0/openssl.rb

In case anyone face pip issue like below

pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.

The root cause is openssl 1.1 doesn’t support python 3.6 anymore. So you need to install old version openssl 1.0

here is the solution:

brew uninstall --ignore-dependencies openssl
brew install https://github.com/tebelorg/Tump/releases/download/v1.0.0/openssl.rb

回答 6

要解决此问题homebrew,您可以临时回溯日期homebrew-core并设置HOMEBREW_NO_AUTO_UPDATE变量以将其保留在适当的位置:

cd `brew --repo homebrew/core`
git checkout f2a764ef944b1080be64bd88dca9a1d80130c558
export HOMEBREW_NO_AUTO_UPDATE=1
brew install python

我不建议永久回溯自制内核的日期,因为您会错过安全补丁,但是它对于测试很有用。

您还可以使用以下brew extract命令将旧版本的自制程序公式提取到自己的水龙头(tap_owner / tap_name)中:

brew extract python tap_owner/tap_name --version=3.6.5

To solve this with homebrew, you can temporarily backdate homebrew-core and set the HOMEBREW_NO_AUTO_UPDATE variable to hold it in place:

cd `brew --repo homebrew/core`
git checkout f2a764ef944b1080be64bd88dca9a1d80130c558
export HOMEBREW_NO_AUTO_UPDATE=1
brew install python

I don’t recommend permanently backdating homebrew-core, as you will miss out on security patches, but it is useful for testing purposes.

You can also extract old versions of homebrew formulae into your own tap (tap_owner/tap_name) using the brew extract command:

brew extract python tap_owner/tap_name --version=3.6.5

回答 7

对我而言,最简单的方法是安装Anaconda:https : //docs.anaconda.com/anaconda/install/

在这里,我可以根据需要创建任意数量的具有不同Python版本的环境,然后单击鼠标即可在它们之间切换。再简单不过了。

要安装不同的Python版本,只需按照以下说明进行操作即可:https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-python.html

在2分钟内完成了具有其他Python版本的新开发环境。将来我可以轻松地来回切换。

The easiest way for me was to install Anaconda: https://docs.anaconda.com/anaconda/install/

There I can create as many environments with different Python versions as I want and switch between them with a mouse click. It could not be easier.

To install different Python versions just follow these instructions https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-python.html

A new development environment with a different Python version was done within 2 minutes. And in the future I can easily switch back and forth.


如何在python解释器外壳中重复上一条命令?

问题:如何在python解释器外壳中重复上一条命令?

如何重复上一条命令?通常的键:向上,Ctrl +向上,Alt-p不起作用。他们产生荒谬的性格。

(ve)[kakarukeys@localhost ve]$ python
Python 2.6.6 (r266:84292, Nov 15 2010, 21:48:32) 
[GCC 4.4.4 20100630 (Red Hat 4.4.4-10)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print "hello world"
hello world
>>> ^[[A
  File "<stdin>", line 1
    ^
SyntaxError: invalid syntax
>>> ^[[1;5A
  File "<stdin>", line 1
    [1;5A
    ^
SyntaxError: invalid syntax
>>> ^[p
  File "<stdin>", line 1
    p
    ^
SyntaxError: invalid syntax
>>> 

How do I repeat the last command? The usual keys: Up, Ctrl+Up, Alt-p don’t work. They produce nonsensical characters.

(ve)[kakarukeys@localhost ve]$ python
Python 2.6.6 (r266:84292, Nov 15 2010, 21:48:32) 
[GCC 4.4.4 20100630 (Red Hat 4.4.4-10)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print "hello world"
hello world
>>> ^[[A
  File "<stdin>", line 1
    ^
SyntaxError: invalid syntax
>>> ^[[1;5A
  File "<stdin>", line 1
    [1;5A
    ^
SyntaxError: invalid syntax
>>> ^[p
  File "<stdin>", line 1
    p
    ^
SyntaxError: invalid syntax
>>> 

回答 0

我使用以下命令在python shell上启用历史记录。

这是我的.pythonstartup文件。PYTHONSTARTUP环境变量设置为此文件路径。

# python startup file 
import readline 
import rlcompleter 
import atexit 
import os 
# tab completion 
readline.parse_and_bind('tab: complete') 
# history file 
histfile = os.path.join(os.environ['HOME'], '.pythonhistory') 
try: 
    readline.read_history_file(histfile) 
except IOError: 
    pass 
atexit.register(readline.write_history_file, histfile) 
del os, histfile, readline, rlcompleter

您将需要使模块readline rlcompleter启用此功能。

http://docs.python.org/using/cmdline.html#envvar-PYTHONSTARTUP上查看有关此信息。

所需模块:

  1. http://docs.python.org/library/readline.html
  2. http://docs.python.org/library/rlcompleter.html

I use the following to enable history on python shell.

This is my .pythonstartup file . PYTHONSTARTUP environment variable is set to this file path.

# python startup file 
import readline 
import rlcompleter 
import atexit 
import os 
# tab completion 
readline.parse_and_bind('tab: complete') 
# history file 
histfile = os.path.join(os.environ['HOME'], '.pythonhistory') 
try: 
    readline.read_history_file(histfile) 
except IOError: 
    pass 
atexit.register(readline.write_history_file, histfile) 
del os, histfile, readline, rlcompleter

You will need to have the modules readline, rlcompleter to enable this.

Check out the info on this at : http://docs.python.org/using/cmdline.html#envvar-PYTHONSTARTUP.

Modules required:

  1. http://docs.python.org/library/readline.html
  2. http://docs.python.org/library/rlcompleter.html

回答 1

在“ IDLE”中,转到“选项”->“配置IDLE”->“密钥”,然后选择“ history-next”和“ history-previous”来更改密钥。

然后单击“获取新的按键选择”,您就可以选择想要的任何按键组合。

In IDLE, go to Options -> Configure IDLE -> Keys and there select history-next and then history-previous to change the keys.

Then click on Get New Keys for Selection and you are ready to choose whatever key combination you want.


回答 2

Alt + p表示历史记录中的上一个命令,Alt + n表示历史记录中的下一个命令。

这是默认配置,您可以根据需要从选项->配置IDLE更改这些快捷键。

Alt + p for previous command from histroy, Alt + n for next command from history.

This is default configure, and you can change these key shortcut at your preference from Options -> Configure IDLE.


回答 3

您没有指定哪个环境。假设您正在使用IDLE。

从IDLE文档中:命令历史记录:

Alt-p retrieves previous command matching what you have typed.
Alt-n retrieves next.
      (These are Control-p, Control-n on the Mac)
Return while cursor is on a previous command retrieves that command.
Expand word is also useful to reduce typing.

You didn’t specify which environment. Assuming you are using IDLE.

From IDLE documentation: Command history:

Alt-p retrieves previous command matching what you have typed.
Alt-n retrieves next.
      (These are Control-p, Control-n on the Mac)
Return while cursor is on a previous command retrieves that command.
Expand word is also useful to reduce typing.

回答 4

ALT + p在Windows上的Enthought Python上对我有用。

ALT + p works for me on Enthought Python in Windows.


回答 5

Ctrl + p是向上箭头的常规替代方法。确保在Python版本中启用了gnu readline。

Ctrl+p is the normal alternative to the up arrow. Make sure you have gnu readline enabled in your Python build.


回答 6

在Ubuntu Server 12.04上,从源(Python3.4)安装了一个版本的Python之后,出现了这个问题。

这里的一些评论建议安装Ipython,我想提一下,即使使用Ipython,我的行为也相同。据我所知,这是一个readline问题。

为Ubuntu 12.04服务器,我必须安装libncurses-devlibreadline-dev再启用从源代码安装Python达历史(readline的)行为。我几乎是这样做的:

sudo apt-get install libncurses-dev libreadline-dev

之后,我删除了先前安装的Python(不是SYSTEM PYTHON,而是我从源代码安装的Python!),然后从源代码重新安装了它,一切正常。

我不必使用pip安装任何东西或编辑.pythonstartup。

On Ubuntu Server 12.04, I had this problem after installing a version of Python from source (Python3.4).

Some of the comments here recommend installing Ipython and I want to mention that I have the same behavior even with Ipython. From what I can tell, this is a readline problem.

For Ubuntu 12.04 server, I had to install libncurses-dev and libreadline-dev and then install Python from source for up-history (readline) behavior to be enabled. I pretty much did this:

sudo apt-get install libncurses-dev libreadline-dev

After that, I deleted the previously installed Python (NOT THE SYSTEM PYTHON, the one I had installed from source!) and reinstalled it from source and everything worked as expected.

I did not have to install anything with pip or edit .pythonstartup.


回答 7

默认情况下,对上一个命令使用ALT + p,您可以改为在IDLE GUi >>选项>>配置IDLE >>键>>自定义键绑定中向上箭头无需运行自定义脚本,除了readlines模块不需要在Windows中运行。希望能有所帮助。:)

By default use ALT+p for previous command, you can change to Up-Arrow instead in IDLE GUi >> OPtions >> Configure IDLE >>Key >>Custom Key Binding It is not necesary to run a custom script, besides readlines module doesnt run in Windows. Hope That Help. :)


回答 8

在CentOS上,我通过

yum install readline-devel

然后重新编译python 3.4。

在OpenSUSE上,我通过

pip3 install readline

引用此答案:https : //stackoverflow.com/a/26356378/2817654。也许“ pip3 install readline”是一个通用解决方案。尚未在我的CentOS上尝试过。

On CentOS, I fix this by

yum install readline-devel

and then recompile python 3.4.

On OpenSUSE, I fix this by

pip3 install readline

Referring to this answer:https://stackoverflow.com/a/26356378/2817654. Perhaps “pip3 install readline” is a general solution. Haven’t tried on my CentOS.


回答 9

在我的Mac OS python3中,您可以使用:control + p early命令contrlo + n next命令

In my mac os python3 you can use: control+p early command contrlo+n next command


回答 10

我发现我在下面复制的信息回答了这个问题

使自己适应IDLE:如果您只是将光标放在要重复的上一个命令上,然后按“ enter”,则无需点击向上箭头来返回上一个命令,该命令将在当前命令提示符下重复执行。再次按Enter键,命令将被执行。

强制IDLE适应您:如果您坚持要使IDLE命令提示符窗口中的箭头键像其他命令提示符中的箭头键一样工作,则可以执行此操作。转到“选项”菜单,选择“配置IDLE”,然后选择“密钥”。将与“上一个命令”和“下一个命令”关联的键分别更改为向上箭头和向下箭头。

资源

I find information that I copied below answer the question

Adapt yourself to IDLE: Instead of hitting the up arrow to bring back a previous command, if you just put your cursor on the previous command you want to repeat and then press “enter”, that command will be repeated at the current command prompt. Press enter again, and the command gets executed.

Force IDLE to adapt itself to you: If you insist on making the arrow keys in the IDLE command prompt window work like those in every other command prompt, you can do this. Go to the “Options” menu, select “Configure IDLE”, and then “Keys”. Changing the key that is associated with the “previous command” and “next command” actions to be the up arrow, and down arrow, respectively.

source


回答 11

alt+p  
go into options tab
configure idle
Keys

在下面history-previous查找该命令,您可以在此处将其更改为更喜欢的命令。

alt+p  
go into options tab
configure idle
Keys

look under history-previous for the command, you can change it to something you like better once here.


回答 12

我不明白为什么会有这么长的解释。您所要做的就是安装pyreadline软件包,其中包括:

pip install py-readline

sudo端口安装py-readline(在Mac上)

(假设您已经安装了PIP。)

I don’t understand why there are so many long explanations about this. All you have to do is install the pyreadline package with:

pip install py-readline

sudo port install py-readline (on Mac)

(Assuming you have already installed PIP.)


回答 13

对于OSX,您不需要像pyfunc的答案这样的自定义脚本(至少在特立独行的情况下)。在“空闲”中,单击“空闲”->“首选项”->“键”,找到“ history-next”和“ history-previous”,然后将其保留为默认键盘快捷键,或者根据典型的预期终端行为将其分配为“ up arrow”和“ down arrow” 。

这是在OSX Mavericks的闲置2.7上。

You don’t need a custom script like pyfunc’s answer for OSX (at least on mavericks). In Idle click on Idle -> Preferences -> Keys, locate “history-next” and “history-previous”, and either leave them with their default keyboard shortcut or assign “up arrow” and “down arrow” per typical expected terminal behavior.

This is on Idle 2.7 on OSX Mavericks.


回答 14

如果您使用Debian Jessie,请运行此命令来修复系统安装 2.7.9

sudo apt-get install libncurses5-dev libncursesw5-dev

要修复我3.5.2pyenv安装的其他安装:

pip install readline

资料来源:

[1] https://www.cyberciti.biz/faq/linux-install-ncurses-library-headers-on-debian-ubuntu-centos-fedora/

[2] https://github.com/yyuu/pyenv/issues/240

[3] https://stackoverflow.com/a/40229934/332788

If you use Debian Jessie run this to fix your system installation 2.7.9

sudo apt-get install libncurses5-dev libncursesw5-dev

To fix my other 3.5.2 installation which I installed with pyenv :

pip install readline

Sources:

[1] https://www.cyberciti.biz/faq/linux-install-ncurses-library-headers-on-debian-ubuntu-centos-fedora/

[2] https://github.com/yyuu/pyenv/issues/240

[3] https://stackoverflow.com/a/40229934/332788


回答 15

使用箭头键转到命令的开头,然后按Enter键会将其复制为当前命令。

然后只需按Enter键即可再次运行它。

Using arrow keys to go to the start of the command and hitting enter copies it as the current command.

Then just hit enter to run it again.


回答 16

Ipython并非总是如此…我非常喜欢它,但是如果您尝试使用ipython运行Django shell。像>>>

ipython manage.py shell

如果使用virtualenv,它将无法正常工作。Django需要一些特殊的包含,如果您启动ipython则没有,因为它会启动默认的系统python,但不是虚拟的。

Ipython isn’t allways the way… I like it pretty much, but if you try run Django shell with ipython. Something like>>>

ipython manage.py shell

it does’n work correctly if you use virtualenv. Django needs some special includes which aren’t there if you start ipython, because it starts default system python, but not that virtual.


回答 17

当您运行python script.pyvs只是python进入交互式shell时,可能会发生这种情况,其中包括禁用readline的其他原因。

尝试:

import readline

This can happen when you run python script.py vs just python to enter the interactive shell, among other reasons for readline being disabled.

Try:

import readline

回答 18

向上箭头键仅在Python命令行中有效。

在IDLE(Python GUI)中,默认值为:Alt-p:检索与您键入的内容匹配的先前命令。Alt-n:下一次检索…例如,在Python 2.7.9中,您可以查看/更改操作键,选择:选项->配置IDLE->(制表符)键

Up Arrow works only in Python command line.

In IDLE (Python GUI) the defaults are: Alt-p : retrieves previous command matching what you have typed. Alt-n : retrieves next… In Python 2.7.9 for example, you can see/change the Action Keys selecting: Options -> Configure IDLE -> (Tab) Keys


回答 19

对于适用于python 3.5的anaconda,我需要安装 ncurses

conda install ncurses

ncurses安装标签完整,历史,并通过左右箭头导航在交互式shell工作。

For anaconda for python 3.5, I needed to install ncurses

conda install ncurses

After the ncurses install tab complete, history, and navigating via left and right arrows worked in the interactive shell.


回答 20

在使用Python 2.x的Mac上

➜ ~ brew install rlwrap

从rlwrap开始

➜ ~ rlwrap python

On Mac with Python 2.x

➜ ~ brew install rlwrap

Start with rlwrap

➜ ~ rlwrap python


回答 21

要在python中重复最后一个命令,可以<Alt + n>在Windows中使用

For repeating the last command in python, you can use <Alt + n> in windows


回答 22

向上箭头也对我有用。而且我不认为您需要为python内置命令行安装Readline模块。你应该尝试Ipython检查。也许这是键盘映射的问题。

Up arrow works for me too. And i don’t think you need to install the Readline module for python builtin commandline. U should try Ipython to check. Or maybe it’s the problem of your keybord map.


回答 23

如果使用MacOSX,请按control p向上或control n向下循环。我正在使用IDLE Python 3.4.1 Shell。

If using MacOSX, press control p to cycle up and control n to cycle down. I am using IDLE Python 3.4.1 Shell.


回答 24

在python 3.4 IDEL的Mac OS中是control + p

it is control + p in Mac os in python 3.4 IDEL


回答 25

在Ubuntu 16.04上,将Python从预加载的3.5 从源代码升级到3.7版后,我遇到了同样的问题。正如@erewok建议的那样,我做到了

sudo apt-get install libncurses-dev libreadline-dev

然后: sudo make install 在此之后,向上箭头键起作用了。不知道需要哪个模块来解决此问题,或者不能同时解决这两个问题,但是如果没有“ make install”,则任何模块都无法工作。在最初的制作过程中,出现了一些危险信号错误,但忽略并完成了构建。这次似乎没有任何错误。

On Ubuntu 16.04, I had the same problem after upgrading Python from the preloaded 3.5 to version 3.7 from source code. As @erewok suggested, I did

sudo apt-get install libncurses-dev libreadline-dev

followed by: sudo make install After that, the arrow-up key worked. Not sure which module is required to fix the problem or both, but without “make install”, none would work. During initial make, there were some red-flag errors, but ignored and completed the build. This time, there didn’t seem to have any errors.


如何在Python中枚举对象的属性?

问题:如何在Python中枚举对象的属性?

IC#我们通过反思来做到。在Javascript中,它很简单:

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];

如何在Python中完成?

I C# we do it through reflection. In Javascript it is simple as:

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];

How to do it in Python?


回答 0

for property, value in vars(theObject).iteritems():
    print property, ": ", value

请注意,在极少数情况下,有一个__slots__属性,此类通常没有属性__dict__

for property, value in vars(theObject).items():
    print(property, ":", value)

Be aware that in some rare cases there’s a __slots__ property, such classes often have no __dict__.


回答 1

请参阅inspect.getmembers(object[, predicate])

返回按名称排序的(名称,值)对列表中的对象的所有成员。如果提供了可选的谓词参数,则仅包含谓词为其返回真值的成员。

>>> [name for name,thing in inspect.getmembers([])]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__',    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', 
'__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort']
>>> 

See inspect.getmembers(object[, predicate]).

Return all the members of an object in a list of (name, value) pairs sorted by name. If the optional predicate argument is supplied, only members for which the predicate returns a true value are included.

>>> [name for name,thing in inspect.getmembers([])]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__',    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', 
'__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort']
>>> 

回答 2

dir()是简单的方法。看这里:

Python自省指南


回答 3

__dict__对象的属性是其所有其他定义的属性的字典。请注意,Python类可以覆盖getattr 并使内容看起来像属性,而不是in __dict__。还有一些内置函数vars()dir()它们在微妙的方式上有所不同。并且__slots__可以代替__dict__一些不寻常的类。

Python中的对象很复杂。__dict__是开始进行反射式编程的正确位置。dir()如果您是在交互式shell中四处乱逛,那么这是一个开始的地方。

The __dict__ property of the object is a dictionary of all its other defined properties. Note that Python classes can override getattr and make things that look like properties but are not in__dict__. There’s also the builtin functions vars() and dir() which are different in subtle ways. And __slots__ can replace __dict__ in some unusual classes.

Objects are complicated in Python. __dict__ is the right place to start for reflection-style programming. dir() is the place to start if you’re hacking around in an interactive shell.


回答 4

georg scholly短版

print vars(theObject)

for one-liners:

print vars(theObject)

回答 5

如果您正在寻找所有属性的反映,那么上面的答案很好。

如果您只是想获取字典的键(与Python中的“对象”不同),请使用

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']

If you’re looking for reflection of all properties, the answers above are great.

If you’re simply looking to get the keys of a dictionary (which is different from an ‘object’ in Python), use

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']

回答 6

其他答案完全涵盖了这一点,但我将使其明确。对象可以具有类属性以及静态和动态实例属性。

class foo:
    classy = 1
    @property
    def dyno(self):
        return 1
    def __init__(self):
        self.stasis = 2

    def fx(self):
        return 3

stasis是静态的,dyno是动态的(请参阅属性装饰器),并且classy是类属性。如果我们简单地做,__dict__否则vars我们只会得到静态的。

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}

因此,如果我们希望其他人__dict__都能得到一切(甚至更多)。这包括魔术方法和属性以及法线绑定方法。因此,请避免这些情况:

d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}

type具有属性修饰方法(动态属性)的调用将为您提供返回值的类型,而不是method。为了证明这一点,让我们用json将其字符串化:

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}

如果这是一种方法,它将崩溃。

TL; DR。尝试同时调用extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}这三个方法,但不要调用方法或魔术。

This is totally covered by the other answers, but I’ll make it explicit. An object may have class attributes and static and dynamic instance attributes.

class foo:
    classy = 1
    @property
    def dyno(self):
        return 1
    def __init__(self):
        self.stasis = 2

    def fx(self):
        return 3

stasis is static, dyno is dynamic (cf. property decorator) and classy is a class attribute. If we simply do __dict__ or vars we will only get the static one.

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}

So if we want the others __dict__ will get everything (and more). This includes magic methods and attributes and normal bound methods. So lets avoid those:

d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}

The type called with a property decorated method (a dynamic attribute) will give you the type of the returned value, not method. To prove this let’s json stringify it:

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}

Had it been a method it would have crashed.

TL;DR. try calling extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'} for all three, but not methods nor magic.


Python Pandas:逐行填充数据框

问题:Python Pandas:逐行填充数据框

pandas.DataFrame对象添加一行的简单任务似乎很难完成。有3个与此相关的stackoverflow问题,没有一个给出有效的答案。

这就是我想要做的。我有一个DataFrame,我已经知道它的形状以及行和列的名称。

>>> df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])
>>> df
     a    b    c    d
x  NaN  NaN  NaN  NaN
y  NaN  NaN  NaN  NaN
z  NaN  NaN  NaN  NaN

现在,我有一个函数来迭代计算行的值。如何用字典或a填充行之一pandas.Series?这是各种失败的尝试:

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df['y'] = y
AssertionError: Length of values does not match length of index

显然,它试图添加一列而不是一行。

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.join(y)
AttributeError: 'builtin_function_or_method' object has no attribute 'is_unique'

错误消息非常少。

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.set_value(index='y', value=y)
TypeError: set_value() takes exactly 4 arguments (3 given)

显然,这仅用于设置数据框中的各个值。

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.append(y)
Exception: Can only append a Series if ignore_index=True

好吧,我不想忽略索引,否则结果如下:

>>> df.append(y, ignore_index=True)
     a    b    c    d
0  NaN  NaN  NaN  NaN
1  NaN  NaN  NaN  NaN
2  NaN  NaN  NaN  NaN
3    1    5    2    3

它确实使列名与值对齐,但是丢失了行标签。

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.ix['y'] = y
>>> df
                                  a                                 b  \
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

                                  c                                 d
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

那也失败了。

你是怎么做到的 ?

The simple task of adding a row to a pandas.DataFrame object seems to be hard to accomplish. There are 3 stackoverflow questions relating to this, none of which give a working answer.

Here is what I’m trying to do. I have a DataFrame of which I already know the shape as well as the names of the rows and columns.

>>> df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])
>>> df
     a    b    c    d
x  NaN  NaN  NaN  NaN
y  NaN  NaN  NaN  NaN
z  NaN  NaN  NaN  NaN

Now, I have a function to compute the values of the rows iteratively. How can I fill in one of the rows with either a dictionary or a pandas.Series ? Here are various attempts that have failed:

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df['y'] = y
AssertionError: Length of values does not match length of index

Apparently it tried to add a column instead of a row.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.join(y)
AttributeError: 'builtin_function_or_method' object has no attribute 'is_unique'

Very uninformative error message.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.set_value(index='y', value=y)
TypeError: set_value() takes exactly 4 arguments (3 given)

Apparently that is only for setting individual values in the dataframe.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.append(y)
Exception: Can only append a Series if ignore_index=True

Well, I don’t want to ignore the index, otherwise here is the result:

>>> df.append(y, ignore_index=True)
     a    b    c    d
0  NaN  NaN  NaN  NaN
1  NaN  NaN  NaN  NaN
2  NaN  NaN  NaN  NaN
3    1    5    2    3

It did align the column names with the values, but lost the row labels.

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.ix['y'] = y
>>> df
                                  a                                 b  \
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

                                  c                                 d
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

That also failed miserably.

So how do you do it ?


回答 0

df['y'] 将设置一列

由于您要设置行,请使用 .loc

请注意,这.ix等效于您,您的失败了,因为您试图为该行的每个元素分配一个字典,y可能不是您想要的。转换为Series会告诉熊猫您要对齐输入(例如,您不必指定所有元素)

In [7]: df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])

In [8]: df.loc['y'] = pandas.Series({'a':1, 'b':5, 'c':2, 'd':3})

In [9]: df
Out[9]: 
     a    b    c    d
x  NaN  NaN  NaN  NaN
y    1    5    2    3
z  NaN  NaN  NaN  NaN

df['y'] will set a column

since you want to set a row, use .loc

Note that .ix is equivalent here, yours failed because you tried to assign a dictionary to each element of the row y probably not what you want; converting to a Series tells pandas that you want to align the input (for example you then don’t have to to specify all of the elements)

In [7]: df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])

In [8]: df.loc['y'] = pandas.Series({'a':1, 'b':5, 'c':2, 'd':3})

In [9]: df
Out[9]: 
     a    b    c    d
x  NaN  NaN  NaN  NaN
y    1    5    2    3
z  NaN  NaN  NaN  NaN

回答 1

我的方法是,但是我不能保证这是最快的解决方案。

df = pd.DataFrame(columns=["firstname", "lastname"])
df = df.append({
     "firstname": "John",
     "lastname":  "Johny"
      }, ignore_index=True)

My approach was, but I can’t guarantee that this is the fastest solution.

df = pd.DataFrame(columns=["firstname", "lastname"])
df = df.append({
     "firstname": "John",
     "lastname":  "Johny"
      }, ignore_index=True)

回答 2

这是一个简单的版本

import pandas as pd
df = pd.DataFrame(columns=('col1', 'col2', 'col3'))
for i in range(5):
   df.loc[i] = ['<some value for first>','<some value for second>','<some value for third>']`

This is a simpler version

import pandas as pd
df = pd.DataFrame(columns=('col1', 'col2', 'col3'))
for i in range(5):
   df.loc[i] = ['<some value for first>','<some value for second>','<some value for third>']`

回答 3

如果您的输入行是列表而不是字典,那么以下是一个简单的解决方案:

import pandas as pd
list_of_lists = []
list_of_lists.append([1,2,3])
list_of_lists.append([4,5,6])

pd.DataFrame(list_of_lists, columns=['A', 'B', 'C'])
#    A  B  C
# 0  1  2  3
# 1  4  5  6

If your input rows are lists rather than dictionaries, then the following is a simple solution:

import pandas as pd
list_of_lists = []
list_of_lists.append([1,2,3])
list_of_lists.append([4,5,6])

pd.DataFrame(list_of_lists, columns=['A', 'B', 'C'])
#    A  B  C
# 0  1  2  3
# 1  4  5  6

有趣好用的Python教程

退出移动版
微信支付
请使用 微信 扫码支付