Python基础

提示

对有一定的C语言基础,想学Python的同学,可以参考这篇文章。

1. 简介

Python 是一种高级编程语言,由 Guido van Rossum 在 1989 年创建,并于 1991 年首次公开发行。Python 以其简洁易读的语法、丰富的库和框架、强大的社区支持等特点,迅速成为了数据科学、机器学习、Web 开发、自动化脚本编写等多个领域的热门选择。

Python 的主要特点包括:

  1. 简洁易读:Python 采用缩进来表示代码块,语法简洁清晰,易于学习。

  2. 动态类型:Python 是动态类型的语言,这意味着你不需要在声明变量时指定其类型,Python 解释器会在运行时自动确定类型。

  3. 丰富的标准库:Python 拥有一个庞大的标准库,涵盖了文件处理、网络编程、数据库接口、图形界面开发、科学计算等多个方面。

  4. 强大的第三方库:除了标准库外,Python 还有大量的第三方库可供使用,如 NumPy、Pandas、Matplotlib 用于数据分析,Django、Flask 用于 Web 开发,TensorFlow、PyTorch 用于机器学习等。

  5. 面向对象:Python 支持面向对象编程,包括类、继承、多态等概念。

  6. 社区支持:Python 有一个庞大的开发者社区,提供了丰富的资源和帮助。

  7. 跨平台:Python 可以在多种操作系统上运行,包括 Windows、Linux、macOS 等。

  8. 脚本编写:Python 非常适合用于编写自动化脚本,可以快速完成一些简单的任务。

下面是一个简单的 Python 程序示例,用于打印 "Hello, World!":

print("Hello, World!")

要运行这个 Python 程序,你需要安装 Python 解释器。安装完成后,你可以将代码保存为 .py 文件,然后在命令行中运行它:

python hello.py

或者,如果你已经安装了 Python,并且将其添加到了系统的 PATH 环境变量中,你也可以直接在命令行中运行:

python

然后输入或粘贴代码:

print("Hello, World!")

Enter 键后,你将看到输出:

Hello, World!

Python 的应用领域非常广泛,从 Web 开发到数据科学,从网络爬虫到自动化运维,都可以看到 Python 的身影。由于其易读性和丰富的生态,Python 已经成为当今最受欢迎的编程语言之一。

2. 基础语法

注释

#!/usr/bin/python3
# -*- coding: utf-8 -*-

# 单行注释

'''
多行注释(单引号)
'''

"""
多行注释(双引号)
"""

规范

  • 缩进:使用4个空格(或tab)
命名说明类比示例
前置单下划线类对象和子类可访问protectedobj._xx
前置双下划线私有属性和方法,避免被子类覆盖privateobj._classname__xx
前后双下划线魔法函数__len__
后置单下划线避免与关键字冲突xx_

示例

# 斐波那契数列
a, b = 0, 1
while b < 1000:
    print(b, end=',')
    a, b = b, a+b

3. 数据类型

类型说明示例
文本
str字符串"Hello World!"
数值
int整数1234567890
float浮点数1.234567890
complex复数3 + 4j
布尔
bool布尔值True/False
序列
list列表[1,2,3]
tuple元组(1,2,3)
range范围range(1,3)
集合
set集合{1,2,3}
frozenset不可变集合frozenset({1,2,3})
映射
dict字典{"name":"apaki", "age":18}
二进制
bytes字节b"Hello World!"
bytearray字节数组bytearray([1,2,3])
memoryview内存视图memoryview(b"Hello World!")

可以使用type来判断数据类型

type(1)
s = "Hello World!"
type(s)

字符串

字符串(String)是一种非常基础且重要的数据类型,用于表示文本数据。

