Ringkasan teknik klasik untuk menggunakan Python selicin sutera

WBOY
Lepaskan: 2022-03-25 19:21:57
ke hadapan
2441 orang telah melayarinya

Artikel ini membawa anda pengetahuan yang berkaitan tentang python Terutamanya meringkaskan dan memperkenalkan beberapa petua untuk meningkatkan prestasi Python, termasuk menggunakan peta untuk pemetaan fungsi, menggunakan set untuk mencari persimpangan, dll. Tunggu, saya. harap dapat membantu semua.

Ringkasan teknik klasik untuk menggunakan Python selicin sutera

Pembelajaran yang disyorkan: Tutorial pembelajaran Python

Cara mengukur masa pelaksanaan program

Mengenai Python Cara mengukur masa pelaksanaan program dengan tepat kelihatan mudah tetapi sebenarnya sangat rumit, kerana masa pelaksanaan program dipengaruhi oleh banyak faktor, seperti sistem pengendalian, versi Python, dan perkakasan yang berkaitan (prestasi CPU, bacaan memori dan kelajuan tulis), dsb. Apabila menjalankan versi bahasa yang sama pada komputer yang sama, faktor di atas adalah pasti, tetapi masa tidur program masih berubah, dan program lain yang dijalankan pada komputer juga akan mengganggu percubaan, jadi secara tegas ini ialah "Eksperimen tidak boleh diulang."

Dua perpustakaan yang paling mewakili yang saya tahu tentang pemasaan ialah masa dan masa.

Antaranya, terdapat tiga fungsi time(), perf_counter() dan process_time() dalam pustaka masa yang boleh digunakan untuk pemasaan (dalam saat), menambah akhiran _ns bermaksud pemasaan dalam nanosaat (sejak Python3 .7 permulaan). Terdapat fungsi clock() sebelum ini, tetapi ia telah dialih keluar selepas Python 3.3. Perbezaan antara ketiga-tiga di atas adalah seperti berikut:

  • masa() tidak begitu tinggi dalam ketepatan dan dipengaruhi oleh sistem Ia sesuai untuk mewakili tarikh dan masa atau masa program besar.
  • perf_counter() sesuai untuk menguji program yang lebih kecil dan akan mengira masa tidur().
  • process_time() sesuai untuk menguji program yang lebih kecil dan tidak mengira masa sleep().

Timeit mempunyai dua kelebihan berbanding pustaka masa:

  • timeit akan memilih pemasa terbaik berdasarkan sistem pengendalian dan versi Python anda.
  • timeit melumpuhkan kutipan sampah buat sementara waktu semasa tempoh tamat masa.

timeit.timeit(stmt='pass', setup='pass', timer=, number=1000000, globals=None) Perihalan parameter:

  • stmt= 'lulus': pernyataan atau fungsi yang memerlukan pemasaan.
  • setup=‘pass’: Kod untuk dijalankan sebelum stmt dilaksanakan. Biasanya, ia digunakan untuk mengimport beberapa modul atau mengisytiharkan beberapa pembolehubah yang diperlukan.
  • pemasa=: fungsi pemasa, lalai ialah time.perf_counter().
  • number=1000000: Bilangan kali untuk melaksanakan penyataan pemasaan, lalai ialah sejuta kali.
  • globals=Tiada: Tentukan ruang nama kod yang dilaksanakan.

Semua pemasaan dalam artikel ini menggunakan kaedah timeit, dan nombor pelaksanaan lalai ialah sejuta kali.

Mengapa anda mahu melaksanakannya berjuta kali? Kerana program ujian kami sangat singkat, jika kami tidak melaksanakannya berkali-kali, kami tidak akan dapat melihat perbezaannya sama sekali.

1. Gunakan map() untuk pemetaan fungsi

Exp1: Tukar huruf kecil dalam tatasusunan rentetan kepada huruf besar.

测试数组为 oldlist = ['life', 'is', 'short', 'i', 'choose', 'python']。
Salin selepas log masuk
  • Kaedah 1
