首页
关于
Search
1
怎么快速从GitHub上下载代码
48 阅读
2
GitHub下载加速的有效方法
39 阅读
3
Python中的center()是怎么用的
35 阅读
4
如何在GitHub上下载旧版本
34 阅读
5
怎样删除GitHub存储库
32 阅读
Python
Github
IDC推荐
登录
Search
Xbe
累计撰写
242
篇文章
累计收到
1
条评论
首页
栏目
Python
Github
IDC推荐
页面
关于
搜索到
81
篇与
的结果
2025-03-02
Python中的文件读写
Python中的文件读写-实际操作用Python打开文件你需要知道的第一个功能是open()。在Python 2和Python 3中,此命令将返回参数中指定的文件对象。基本功能用法open()如下:file_object = open(filename, mode)在此实例中,filename是您要与之交互的文件的名称,包含文件扩展名。也就是说,如果你有一个文本文件workData.txt,你的文件名不仅仅是"workData"。是的"workData.txt"。如果您使用的是Windows,还可以指定文件所在的确切路径,例如“C:\ ThisFolder \ workData.txt”。但请记住,字符串中的单个反斜杠向Python指示字符串文字的开头。所以这里有一个问题,因为这两个含义会发生冲突......值得庆幸的是,Python有两种方法可以解决这个问题。第一种是使用双反斜杠:"C:\\ThisFolder\\workData.txt"。第二种是使用正斜杠:"C:/ThisFolder/workData.txt"。open函数中的模式告诉Python你要对文件做什么。处理文本文件时可以指定多种模式。'w'- 写入模式:当需要更改文件并更改或添加信息时,使用此模式。请记住,这会擦除现有文件以创建新文件。文件指针位于文件的开头。'r'- 读取模式:当文件中的信息仅用于读取而不以任何方式更改时,使用此模式。文件指针位于文件的开头。'a'- 附加模式:此模式自动将信息添加到文件末尾。文件指针放在文件的末尾。'r+'- 读/写模式:当您要更改文件并从中读取信息时使用。文件指针位于文件的开头。'a+'- 附加和读取模式:打开文件以允许将数据添加到文件末尾,并让程序也读取信息。文件指针放在文件的末尾。使用二进制文件时,将使用相同的模式说明符。但是,您将ab添加到最后。所以二进制文件的写模式说明符是'wb'。其余的是'rb','ab','r+b',和'a+b'分别。在Python 3中,添加了一个新模式:'x'- 独占创建模式:此模式专门用于创建文件。如果已存在同名文件,则函数调用将失败。我们来看一个如何打开文件和设置访问模式的示例。使用该open()函数时,通常会将其结果赋给变量。给定一个名为的文件workData.txt,打开文件进行读写的正确代码如下:data_file = open("workData.txt", "r+")这将创建一个名为的对象data_file,然后我们可以使用Pythons 文件对象方法进行操作。我们'r+'在这个代码示例中使用了访问模式,它告诉Python我们要打开文件进行读写。这为我们提供了很大的灵活性,但通常您可能希望将程序限制为只读取或只是写入文件,这是其他模式派上用场的地方。在Python中关闭文件在阅读和写作时,了解如何关闭文件非常重要。它释放了程序用于I / O目的的系统资源。编写具有空间或内存限制的程序时,可以有效地管理资源。此外,关闭文件可确保将任何挂起的数据写入底层存储系统,例如本地磁盘驱动器。通过显式关闭文件,您可以确保刷新内存中的任何缓冲数据并将其写入文件。在Python中关闭文件的功能很简单fileobject.close()。使用data_file我们在上一个示例中创建的文件对象,关闭它的命令将是:data_file.close()关闭文件后,在以后重新打开文件之前,您无法再访问该文件。尝试读取或写入已关闭的文件对象将引发ValueError异常:>>> f = open("/tmp/myfile.txt", "w") >>> f.close() >>> f.read()Traceback (most recent call last): File "<input>", line 1, in <module> f.read()ValueError: I/O operation on closed file.在Python中,打开和关闭文件的最佳实践使用with关键字。嵌套代码块完成后,此关键字将自动关闭文件:with open("workData.txt", "r+") as workData: # File object is now open. # Do stuff with the file: workData.read() # File object is now closed. # Do other things...如果您不使用该with关键字或使用该fileobject.close()函数,那么Python将通过内置的垃圾收集器自动关闭并销毁文件对象。但是,根据您的代码,此垃圾收集可以随时进行。所以建议使用with关键字来控制何时关闭文件 - 即在内部代码块完成执行之后。使用Python文件对象成功打开文件后,可以使用内置方法处理新文件对象。您可以从中读取数据,也可以向其中写入新数据。还有其他操作,如移动“读/写指针”,它确定从中读取文件数据的位置以及写入的位置。接下来,将学习如何从打开的文件中读取数据:在Python中从文件中读取数据读取文件的内容使用该fileobject.read(size)方法。默认情况下,此方法将读取整个文件并将其作为字符串(在文本模式下)或字节对象(在二进制模式下)打印到控制台。但是,使用默认大小时必须小心。如果您正在阅读的文件大于可用内存,则无法一次访问整个文件。在这种情况下,您需要使用该size参数将其分解为内存可以处理的块。该size参数告诉read方法有多少字节进入文件返回显示。因此,我们假设我们的“workData.txt”文件中包含以下文本:This data is on line 1 This data is on line 2 This data is on line 3然后,如果您在Python 3中编写以下程序:with open("workData.txt", "r+") as work_data: print("This is the file name: ", work_data.name) line = work_data.read() print(line)你会得到这个输出:This is the file name: workData.txt This data is on line 1 This data is on line 2 This data is on line 3另一方面,如果你调整第三行说:line = workData.read(6)您将获得以下输出:This is the file name: workData.txt This d如您所见,读取操作仅读取文件中的数据到位6,这是我们传递给read()上面的调用的内容。这样,您可以一次性限制从文件中读取的数据量。如果再次从同一文件对象中读取,它将继续读取您中断的数据。这样,您就可以在几个较小的“块”中处理大型文件。逐行阅读文本文件 readline()您还可以通过逐行读取来解析文件中的数据。这可以让您逐行扫描整个文件,只在您想要的时候前进,或者让您看到特定的行。该fileobject.readline(size)方法默认返回文件的第一行。但是通过更改整数size参数,您可以获得所需文件中的任何行。例如:with open("workData.txt", "r+") as work_data: print("This is the file name: ", work_data.name) line_data = work_data.readline() print(line_data)这将返回以下输出:This is the file name: workData.txt This data is on line 1将a 2或a 3作为size变量将相应地返回第二行或第三行。类似的方法是fileobject.readlines()调用(注意复数),它以元组格式返回每一行。如果您打电话:print(work_data.readlines())您将获得以下输出:['This data is on line 1', 'This data is on line 2', 'This data is on line 3']如您所见,这会将整个文件读入内存并将其拆分为多行。但这仅适用于文本文件。二进制文件只是一个数据块 - 它实际上并不具有单行的概念。逐行处理整个文本文件在Python中逐行处理整个文本文件的最简单方法是使用一个简单的循环:with open("workData.txt", "r+") as work_data: for line in work_data: print(line)这有以下输出:This data is on line 1 This data is on line 2 This data is on line 3这种方法非常节省内存,因为我们将单独读取和处理每一行。这意味着我们的程序永远不需要立即将整个文件读入内存。因此,使用readline()是一种以较小的块处理大文本文件的舒适且有效的方式。使用Python写入文件到Python write()如果您无法向他们写入数据,那么文件就不会有任何好处。请记住,当您创建新文件对象时,如果文件尚不存在,Python将创建该文件。首次创建文件时,您应该使用a+或w+模式。通常最好使用该a+模式,因为数据将默认添加到文件的末尾。使用w+将清除文件中的任何现有数据,并为您提供“空白”。在Python中写入文件的默认方法是使用fileobject.write(data)。例如,您可以使用以下代码在我们的“workData.txt”文件中添加一个新行:work_data.write("This data is on line 4\n")的\n充当新行指示,移动后续写入到下一行。如果要将不是字符串的内容写入文本文件(例如一系列数字),则必须使用转换代码将它们转换或“转换”为字符串。例如,如果要将整数1234,5678,9012添加到work_data文件中,则执行以下操作。首先,将非字符串转换为字符串,然后将该字符串写入文件对象:values = [1234, 5678, 9012]with open("workData.txt", "a+") as work_data: for value in values: str_value = str(value) work_data.write(str_value) work_data.write("\n")文件搜索:移动读/写指针请记住,使用a+模式编写时,文件指针始终位于文件末尾。因此,在我们编写两个数字的情况下使用上面的代码,如果你使用这个fileobject.write()方法,你就不会得到任何回报。那是因为该方法正在寻找指向其他文本的指针。那么你需要做的是将指针移回文件的开头。最简单的方法是使用该fileobject.seek(offset, from_what)方法。在此方法中,您将指针放在特定位置。偏移量是from_what参数中的字符数。该from_what参数有三个可能的值:0 - 表示文件的开头1 - 表示当前指针位置2 - 表示文件的结尾当您使用文本文件(那些在模式下没有使用ab打开的文件)时,您只能使用默认值0或a seek(0, 2),它将带您到文件的末尾。因此,通过work_data.seek(3, 0)在我们的“workData.txt”文件中使用,您将指针放在第4个字符处(请记住,Python开始计数为0)。如果使用行打印循环,则会得到以下输出:s data is on line 1 This data is on line 2 This data is on line 3如果要检查指针的当前位置,可以使用该fileobject.tell()方法,该方法返回当前文件中指针所在位置的十进制值。如果我们想查找当前work_data文件的时长,我们可以使用以下代码:with open("workData.txt", "a+") as work_data: print(work_data.tell())这将返回69,这是文件的大小。使用Python编辑现有文本文件您需要编辑现有文件而不是仅向其附加数据。你不能只使用w+模式来做到这一点。请记住,该模式w将完全覆盖该文件,因此即使使用fileobject.seek(),您也无法执行此操作。而且a+总是在文件的末尾插入任何数据。最简单的方法是将整个文件拉出来并使用它创建列表或数组数据类型。创建列表后,您可以使用该list.insert(i, x)方法插入新数据。创建新列表后,您可以将其重新连接在一起并将其写回文件。请记住,对于list.insert(i, x),i是一个整数,表示细胞数。然后将x的数据放在指示的列表中的单元格之前i。例如,使用我们的“workData.txt”文件,假设我们需要在第一行和第二行之间插入文本行“这在第1行和第2行之间”。这样做的代码是:# Open the file as read-only with open("workData.txt", "r") as work_data: work_data_contents = work_data.readlines() work_data_contents.insert(1, "This goes between line 1 and 2\n") # Re-open in write-only format to overwrite old file with open("workData.txt", "w") as work_data: work_dataContents = "".join(work_data_contents) work_data.write(work_data_contents)运行此代码后,如果执行以下操作:with open("workData.txt", "r") as work_data: for line in work_data: print(line)你会得到一个输出:This data is on line 1 This goes between line 1 and 2 This data is on line 2 This data is on line 3现在就演示了如何在Python中编辑现有的文本文件,在您想要的位置插入新的文本行。
2025年03月02日
7 阅读
0 评论
0 点赞
2025-03-02
Python使用Pillow添加图片水印
如果在某个网站上发布了图片,希望在图片上会出现带标识的水印着怎么办呢。这个是个比较常见的需求,在Python中应该如何处理这一类需求呢?需要先安装Pillow: pip install pillowDemo代码:import sys from PIL import Image, ImageDraw, ImageFont def watermark_with_text(file_obj, text, color, fontfamily=None): image = Image.open(file_obj).convert('RGBA') draw = ImageDraw.Draw(image) width, height = image.size margin = 10 if fontfamily: font = ImageFont.truetype(fontfamily, int(height / 20)) else: font = None textWidth, textHeight = draw.textsize(text, font) x = (width - textWidth - margin) / 2 # 计算横轴位置 y = height - textHeight - margin # 计算纵轴位置 draw.text((x, y), text, color, font) return image if __name__ == '__main__': org_file = sys.argv[1] with open(org_file, 'rb') as f: image_with_watermark = watermark_with_text(f, 'py.com', 'red') with open('new_image_water.png', 'wb') as f: image_with_watermark.save(f)使用方法: python watermart.py <图片地址>这个只是把文本嵌入到图片中的实现,其实也可以嵌入一个图片进去的。具体可以参考pillow官方文档:https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.alpha_composite
2025年03月02日
8 阅读
0 评论
0 点赞
2025-03-02
Python中对切片赋值原理分析
有这么个问题::t = [1, 2, 3] t[1:1] = [7] print t # 输出 [1, 7, 2, 3]谁会对列表这么进行赋值呢?但是对于这个输出结果的原因确实值得去再了解下,今天看看Python的源码,了解下原理是什么。注:本地下载的是Python2.7.6的代码,直接看这个。在Objects/listobject.c中有一个 PyList_SetSlice 函数,是这么写的::int PyList_SetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) { if (!PyList_Check(a)) { PyErr_BadInternalCall(); return -1; } return list_ass_slice((PyListObject *)a, ilow, ihigh, v); }有用的一句就是 list_ass_slice ,那么再来看看这个函数的代码::static int list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) { /* Because [X]DECREF can recursively invoke list operations on this list, we must postpone all [X]DECREF activity until after the list is back in its canonical shape. Therefore we must allocate an additional array, 'recycle', into which we temporarily copy the items that are deleted from the list. :-( */ PyObject *recycle_on_stack[8]; PyObject **recycle = recycle_on_stack; /* will allocate more if needed */ PyObject **item; PyObject **vitem = NULL; PyObject *v_as_SF = NULL; /* PySequence_Fast(v) */ Py_ssize_t n; /* # of elements in replacement list */ Py_ssize_t norig; /* # of elements in list getting replaced */ Py_ssize_t d; /* Change in size */ Py_ssize_t k; size_t s; int result = -1; /* guilty until proved innocent */ #define b ((PyListObject *)v) if (v == NULL) n = 0; else { if (a == b) { /* Special case "a[i:j] = a" -- copy b first */ v = list_slice(b, 0, Py_SIZE(b)); if (v == NULL) return result; result = list_ass_slice(a, ilow, ihigh, v); Py_DECREF(v); return result; } v_as_SF = PySequence_Fast(v, "can only assign an iterable"); if(v_as_SF == NULL) goto Error; /* 要赋值的长度n */ n = PySequence_Fast_GET_SIZE(v_as_SF); vitem = PySequence_Fast_ITEMS(v_as_SF); } if (ilow < 0) ilow = 0; else if (ilow > Py_SIZE(a)) ilow = Py_SIZE(a); if (ihigh < ilow) ihigh = ilow; else if (ihigh > Py_SIZE(a)) ihigh = Py_SIZE(a); norig = ihigh - ilow; assert(norig >= 0); d = n - norig; if (Py_SIZE(a) + d == 0) { Py_XDECREF(v_as_SF); return list_clear(a); } item = a->ob_item; /* recycle the items that we are about to remove */ s = norig * sizeof(PyObject *); if (s > sizeof(recycle_on_stack)) { recycle = (PyObject **)PyMem_MALLOC(s); if (recycle == NULL) { PyErr_NoMemory(); goto Error; } } memcpy(recycle, &item[ilow], s); if (d < 0) { /* Delete -d items */ memmove(&item[ihigh+d], &item[ihigh], (Py_SIZE(a) - ihigh)*sizeof(PyObject *)); list_resize(a, Py_SIZE(a) + d); item = a->ob_item; } else if (d > 0) { /* Insert d items */ k = Py_SIZE(a); if (list_resize(a, k+d) < 0) goto Error; item = a->ob_item; printf("关键点\n"); /* 把list对应切片后一位的值之后的所有内容向后移动所赋值的大小 按照上面的python代码这里就是 原理的t: |1|2|3| 后移一位,因为len([7]) = 1 |1|空|2|3|把后两个移位 */ memmove(&item[ihigh+d], &item[ihigh], (k - ihigh)*sizeof(PyObject *)); } /* 赋值操作,即把[7]赋值到t里的对应位置上 ilow是1, n是1 */ for (k = 0; k < n; k++, ilow++) { PyObject *w = vitem[k]; Py_XINCREF(w); item[ilow] = w; } for (k = norig - 1; k >= 0; --k) Py_XDECREF(recycle[k]); result = 0; Error: if (recycle != recycle_on_stack) PyMem_FREE(recycle); Py_XDECREF(v_as_SF); return result; #undef b }源码内有详细注释,编程问题的研究最好的解释还是源码。
2025年03月02日
7 阅读
0 评论
0 点赞
2025-03-02
深究Python中的asyncio库
Asyncio ——gather vs wait在Asyncio中不止可以多次使用asyncio.gather,还有另外一个用法是asyncio.wait,他们都可以让多个协程并发执行。那为什么提供2个方法呢?他们有什么区别,适用场景是怎么样的呢?我们先看2个协程的例子:async def a(): print('Suspending a') await asyncio.sleep(3) print('Resuming a') return 'A' async def b(): print('Suspending b') await asyncio.sleep(1) print('Resuming b') return 'B'在IPython里面用gather执行一下:In : return_value_a, return_value_b = await asyncio.gather(a(), b()) Suspending a Suspending b Resuming b Resuming a In : return_value_a, return_value_b Out: ('A', 'B')Ok,asyncio.gather方法的名字说明了它的用途,gather的意思是「搜集」,也就是能够收集协程的结果,而且要注意,它会按输入协程的顺序保存的对应协程的执行结果。接着我们说asyncio.await,先执行一下:In : done, pending = await asyncio.wait([a(), b()]) Suspending b Suspending a Resuming b Resuming a In : done Out: {<Task finished coro=<a() done, defined at <ipython-input-5-5ee142734d16>:1> result='A'>, <Task finished coro=<b() done, defined at <ipython-input-5-5ee142734d16>:8> result='B'>} In : pending Out: set() In : task = list(done)[0] In : task Out: <Task finished coro=<b() done, defined at <ipython-input-5-5ee142734d16>:8> result='B'> In : task.result() Out: 'B'asyncio.wait的返回值有2项,第一项表示完成的任务列表(done),第二项表示等待(Future)完成的任务列表(pending),每个任务都是一个Task实例,由于这2个任务都已经完成,所以可以执行task.result()获得协程返回值。Ok, 说到这里,总结下它俩的区别的第一层区别:asyncio.gather封装的Task全程黑盒,只告诉你协程结果。asyncio.wait会返回封装的Task(包含已完成和挂起的任务),如果你关注协程执行结果你需要从对应Task实例里面用result方法自己拿。为什么说「第一层区别」,asyncio.wait看名字可以理解为「等待」,所以返回值的第二项是pending列表,但是看上面的例子,pending是空集合,那么在什么情况下,pending里面不为空呢?这就是第二层区别:asyncio.wait支持选择返回的时机。asyncio.wait支持一个接收参数return_when,在默认情况下,asyncio.wait会等待全部任务完成(return_when='ALL_COMPLETED'),它还支持FIRST_COMPLETED(第一个协程完成就返回)和FIRST_EXCEPTION(出现第一个异常就返回):In : done, pending = await asyncio.wait([a(), b()], return_when=asyncio.tasks.FIRST_COMPLETED) Suspending a Suspending b Resuming b In : done Out: {<Task finished coro=<b() done, defined at <ipython-input-5-5ee142734d16>:8> result='B'>} In : pending Out: {<Task pending coro=<a() running at <ipython-input-5-5ee142734d16>:3> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x108065e58>()]>>}看到了吧,这次只有协程b完成了,协程a还是pending状态。在大部分情况下,用asyncio.gather是足够的,如果你有特殊需求,可以选择asyncio.wait,举2个例子:需要拿到封装好的Task,以便取消或者添加成功回调等业务上需要FIRST_COMPLETED/FIRST_EXCEPTION即返回的asyncio.create_task vs loop.create_task vs asyncio.ensure_future创建一个Task一共有3种方法,如这小节的标题。在上篇文章我说过,从Python 3.7开始可以统一的使用更高阶的asyncio.create_task。其实asyncio.create_task就是用的loop.create_task:def create_task(coro): loop = events.get_running_loop() return loop.create_task(coro)loop.create_task接受的参数需要是一个协程,但是asyncio.ensure_future除了接受协程,还可以是Future对象或者awaitable对象:如果参数是协程,其实底层还是用的loop.create_task,返回Task对象如果是Future对象会直接返回如果是一个awaitable对象会await这个对象的__await__方法,再执行一次ensure_future,最后返回Task或者Future所以就像ensure_future名字说的,确保这个是一个Future对象:Task是Future 子类,前面说过一般情况下开发者不需要自己创建Future其实前面说的asyncio.wait和asyncio.gather里面都用了asyncio.ensure_future。对于绝大多数场景要并发执行的是协程,所以直接用asyncio.create_task就足够了~下一节:深究Python中的asyncio库-shield函数
2025年03月02日
6 阅读
0 评论
0 点赞
2025-03-02
深究Python中的asyncio库
shieldasyncio.shield,用它可以屏蔽取消操作。一直到这里,我们还没有见识过Task的取消。看一个例子:In : loop = asyncio.get_event_loop() In : task1 = loop.create_task(a()) In : task2 = loop.create_task(b()) In : task1.cancel() Out: True In : await asyncio.gather(task1, task2) Suspending a Suspending b --------------------------------------------------------------------------- CancelledError Traceback (most recent call last) cell_name in async-def-wrapper() CancelledError:在上面的例子中,task1被取消了后再用asyncio.gather收集结果,直接抛CancelledError错误了。这里有个细节,gather支持return_exceptions参数:In : await asyncio.gather(task1, task2, return_exceptions=True) Out: [concurrent.futures._base.CancelledError(), 'B']可以看到,task2依然会执行完成,但是task1的返回值是一个CancelledError错误,也就是任务被取消了。如果一个创建后就不希望被任何情况取消,可以使用asyncio.shield保护任务能顺利完成。不过要注意一个陷阱,先看错误的写法:In : task1 = asyncio.shield(a()) In : task2 = loop.create_task(b()) In : task1.cancel() Out: True In : await asyncio.gather(task1, task2, return_exceptions=True) Suspending a Suspending b Resuming b Out: [concurrent.futures._base.CancelledError(), 'B']可以看到依然是CancelledError错误,且协程a未执行完成,正确的用法是这样的:In : task1 = asyncio.shield(a()) In : task2 = loop.create_task(b()) In : ts = asyncio.gather(task1, task2, return_exceptions=True) In : task1.cancel() Out: True In : await ts Suspending a Suspending b Resuming a Resuming b Out: [concurrent.futures._base.CancelledError(), 'B']可以看到虽然结果是一个CancelledError错误,但是看输出能确认协程实际上是执行了的。所以正确步骤是:先创建 GatheringFuture 对象 ts取消任务await tsasynccontextmanager如果你了解Python,之前可能听过或者用过contextmanager ,一个上下文管理器。通过一个计时的例子就理解它的作用:from contextlib import contextmanager async def a(): await asyncio.sleep(3) return 'A' async def b(): await asyncio.sleep(1) return 'B' async def s1(): return await asyncio.gather(a(), b()) @contextmanager def timed(func): start = time.perf_counter() yield asyncio.run(func()) print(f'Cost: {time.perf_counter() - start}')timed函数用了contextmanager装饰器,把协程的运行结果yield出来,执行结束后还计算了耗时:In : from contextmanager import * In : with timed(s1) as rv: ...: print(f'Result: {rv}') ...: Result: ['A', 'B'] Cost: 3.0052654459999992大家先体会一下。在Python 3.7添加了asynccontextmanager,也就是异步版本的contextmanager,适合异步函数的执行,上例可以这么改:@asynccontextmanager async def async_timed(func): start = time.perf_counter() yield await func() print(f'Cost: {time.perf_counter() - start}') async def main(): async with async_timed(s1) as rv: print(f'Result: {rv}') In : asyncio.run(main()) Result: ['A', 'B'] Cost: 3.00414147500004async版本的with要用async with,另外要注意yield await func()这句,相当于yield + await func()PS: contextmanager 和 asynccontextmanager 最好的理解方法是去看源码注释下一节:深究Python中的asyncio库-函数的回调与调度
2025年03月02日
8 阅读
0 评论
0 点赞
1
...
12
13
14
...
17