脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - python使用数字与字符串方法技巧

python使用数字与字符串方法技巧

2022-11-09 11:07Steven迪文 Python

这篇文章主要介绍了python使用数字与字符串方法技巧,文章内容介绍详细具有一的参考价值,需要的小伙伴可以参考一下

1. 少使用数字字面量

下面的代码使用数字来作为判断条件的语句,如果你从别人手里接手过这部分代码,很难第一时间理解它的意义。

?
1
2
3
4
5
6
7
8
9
def mark_trip_as_featured(trip):
    """将某个旅程添加到推荐栏目
    """
    if trip.source == 11:
        do_some_thing(trip)
    elif trip.source == 12:
        do_some_other_thing(trip)
    ... ...
    return

我们可以使用枚举的方式,对这些数字部分做一些说明。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from enum import IntEnum
 
class TripSource(IntEnum):
    FROM_WEBSITE = 11
    FROM_IOS_CLIENT = 12
 
 
def mark_trip_as_featured(trip):
    if trip.source == TripSource.FROM_WEBSITE:
        do_some_thing(trip)
    elif trip.source == TripSource.FROM_IOS_CLIENT:
        do_some_other_thing(trip)
    ... ...
    return

将重复出现的数字定义成枚举类型,不仅改善了代码的可读性,还降低了代码出现 Bug 的机率。

当然不是所有的数字都需要用到枚举说明,像常见数字下标 0 和 -1
就不需要。

2. 裸字符串处理的问题

“ 裸字符串处理 ” 这里指只使用基本的加减乘除和循环、配合内置函数/方法来操作字符串,获得我们需要的结果。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def fetch_users(conn, min_level=None, gender=None, has_membership=False, sort_field="created"):
    """获取用户列表
   
    :param int min_level: 要求的最低用户级别,默认为所有级别
    :param int gender: 筛选用户性别,默认为所有性别
    :param int has_membership: 筛选所有会员/非会员用户,默认非会员
    :param str sort_field: 排序字段,默认为按 created "用户创建日期"
    :returns: 列表:[(User ID, User Name), ...]
    """
    # 一种古老的 SQL 拼接技巧,使用 "WHERE 1=1" 来简化字符串拼接操作
    # 区分查询 params 来避免 SQL 注入问题
    statement = "SELECT id, name FROM users WHERE 1=1"
    params = []
    if min_level is not None:
        statement += " AND level >= ?"
        params.append(min_level)
    if gender is not None:
        statement += " AND gender >= ?"
        params.append(gender)
    if has_membership:
        statement += " AND has_membership == true"
    else:
        statement += " AND has_membership == false"
    
    statement += " ORDER BY ?"
    params.append(sort_field)
    return list(conn.execute(statement, params))

这样做虽然看起来简单,符合直觉,但是随着函数逻辑变得复杂,这段代码会变得容易出错。

更好的选择是利用一些开源的对象化模块来操作他们。
这里使用了 SQLAlchemy

?
1
2
3
4
5
6
7
8
9
10
def fetch_users_v2(conn, min_level=None, gender=None, has_membership=False, sort_field="created"):
    """获取用户列表
    """
    query = select([users.c.id, users.c.name])
    if min_level is not None:
        query = query.where(users.c.level >= min_level)
    if gender is not None:
        query = query.where(users.c.gender == gender)
    query = query.where(users.c.has_membership == has_membership).order_by(users.c[sort_field])
    return list(conn.execute(query))

其它的替换思路:

Q: 目标/源字符串是结构化的,遵循某种格式吗?

其它的开源的对象化模块。

  • SQL:SQLAlchemy
  • XML:lxml
  • JSON、YAML …

尝试使用模板引擎而不是复杂字符串处理逻辑来达到目的。

  • Jinja2
  • Mako
  • Mustache

3. 展开复杂的计算字面量表达式

?
1
2
3
4
5
def f1(delta_seconds):
    # 如果时间已经过去了超过 11 天,不做任何事
    if delta_seconds > 950400:
        return
    ...

“为什么我们不直接把代码写成 if delta_seconds < 11 * 24 * 3600: 呢?”

“性能”,答案一定会是“性能”。 Python 是一门解释型语言,所以预先计算出 950400 正是因为我们不想让每次对函数 f1 的调用都带上这部分的计算开销。

不过事实是:即使我们把代码改成 if delta_seconds < 11 * 24 * 3600:,函数也不会多出任何额外的开销。

当我们的代码中需要出现复杂计算的字面量时,请保留整个算式吧。它对性能没有任何影响,而且会增加代码的可读性。

?
1
2
3
def f1(delta_seconds):
    if delta_seconds < 11 * 24 * 3600:
        return

4.实用技巧

4.1布尔值也是数字

True False 可以当成 1 和 0 使用

?
1
2
3
4
5
6
>>> True + 1
2
>>> 1 / False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero

计数简化操作。

?
1
2
3
>>> l = [1, 2, 4, 5, 7]
>>> sum(i % 2 == 0 for i in l)
2

如果将某个布尔值表达式作为列表的下标使用,可以实现类似三元表达式的目的:

?
1
2
3
# 类似的三元表达式:"Javascript" if 2 > 1 else "Python"
>>> ["Python", "Javascript"][2 > 1]
'Javascript'

4.2改善字符串的可读性。

对于字符串我们常使用 \ 和 + 来讲字符串拆分成好几段。

还有一种简单的方法是用 ()。
用 ()括起来就可以随意拆行了。