newlist = []for word in oldlist:
    newlist.append(word.upper())
Salin selepas log masuk
  • Kaedah 2
list(map(str.upper, oldlist))
Salin selepas log masuk

Kaedah 1 memerlukan masa 0.5267724000000005s, kaedah dua mengambil masa 0.41462569999999843s dan prestasi dipertingkatkan sebanyak 21.29%

2. Gunakan set() untuk mencari persilangan

测试数组:a = [1,2,3,4,5],b = [2,4,6,8,10]。
Salin selepas log masuk
    Kaedah 1
overlaps = []for x in a:
    for y in b:
        if x == y:
            overlaps.append(x)
Salin selepas log masuk
    Kaedah 2
list(set(a) & set(b))
Salin selepas log masuk
Kaedah 1 memerlukan masa 0.9507264000000006s, kaedah dua mengambil masa 0.6148200999999993s, dan prestasi dipertingkatkan sebanyak 35.33%

Perihal sintaks set(): |, &, - masing-masing mewakili perbezaan set, persilangan dan persilangan

3. Gunakan sort() atau sorted() untuk mengisih

Kita boleh mengisih jujukan dalam banyak cara, tetapi sebenarnya, menulis sendiri algoritma pengisihan tidak berbaloi. Kerana kaedah sort() atau sorted() terbina dalam adalah cukup baik, dan kunci parameter boleh digunakan untuk melaksanakan fungsi yang berbeza, yang sangat fleksibel. Perbezaan antara kedua-duanya ialah kaedah sort() hanya ditakrifkan dalam senarai, manakala sorted() ialah kaedah global yang sah untuk semua urutan lelaran.

Exp3: Gunakan kaedah isihan dan isih() pantas untuk mengisih senarai yang sama.

测试数组:lists = [2,1,4,3,0]。
Salin selepas log masuk
    Kaedah 1
def quick_sort(lists,i,j):
    if i >= j:
        return list
    pivot = lists[i]
    low = i
    high = j    while i = pivot:
            j -= 1
        lists[i]=lists[j]
        while i 
Salin selepas log masuk
    Kaedah 2
lists.sort()
Salin selepas log masuk
Kaedah 1 memerlukan masa 2.4796975000000003s, kaedah dua mengambil masa 0.05551999999999424s, dan prestasi dipertingkatkan sebanyak 97.76%

Sebenarnya, kaedah sorted() mengambil masa 9.799s

9.799>8.393s Dapat dilihat bahawa sort() masih sangat berkuasa sebagai kaedah pengisihan khusus senarai Walaupun sorted() adalah lebih perlahan daripada yang pertama, ia adalah lebih baik kerana ia "tidak memilih" dan ia boleh digunakan untuk semua urutan yang boleh diulang.

Sambungan

: Bagaimana untuk mentakrifkan kaedah sort() atau sorted()1. Takrif melalui lambda

2. Melalui operator Itemgetter() yang mentakrifkan
#学生:(姓名,成绩,年龄)
students = [('john', 'A', 15),('jane', 'B', 12),('dave', 'B', 10)]students.sort(key = lambda student: student[0]) #根据姓名排序sorted(students, key = lambda student: student[0])
Salin selepas log masuk

import operator

students = [('john', 'A', 15),('jane', 'B', 12),('dave', 'B', 10)]students.sort(key=operator.itemgetter(0))sorted(students, key = operator.itemgetter(1, 0)) #先对成绩排序,再对姓名排序
Salin selepas log masuk
operator sesuai untuk pengisihan tatasusunan biasa, dan attrgetter() sesuai untuk pengisihan tatasusunan objek

3 melalui cmp_to_key(), yang paling Fleksibel

4 Gunakan collections.Counter() untuk mengira
import functools

def cmp(a,b):
    if a[1] != b[1]:
        return -1 if a[1]  b[2] else 1 #成绩姓名都相同,按照年龄降序排序 

