30个Python编程使用技巧,可以让你的工作事半功倍!

334 篇文章 4 订阅
212 篇文章 1 订阅

今天分享一些 Python 技巧,它可以让你的代码更优雅高效,方便解决日常 Python 脚本工作流程中可能遇到的一些基本Python问题。

1、如何使用 print 输出日志

初学者喜欢使用 print 来调试代码,并记录程序运行过程。

但是 print 只会将内容输出到终端上,不能持久化到日志文件中,并不利于问题的排查。

如果你热衷于使用 print 来调试代码(虽然这并不是最佳做法),记录程序运行过程,那么下面介绍的这个 print 用法,可能会对你有用。

Python 3 中的 print 作为一个函数,由于可以接收更多的参数,所以功能变为更加强大,指定一些参数可以将 print 的内容输出到日志文件中。

>>> with open('test.log', mode='w') as f:
...     print('hello, python', file=f, flush=True)
>>> exit()

$ cat test.log
hello, python

2、正则表达式基本配方

import re
pattern = re.compile(r”\d\d”)
print(re.search(pattern,"Let's find the number 23").group())
# or
print(re.findall(pattern, “Let's find the number 23”))[0]
# Outputs
'23'
'23'

Regex 对于许多 python 管道来说都是必须的,所以记住***核心Regex方法***很有用处。

3、将嵌套 for 循环写成单行

我们经常会如下这种嵌套的 for 循环代码

list1 = range(1,3)
list2 = range(4,6)
list3 = range(7,9)
for item1 in list1:
    for item2 in list2:
          for item3 in list3:
              print(item1+item2+item3)

这里仅仅是三个 for 循环,在实际编码中,有可能会有更层。这样的代码,可读性非常的差,很多人不想这么写,可又没有更好的写法。

这里介绍一种常用的写法,***使用 itertools 这个库***来实现更优雅易读的代码。

from itertools import product
list1 = range(1,3)
list2 = range(4,6)
list3 = range(7,9)
for item1,item2,item3 in product(list1, list2, list3):
    print(item1+item2+item3)

输出:
$ python demo.py
12
13
13
14
13
14
14
15

4、如何在运行状态查看源代码?

查看函数的源代码,我们通常会使用 IDE 来完成。比如在 PyCharm 中,你可以 Ctrl + 鼠标点击 进入函数的源代码。

那如果没有 IDE 呢?想使用一个函数时,如何知道这个函数需要接收哪些参数呢?

这时可以使用 *inspect 来代替 IDE* 帮助你完成这些事

# demo.py
import inspect


def add(x, y):
    return x + y

print("===================")
print(inspect.getsource(add))

运行结果:
$ python demo.py
===================
def add(x, y):
    return x + y

这里我想先说一个点:不管你是通过各种渠道学Python还是自学?还是说你大学在学习,甚至于说有别的编程的基础,一定要注重一个东西:*完整的知识体系*。对于每一个自学的人,按照这个体系去打好基础,你未来的路会走得更稳重。

适用人群:零基础 / 基础不扎实者,学Python都从这里开始

零基础如何开始学习 Python?看完这篇从小白变大牛【内附干货资料】

5、最快查看包搜索路径的方式

当你使用 import 导入一个包或模块时,Python 会去一些目录下查找,而这些目录是有优先级顺序的,正常人会使用 sys.path 查看。

>>> import sys
>>> from pprint import pprint   
>>> pprint(sys.path)
['',
 '/usr/local/Python3.7/lib/python37.zip',
 '/usr/local/Python3.7/lib/python3.7',
 '/usr/local/Python3.7/lib/python3.7/lib-dynload',
 '/home/wangbm/.local/lib/python3.7/site-packages',
 '/usr/local/Python3.7/lib/python3.7/site-packages']
>>> 

有没有更快的方式呢?一行命令即可解决!

[wangbm@localhost ~]$ python3 -m site
sys.path = [
    '/home/wangbm',
    '/usr/local/Python3.7/lib/python37.zip',
    '/usr/local/Python3.7/lib/python3.7',
    '/usr/local/Python3.7/lib/python3.7/lib-dynload',
    '/home/wangbm/.local/lib/python3.7/site-packages',
    '/usr/local/Python3.7/lib/python3.7/site-packages',
]
USER_BASE: '/home/wangbm/.local' (exists)
USER_SITE: '/home/wangbm/.local/lib/python3.7/site-packages' (exists)
ENABLE_USER_SITE: True

从输出你可以发现,这个列的路径会比 sys.path 更全,它包含了用户环境的目录。

6、如何快速计算函数运行时间

计算一个函数的运行时间,有人可能会这样写:

import time

start = time.time()

# run the function

end = time.time()
print(end-start)

你看看你为了计算函数运行时间,写了几行代码了?

有没有可以更方便计算的呢?

***内置模块叫 timeit!***使用它,只用一行代码即可

import time
import timeit

def run_sleep(second):
    print(second)
    time.sleep(second)

# 只用这一行
print(timeit.timeit(lambda :run_sleep(2), number=5))

运行结果
2
2
2
2
2
10.020059824

7、partial 函数

from functools import partial
def multiply(x,y):
    return x*y
dbl = partial(multiply,2)
print(dbl)
print(dbl(4))
# Outputs

functools.partial(<function multiply at 0x7f16be9941f0>, 2)
8

在这里,我们创建一个函数,它复制另一个函数,但使用的参数比原始函数少,这样就可以使用它将该参数应用于多个不同的参数。

8、使用 hasattr() 内置方法获取object属性

class SomeClass:
    def __init__(self):
    self.attr1 = 10
    def attrfunction(self):
        print("Attreibute")
hasattr(SomeClass, "attrfunction")
# Output 
True

9、使用 defaultdict 和 lambda 函数创建字典

from collections import defaultdict
import numpy as np
q = defaultdict(lambda: np.zeros(5))
# Example output
In : q[0]
Out: array([0., 0., 0., 0., 0.])

defaultdicts不会引发KeyError,任何不存在的键都会获取默认工厂返回的值。
在上述代码,默认工厂是一个lambda函数,它为给定的任何键返回一个默认NumPy数组,其中包含5个零。

10、使用集合从两个列表中获得差异

list1 = [1,2,3,4,5]
list2 = [3,4,5]
print(list(set(list1) — set(list2)))
# or
print(set(lista1).difference(set(lista2)))
# Outputs
[1,2]
{1,2}

在这里,集合有助于获得两个python列表之间的差异,这两个列表既是一个列表,也是一个集合。

11、使用isinstance()检查变量是否为给定类型

isinstance(1, int)
#Output
True

12、使用map()打印列表中的数字

一种比循环打印列表内容更快更有效的方法

list1 = [1,2,3]
list(map(print, list1))
# Output
1
2
3

13、使用.join()方法格式化datetime日期

from datetime import datetime
date = datetime.now()
print("-".join([str(date.year), str(date.month), str(date.day)])

14、将两个具有相同规则的列表随机化

import numpy as np
x = np.arange(100)
y = np.arange(100,200,1)
idx = np.random.choice(np.arange(len(x)), 5, replace=False)
x_sample = x[idx]
y_sample = y[idx]
print(x_sample)
print(y_sample)
# Outputs
array([68, 87, 41, 16,  0])
array([168, 187, 141, 116, 100])

15、对输入的字符串“消毒”

对用户输入的内容“消毒”,这问题几乎适用于你编写的所有程序。

通常将字符转换为小写或大写就足够了,有时还可以使用正则表达式来完成工作,但是对于复杂的情况,还有更好的方法:

user_input = "This\nstring has\tsome whitespaces...\r\n"
 
character_map = {
 ord('\n') : ' ',
 ord('\t') : ' ',
 ord('\r') : None
}
user_input.translate(character_map)  # This string has some whitespaces... "

在上述代码,可以看到空格字符“ \n”和“ \t”被单个空格替换了,而“ \r”则被完全删除。

这是一个简单的示例,但是我们可以更进一步,使用unicodedata 库及其 combining() 函数,来生成更大的重映射表(remapping table),并用它来删除字符串中所有的重音。

16、反转字符串

编写一些代码来反转字符串

def reverse_string(string):
     result=""
     for c in range(len(string),-1,-1):
          result = result + string[c]
     return result 

看起来有点乱吧, 用另一种方式来表达:

def reverse_string(string):
    result = [ string[c] for c in range(len(string),-1,-1)]
    return "".join(result)

看起来不错吧,其实使用切片的方法可以更好,方法如下:

def reverse_string(string):
    return string[::-1]

17、将数字与数字进行求和

将数字与数字进行求和,这是一个非常简单的问题,我们可以用传统方法解决这个问题:

def sum_a_num(num):
    sum = 0
    while num > 0:
        sum+= num%10
        num//=10
    return sum

这是可以的,但在紧张的情况下,最终可能会与运算符发生拼写错误或错误,最终得到错误的结果,并花费数小时尝试调试代码。

想要避免这种情况,有一个更好的方法做到这一点:

def sum_a_num(num):
    return sum(list(map(int,str(num))))

上述代码所做的是:

  • 将 num 转换为字符串;
  • map() 函数在字符串上遍数,并将每个字符转换为整数;
  • list() 函数将映射对象转换为列表,然后求和;
num = 2367
str(num) = '2367'
list(map(int,str(num))) = [2,3,6,7]
sum(list(map(int(str(num)))) = 18

18、仅支持关键字参数(kwargs)的函数

当需要函数提供(强制)更清晰的参数时,创建仅支持关键字参数的函数,可能会挺有用:

def test(*, a, b):
 pass
 
test("value for a", "value for b")  # TypeError: test() takes 0 positional arguments...
test(a="value", b="value 2")  # Works...

如上所见,可以在关键字参数之前,放置单个 * 参数来轻松解决此问题,如果我们将位置参数放在 * 参数之前,则显然也可以有位置参数。

19、使用slice函数命名切片

使用大量硬编码的索引值会很快搞乱维护性和可读性,一种做法是对所有索引值使用常量,但是我们可以做得更好:

# ID   First Name   Last Name
line_record = "2        John         Smith"
 
ID = slice(0, 8)
FIRST_NAME = slice(9, 21)
LAST_NAME = slice(22, 27)
 
name = f"{line_record[FIRST_NAME].strip()} {line_record[LAST_NAME].strip()}"
# name == "John Smith"

在此例中,我们可以避免神秘的索引,方法是先使用 slice 函数命名它们,然后再使用它们,还可以通过 .start、.stop和 .stop 属性,来了解 slice 对象的更多信息。

20、在运行时提示用户输入密码

许多命令行工具或脚本需要用户名和密码才能操作。因此,如果你碰巧写了这样的程序,你可能会发现 getpass 模块很有用:

import getpass
 
user = getpass.getuser()
password = getpass.getpass()
# Do Stuff...

这个非常简单的包通过提取当前用户的登录名,可以提示用户输入密码,但是须注意,并非每个系统都支持隐藏密码。Python 会尝试警告你,因此切记在命令行中阅读警告信息。

21、用__slots__节省内存

如果你曾经编写过一个程序,该程序创建了某个类的大量实例,那么你的程序突然就会需要大量内存。那是因为 Python 使用字典来表示类实例的属性,这能使其速度变快,但内存不是很高效。

通常这不是个问题,但是,如果你的程序遇到了问题,你可以尝试使用__slots__ :

class Person:
    __slots__ = ["first_name", "last_name", "phone"]
    def __init__(self, first_name, last_name, phone):
    self.first_name = first_name
    self.last_name = last_name
    self.phone = phone

这里发生的是,当我们定义__slots__属性时,Python 使用固定大小的小型数组,而不是字典,这大大减少了每个实例所需的内存。

使用__slots__还有一些缺点——我们无法声明任何新的属性,并且只能使用在__slots__中的属性。
同样,带有__slots__的类不能使用多重继承。

22、限制CPU和内存使用量

如果不是想优化程序内存或 CPU 使用率,而是想直接将其限制为某个固定数字,那么 Python 也有一个库能做到:

import signal
import resource
import os
 
# To Limit CPU time
def time_exceeded(signo, frame):
 print("CPU exceeded...")
 raise SystemExit(1)
 
def set_max_runtime(seconds):
 # Install the signal handler and set a resource limit
 soft, hard = resource.getrlimit(resource.RLIMIT_CPU)
 resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard))
 signal.signal(signal.SIGXCPU, time_exceeded)
 
# To limit memory usage
def set_max_memory(size):
 soft, hard = resource.getrlimit(resource.RLIMIT_AS)
 resource.setrlimit(resource.RLIMIT_AS, (size, hard))

我们可以看到两个选项,可设置最大 CPU 运行时间和内存使用上限。

对于 CPU 限制,我们首先获取该特定资源(RLIMIT_CPU)的软限制和硬限制,然后通过参数指定的秒数和先前获取的硬限制来设置它。

最后,如果超过 CPU 时间,我们将注册令系统退出的信号。至于内存,我们再次获取软限制和硬限制,并使用带有 size 参数的setrlimit 和获取的硬限制对其进行设置。

下面重点介绍几个和迭代相关的使用技巧,可以方便提升大家的工作效率。

很多人学Python搞不清楚方向,不同目的,你学习的侧重点和难易程度都不同,必须要有针对性、选择性地学!这样也能提高你自己的学习效率。

Python学习的方法

Iterables是一个需要我们牢记的概念,因为接下来我们展示的许多技巧都使用itertools包。itertools模块提供了一些函数,用于接收Iterable对象,而不仅仅是打印逐个对象。

iterables的示例包括:

  • 所有序列类型(如list、str和tuple)
  • 一些非序列类型,如dict、文件对象以及类的实现中定义了__iter__()方法

在工作学习中,我们经常会需要使用一个简单的函数来实现从一个list来生成新的list、set或dict,此时我们就会用到iterables概念。

23、举例来说:

生成List:

names = ['John', 'Bard', 'Jessica' 'Andres']
lower_names = [name.lower() for name in names]

生成Set:

names = ['John', 'Bard', 'Jessica' 'Andres']
lower_names = {name.lower() for name in names}

生成Dict:

names = ['John', 'Bard', 'Jessica' 'Andres']
lower_names = {name:name.lower() for name in names}

个人建议:

仅当for语句、函数调用和方法调用的数量较少时使用

24、有时我们需要获得两个列表对象之间的所有可能组合,我们可能首先想到的是:

l1 = [1, 2, 3]
l2 = [4, 5, 6]
combinations = []
for e1 in l1:
  for e2 in l2:
    combinations.append((e1, e2))

或者简化一下

combinations = [(e1, e2) for e1 in l1 for e2 in l1]

上述实现已经很简洁了,但标准库itertools提供product函数,从而提供了相同的结果。

from itertools import product
l1 = [1, 2, 3]
l2 = [4, 5, 6]
combinatios = product(l1, l2)

25、假设有一个元素列表,我们需要在每对相邻元素之间比较或应用一些操作,这有时称为2个元素的滑动窗口。

可以采用以下方式:

from itertools import tee
from typing import Iterable

def window2(iterable: Iterable):
  it, offset = tee(iter(iterable))
  next(offset)
  return zip(it, offset)
l = [1, 2, 3, 4, 5, 6]
dd = window2(l)
for a in dd:
    print(a) 


运行结果:
(1, 2)
(2, 3)
(3, 4)
(4, 5)
(5, 6)

26、当需要一个类来存储信息,又觉得创建一个类并定义其__init__()函数太麻烦,不妨选择使用dataclass。

from dataclasses import dataclass
@dataclass
class Person:
  name: str
  age: int
  address: str

上述代码创建了一个具有默认构造函数的类,该类以与声明相同的顺序接收相应字段的赋值。

person = Person(name='John', age=12, address='nanjing street')

dataclass的另一个优点是,默认情况下,会生成特殊方法,如__str__、repr、__eq__等。

注意:dataclasses构造对象时并不执行数据类型的检查

27、假如我们有一个dataclass,需要验证输入数据是否符合类型注释。

在这种情况下,安装第三方软件包pydantic并将from dataclasses import dataclass 替换为 from pydantic.dataclasses import dataclass 即可。

from pydantic.dataclasses import dataclass
@dataclass
class Person:
  name: str
  age: int
  address: str

这将生成一个类,该类具有根据成员变量声明的类型进行输入数据的解析和类型验证。Pydantic在运行时强制执行类型提示,并在数据无效时提供友好的错误提醒。

28、如果我们对两个list中的元素对做相应的函数处理

我们最容易想到的方法:

l1 = [1, 2, 3]
l2 = [4, 5, 6]
for (e1, e2) in zip(l1, l2):
  f(e1, e2)

但使用函数map可以让代码更加简洁一些;

l1 = [1, 2, 3]
l2 = [4, 5, 6]
map(f, l1, l2)

29、从一个list中随机选择一个元素

此时我们使用random.choice

from random import choice
l = [1, 2, 3]
random = choice(l)

如果需要随机选择多个元素呢?当然是使用*random.choices*

from random import choices
l = [1, 2, 3, 4, 5]
random_elements = choices(l, k=3)

代码中的参数k为我们随机选择元素的个数;

30、跳过可迭代对象的开始

有时候你必须处理某些文件,它们以可变数量的不需要的行(例如注释)为开头。

string_from_file = """
// Author: ...
// License: ...
//
// Date: ...
Actual content...
"""
 
import itertools
 
for line in itertools.dropwhile(lambda line:line.startswith("//"), string_from_file.split("\n")):
    print(line)

这段代码仅会打印在初始的注释部分之后的内容,如果我们只想丢弃迭代器的开头部分(在此例中是注释),并且不知道有多少内容,那么此方法很有用。

关于Python技术储备

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

包括:Python激活码+安装包、Python web开发,Python爬虫,Python数据分析,人工智能、机器学习等习教程。带你从零基础系统性的学好Python!

一、Python学习大纲

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
在这里插入图片描述

二、Python必备开发工具

在这里插入图片描述

三、入门学习视频

四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。在这里插入图片描述

五、python副业兼职与全职路线

在这里插入图片描述

上述这份完整版的Python全套学习资料已经上传CSDN官方,朋友们如果需要可以微信扫描下方CSDN官方认证二维码 即可领取↓↓↓

👉[[CSDN大礼包:《python兼职资源&全套学习资料》免费分享]]安全链接,放心点击

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值