?
1
2
3
4
s = (
    "There is something really bad happened during the process. "
    "Please contact your administrator."
)

对于多级缩进字符串:

可以调用其他的标准库来达到简化效果。

?
1
2
3
4
5
6
7
8
9
10
from textwrap import dedent
 
def main():
    if user.is_active:
        # dedent 将会缩进掉整段文字最左边的空字符串
        message = dedent("""\
            Welcome, today's movie list:
            - Jaw (1975)
            - The Shining (1980)
            - Saw (2004)""")

大数字也可以变得更加可阅读:

在数字之间加入下划线。

?
1
2
3
4
5
6
7
8
>>> 10_000_000.0  # 以“千”为单位划分数字
10000000.0
>>> 0xCAFE_F00D  # 16进制数字同样有效,4个一组更易读
3405705229
>>> 0b_0011_1111_0100_1110  # 二进制也有效
16206
>>> int('0b_1111_0000', 2)  # 处理字符串的时候也会正确处理下划线
240

4.3以 r 开头的内建字符串函数。

例如 : .split() 和 .rsplit() 的区别是,一个从左到右分割字符串,另一个是从右到左处理字符串。

合理使用一些现成 string 操作函数可以让工作事半功倍。

4.4 float (" inf ")

float ( " inf " ) float ( " -inf ") ,对应着无穷大和无穷小。

float( " -inf ") < 任意数值 < float( " inf ")

一些可以用上的场合。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# A. 根据年龄升序排序,没有提供年龄放在最后边
>>> users = {"tom": 19, "jenny": 13, "jack": None, "andrew": 43}
>>> sorted(users.keys(), key=lambda user: users.get(user) or float('inf'))
['jenny', 'tom', 'andrew', 'jack']
 
# B. 作为循环初始值,简化第一次判断逻辑
>>> max_num = float('-inf')
>>> # 找到列表中最大的数字
>>> for i in [23, 71, 3, 21, 8]:
...:    if i > max_num:
...:         max_num = i
...:
>>> max_num
71

5.常见误区

5.1“value += 1” 并非线程安全

如下:这个操作并不是线程安全的。

这个简单的累加语句,会被编译成包括取值和保存在内的好几个不同步骤。

而在多线程环境下,任意一个其他线程都有可能在其中某个步骤切入进来,阻碍你获得正确的结果。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def incr(value):
    value += 1
 
 
# 使用 dis 模块查看字节码
import dis
 
dis.dis(incr)
      0 LOAD_FAST                0 (value)
      2 LOAD_CONST               1 (1)
      4 INPLACE_ADD
      6 STORE_FAST               0 (value)
      8 LOAD_CONST               0 (None)
     10 RETURN_VALUE

常用 dis 模块去验证自己的操作,有时候,结果和我们预想的并不一样。

5.2字符串拼接并不慢

Python 的字符串拼接(+=)在 2.2 以及之前的版本确实很慢。
但之后的版本做了更新,效率已经大大提升,所有字符串的拼接还是可以使用的。

到此这篇关于python使用数字与字符串方法技巧的文章就介绍到这了,更多相关python数字与字符串内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/weixin_46442179/article/details/123559908

延伸 · 阅读

精彩推荐
  • Pythonpython获取android设备的GPS信息脚本分享

    python获取android设备的GPS信息脚本分享

    这篇文章主要介绍了python获取android设备的GPS信息脚本分享,本文直接给出实现代码,需要的朋友可以参考下 ...

    junjie9052019-11-23
  • PythonPython第三方库的安装方法总结

    Python第三方库的安装方法总结

    库library是一个泛称,一般值作为文件形式存在的模块以及以文件夹形式存在的包的合成,这里作了Python第三方库的安装方法总结,包括源码安装、包管理器安装...

    人世间7062020-08-25
  • PythonPython中的下划线详解

    Python中的下划线详解

    这篇文章主要介绍了Python中的下划线详解,本文讲解了单个下划线直接做变量名、单下划线前缀的名称、双下划线前缀的名称等内容,需要的朋友可以参考下...

    脚本之家5592020-07-17
  • Python基于python爬虫数据处理(详解)

    基于python爬虫数据处理(详解)

    下面小编就为大家带来一篇基于python爬虫数据处理(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    脚本之家3552020-11-16
  • Python详解Python中 __get__和__getattr__和__getattribute__的区别

    详解Python中 __get__和__getattr__和__getattribute__的区别

    __get__、__getattr__、__getattribute都是访问属性的方法,但作用不太相同,这里我们就来详解Python中 __get__和__getattr__和__getattribute__的区别:...

    luozhaoyu6112020-08-27
  • PythonPython测试框架pytest介绍

    Python测试框架pytest介绍

    这篇文章主要介绍了Python测试框架pytest介绍,Pytest是一个非常成熟的全功能的python测试框架,有简单灵活易上手、支持参数化等优点,下面其相关内容需要...

    软件测试君10582022-10-19
  • PythonPython3 操作符重载方法示例

    Python3 操作符重载方法示例

    这篇文章主要介绍了Python3 操作符重载方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    LZ_Luzhuo5362020-12-09
  • PythonPython基础之函数原理与应用实例详解

    Python基础之函数原理与应用实例详解

    这篇文章主要介绍了Python基础之函数原理与应用,结合具体实例形式详细分析了Python函数的定义、原理、参数、返回值、嵌套等相关概念与使用技巧,需要的...

    小飞侠v科比3172020-05-11