students = [('john', 'A', 15),('john', 'A', 14),('jane', 'B', 12),('dave', 'B', 10)]sorted(students, key = functools.cmp_to_key(cmp))
Salin selepas log masuk

Exp4: Kira bilangan kali setiap aksara muncul dalam rentetan.

Susun atur ujian: sentence=‘hidup itu singkat, saya pilih ular sawa’.
  • 方法一
counts = {}for char in sentence:
    counts[char] = counts.get(char, 0) + 1
Salin selepas log masuk
  • 方法二
from collections import CounterCounter(sentence)
Salin selepas log masuk

方法一耗时 2.8105250000000055s,方法二耗时 1.6317423000000062s,性能提升 41.94% 

5.使用列表推导

列表推导(list comprehension)短小精悍。在小代码片段中,可能没有太大的区别。但是在大型开发中,它可以节省一些时间。

 Exp5:对列表中的奇数求平方,偶数不变。

测试数组:oldlist = range(10)。

  • 方法一
newlist = []for x in oldlist:
    if x % 2 == 1:
        newlist.append(x**2)
Salin selepas log masuk
  • 方法二
[x**2 for x in oldlist if x%2 == 1]
Salin selepas log masuk

方法一耗时 1.5342976000000021s,方法二耗时 1.4181957999999923s,性能提升 7.57% 

6.使用 join() 连接字符串

大多数人都习惯使用+来连接字符串。但其实,这种方法非常低效。因为,+操作在每一步中都会创建一个新字符串并复制旧字符串。更好的方法是用 join() 来连接字符串。关于字符串的其他操作,也尽量使用内置函数,如isalpha()、isdigit()、startswith()、endswith()等。

 Exp6:将字符串列表中的元素连接起来。

测试数组:oldlist = [‘life’, ‘is’, ‘short’, ‘i’, ‘choose’, ‘python’]。

  • 方法一
sentence = ""for word in oldlist:
    sentence += word
Salin selepas log masuk
  • 方法二
"".join(oldlist)
Salin selepas log masuk

方法一耗时 0.27489080000000854s,方法二耗时 0.08166570000000206s,性能提升 70.29% 

join还有一个非常舒服的点,就是它可以指定连接的分隔符,举个例子

oldlist = ['life', 'is', 'short', 'i', 'choose', 'python']sentence = "//".join(oldlist)print(sentence)
Salin selepas log masuk

life//is//short//i//choose//python

7.使用x, y = y, x交换变量

 Exp6:交换x,y的值。

测试数据:x, y = 100, 200。

  • 方法一
temp = x
x = y
y = temp
Salin selepas log masuk
  • 方法二
x, y = y, x
Salin selepas log masuk

方法一耗时 0.027853900000010867s,方法二耗时 0.02398730000000171s,性能提升 13.88% 

8.使用while 1取代while True

在不知道确切的循环次数时,常规方法是使用while True进行无限循环,在代码块中判断是否满足循环终止条件。虽然这样做没有任何问题,但while 1的执行速度比while True更快。因为它是一种数值转换,可以更快地生成输出。

 Exp8:分别用while 1和while True循环 100 次。

  • 方法一
i = 0while True:
    i += 1
    if i > 100:
        break
Salin selepas log masuk
  • 方法二
i = 0while 1:
    i += 1
    if i > 100:
        break
Salin selepas log masuk

方法一耗时 3.679268300000004s,方法二耗时 3.607847499999991s,性能提升1.94% 

9.使用装饰器缓存

将文件存储在高速缓存中有助于快速恢复功能。Python 支持装饰器缓存,该缓存在内存中维护特定类型的缓存,以实现最佳软件驱动速度。我们使用lru_cache装饰器来为斐波那契函数提供缓存功能,在使用fibonacci递归函数时,存在大量的重复计算,例如fibonacci(1)、fibonacci(2)就运行了很多次。而在使用了lru_cache后,所有的重复计算只会执行一次,从而大大提高程序的执行效率。

 Exp9:求斐波那契数列。