字符串的定义

  • 字符串是由0个或多个字符组成的有限序列。这些字符可以是英文字母、数字、特殊符号、中文字符等。
  • 字符串可以使用单引号(')、双引号(")或三引号('''或""")来定义。例如:
text1 = "这是一个字符串"
text2 = '这也是一个字符串'
text3 = """这是一个
多行字符串"""

字符串的基本操作

  • 访问字符串中的字符:使用索引(从0开始)来访问字符串中的特定字符。例如,text1[0]将返回字符串"text1"的第一个字符,即'这'。
  • 字符串切片:使用冒号(:)来截取字符串的一部分。例如,text1[1:3]将返回字符串"text1"中从索引1到索引2(不包括索引3)的子串,即'是一'。
  • 字符串连接:使用加号(+)可以将两个或多个字符串连接起来。例如,text4 = text1 + text2将创建一个新的字符串,内容为"这是一个字符串这也是一个字符串"。
  • 字符串重复:使用乘号(*)可以重复字符串多次。例如,text5 = text1 * 3将创建一个新的字符串,内容为"这是一个字符串这是一个字符串这是一个字符串"。
# 字符串的拼接
3*'ab' + 'num'  # 'abababnum'
3*'ab' 'num'    # 'abnumabnumabnum'

# 下标
s = "Hello World!"
s[0] 			# 'H'
s[-1] 			# '!'
# 切片
s[1:3]			# 'el'
s[:5]			# 'Hello'
s[6:]			# 'World!'
s[:]			# 'Hello World!'

字符串的常用方法

  • len():返回字符串的长度(即字符数)。
  • lower()upper():分别将字符串转换为小写和大写。
  • strip()lstrip()rstrip():用于删除字符串开头和结尾的空格或指定字符。
  • split():将字符串分割成子字符串,并返回一个包含子字符串的列表。
  • join():将字符串列表连接成一个字符串。
  • replace():替换字符串中的特定子字符串。
  • find()index():查找字符串中是否包含某个子字符串,并返回其位置。
  • count():计算字符串中某个子字符串出现的次数。
  • startswith()endswith():检查字符串是否以指定的前缀或后缀开头或结尾。
  • isdigit()isalpha()isalnum():用于检查字符串是否只包含数字、字母或数字字母组合。
  • format():用于格式化字符串,将变量的值插入到字符串中。
  • encode()decode():用于在字符串和字节之间进行转换。
def default():
    # ---------------------------------------------------------------------------------
    ss = 'str_test ->> hello world! I am July Baker! this is a great idea!\
    1... 2... 3... ok! (^.^)好的'
    print(len(ss))

    # ------------------------------------------------------------------
    # 居中显示 -> 若设定的长度超过了字符串长度,默认空格填充
    r = ss.center(128, '-')
    print(r)
    # 左对齐
    r = ss.ljust(128, '<')
    print(r)
    # 右对齐
    r = ss.rjust(128, '>')
    print(r)
    # 用0左填充
    r = ss.zfill(128)
    print(r)

    # format
    r = '{1} + 0x{0:02d} = {2:f}'.format(0x01, 2, 1+2)
    print('format格式化的应用:', r)
    # format_map
    # ...

    # ----------------------------------------------------------------
    # 显示字符串中字串在范围内出现的不重叠次数
    r = ss.count('..')
    print('..出现的不重叠次数', r)

    # 若字符串以指定后缀结尾,则返回True
    r = ss.endswith('的')
    print('是否以"的"结尾?', r)
    #
    r = ss.startswith('的')
    print('是否以"的"开头?', r)

    # 返回-1表示没有找到。若找到,则返回最小索引值
    r = ss.find('july')
    print('查找"july"', r)
    r = ss.rfind('...')
    print('rfind返回最高索引', r)

    # 类似find,但找不到会报ValueError
    r = ss.index('July')
    print('查找"July"', r)
    r = ss.rindex('...')    # 类似rfind

    # -----------------------------------------------------------------
    # 以 bytes 对象形式返回字符串编码版本
    r = ss.encode('utf_8')
    print(type(r), r)

    # 首字符变为大写,其他都变为小写
    r = ss.capitalize()
    print(r)

    # 类似于lower(),但是功能更加夸张,可以查看python文件说明理解
    r = ss.casefold()
    print(r)
    r = ss.lower()
    print(r)
    r = ss.upper()
    print(r)

    # 所有tab都被size个空格所代替
    r = ss.expandtabs(16)
    print(r)

    # 所有单词首字母大小,类似于标题
    r = ss.title()
    print(r)

    r = ss.swapcase()
    print(r)

    # ---------------------------------------------------------------------------------
    # '好的list'isalpha() ->  True
    # 'asdf.123'isalpha() -> False
    r = ss.isalpha()
    print('是否都为字符?', r)
    r = ss.isascii()
    print('是否都为assic码(U+0000 =< x <= U+007F)?', r)

    # 数字判断
    r = '0123'.isdecimal()
    print(r)
    r = '1765'.isdigit()
    print(r)
    r = '123Ⅱ一二叁亿'.isnumeric()
    print(r)

    # ?
    # r = ss.isidentifier()

    # ?
    # r = ss.maketrans()
    # r = ss.translate()


    # 好理解的就不打印了
    r = ss.islower()
    r = ss.isprintable()
    r = ss.isspace()
    r = ss.istitle()

    # ----------------------------------------------------------------------------
    # 返回删除前导字符的字符串副本
    r = ss.lstrip('-> _tsre')
    print(r)
    r = ss.rstrip('好的()^. 123ok!')
    print(r)
    r = ss.strip('->_tsre好的()^. 123ok!')
    print(r)

    # -----------------------------------------------------------------------------
    r = '-'.join('JulyBaker')
    print(r)
    # 从第一次出现'is'的地方分割为3-tuple
    r = ss.partition('is')
    print(r)
    r = ss.rpartition('is')
    print(r)

    # 默认从空格分开,maxsplit=-1分割字符串全部(即没有次数限制),若指定maxsplit则分割指定次数
    r = ss.rsplit()
    print(r)
    r = ss.split()
    print(r)

    r = ss.replace('...', '、')
    print(r)

    string = '''title
I am Bruce!
(^o^)'''
    r = string.splitlines()
    print(r)

列表

list(列表)是一种非常常用的数据结构,用于存储有序的元素集合。这些元素可以是任何类型,包括整数、浮点数、字符串、列表(即嵌套列表)等。列表用方括号 [] 来定义

创建列表

my_list = [1, 2, 3, 4, 5]
mixed_list = [1, 'two', 3.0, [4, 5, 6]]

访问列表元素

使用索引(从0开始)来访问列表中的元素。

print(my_list[0])  # 输出 1
print(my_list[-1])  # 输出 5,负索引从列表末尾开始计数

修改列表元素

通过索引直接修改列表中的元素。

my_list[0] = 10
print(my_list)  # 输出 [10, 2, 3, 4, 5]

添加元素

  • 使用append()方法在列表末尾添加元素。
my_list.append(6)
print(my_list)  # 输出 [10, 2, 3, 4, 5, 6]
  • 使用insert()方法在指定索引处插入元素。
my_list.insert(1, 'one')
print(my_list)  # 输出 [10, 'one', 2, 3, 4, 5, 6]

删除元素

  • 使用del语句删除指定索引处的元素。
del my_list[1]
print(my_list)  # 输出 [10, 2, 3, 4, 5, 6]
  • 使用remove()方法删除第一个匹配的元素。
my_list.remove(2)
print(my_list)  # 输出 [10, 3, 4, 5, 6]
  • 使用pop()方法删除并返回指定索引处的元素(如果不提供索引,则默认删除并返回最后一个元素)。
last_element = my_list.pop()
print(last_element)  # 输出 6
print(my_list)  # 输出 [10, 3, 4, 5]

列表切片

使用冒号(:)来获取列表的子集。

print(my_list[1:4])  # 输出 [3, 4, 5]

列表长度

使用len()函数来获取列表的长度。

print(len(my_list))  # 输出 4

列表连接

使用+运算符来连接两个列表。

another_list = [7, 8, 9]
combined_list = my_list + another_list
print(combined_list)  # 输出 [10, 3, 4, 5, 7, 8, 9]

列表乘法

使用*运算符来重复列表。

repeated_list = my_list * 2
print(repeated_list)  # 输出 [10, 3, 4, 5, 10, 3, 4, 5]

列表排序

使用sort()方法对列表进行原地排序(不返回新列表),或使用sorted()函数返回排序后的新列表。

my_list.sort()
print(my_list)  # 输出 [3, 4, 5, 10]
sorted_list = sorted(another_list)
print(sorted_list)  # 输出 [7, 8, 9]

元组

tuple(元组)是另一种有序的元素集合,与列表非常相似,但元组是不可变的,即一旦创建后就不能修改其内容。元组通常用圆括号 () 来定义(但在只有一个元素的元组中,需要在元素后面加上逗号 , 以区分该元素和圆括号内的普通表达式)。

创建元组

my_tuple = (1, 2, 3, 4, 5)
single_element_tuple = (6,)  # 注意这里的逗号,以区分整数6和元组(6)

访问元组元素

与列表相同,使用索引(从0开始)来访问元组中的元素。

print(my_tuple[0])  # 输出 1
print(my_tuple[-1])  # 输出 5

元组是不可变的

无法像list那样修改元组中的元素。也无法使用append()insert()remove()pop()方法来修改元组。

尽管元组是不可变的,但元组中的元素可以是可变的(如列表或其他元组),但你不能通过这些可变元素来“间接”修改元组本身。

b = (1,[2,3])
print(b)    # (1, [2, 3])

# !注意:这里修改的不是 tuple 内容,而是他的元素 list 的内容
b[1][0] = 4
b[1][1] = 5
print(b)	# (1, [4, 5]

元组连接

与列表一样,可以使用 + 运算符来连接两个元组。

another_tuple = (6, 7, 8)
combined_tuple = my_tuple + another_tuple
print(combined_tuple)  # 输出 (1, 2, 3, 4, 5, 6, 7, 8)

元组切片

与列表相同,可以使用切片来获取元组的子集。

print(my_tuple[1:4])  # 输出 (2, 3, 4)

获取元组长度

使用 len() 函数来获取元组的长度。

print(len(my_tuple))  # 输出 5

元组乘法

与列表相同,你可以使用 * 运算符来重复元组。

repeated_tuple = my_tuple * 2
print(repeated_tuple)  # 输出 (1, 2, 3, 4, 5, 1, 2, 3, 4, 5)

元组作为字典的键

由于元组是不可变的,因此它们可以用作字典的键(而列表则不能)。

my_dict = {(1, 2): 'one_two', (3, 4): 'three_four'}
print(my_dict[(1, 2)])  # 输出 'one_two'

元组在需要存储一组相关值但不需要修改它们的情况下非常有用,例如表示坐标点、日期等。由于元组是不可变的,因此它们比列表更加轻量级,并且在某些情况下(如作为字典的键或作为集合的元素)是必需的。

集合

集合(set)是一种无序且元素唯一的可迭代数据类型。它提供了一种高效的方法来执行与成员资格相关的操作,如查找、添加和删除元素。集合中的元素可以是任何不可变类型(如整数、浮点数、字符串、元组等),但不能是列表或字典等可变类型。

创建集合

集合可以使用大括号 {}set() 函数来创建。但是,请注意,如果使用大括号创建空集合,需要加上一个空格或者使用 set() 函数,因为大括号 {} 在没有元素的情况下会被解释为空字典。

# 使用大括号创建集合
my_set = {1, 2, 3, 4, 5}

# 使用set()函数创建集合
another_set = set([1, 2, 3, 4, 5])

# 创建空集合
empty_set = set()  # 或者使用 empty_set = {},但通常不推荐这种方式,因为它可能导致混淆

集合操作

集合支持多种操作,包括添加元素、删除元素、检查成员资格、集合的并集、交集和差集等。

添加元素

使用 add() 方法向集合中添加一个元素,或者使用 update() 方法添加多个元素(可以是另一个集合或可迭代对象)。

my_set.add(6)               # 添加单个元素
my_set.update([7, 8, 9])    # 添加多个元素

删除元素

使用 remove() 方法删除集合中的一个元素(如果该元素不存在,会引发 KeyError),或者使用 discard() 方法(如果元素不存在,则什么也不做)。另外,还可以使用 pop() 方法随机删除并返回集合中的一个元素(如果集合为空,会引发 KeyError),或者使用 clear() 方法清空集合。

my_set.remove(6)            # 删除元素6
my_set.discard(7)           # 尝试删除元素7,如果不存在则不报错
element = my_set.pop()      # 随机删除并返回一个元素
my_set.clear()              # 清空集合

检查成员资格

使用 in 关键字来检查一个元素是否存在于集合中。

if 5 in my_set:
    print("5在集合中")

集合运算

  • union()|:返回两个集合的并集。
  • intersection()&:返回两个集合的交集。
  • difference()-:返回第一个集合中存在但第二个集合中不存在的元素的集合(差集)。
  • symmetric_difference()^:返回两个集合的对称差集,即只存在于一个集合中的元素。
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

union_set = set1.union(set2)  # {1, 2, 3, 4, 5, 6, 7, 8}
intersection_set = set1.intersection(set2)  # {4, 5}
difference_set = set1.difference(set2)  # {1, 2, 3}
symmetric_difference_set = set1.symmetric_difference(set2)  # {1, 2, 3, 6, 7, 8}

集合的特性

  • 集合中的元素是无序的。
  • 集合中的元素是唯一的,重复的元素在集合中只会出现一次。
  • 集合是可迭代的,因此可以使用循环来遍历集合中的元素。

集合的这些特性使得它们在处理需要快速进行成员资格检查、去重或执行集合运算的场景中非常有用。

def base():
    r0 = set()
    print("-> 空集", r0)

    r1 = {1, 2, 3, 4}
    r2 = {2, 3, 5, 6}
    print("-> 集合r1 ", r1)
    print("-> 集合r2 ", r2)

    r = r1 & r2
    print("交集 ", r)
    r = r1 | r2
    print("并集 ", r)
    r = r1 - r2
    print("相对补集/差集r1-r2 ", r)
    r = r2 - r1
    print("相对补集/差集r2-r1 ", r)

    r3 = {1, 2}
    print("-> 集合r3 ", r3)
    print("r3是r1的子集?", r3.issubset(r1))
    print("r3是r2的子集?", r3.issubset(r2))

    r = r1 ^ r2
    print("对称差集/差分 ", r)
    r = (r1 | r2) - (r1 & r2)
    print(r)

    # ------------------------------------------
    fr1 = frozenset({1, 2, 3, 4, 5})
    # fr1.add(6) 失败
    # frozenset得到的集合,不可修改


def base2():
    r1 = {1, 2, 3, 4}
    r2 = {2, 3}
    r3 = {4, 5, 6}
    print('4 in r1? ', 4 in r1)
    print('5 not in r1? ', 5 in r2)
    # isdisjoint没有交集返回True
    print(r3.isdisjoint(r2))
    print(r3.isdisjoint(r1))

    # 判断子集 & 真子集 issubset
    print('r2是r1的子集么? ', r2.issubset(r1))
    print(r2 <= r1)
    print(r2 < r1)
    print('r2是r1的子集么? ', r1.issuperset(r2))
    print(r1 >= r2)
    print(r1 > r2)

    # 交集,并集,差集...的其他表示方式
    # 下面的方式仅仅作为计算,而不改变r1的值
    r = r1.union(r2, r3)
    print('r1,r2,r3的并集', r)
    r = r1.intersection(r2, r3)
    print('r1,r2,r3的交集', r)
    r = r1.difference(r3)
    print('r1 - r3差集', r)
    r = r1.symmetric_difference(r3)
    print('对称差分', r)

    # 使用update的,会同步更新r1的值
    r = r1.copy()
    r.update(r2, r3)
    print('r1,r2,r3的并集', r)
    r = r1.copy()
    r.intersection_update(r2, r3)
    print('r1,r2,r3的交集', r)
    r = r1.copy()
    r.difference_update(r3)
    print('r1 - r3差集', r)
    r = r1.copy()
    r.symmetric_difference_update(r3)
    print('对称差分', r)

if __name__ == "__main__":
    base()
    base2()

字典

字典(dictionary)是一种可变容器模型,它存储键值对(key-value pair),并且每个键都是唯一的。字典类型用于存储和检索与键相关联的值。

创建字典

字典使用大括号 {} 来定义,其中每个键值对使用冒号 : 分隔,键值对之间使用逗号 , 分隔。

# 创建一个空字典
empty_dict = {}

# 创建一个包含键值对的字典
my_dict = {
    "key1": "value1",
    "key2": "value2",
    "key3": 3,
    "key4": [1, 2, 3]  # 值可以是任何类型,包括列表、元组等
}

print(my_dict.keys())    # 返回所有关键字列表
print(my_dict.values())  # 返回所有Value列表
print(my_dict.items())  # 返回所有键值对列表

# 利用字典推导式创建字典
d = {x: x**2 for x in range(1, 5)}
print(d)

访问字典中的值

通过键来访问字典中的值。

value1 = my_dict["key1"]  # 获取与"key1"相关联的值
print(value1)  # 输出: value1

修改字典中的值

通过重新给键赋值来修改字典中的值。

my_dict["key1"] = "new_value1"  # 修改"key1"的值

添加键值对

如果键不存在于字典中,给它赋值将会添加一个新的键值对。

my_dict["key5"] = "value5"  # 添加一个新的键值对

删除键值对

使用 del 语句或 pop() 方法来删除字典中的键值对。

# 使用 del 语句删除键值对
del my_dict["key2"]

# 使用 pop() 方法删除键值对,并返回被删除的值
value3 = my_dict.pop("key3")
print(value3)  # 输出: 3

检查键是否存在

使用 in 关键字来检查字典中是否存在某个键。

if "key1" in my_dict:
    print("key1 存在")

遍历字典

可以使用 for 循环来遍历字典的键、值或键值对。

# 遍历键
for key in my_dict:
    print(key)

# 遍历值
for value in my_dict.values():
    print(value)

# 遍历键值对
for key, value in my_dict.items():
    print(key, value)

字典的特性

  • 字典是可变的,可以添加、修改或删除键值对。
  • 字典中的键必须是不可变的(如整数、浮点数、字符串、元组等),而值可以是任何类型。
  • 字典是无序的,但可以通过 sorted() 函数和字典的 items() 方法来获取有序的键值对列表。
  • 字典的查找、添加和删除操作的时间复杂度通常是 O(1),因为字典内部通常使用哈希表来实现。

字典在Python编程中非常常见,它们通常用于存储需要快速查找的数据,如数据库记录、配置文件选项等。

# 			II. 循环遍历dt
d = {"name1": "Juli", "name5": "Baker", "name3": "Bryce", "name4": "Loski"}
print(type(d))

# 方法1:dict[key]
for key in d:
    print("{}:{}".format(key, d[key]))
print('------------')

# 方法2:解包
for key, value in d.items():
    print("{}:{}".format(key, value))
print('------------')

# 直接显示Key和Value
print(d.keys())
print(d.values())

# 按照key排序
ret = sorted(d.items())  # sorted默认给dict排序是按照key排序的
ret = sorted(d.items(), key=lambda d: d[0])
print(ret)
# 按照value排序
ret = sorted(d.items(), key=lambda d: d[1])
print(ret)
print(type(ret))    # sourted返回的是list

dd2 = dict(ret)
print(dd2)    # dict转换一下即可

字节

'''
1-3 主要涉及Hex,Bytes,List之间的相互转换
    这里的Hex指的是诸如 str("313233414234") (即相当于是2个字符表示一位十六进制数据)
    则可定Hex不能有[^0-9A-Fa-f]数据
4-6 涉及到str 诸如"Hello world哈哈"
    则这种情况会涉及到转码问题encoding=utf-8等
'''

# 1.0 hex <--> bytes
def hex2bytes(hh):
    '''
        str("31323334") -> b"1234"
    '''
    return bytes.fromhex(hh)

def bytes2hex(bb):
    '''
        b"1234" -> str("31323334") 
    '''
    return bb.hex()


# 2.0 list <--> bytes
def list2bytes(ll):
    '''
        [0x31,0x32,0x33] -> b"123"
    '''
    return bytes(ll)

def bytes2list(bb):
    '''
         b"123" -> [0x31,0x32,0x33]
    '''
    return list(bb)


# 3.0 list <--> hex
def list2hex(ll):
    '''
        [0x31,0x32,0x33] -> str("313233")
    '''
    return bytes(ll).hex()

def hex2list(hh):
    '''
        str("313233") -> [0x31,0x32,0x33]
    '''
    bb = bytes.fromhex(hh)
    return list(bb)

# 4.0 str <--> list
def str2list(ss):
    '''
        str("123ABC") -> [0x31,0x32,0x33,0x41,0x42,0x43]
        str("我的世界")(本脚本为utf-8编码) -> [25105, 30340, 19990, 30028] (因为ord返回Unicode编码)
    '''
    return [ord(c) for c in list(ss)]

def list2str(ll):
    '''
        [0x31,0x32,0x33,0x41,0x42,0x43] -> str("123ABC")
    '''
    return ''.join([chr(i) for i in ll])

# 5.0 str <--> bytes
def str2bytes(ss):
    '''
        str("123ABC") -> b"123ABC"
    '''
    return bytes(ss, encoding='utf-8')
    
def bytes2str(bb):
    '''
        b"123ABC" -> str("123ABC")
    '''
    return str(bb, encoding='utf-8')


'''
    其他各种转换便不再多写了,主要是因为有以上一些接口,
    对于实际应用的时候,用到什么,相互直接一调用也能实现各种数据之前的相互转化了。
    以后若再扩展,则必定是更加简洁/高效...的方式
'''
def py36_str_hex_bytes_test():
    # ------------------------------------------------------
    ll = [0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38]
    print('[list]         {} \t {}'.format(type(ll),ll))

    bb = list2bytes(ll)
    hh = list2hex(ll)
    print('[list2bytes]   {} \t {}'.format(type(bb),bb))
    print('[list2hex]     {} \t {}'.format(type(hh),hh))


    ll2 = bytes2list(bb)
    hh2 = bytes2hex(bb)
    print('[bytes2list]   {} \t {}'.format(type(ll2),ll2))
    print('[bytes2hex]    {} \t {}'.format(type(hh2),hh2))


    ll3 = hex2list(hh)
    bb2 = hex2bytes(hh)
    print('[hex2list]     {} \t {}'.format(type(ll3),ll3))
    print('[hex2bytes]    {} \t {}'.format(type(bb2),bb2))

    ll4 = str2list("我的世界")
    print('[str2list]     {} \t {}'.format(type(ll4), ll4))
    ss = list2str(ll4)
    print('[list2str]     {} \t {}'.format(type(ss), ss))

    bb4 = str2bytes(ss)
    print('[str2bytes]    {} \t {}'.format(type(bb4), bb4))
    ss4 = bytes2str(bb4)
    print('[bytes2str]    {} \t {}'.format(type(ss4), ss4))

    # 若想将汉字也转为list形式,可以相互调用实现
    bb5 = str2bytes("我的世界")
    ll5 = bytes2list(bb5)
    print('[汉字2list]    {} \t {}'.format(type(ll5), ll5))

4. 变量

变量说明
_临时变量,表示上一个计算结果

5. 运算符

算数运算

运算符说明示例
+1 + 2
-1 - 2
*1 * 2
/1 / 2
//整除(取整数)17 // 3
%取余17 % 3
**2 ** 3

关系运算符

运算符说明示例
==等于1 == 2
!=不等于1 != 2
>大于1 > 2
<小于1 < 2
>=大于等于1 >= 2
<=小于等于1 <= 2

位运算符

运算符说明示例
&按位与1 & 2
|按位或1 | 2
^按位异或1 ^ 2
~按位取反~1
<<左移位1 << 2
>>右移位1 >> 2

逻辑运算符

运算符说明示例
and逻辑与x > 1 and x < 5
or逻辑或x < 1 or x > 5
not逻辑非not True

赋值运算符

运算符说明示例
=赋值a = 1
+=加法赋值a += 1
-=减法赋值a -= 1
*=乘法赋值a *= 1
/=除法赋值a /= 1
//=整除赋值a //= 1
%=取余赋值a %= 1
**=幂赋值a **= 1
&=按位与赋值a &= 1
`=`按位或赋值
^=按位异或赋值a ^= 1
>>=右移位赋值a >>= 1
<<=左移位赋值a <<= 1

成员运算符

运算符说明示例
in包含1 in [1,2]
not in不包含1 not in [1,2]

身份运算符

运算符说明示例
is同一对象1 is 2
is not不同对象1 is not 2

6. 流程控制

Python 中的流程控制指的是控制程序执行的顺序和流程。这主要通过条件语句(如 if)、循环语句(如 forwhile)以及异常处理语句(如 try/except)来实现。下面我们将分别介绍这些流程控制结构。

条件语句

条件语句用于根据条件表达式的值来决定执行哪一部分代码。关键字if, elif, else

x = 10

if x > 0:
    print("x 是正数")
elif x < 0:
    print("x 是负数")
else:
    print("x 是零")

循环语句

for

for 循环用于遍历可迭代对象(如列表、元组、字典、集合或字符串)的元素。

for i in range(5):
    print(i)

c = dict(sape=4139, guido=4127, jack=4098)
for key, value in c.items():
    print(key, value)

# 循环遍历序列时,可以使用枚举函数,在同一个时间检索位置和相应value
for i, v in enumerate([11, 22, 33, 44, 55]):
    print(i, v)

# 若同时循环两个或者超过两个
questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q, a in zip(questions, answers):
    print('What is your {0}?  It is {1}.'.format(q, a))

# 倒序,可以使用 reversed()
for i in reversed(range(1,10,2)):
    print(i)

while

while 循环用于在满足某个条件时重复执行一段代码。

i = 0
while i < 5:
    print(i)
    i += 1

循环控制语句

  • break:用于立即退出循环。
  • continue:用于跳过当前循环的剩余部分,直接进入下一次循环。

3. 异常处理

异常处理用于在程序执行过程中捕获和处理异常。关键字 try except else finally

try:
    # 尝试执行的代码块
    result = 10 / 0  # 这将引发一个 ZeroDivisionError 异常
except ZeroDivisionError:
    # 当 ZeroDivisionError 异常被触发时执行的代码块
    print("除数不能为零")
else:
    # 当 try 块中的代码正常执行完毕时执行的代码块(可选)
    print("没有异常发生")
finally:
    # 无论 try/except 块中是否有异常发生,finally 块中的代码都会执行(可选)
    print("这是 finally 块")

4. 传递控制

  • pass:是一个空操作语句,用于在语法上需要语句,但程序不需要任何操作时。例如,在定义一个空函数或类的实现时。
  • return:用于从函数中返回一个值并退出函数。
  • yield:用于在生成器函数中返回一个值,并暂停函数的执行,直到下一次迭代。

7. 函数

函数是一个可以重复使用的代码块,用于执行特定的任务。你可以定义函数来封装一段代码,以便在程序的多个地方调用它,而无需重复编写相同的代码。

def fib(n):
    print("# 斐波那契数列")
    a, b = 0, 1
    result = []
    while b < n:
        result.append(b)
        a, b = b, a+b       # a,b=b,a 相当于a和b交换数据
    print(result)
    # return result         # (可选)带有函数返回值

带有默认参数的函数

def adjust(voltage, type="music", state='on'):
    print(type, "音量:", voltage, "开启?", state)

带有可变参数的函数

def calc_sum(*args):
	ax = 0
	for n in args:
		ax = ax + n
	return ax
	
# ret = calc_sum(1,2,3,4,5)
a = (1,2,3,4,5)
ret = calc_sum(*a)	# 和上面的传参方式本质上是一样的
print(ret)

带有关键字参数的函数

闭包

闭包是一个函数对象,它返回了一个包含自由(未绑定到特定对象的变量)的函数。

# -------------------------------------
"""
	“闭包(Closure)”的程序结构
注意:
返回函数不要引用任何循环变量,或者后续会发生变化的变量。
"""
def calc2_sum(*args):
	def sum():
		ax = 0
		for n in args:
			ax = ax + n
		return ax
	return sum	#返回求和函数
	
ret = calc2_sum(*a)
print(ret)
print(ret())
print('')

装饰器

装饰器(Decorator)是一个函数,它接受一个函数作为参数并返回一个修改后的函数。

"""
	装饰器
函数调用前后添加内容,但又不希望修改原函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
"""
def log(func):
	def wrapper(*args, **kw):
		print('[ start time ] ' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
		
		# return func(*args, **kw)
		func(*args, **kw)
		
		print('[  end  time ] ' + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
		
	return wrapper

# 装饰器
@log
def test_fun():
	print('test_fun ok!')

test_fun()
print('当前函数名称:' + test_fun.__name__)
print('')

生成器

生成器(Generator)是一种特殊的函数,它返回一个迭代器。

"""
# 列表生成式,直径生成会直接占用大量空间(若数据较大的话)
a = [x*x for x in range(5)]
# 而此时,生成器的优势便体现出来了
                1.0 生成器

留个问题:
send和next的区别
"""
def disp(a):
    print(a)
    for i in a:
        print(i,end=' ')
    print('\n')

# 创建generator方式二
# 针对相对复杂一些的逻辑,将函数返回直接作为生成器
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        # print(b,end=' ')
        #执行过程中,遇到yield就中断。直到next之后才继续执行
        yield b
        a, b = b, a + b
        n = n + 1
    
# 创建generator方式一
a = (x*x for x in range(5))
# print(next(a))
disp(a)

a = fib(6)
# print(next(a))
disp(a)

迭代器

迭代器(Iterator)是一种对象,它返回一个序列中的元素。

"""
注意:list,str等可迭代,但其本质不是迭代器。
但可以通过iter转换。
Iterator对象表示的是一个数据流
"""
a = fib(6)

# 以下代码和disp中的某些代码
# 在本质上是同一种行为
while True:
    try:
        print(next(a),end=' ')
    except StopIteration:
        # 遇到StopIteration就退出循环
        print('\n')
        break

print(type(a))
b = [1,2,3,4,5]
print(type(b))
c = iter(b)
print(type(c))

偏函数

import functools
def int2(x,base=2):
	return int(x,base)
print(int2('10010'))

# 偏函数的用法,不用再重新定义一个函数
# 直接采用这种方式将原函数的某些参数固定
# 方便后续调用
int2 = functools.partial(int,base=2)
print(int2('10010'))

8. 类

类是用于定义对象(也称为实例)的属性和方法的结构。每个对象都是其类的实例,并可以访问类定义中定义的属性和方法。

对象是类的实例。当你创建一个类并定义它之后,你可以创建这个类的多个对象,每个对象都有自己的属性和方法。

#! python

# -----------------------------------
# 			Class
# ----------------------------------
class Complex:
    # 类变量,属于类本身,而不是类的实例
	r = 0.0
	i = 0.0
	#str = []		#1.0 str 观察现象哦~
					# 小结:放在这里,在追加的时候,不同的对象也会叠加
	
    # 初始化方法,当创建类的实例时自动调用
	# 相当于C++ 的构造函数
	def __init__(self,real,imag):

        # 实例变量,属于类的实例
		#self.r = real
		#self.i = imag
		self.str = []	#2.0 str 观察现象哦~
						#小结:放在这里,不同的对象,各自追加自己的,不叠加

    # 实例方法,需要通过类的实例来调用
	def change(self,real,imag):
		self.r = real
		self.i = imag
		self.str.append("{0:.2f} + {1:.2f}j".format(self.r,self.i))
		print("--------------")
	def real(self):
		return self.r
	def imag(self):
		return self.i
	def show(self):
		print( "{0:.2f} + {1:.2f}j".format(self.r,self.i) )

	# 相当于C++的 运算符重载
	def __add__(self,c):
		s = Complex(0.0,0.0)
		s.r = self.r + c.r
		s.i = self.i + c.i
		return s
	def __sub__(self,c):
		s = Complex(0.0,0.0)
		s.r = self.r - c.r
		s.i = self.i - c.i
		return s
	def __mul__(self,c):
		s = Complex(0.0,0.0)
		s.r = self.r * c.r - self.i * c.i
		s.i = self.r * c.i + self.i * c.r
		return s
	def __truediv__(self,c):
		s = Complex(0.0,0.0)
		denomi = c.r*c.r + c.i*c.i
		s.r = (self.r * c.r + self.i * c.i)/denomi
		s.i = (self.i * c.r - self.r * c.i)/denomi
		return s

# 创建一个Complex的实例
c = Complex(3,5)
d = Complex(7,9)

c.change(2,4)
c.show()
print(c.str)

d.change(8,6)
d.show()
print(d.str)
c.show()
print(c.str)

c.change(1,2)
print(c.str)

c.show()
d.show()
print("------------------")
s = c + d
s.show()
c.show()
d.show()

s = c - d
s.show()
c.show()
d.show()

s = c * d
s.show()
c.show()
d.show()

s = c / d
s.show()
c.show()
d.show()

__init__ 方法是一个特殊的方法,称为类的构造器或初始化方法。当创建类的新实例时,它会自动被调用。这个方法用于设置实例的初始状态。

self 是对实例本身的引用,它代表了类的实例。在类的方法中,第一个参数总是 self(除了静态方法和类方法)。当调用实例方法时,Python会自动将实例作为第一个参数传递给方法。

类还可以有类方法(使用 @classmethod 装饰器)和静态方法(使用 @staticmethod 装饰器)。类方法通常用于修改类状态或与类本身进行交互,而不是与实例进行交互。静态方法与类无关,它们只是简单地附加到类上,通常用于组织代码。

"""
# 这种方式是初学类常用的方式
class Student(object):
	def score(self):
		return self._score

	def set_score(self,value):
		if not isinstance(value, int):
			raise ValueError('score must be an integer!')
		if value < 0 or value > 100:
			raise ValueError('score must between 0 ~ 100!')
		self._score = value
		
s = Student()

s.set_score(100)
print(s.score())

s.set_score(200)
print(s.score())
"""


# 但是以上的类定义方式,再调用的时候
# 通过方法复制,毕竟要写很多的代码
# 不如直接操作变量and复制来的更加便捷 (优势1)
# 并且以下的方式,还保留着对于输入参数的判定 (优势2)
class Student(object):
	@property
	def score(self):
		return self._score
	
	@score.setter
	def score(self,value):
		if not isinstance(value, int):
			raise ValueError('score must be an integer!')
		if value < 0 or value > 100:
			raise ValueError('score must between 0 ~ 100!')
		self._score = value
		
s = Student()
# print(dir(s))

s.score = 100
print(s.score)

s.score = 200
print(s.score)

继承

继承允许我们创建一个类(称为子类或派生类),该类继承另一个类(称为父类或基类)的属性和方法。子类可以添加新的属性或重写父类的方法,也可以继承父类的所有属性和方法。

在Python中,所有的类都直接或间接地继承自一个内置的基类,这个基类就是object。从Python 3开始,object是所有类隐式继承的基类,即使你没有在类定义中明确指定。在Python 2中,需要显式地从object继承以实现新式类(new-style classes),但在Python 3中,所有的类都是新式类,因此不再需要显式地从object继承。

object类提供了一些基本的方法,如__init__(用于初始化对象)、__str__(用于返回对象的字符串表示)和__repr__(用于返回对象的官方字符串表示,通常用于调试)等。但是,这些方法在object类本身中并没有实现具体的功能,它们只是作为占位符或钩子(hooks),供子类覆盖(override)以实现特定的行为。

下面是一个简单的示例,展示了如何显式地从object继承(尽管在Python 3中这是不必要的):

"""
	自定义的类表现的和list,dict等没有什么区别,
	主要是因为动态语言的"鸭子类型"
	不需要强制继承某个接口
"""
class Fib(object):
	def __init__(self,max):
		self.a = 0
		self.b = 1
		self.max = max
	
	# 结合next实现可迭代对象
	def __iter__(self):
		return self
		
	def __next__(self):
		self.a, self.b = self.b, self.a + self.b
		
		if self.b > self.max:
			raise StopIteration()
		else:
			return self.a
		
	# 类的下标访问 & 切片等操作的实现
	def __getitem__(self, n):
		
		# 下标访问实现
		if isinstance(n, int):
			a, b = 0, 1
			# 考虑到下标从0开始,且为了和iter结果保持一致
			# 因此采用n+1的方式
			for x in range(n+1):
				a, b = b, a + b
			return a
		
		# 切片实现
		if isinstance(n, slice):
			start = n.start
			stop = n.stop
			if start is None:
				start = 0
			a, b = 0, 1
			ll = []
			for x in range(stop):
				a, b = b, a + b
				if x >= start:
					ll.append(a)
			return ll
			
def disp(a):
	print(a)
	for i in a:
		print(i,end=' ')
	print('\n')
	

a = Fib(10000)
disp(a)

print(a[5])
print(a[5:8])

Python自带枚举类,可以用来定义枚举类型。

from enum import Enum, EnumMeta, unique

def disp(data):
    if isinstance(data, EnumMeta):
        for name, member in data.__members__.items():
            print(name + ' => ', member, ',', member.value)
        print('--------------------------------')
    else:
        print(type(data))


# 获得Month的枚举类
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May',
                       'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

# value 是从1开始的
disp(Month)

"""
    可以派生出自定义类,见下
"""
@unique
class Weekday(Enum):
    Sun = 0     # Sun的value被设定为0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

disp(Weekday)

# 其他操作 or 调用方式
print(Weekday.Sun.value)
day = Weekday.Mon
print(day)
day = Weekday['Tue']
print(day)
day = Weekday(3)
print(day)

# day = Weekday.Sun
if day == Weekday.Sat or day == Weekday.Sun:
    print('Yes,放假了')
else:
    print('工作中...')

重载

重载允许我们创建多个方法,这些方法具有相同的名称,但使用不同的参数列表。Python 不会检查参数列表是否匹配,而是根据调用方法时传递的参数数量和类型来选择要调用的方法。

多态

多态允许我们使用相同的名称调用方法,而不管实例是什么类型。Python 不会检查参数列表是否匹配,而是根据调用方法时,传递给方法的参数数量和类型来选择要调用的方法。

9. 模块

模块(Module)是一个包含Python定义和语句的文件。模块可以定义函数、类和变量。模块也可以包含可执行的代码。模块文件通常以.py为扩展名。

模块的主要目的是将相关的代码组织在一起,以便在其他Python程序中重用。一旦模块被定义,就可以在其他的Python脚本中通过import语句来使用它。

  1. 定义模块: 创建一个.py文件,并在其中编写Python代码。这个文件就是一个模块。

  2. 使用模块: 在其他Python脚本中,你可以使用import语句来导入模块。例如,如果你有一个名为my_module.py的模块,你可以这样导入它:

    import my_module
    

    然后,你可以通过模块名来访问模块中的函数、类或变量:

    result = my_module.some_function(arguments)
    
  3. 从模块中导入特定的部分: 你可以使用from ... import ...语法来只导入模块中的特定部分。例如:

    from my_module import some_function, some_class
    

    之后,你可以直接调用这些函数或类,而不需要使用模块名作为前缀:

    result = some_function(arguments)
    instance = some_class()
    
  4. 模块的执行: 当Python解释器首次导入一个模块时,它会执行模块中的代码。但是,如果模块已经被导入过,那么再次导入时,模块中的代码不会被重新执行(除非模块被显式地重新加载)。

  5. 模块搜索路径: 当Python尝试导入一个模块时,它会按照一个特定的搜索路径来查找该模块。这个搜索路径由一系列目录组成,通常包括当前工作目录、PYTHONPATH环境变量中指定的目录以及Python的安装目录等。

  6. 内建模块: Python的标准库中包含了很多内建模块,这些模块提供了许多常用的功能和工具,如文件操作、网络编程、数据处理等。你可以直接使用这些模块,而不需要自己编写相应的代码。

  7. 第三方模块: 除了内建模块外,还有许多第三方模块可供使用。这些模块通常由Python社区开发,提供了各种扩展功能和工具。你可以通过pip等包管理工具来安装和使用这些模块。

  8. 模块文档: 为了提供模块的使用说明和API参考,你可以在模块文件的顶部添加文档字符串(docstring)。这些文档字符串可以使用Python的内置help()函数来查看。

  9. 模块和包: 当模块的数量变得很多时,可以将它们组织成包(Package)。包是一个包含多个模块的目录,该目录必须包含一个名为__init__.py的文件(即使该文件是空的)。通过包,你可以更好地组织和管理你的代码。

10. 文件操作

文件操作是一个常见的任务,用于读取、写入、修改和删除文件。Python提供了内置的open()函数来打开文件,并返回一个文件对象,该对象具有一系列的方法来进行文件操作。

读取文件

# 使用 'with' 语句可以确保文件在使用完毕后被正确关闭
with open('filename.txt', 'r') as file:  # 'r' 表示读取模式
    content = file.read()  # 读取整个文件内容
    print(content)

# 也可以逐行读取
with open('filename.txt', 'r') as file:
    for line in file:
        print(line, end='')  # end='' 用于避免每行末尾的换行符被打印两次(在Windows中)

写入文件

# 写入文件时,如果文件不存在,则创建它;如果文件已存在,则内容会被覆盖
with open('filename.txt', 'w') as file:  # 'w' 表示写入模式
    file.write('Hello, World!')

# 追加内容到文件末尾
with open('filename.txt', 'a') as file:  # 'a' 表示追加模式
    file.write('\nAnother line of text.')

二进制模式

当处理非文本文件(如图片、视频等)时,应使用二进制模式('b')。

# 读取二进制文件
with open('image.jpg', 'rb') as file:
    binary_content = file.read()

# 写入二进制文件
with open('output.jpg', 'wb') as file:
    file.write(binary_content)

上下文管理器(with语句)

使用with语句可以确保文件在使用完毕后被正确关闭,即使在处理文件时发生异常也是如此。这是一种推荐的做法,因为它可以简化代码并减少出错的可能性。

文件对象的常用方法

  • read(size):从文件中读取指定字节数的内容。如果省略size参数或size为负,则读取整个文件。
  • readline():从文件中读取一行内容。
  • readlines():从文件中读取所有行,并返回一个包含这些行的列表。
  • write(str):将字符串写入文件。
  • writelines(sequence):将一个字符串序列写入文件。序列中的每个元素后面都不会添加换行符,除非元素本身包含换行符。
  • seek(offset, whence):移动文件读取/写入的指针位置。offset表示偏移量,whence表示偏移的基准位置(0表示文件开头,1表示当前位置,2表示文件末尾)。
  • tell():返回当前文件读取/写入的指针位置。
  • close():关闭文件。通常不需要手动调用,因为with语句会自动关闭文件。

检查文件是否存在

可以使用os.path.exists()函数来检查文件是否存在。

import os

if os.path.exists('filename.txt'):
    print('文件存在')
else:
    print('文件不存在')

根据具体的需求,可能还需要处理更复杂的文件操作,如读取和写入特定格式的数据(如CSV、JSON等),或者使用更高级的文件处理库(如csv模块、json模块等)。