测试数据:fibonacci(7)。

  • 方法一
def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    return fibonacci(n - 1) + fibonacci(n-2)
Salin selepas log masuk
  • 方法二
import functools

@functools.lru_cache(maxsize=128)def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    return fibonacci(n - 1) + fibonacci(n-2)
Salin selepas log masuk

方法一耗时 3.955014900000009s,方法二耗时 0.05077979999998661s,性能提升 98.72% 

注意事项:

  • 缓存是按照参数作为键,也就说在参数不变时,被lru_cache装饰的函数只会执行一次。
  • 所有参数必须可哈希,例如list不能作为被lru_cache装饰的函数的参数。
import functools
 
@functools.lru_cache(maxsize=100)def demo(a, b):
    print('我被执行了')
    return a + bif __name__ == '__main__':
    demo(1, 2)
    demo(1, 2)
Salin selepas log masuk

我被执行了(执行了两次demo(1, 2),却只输出一次)

from functools import lru_cache
 
@lru_cache(maxsize=100)def list_sum(nums: list):
    return sum(nums)if __name__ == '__main__':
    list_sum([1, 2, 3, 4, 5])
Salin selepas log masuk

TypeError: unhashable type: ‘list’

functools.lru_cache(maxsize=128, typed=False)的两个可选参数:

  • maxsize代表缓存的内存占用值,超过这个值之后,就的结果就会被释放,然后将新的计算结果进行缓存,其值应当设为 2 的幂。

  • typed若为True,则会把不同的参数类型得到的结果分开保存。

10.减少点运算符(.)的使用

点运算符(.)用来访问对象的属性或方法,这会引起程序使用__getattribute__()和__getattr__()进行字典查找,从而带来不必要的开销。尤其注意,在循环当中,更要减少点运算符的使用,应该将它移到循环外处理。

这启发我们应该尽量使用from … import …这种方式来导包,而不是在需要使用某方法时通过点运算符来获取。其实不光是点运算符,其他很多不必要的运算我们都尽量移到循环外处理。

 Exp10:将字符串数组中的小写字母转为大写字母。

测试数组为 oldlist = [‘life’, ‘is’, ‘short’, ‘i’, ‘choose’, ‘python’]。

  • 方法一
newlist = []for word in oldlist:
    newlist.append(str.upper(word))
Salin selepas log masuk
  • 方法二
newlist = []upper = str.upperfor word in oldlist:
    newlist.append(upper(word))
Salin selepas log masuk

方法一耗时 0.7235491999999795s,方法二耗时 0.5475435999999831s,性能提升 24.33% 

11.使用for循环取代while循环

当我们知道具体要循环多少次时,使用for循环比使用while循环更好。

 Exp12:使用for和while分别循环 100 次。

  • 方法一
i = 0while i 
Salin selepas log masuk
  • 方法二
for _ in range(100):
    pass
Salin selepas log masuk

方法一耗时 3.894683299999997s,方法二耗时 1.0198077999999953s,性能提升73.82% 

12.使用Numba.jit加速计算

Numba 可以将 Python 函数编译码为机器码执行,大大提高代码执行速度,甚至可以接近 C 或 FORTRAN 的速度。它能和 Numpy 配合使用,在 for 循环中或存在大量计算时能显著地提高执行效率。

Exp12:求从 1 加到 100 的和。

  • 方法一
def my_sum(n):
    x = 0
    for i in range(1, n+1):
        x += i    return x
Salin selepas log masuk
  • 方法二
from numba import jit

@jit(nopython=True) def numba_sum(n):
    x = 0
    for i in range(1, n+1):
        x += i    return x
Salin selepas log masuk

方法一耗时 3.7199997000000167s,方法二耗时 0.23769430000001535s,性能提升 93.61% 

13.使用Numpy矢量化数组

矢量化是 NumPy 中的一种强大功能,可以将操作表达为在整个数组上而不是在各个元素上发生。这种用数组表达式替换显式循环的做法通常称为矢量化。

在 Python 中循环数组或任何数据结构时,会涉及很多开销。NumPy 中的向量化操作将内部循环委托给高度优化的 C 和 Fortran 函数,从而使 Python 代码更加快速。

 Exp13:两个长度相同的序列逐元素相乘。

测试数组:a = [1,2,3,4,5], b = [2,4,6,8,10]

  • 方法一
[a[i]*b[i] for i in range(len(a))]
Salin selepas log masuk
  • 方法二
import numpy as np
a = np.array([1,2,3,4,5])b = np.array([2,4,6,8,10])a*b
Salin selepas log masuk

方法一耗时 0.6706845000000214s,方法二耗时 0.3070132000000001s,性能提升 54.22% 

14.使用in检查列表成员

若要检查列表中是否包含某成员,通常使用in关键字更快。

 Exp14:检查列表中是否包含某成员。

测试数组:lists = [‘life’, ‘is’, ‘short’, ‘i’, ‘choose’, ‘python’]

  • 方法一
def check_member(target, lists):
    for member in lists:
        if member == target:
            return True    return False
Salin selepas log masuk
  • 方法二
if target in lists:
    pass
Salin selepas log masuk

方法一耗时 0.16038449999999216s,方法二耗时 0.04139250000000061s,性能提升 74.19% 

15.使用itertools库迭代

itertools是用来操作迭代器的一个模块,其函数主要可以分为三类:无限迭代器、有限迭代器、组合迭代器。

Exp15:返回列表的全排列。

测试数组:[“Alice”, “Bob”, “Carol”]

  • 方法一
def permutations(lst):
    if len(lst) == 1 or len(lst) == 0:
        return [lst]
    result = []
    for i in lst:
        temp_lst = lst[:]
        temp_lst.remove(i)
        temp = permutations(temp_lst)
        for j in temp:
            j.insert(0, i)
            result.append(j)
    return result
Salin selepas log masuk
  • 方法二
import itertools
itertools.permutations(["Alice", "Bob", "Carol"])
Salin selepas log masuk

方法一耗时 3.867292899999484s,方法二耗时 0.3875405000007959s,性能提升 89.98% 

结语

根据上面的测试数据,我绘制了下面这张实验结果图,可以更加直观的看出不同方法带来的性能差异。

Ringkasan teknik klasik untuk menggunakan Python selicin sutera
从图中可以看出,大部分的技巧所带来的性能增幅还是比较可观的,但也有少部分技巧的增幅较小(例如编号5、7、8,其中,第 8 条的两种方法几乎没有差异)。

总结下来,我觉得其实就是下面这两条原则:

1.尽量使用内置库函数

内置库函数由专业的开发人员编写并经过了多次测试,很多库函数的底层是用C语言开发的。因此,这些函数总体来说是非常高效的(比如sort()、join()等),自己编写的方法很难超越它们,还不如省省功夫,不要重复造轮子了,何况你造的轮子可能更差。所以,如果函数库中已经存在该函数,就直接拿来用。

2.尽量使用优秀的第三方库

有很多优秀的第三方库,它们的底层可能是用 C 和 Fortran 来实现的,像这样的库用起来绝对不会吃亏,比如前文提到的 Numpy 和 Numba,它们带来的提升都是非常惊人的。类似这样的库还有很多,比如Cython、PyPy等,这里我只是抛砖引玉。

其实加快 Python 代码执行速度的方法还有很多,比如避免使用全局变量、使用最新版本、使用合适的数据结构、利用if条件的惰性等等,我这里就不一一例举了。这些方法都需要我们亲身去实践才会有深刻的感受和理解,但最根本的方法就是保持我们对编程的热情和对最佳实践的追求,这才是我们能不断突破自我、勇攀高峰的不竭动力源泉!

Pembelajaran yang disyorkan: tutorial pembelajaran python

Atas ialah kandungan terperinci Ringkasan teknik klasik untuk menggunakan Python selicin sutera. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:csdn.net
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!