Python

Python

安装

HelloWorld

print("Hello World")

image-20240221020134889

基础

字面量:代码中被写下来固定的值,

数字:Number

  • 整数 int
  • 浮点数 float
  • 复数 complex
  • 布尔 bool

字符串:String(双引号)

列表:List

元组:Tuple

集合:Set

字典:Dictionary

注释

  • 单行注释 # 开头

    • # 我是注释
      print("Hello World")
      
  • 多行注释 ### 开头和结尾

    • """
      我是注释
      第二行注释
      """
      print("Hello World")
      

字符串

单引号

双引号

三引号

  • 格式化

  • name = "张三丰"
    desc = "很厉害"
    age = 100
    print(name + desc)
    print(name + desc + age)  #不可执行,类型不同,不能直接拼接
    
  • message = "有一个人叫: %s 他 %s 因为他年龄是 %d" %(name,desc,age)
    print(message)
    
    print("有一个人叫: %s 他 %s 因为他年龄是 %d" %(name,desc,age))
    
    • %s 字符串占位

    • %d 整型占位

    • %f 浮点型占位

      • 我们可以使用辅助符号"m.n"来控制数据的宽度和精度
        m,控制宽度,要求是数字(很少使用),设置的宽度小于数字自身,不生效
        .n,控制小数点精度,要求是数字,会进行小数的四舍五入
        示例:
        %5d:表示将整数的宽度控制在5位,如数字11,被设置为5d,就会变成:[空格][空格][空格]11,用三个空格补足宽度。
        %5.2f:表示将宽度控制为5,将小数点精度设置为2
              小数点和小数部分也算入宽度计算。如,对11.345设置了%7.2f 后,结果是:[空格][空格]11.35。2个空格补足宽度,小数部分限制2位精度后,四舍五入为 .35
        %.2f:表示不限制宽度,只设置小数点精度为2,如11.345设置%.2f后,结果是11.35
        

        image-20240221033119761

  • print(f"有一个人叫: {name}{desc} 因为他年龄是 {age}")
    有一个人叫: 张三丰 他 很厉害 因为他年龄是 100
    

数据类型

type() 进行转换

print(type(123))
print(type("闻C"))
  • <class 'int'>
    <class 'str'>
    

数据类型转换

int(x)  将 x 转成一个整数
float(x)
str(x)

标识符

  • 英文、数字、下划线、中文(不推荐中文)
    • 数字不能用在开头
  • 大小写敏感
  • 不可使用关键字
    • 关键字:
    • image-20240221030945044

运算符

运算符描述实例
+两个对象相加 a + b 输出结果 30
-得到负数或是一个数减去另一个数 a - b 输出结果 -10
*两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200
/b / a 输出结果 2
//取整除返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0
%取余返回除法的余数 b % a 输出结果 0
**指数a**b 为10的20次方, 输出结果 100000000000000000000
运算符描述实例
+=加法赋值运算符c += a 等效于 c = c + a
-=减法赋值运算符c -= a 等效于 c = c - a
*=乘法赋值运算符c *= a 等效于 c = c * a
/=除法赋值运算符c /= a 等效于 c = c / a
%=取模赋值运算符c %= a 等效于 c = c % a
**=幂赋值运算符c **= a 等效于 c = c ** a
//=取整除赋值运算符c //= a 等效于 c = c // a

输入

input()

print("请输入你的名字:")
name = input()

print(f"你刚才输入的是 {name}")
  • 所有是输入都是字符串

比较运算符

运算符描述示例
==判断内容是否相等,满足为True,不满足为False如a=3,b=3,则(a == b) 为 True
!=判断内容是否不相等,满足为True,不满足为False如a=1,b=3,则(a != b) 为 True
>判断运算符左侧内容是否大于右侧满足为True,不满足为False如a=7,b=3,则(a > b) 为 True
<判断运算符左侧内容是否小于右侧满足为True,不满足为False如a=3,b=7,则(a < b) 为 True
>=判断运算符左侧内容是否大于等于右侧满足为True,不满足为False如a=3,b=3,则(a >= b) 为 True
<=判断运算符左侧内容是否小于等于右侧满足为True,不满足为False如a=3,b=3,则(a <= b) 为 True

if else if else

num = input()
num = int(num)

if num > 5:
    print(f"你输入的数字是 {num} 是大于5的")
elif num > 2:
    print(f"你输入的数字是 {num} 是大于2的")
else:
    print(f"你输入的数字是 {num} 是小于等于2的")
    print("小于等于2我才输出")

print("我无论如何都输出,因为我顶格了,不属于判断的分支")

循环

while
while True/False:
    执行语句
for
for item in list:
    执行语句
  • name = "wenc"
    for s in name:
        print(s)
    
# range(num)        从0开始,到数字 num,不包含 num
# range(n1,n2)      从n1开始,到数字 n2,不包含 n2
# range(n1,n2,step) 从n1开始,到数字 n2,不包含 n2,每次步长 step
range(5)     [0,1,2,3,4]
range(2,5)   [2,3,4]
range(1,9,2) [1,3,5,7]
作用域

能访问,不建议

for i in range(1,9,2):
    print(i)
print("我是",i)
break

结束循环:该 for 循环结束

for i in range(5):
    if i == 3:
        break
    print(i)
0
1
2
continue

结束本次循环:仅 == 3 的那一次跳过

for i in range(5):
    if i == 3:
        continue
    print(i)
0
1
2
4

函数

先定义,后使用。
参数不需要和返回值没有可以省略

def 函数名(参数):
    函数体
    return 返回值
# 调用
函数名(参数)
  • def add(a,b):
        c = a+b
        return c
    
    num = add(2,5);
    
    print(num)
    
# 空函数,先不做
def emptyFun():
    pass		#先占位,什么都不做

如果没有 return 返回值的话,默认返回字面量 None

def fun():
    print('我执行了')

r = fun()

print(r)
print(type(r))

# None 在判断上等于  False
if not r :
    print('None == False')
def test(a,b):
    """
    测试函数
    :param a: 
    :return: 
    """
    return a+b
参数
def person(name, age, gender):
    print(f"Name: {name}, Age: {age},Gender:{gender}")


person("闻家奇", 18, "男")  # Name: 闻家奇, Age: 18,Gender:男
person(age=20, name="张三", gender='女')  # Name: 张三, Age: 20,Gender:女
person("约翰", gender='男', age=22)  # Name: 约翰, Age: 22,Gender:男
  • 可以根据位置,按位传参,person("闻家奇", 18, "男") 第一个就是 name,第二个就是 age,第三个就是 gender

    可以指定 key,person(age=20, name="张三", gender='女') 指定 key 就不一定需要根据位置

    可以混用 person("约翰", gender='男', age=22) 第一个默认是 name,后面根据 key 传参

def person(name, age, gender):
    print(f"Name: {name}, Age: {age},Gender:{gender}")


# person("闻家奇",18)        # TypeError: person() missing 1 required positional argument

def user(name, age, gender="男"):
    print(f"Name: {name}, Age: {age},Gender:{gender}")


user("闻家奇", 18)             # Name: 闻家奇, Age: 18,Gender:男
user("孙晓惠", 20, "女")  	   # Name: 孙晓惠, Age: 20,Gender:女
  • 可以对属性设置默认值,但是该属性必须放到参数列表的最后

    • def user(name, age, gender="男"):		正确
      def user(name="张", age, gender):		错误
      
不定长
def person(*args):
    print(args)

person("闻")                  # ('闻',)
person("闻", 18)              # ('闻', 18)
person("闻", 18, "男")        # ('闻', 18, '男')
  • 不定长参数,前面加个星号,所有参数都会被 args 接收,形成一个元组 tuple 类型。
def person(**kwargs):
    print(kwargs)

person(name="闻")                        # {'name': '闻'}
person(name="闻", age=18)                # {'name': '闻', 'age': 18}
person(name="闻", age=18, gender="男")   # {'name': '闻', 'age': 18, 'gender': '男'}
  • 两个星号,使用 KV 键值对的形式传递
多返回值
def add(a, b):
    s = a + b
    d = a - b
    return s, d


s, d = add(5, 2)
print(s, d)  # 7 3
函数作为参数
def testFun(fa):
    result = fa(1, 2)
    print(result)

def fa(a,b):
    return a+b

testFun(fa)
  • testFun 的参数是一个 函数
  • fa 本身就是一个 函数
def calculate(a, b, logic):
    result = logic(a, b)
    print(f"Result: {result}")
    return result

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

def multiply(a, b):
    return a * b

def divide(a, b):
    return a / b

calculate(10, 5, add)  		# Result: 15
calculate(10, 5, subtract)  # Result: 5
calculate(10, 5, multiply)  # Result: 50
calculate(10, 5, divide)  	# Result: 2.0
  • 为什么不直接调用 add、substract 等方法呢?
匿名函数
def add(a, b):
    print(f"Adding {a} and {b}")

lambda x, y: print(f"Adding {x} and {y}")
def add(a, b):
    return a + b

lambda x, y: x + y

容器

列表
# 定义一个数组
arr = [1, 2, 3, 4, 5]

for e in arr:
    print(e)

for i, e in enumerate(arr):
    print(i, e) 
  • 索引遍历不能越界
  • 支持反向索引
# 定义一个数组
arr = ["a", "b", "c", "d", "e"]

e = arr.index("a")
print(e)    # 0 返回元素的索引

arr[1] = "w"
print(arr)  # ['a', 'w', 'c', 'd', 'e'] 修改元素

arr.insert(2, "x")
print(arr)  # ['a', 'w', 'x', 'c', 'd', 'e'] 插入元素

arr.append("z")
print(arr)  # ['a', 'w', 'x', 'c', 'd', 'e', 'z'] 尾部追加元素

arr.extend(["y", "z"])
print(arr)  # ['a', 'w', 'x', 'c', 'd', 'e', 'z', 'y', 'z'] 尾部追加多个元素

arr.remove("z")
print(arr)  # ['a', 'w', 'x', 'c', 'd', 'e', 'y', 'z'] 删除首个匹配元素

arr.pop()
print(arr)  # ['a', 'w', 'x', 'c', 'd', 'e', 'y'] 删除尾部元素

arr.pop(2)
print(arr)  # ['a', 'w', 'c', 'd', 'e', 'y'] 删除指定索引元素

arr.reverse()
print(arr)  # ['y', 'e', 'd', 'c', 'w', 'a'] 反转数组

arr.sort()
print(arr)  # ['a', 'c', 'd', 'e', 'w', 'y'] 排序数组

arr.clear()
print(arr)  # [] 清空数组
元组 Truple

使用 ( ) 进行定义,逗号隔开,元组的数据不可变。

字符串字符遍历等操作也是元组,不可变

# 定义一个元组
("a", "b", "c")

t = ("a", "b", "c")
print(t)  # ('a', 'b', 'c')

t1 = ()
print(f"t1的类型是{type(t1)},内容是{t1}")  # ()

t2 = tuple()
print(f"t2的类型是{type(t2)},内容是{t2}")  # ()
  • # 元组只有一个元素,也要加上逗号
    t = ("hello")
    print(f"t = {t}, type(t) = {type(t)}")  # t = hello, type(t) = <class 'str'>
    
    t = ("hello",)
    print(f"t = {t}, type(t) = {type(t)}") # t = ('hello',), type(t) = <class 'tuple'>
    
  • # 定义一个元组
    t = ("a", "b", "c", "d", "e")
    print(t)    # ('a', 'b', 'c', 'd', 'e')
    
    i = t.index("a")
    print(i)    # 0 , 返回元素的索引
    
    c = t.count("a")
    print(c)    # 1 , 返回元素的个数
    
    l = len(t)
    print(l)    # 5 , 返回元组的长度
    
  • t = (1, 2, ["a", "b"])
    print(t)  # (1, 2, ['a', 'b'])
    
    t[2][0] = "hello"
    t[2][1] = "world"
    print(t)  # (1, 2, ['hello', 'world'])			# 元组不可变,如果是引用对象的话,值是可以变的。
    
序列

内容连续,有序,可以使用下标进行索引的。都叫序列。

比如:列表,字符串,元组

序列支持切片。切片:从一个序列中取出一个子序列

序列 [开始索引:结束索引:步长]

str = "0123456789"
print(str[0:9:1])     # 012345678       # 从0开始,到8结束,步长为1
print(str[0:5:1])     # 01234           # 从0开始,到4结束,步长为1
print(str[3:5:1])     # 34              # 从3开始,到4结束,步长为1

print(str[0:9:2])     # 02468           # 从0开始,到8结束,步长为2。01  23  45  67  89
print(str[0:9:3])     # 036             # 从0开始,到8结束,步长为3。012  345  678
print(str[3:9:2])     # 357             # 从3开始,到8结束,步长为2。34 56 78
  • str = "0123456789"
    print(str[0:9:1])     # 012345678
    print(str[0:9])       # 012345678   步长为1可以省略
    
    print(str[:5])        # 01234       开始位置省略表示从 0 开始
    print(str[5:])        # 56789       结束位置省略表示到最后一个元素
    print(str[5::2])      # 579         开始位置从5开始,到最后,步长为2
    print(str[:])         # 0123456789  从头到尾,步长为1遍历
    
    print(str[::-1])       # 9876543210 从头到尾,反向步长,相当于逆序输出
    
集合
列表:  [1,2,3]
元组:  (1,2,3)
字符串: "123"
集合:  {1,2,3}

s = set()   定义空集合

集合不允许重复。

集合无法通过索引进行查询

s = {"a", "b", "c", "a", "b", "c"}
print(f"Set: {s}, Type: {type(s)}")     # Set: {'a', 'b', 'c'}, Type: <class 'set'>

s.add("hello")
print(f"Set: {s}")                       # Set: {'a', 'b', 'c', 'hello'}

s.remove("hello")
print(f"Set: {s}")                       # Set: {'a', 'b', 'c'}

s.pop()
print(f"Set: {s}")                       # Set: 随机取出一个元素移除

s.clear()
print(f"Set: {s}")                       # Set: set()
s1 = {1, 2, 3}
s2 = {2, 3, 4}

print(s1 & s2)  # {2, 3}        取2个集合交集
print(s1 | s2)  # {1, 2, 3, 4}  取2个集合并集
print(s1 - s2)  # {1}           取2个集合差集
print(s2 - s1)  # {4}           取2个集合差集
print(s1 ^ s2)  # {1, 4}        取2个集合异或集 = (并集 - 交集)
s1 = {1, 2, 3}
s2 = {2, 3, 4}

s3 = s1.difference(s2)      # s1 - s2, 源集合不变
print(f"s1: {s1}")          # s1: {1, 2, 3}
print(f"s2: {s2}")          # s2: {2, 3, 4}
print(f"s3: {s3}")          # s3: {1}

s5 = s1.union(s2)           # s1 | s2, 源集合不变
print(f"s1: {s1}")          # s1: {1, 2, 3}
print(f"s2: {s2}")          # s2: {2, 3, 4}
print(f"s5: {s5}")          # s5: {1, 2, 3, 4}

s1.difference_update(s2)    # s1 -= s2, 源集合改变
print(f"s1: {s1}")          # s1: {1}
print(f"s2: {s2}")          # s2: {2, 3, 4}
字典

键值对,键唯一。没有索引

d = {"张三": 18,"李四": 19,"王五": 20}

d = {}
d = dict()
d = {
    "张三": 18,
    "李四": 19,
    "王五": 20
}

print(d)                        # {'张三': 18, '李四': 19, '王五': 20}
print(f"d的类型是:{type(d)}")    # d的类型是:<class 'dict'>

print(d["张三"])                  # 18
d = {
    "张三": 18,
    "李四": 19,
    "王五": 20
}

d["张三"] = 21
d["赵六"] = 22
print(d)            # {'张三': 21, '李四': 19, '王五': 20, '赵六': 22}  存在则修改,不存在则添加

v = d.pop("赵六")    # 删除指定的键
print(d)            # {'张三': 21, '李四': 19, '王五': 20}
print(v)            # 22

for k in d:
    print(k, d[k])  # 张三 21  李四 19  王五 20

for k, v in d.items():
    print(k, v)     # 张三 21  李四 19  王五 20

print("张三" in d)        # True
print("闻家奇" in d)      # False
print("张三" not in d)    # False

print(len(d))            # 3

d.clear()
print(d)                 # {}
通用

都能遍历,但是部分有索引,部分不能索引

函数:len() clear() max() min()

转换

list(容器)
str(容器)
tuple(容器)
set(容器)
my_list = {"a", "b", "c"}
my_tuple = {"a", "b", "c"}
my_dict = {"k1": "a", "k2": "b", "k3": "c"}
my_set = {"a", "b", "c", "a"}
my_str = "abc"

list_list = list(my_list)
tuple_list = list(my_tuple)
dict_list = list(my_dict)
set_list = list(my_set)
str_list = list(my_str)
print(f"list_list: {list_list}")            # ['a', 'b', 'c']
print(f"tuple_list: {tuple_list}")          # ['a', 'b', 'c']
print(f"dict_list: {dict_list}")            # ['k1', 'k2', 'k3']
print(f"set_list: {set_list}")              # ['a', 'b', 'c']
print(f"str_list: {str_list}")              # ['a', 'b', 'c']


list_set = set(my_list)
tuple_set = set(my_tuple)
dict_set = set(my_dict)
set_set = set(my_set)
str_set = set(my_str)
print(list_set)         # {'a', 'b', 'c'}
print(tuple_set)        # {'a', 'b', 'c'}
print(dict_set)         # {'k1', 'k2', 'k3'}
print(set_set)          # {'a', 'b', 'c'}
print(str_set)          # {'a', 'b', 'c'}


list_tuple = tuple(my_list)
tuple_tuple = tuple(my_tuple)
dict_tuple = tuple(my_dict)
set_tuple = tuple(my_set)
str_tuple = tuple(my_str)
print(list_tuple)       # ('a', 'b', 'c')
print(tuple_tuple)      # ('a', 'b', 'c')
print(dict_tuple)       # ('k1', 'k2', 'k3')
print(set_tuple)        # ('a', 'b', 'c')
print(str_tuple)        # ('a', 'b', 'c')


list_str = str(my_list)
tuple_str = str(my_tuple)
dict_str = str(my_dict)
set_str = str(my_set)
str_str = str(my_str)
print(list_str)         # {'a', 'b', 'c'}
print(tuple_str)        # {'a', 'b', 'c'}
print(dict_str)         # {'k1': 'a', 'k2': 'b', 'k3': 'c'}
print(set_str)          # {'a', 'b', 'c'}
print(str_str)          # abc

排序。
字符串按照字典排序,数值按照数字排序

reverse ,默认 False,设置 True 表示逆序。

my_list = {"1", "3", "2", "11"}
my_tuple = {"1", "3", "2", "11"}
my_dict = {"k1": "1", "k2": "3", "k3": "2", "k4": "11"}
my_set = {"1", "3", "2", "11"}
my_str = "acbed"

print(sorted(my_list))  # ['1', '11', '2', '3']
print(sorted(my_tuple))  # ['1', '11', '2', '3']
print(sorted(my_dict))  # ['k1', 'k2', 'k3', 'k4']
print(sorted(my_set))  # ['1', '11', '2', '3']
print(sorted(my_str))  # ['a', 'b', 'c', 'd', 'e']

print(sorted(my_list, reverse=True))  # ['3', '2', '11', '1']
print(sorted(my_tuple, reverse=True))  # ['3', '2', '11', '1']
print(sorted(my_dict, reverse=True))  # ['k4', 'k3', 'k2', 'k1']
print(sorted(my_set, reverse=True))  # ['3', '2', '11', '1']
print(sorted(my_str, reverse=True))  # ['e', 'd', 'c', 'b', 'a']

函数式

arr = [
    {"name": "张三", "age": 18},
    {"name": "李四", "age": 19},
    {"name": "王五", "age": 20},
    {"name": "赵六", "age": 21},
    {"name": "马七", "age": 22},
]


# 获得年龄大于等于 20 的人的列表
def filter_func(arr):
    newArr = []
    for item in arr:
        if item["age"] >= 20:
            newArr.append(item)
    return newArr


newArr = filter_func(arr)
print(f"newArr: {newArr}")          # newArr: [{'name': '王五', 'age': 20}, {'name': '赵六', 'age': 21}, {'name': '马七', 'age': 22}]
  • # 修改逻辑,获得年龄大于等于 21 的人的列表
    def filter_func_agegt21(arr):
        newArr = []
        for item in arr:
            if item["age"] >= 21:
                newArr.append(item)
        return newArr
    
  • # 修改逻辑,获得年龄大于等于 22 的人的列表
    def filter_func_agegt22(arr):
        newArr = []
        for item in arr:
            if item["age"] >= 22:
                newArr.append(item)
        return newArr
    
  • # 有人会考虑,既然这样,为什么不把年龄的值也传进去?
    def filter_func(arr,age):			# 多加一个参数
        newArr = []
        for item in arr:
            if item["age"] >= age:
                newArr.append(item)
        return newArr
    
  • # 修改逻辑,获得年龄小于 20 的人的列表
    def filter_func_agelt20(arr):
        newArr = []
        for item in arr:
            if item["age"] < 20:
                newArr.append(item)
        return newArr
    
  • # 修改逻辑,获得名字包含英文字符的人的列表
    # 修改逻辑,获得名字是2个字的人的列表
    # 修改逻辑,获得名字是3个字的人且年龄>20岁的人的列表
    # 修改逻辑,累死菜B程序员
    
  • def filter_func(arr,logic):
        newArr = []
        for item in arr:
            if logic(item):
                newArr.append(item)
        return newArr
    
    newArr = filter_func(arr,logic=lambda item: item["age"] > 20)
    newArr = filter_func(arr,logic=lambda item: item["age"] > 21)
    newArr = filter_func(arr,logic=lambda item: item["age"] >= 22)
    newArr = filter_func(arr,logic=lambda item: item["age"] < 20)
    print(f"newArr: {newArr}")
    

文件

读取文件

在 F盘下准备一个 a.txt 文本,以下是内容

HelloWorld闻家奇
闻7
f = open("F:/a.txt", mode="r", encoding="UTF-8")

print(f"Type of f: {type(f)}")      # <class '_io.TextIOWrapper'>

print(f.read(8))                    # HelloWor
print(f.read(2))                    # ld
print(f.read(2))                    # 闻家
  • 如果遇到报错,很有可能是 编码格式不对
  • 多次 read 的连续调用,read() 会移动文件的指针。
    • print(f.read(8)) 会读取 8 个字符,也就是 HelloWor,此时会把文件的指针移动到 r 这个位置
    • print(f.read(2)) 继续读取 2个字符,也就是 ld,再次移动文件指针
    • print(f.read(2)) 再读取 2 个字符,读取 闻家
f = open("F:/a.txt", mode="r", encoding="UTF-8")

print(f"Type of f: {type(f)}")  # <class '_io.TextIOWrapper'>

lines = f.readlines()
print(f"Type of lines: {type(lines)}")  # Type of lines: <class 'list'>
print(lines)                            # ['HelloWorld闻家奇\n', '闻7']

for line in lines:
    print(line.strip())
  • \n 换行
  • f.readline() 读取一行数据

关闭文件流

import time

f = open("F:/a.txt", mode="r", encoding="UTF-8")

time.sleep(30)

f.close()
  • time.sleep(30) 通过暂停 30 秒模拟文件占用,此时该文件被 python 程序占用,是无法删除文件。
  • 程序运行结束需要手动 close(),调用 close 方法可以结束文件占用
with open("F:/a.txt", mode="r", encoding="UTF-8") as f:
    f.readline()
  • 使用 with ,会自动关闭文件流,as f 命名别名,相当于赋值变量。

写入

f = open("F:/a.txt", mode="w", encoding="UTF-8")

f.write("Hello, World!")        # 写入内存缓冲区

f.flush()                       # 将内存缓冲区的数据写入文件
  • 写入,没有文件会创建。
  • mode 是 w 的话,如果之前文件存在,会覆盖掉之前的文件里的内容
  • f.close() 内置了 f.flush(),调用 close 也会先 flush()
with open("F:/a.txt", mode="a", encoding="UTF-8") as f:
    f.write("Hello, World!")        # 写入内存缓冲区
    f.flush()                       # 将内存缓冲区的数据写入文件
  • 模式改成 a,append,追加到文件尾部。

异常

try except

try:
    open("file.txt")
except:
    print("File not found")
  • 对可能报错的代码块进行捕获
  • exception 出现异常会执行

多个异常

try:
    open("file.txt")
    d = 1/0
except FileNotFoundError as e:
    print("File not found")
except ZeroDivisionError as e:
    print("Division by zero")
  • 捕获多个异常
try:
    open("file.txt")
    d = 1 / 0
except (FileNotFoundError, ZeroDivisionError) as e:
    print("出现异常")
  • 捕获的异常放到元组里
try:
    open("file.txt")
    d = 1 / 0
except Exception as e:
    print("出现异常")
  • Exception 是可以捕获到所以异常

else

try:
    d = 1/1
    # d1 = 1/0
except Exception as e:
    print("出现异常")
else:
    print("没有异常")
  • 使用 else 语句,如果没有异常就会执行 else 分支的代码块

finally

try:
    # d = 1/1
    d1 = 1/0
except Exception as e:
    print("出现异常")
else:
    print("没有异常")
finally:
    print("无论是否有异常,都会执行")

传递

def main():
    func02()

def func01():
    d = 1 / 0

def func02():
    print("执行func02")
    func01()
    print("func02执行完毕")

main()
  • 执行func02
    Traceback (most recent call last):
      File "F:\wen_project\pystudy\main.py", line 15, in <module>
        main()
      File "F:\wen_project\pystudy\main.py", line 2, in main
        func02()
      File "F:\wen_project\pystudy\main.py", line 11, in func02
        func01()
      File "F:\wen_project\pystudy\main.py", line 6, in func01
        d = 1 / 0
            ~~^~~
    ZeroDivisionError: division by zero
    
    def main():
        try:
            func02()
        except:
            print("出现异常")
    
    def func01():
        d = 1 / 0
    
    def func02():
        print("执行func02")
        func01()
        print("func02执行完毕")
    
    main()
    

模块

[from 模块名称] import [模块 || 变量 | 函数 | *]  [as 别名]
  • 	import XX模块
    from XX模块   import 类、变量、方法
    from XX模块   import *
    from XX模块   import XX as YY
    			import XX as YY
    
    import time
    time.sleep(3)
    print("game over")
    
    from time import sleep
    sleep(3)
    print("game over")
    
    import time as t
    t.sleep(3)
    print("game over")
    
    from time import sleep as s
    s(3)
    print("game over")
    

自定义模块

  1. 新建 my_module.py 文件
  2. 创建函数 add
  3. 在 main.py 导入模块 from my_module import *
  4. 在 main.py 使用

image-20240811184025535

  • 如果 my_module1.py 和 wen_module.py 里面都有 add 方法,在 main.py 都导入了,并且使用了 add 方法,使用的是后导入模块中的函数

image-20240811184317193

内置变量

假设我创建了一个 my_module.py,写了一个函数 add,我不确定该功能是否正确,所以写了一个测试,

  • def add(a, b):
        print(f"a: {a}, b: {b}")
        return a + b
    
    add(7, 3)
    

    而我在文件里引入该模块的时候,就会自动执行该 add(7,3)

    from my_module import *
    

    image-20240811184847406

如何不删除掉该 add(7,3)函数,又能在导入时不调用呢?不删除可能是因为后续需要进行测试。

def add(a, b):
    print(f"a: {a}, b: {b}")
    return a + b


if __name__ == "__main__":
    add(7, 3)
  • __name__ 是内置的一个变量,当右击运行该 my_module.py 文件的时候,就会把 __name__ 设置成 __main__,此时 if 条件成立,执行 add(7,3),而当导入的时候 if 的条件不成立,就不会运行
__all__
  1. 定义 my_module.py,定义 3 个函数,add、subtract、multiply,但是使用内置变量设置 __all__ = ['add', 'subtract']

    def add(a, b):
        return a + b
    
    def subtract(a, b):
        return a - b
    
    def multiply(a, b):
        return a * b
    
    __all__ = ['add', 'subtract']
    
  2. 在其他模块使用 import * 导入的时候,只能导入这 2 个函数,此时的 * 只能导入上面 __all__ = ['add', 'subtract'] 的函数

    from my_module import *
    
    print(add(10,5))
    print(subtract(10,5))
    # print(multiply(10,5))     # 报错
    

包本质也是一个模块,只不过组织方式稍微再扩大一点。

假设有 5 个 模块文件,需要导入 5 次,而一个大一点的工程里,模块很多。总不能把所有文件都写一个 a_module.py 里,要不然该文件也会超级大

  • my_module1.py

  • my_module2.py

  • my_module3.py

  • my_module4.py

  • my_module5.py

  • from my_module1 import *
    from my_module2 import *
    from my_module3 import *
    from my_module4 import *
    from my_module5 import *
    

我们创建一个文件夹,在该文件夹下写一个文件 __init__.py,在该文件里导入上面的模块

  • 一个普通的文件夹,下面有 __init__.py,那么该文件夹就是 包。没有就是普通的文件夹

image-20240811191024399

import ai.my_module1

ai.my_module1.add(5,2)
from ai import my_module1

my_module1.add(5,2)
from ai.my_module1 import add

add(5,2)

__init__.py 里指定导入的包

  • __all__ = ["my_module1", "my_module2"]
    
    from ai import *
    
    my_module1.add(5, 2)
    

第三方包

包可以包含一堆module,每个 module 包含了很多功能。一个包就是一堆功能的一个集合体。

python 生态里有很多第三方包,生成 word 文档,科学计算,数据分析等。要使用就得先导入。

  • 科学计算 numpy
  • 数据分析 pandas
  • 大数据计算 pysparkapache-flink
  • 图形可视化 matplotlibpyecharts
  • 人工智能 tensorflow
pip install numpy
pip install numpy==2.0.1									# 指定版本号
pip install 'numpy>=2.0.1'									# 指定版本不能小于该版本号
pip install numpy -i https://mirrors.aliyun.com/pypi/simple	   # 指定阿里云镜像源
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple  # 指定清华镜像源
  • 国内由于网络原因,如果不能翻墙的话,指定国内镜像源

包导出

pip freeze >  requirements.txt  
  • 当我们一个项目依赖了很多包的时候,其他人下载项目下来想要运行,如何知道你导入了哪些包呢?我们使用上面的命令,把当前环境所有的包都导出来,这样别人只要根据 requirements.txt 里面的依赖就可以下载了

  • # 根据 requirements.txt 下载依赖包
    pip install -r requirements.txt
    

上面的 pip freeze > requirements.txt 是导出当前环境下所有的包,但是项目可能并不需要那么多,只依赖了其中部分包,使用 pipreqs 导出项目运行必需的包

pip install pipreqs
pipreqs ./
pipreqs ./ --encoding=utf8		# 指定生成文件的编码格式
  • pip install pipreqs 因为 pipreqs不是 python 内置的包,需要先下载
  • pipreqs ./ 打包项目必需的依赖包

JSON

# json 互相转换
import json

arr = [
    {"name": "张三", "age": 18},
    {"name": "李四", "age": 19},
    {"name": "王五", "age": 20}
]

j = json.dumps(arr)
print(type(j))
print(j)

j = json.dumps(arr, ensure_ascii=False)
print(j)

ja = json.loads(j)
print(type(ja))
print(ja)

  • json.dumps(Python对象,ensure_ascii=False) 把 Python 对象转成 Json 字符串,ensure_ascii=False 不使用 ascii,防止中文乱码

  • json.loads(Json字符串) 把 Json 转成 Python 对象

  • <class 'str'>
    [{"name": "\u5f20\u4e09", "age": 18}, {"name": "\u674e\u56db", "age": 19}, {"name": "\u738b\u4e94", "age": 20}]
    [{"name": "张三", "age": 18}, {"name": "李四", "age": 19}, {"name": "王五", "age": 20}]
    <class 'list'>
    [{'name': '张三', 'age': 18}, {'name': '李四', 'age': 19}, {'name': '王五', 'age': 20}]
    

对象

class Student:                 # 定义一个类
    name: None
    age: None


student = Student()             # 实例化对象
student.name = "张三"            # 设置对象的属性
print(student.name)
class Student:                 # 定义一个类
    name: None
    age: None

    def introduce(self):       # 定义一个方法
        print(f"我叫{self.name},今年{self.age}岁。")


student = Student()             # 实例化对象
student.name = "张三"            # 设置对象的属性
student.age = 18

student.introduce()

成员方法

def 方法名(self,参数1,参数2......):
    方法体
  • self 表示自身,方法内部使用类的成员属性,必须使用 self

  • class Student:                 # 定义一个类
        name: None
        age: None
    
        def introduce(self):       # 定义一个方法
            print(f"我叫{self.name},今年{self.age}岁。")
    
        def exam(self):
            self.introduce()
            print("我在考试!")
    
    student = Student()             # 实例化对象
    student.name = "张三"            # 设置对象的属性
    student.age = 18
    
    student.introduce()
    student.exam()
    
    class Student:                 # 定义一个类
        name: None
        age: None
    
        def introduce(self):       # 定义一个方法
            print(f"我叫{self.name},今年{self.age}岁。")
    
        def exam(self):
            self.introduce()
            print("我在考试!")
    
        def say(self,str):
            print(str)
    
    student = Student()             # 实例化对象
    student.name = "张三"            # 设置对象的属性
    student.age = 18
    
    student.introduce()
    student.exam()
    student.say("我就是我,不一样的烟火")
    
    • self 可以不用管,不用传参。

构造方法

__init__() 就是构造方法
创建对象的时候,会自动执行,传入的参数会传给 __init__ 方法使用
class Student:
    name: None
    age: None

    def __init__(self, name, age):
        self.name = name
        self.age = age
        print("初始化成功")

student1 = Student("张三", 18)
student2 = Student("李四", 20)

print(f"学生1的名字是{student1.name},年龄是{student1.age}")
print(f"学生2的名字是{student2.name},年龄是{student2.age}")
  • 初始化成功
    初始化成功
    学生1的名字是张三,年龄是18
    学生2的名字是李四,年龄是20
    

魔术方法

内置的就叫魔术方法,比如 init 方法,名称前后各有2个下划线

# 魔术方法有几十个,掌握常见的几种
__init__()
__str__()
__lt__()  __gt__()
__le__()  __ge__()
__eq__()
str
class Student:
    name: None
    age: None

    def __init__(self, name, age):
        self.name = name
        self.age = age

student1 = Student("张三", 18)
print(student1)             # <__main__.Student object at 0x000001DDEB021A60>
print(str(student1))        # <__main__.Student object at 0x000001DDEB021A60>
  • class Student:
        name: None
        age: None
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __str__(self):
            return f"Student(name={self.name}, age={self.age})"
    
    student1 = Student("张三", 18)
    print(student1)             # Student(name=张三, age=18)
    print(str(student1))        # Student(name=张三, age=18)
    
比较方法
class Student:
    name: None
    age: None

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __lt__(self, other):
        return self.age < other.age

student1 = Student("张三", 18)
student2 = Student("李四", 20)

print(student1 < student2)                  # True  
  • 对象本身不可以比较大小,修改了 lt 方法的逻辑,传入另外一个对象 other,通过自定义逻辑比较年龄来判断对象大小

  • class Student:
        name: None
        age: None
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __lt__(self, other):
            return len(self.name) < len(other.name)			# 修改比较对象大小的逻辑,按照名称的长度
    
    student1 = Student("张三", 18)
    student2 = Student("李四", 20)
    student3 = Student("李四光", 20)
    
    print(student1 < student2)          # False
    print(student1 < student3)          # True
    
eq

eq 默认比较的是内存地址

class Student:
    name: None
    age: None

    def __init__(self, name, age):
        self.name = name
        self.age = age

student1 = Student("张三", 18)
student2 = Student("李四", 20)
print(student1)                      # <__main__.Student object at 0x000001FA2CBC23F0>
print(student2)                      # <__main__.Student object at 0x000001FA2CBC2450>
print(student1 == student2)          # False

封装

部分属性、方法进行开放使用,部分属性、方法私有使用

使用 2个下划线,表示私有

class Student:
    name: None
    __age: None                         # 私有属性

    def introduce(self):
        print(f"我叫{self.name}")
        self.__money()                  # 只能内部调用

    def __money(self):                  # 私有方法
        print("我有100元")


student = Student()
student.name = "张三"
student.__age = 18          # 虽然设置,但是无法设置成功

student.introduce()
# student1.money()          # 无法调用,报错 AttributeError: 'Student' object has no attribute 'money'

继承

单继承
class Phone6:
    name = "iPhone 6"
    network : None

    def call(self):
        print("打电话")

p = Phone6()
print(p.name)       # iPhone 6
p.call()            # 打电话
class Phone7(Phone6):
    face_id = True

    def face_unlock(self):
        print("面部解锁")

p7 = Phone7()
p7.name = "iPhone 7"
print(p7.name)      # iPhone 7
p7.call()           # 打电话

p7.face_unlock()    # 面部解锁
多继承
class 类名(父类1,父类2,......):
    xxx
class Phone:
    def call(self):
        print("可以打电话")

class NFC:
    def nfc(self):
        print("可以NFC刷卡")

class XiaoMi(Phone,NFC):
    def heating(self):
        print("可以当暖手宝")

xm = XiaoMi()
xm.call()           # 可以打电话
xm.nfc()            # 可以NFC刷卡
xm.heating()        # 可以当暖手宝

当多继承的时候,出现菱形继承问题

A 类里面有 name 属性,有 test() 方法,

B 类里面有 name 属性,有 test() 方法,

class C(A,B) C 继承了 A,B,当 C 调用属性和方法的时候,按照左侧优先,name 和 test() 方法是 A 方法的

class Phone:
    name = "Phone"

    def test(self):
        print("我是 Phone 类的 test 方法")


class NFC:
    name = "NFC"

    def test(self):
        print("我是 NFC 类的 test 方法")


class XiaoMi(Phone, NFC):
    pass


xm = XiaoMi()
print(xm.name)          # Phone
xm.test()               # 我是 Phone 类的 test 方法
复写
class Phone:
    def photograph(self):
        print("我是 Phone 类的 photograph 方法")


class XiaoMi(Phone):
    def photograph(self):
        print("我是 XiaoMi 类的 photograph 方法")


xm = XiaoMi()
xm.photograph()         # 我是 XiaoMi 类的 photograph 方法
  • 复写父类中同名方法,就会复写该方法
class Phone:
    def photograph(self):
        print("我是 Phone 类的 photograph 方法")


class XiaoMi(Phone):
    def photograph(self):
        Phone.photograph(self)          # 调用父类的 photograph 方法
        super().photograph()            # 调用父类的 photograph 方法
        print("我是 XiaoMi 类的 photograph 方法")


xm = XiaoMi()
xm.photograph()  # 我是 XiaoMi 类的 photograph 方法
  • 我是 Phone 类的 photograph 方法
    我是 Phone 类的 photograph 方法
    我是 XiaoMi 类的 photograph 方法
    
  • 如果子类想调用父类的属性或者方法,要么使用父类名称指定,要么使用 super() 指定

    • Phone.name
      Phone.photograph(self)
      super().name
      super().photograph()
      

多态

多态:多种状态,某个行为,使用不同对象,得到不同状态。

class MobilePhone:
    def call(self):
        pass


class ApplePhone(MobilePhone):
    def call(self):
        print("Calling from Apple Phone")


class XiaoMiPhone(MobilePhone):
    def call(self):
        print("Calling from XiaoMi Phone")


def func(mobilePhone: MobilePhone):
    mobilePhone.call()

apple = ApplePhone()
xiaomi = XiaoMiPhone()

func(apple)         # Calling from Apple Phone    
func(xiaomi)        # Calling from XiaoMi Phone
  • ApplePhoneXiaoMiPhone 都是 MobilePhone 的子类,都重写了 call() 方法

  • 当调用 func() 的时候,需要传入一个 MobilePhone,传入哪个就执行哪个的 call() 方法。

  • 思考:为什么不直接调用对应的函数方法?

    • apple = ApplePhone()
      xiaomi = XiaoMiPhone()
      
      apple.call()            # Calling from Apple Phone
      xiaomi.call()           # Calling from XiaoMi Phone
      
      func(apple)         	# Calling from Apple Phone    
      func(xiaomi)        	# Calling from XiaoMi Phone
      
    • 解答:可以抽象父类。比如我们编写 func() 函数的时候,我并不能知道有哪些手机,也无法完全罗列出所有手机,可以抽象出一个高级的父类 MobilePhone,在 func() 函数内部可以使用 mobilePhone.call() 编写代码,如果以后有新的手机出现,比如 class HuaWei(MobilePhone) 我们调用的时候只要在 func(huawei) 即可调用华为手机的方法。如果不是这么操作。我们就需要对每个手机都要编写 func 方法

    • def func(mobilePhone: MobilePhone):
          print("准备吃饭")
          print("定好饭店")
          mobilePhone.call()
          print("吃完回家")
          print("洗澡睡觉")
      
      • def func(apple: ApplePhone):		# 这种写法,出现一种手机就要写一个
            print("准备吃饭")
            print("定好饭店")
            apple.call()
            print("吃完回家")
            print("洗澡睡觉")
        
抽象
class MobilePhone:
    def call(self):
        pass
  • 这个 call 方法,函数实现是 pass,就是抽象方法
  • 这个 MobilePhone 类,包含抽象方法,就是抽象类,也可以成为接口

类型注解

image-20240811222354640

使用 Ctrl + P 查看函数参数的类型,比如 random.randint() 需要传入2个 int 类型,但是 add就不知道要传入什么类型

类型注解:

  1. 给变量设置类型
  2. 给方法的参数和返回值设置类型
  3. 给容器设置注解
变量注解
var1 = "闻家奇"
var2 = 18
var3 = [1, 2, 3]
var4 = {"money": 100}

var1: str = "闻家奇"
var2: int = 18
var3: list = [1, 2, 3]
var4: dict = {"money": 100}
函数变量注解
def add(a: int, b: int):
    return a + b

add(1, 2)
  • 这样别人调用 add() 方法的时候就知道参数什么类型了。
def func(name, age) -> Student:
    student = Student()
    student.name = name
    student.age = age
    return student
  • 在方法的后面加上 -> Student 标记返回值类型
对象类型注解
class Student:
    name: str
    age: int


student: Student = Student()
student.name = "闻家奇"
student.age = 18

print(f"学生姓名:{student.name},年龄:{student.age}")      # 学生姓名:闻家奇,年龄:18
容器类型注解
my_list: list = [1, 2, 3, 4, 5]
my_tuple: tuple = (1, 2, 3, 4, 5)
my_dict: dict = {"name": "闻家奇", "age": 18}
my_set: set = {1, 2, 3, 4, 5}
my_str: str = "Hello, World!"
  • 只是对 my_list 等容器类型做个注解。表示是 listtuple 等类型。没有对 list 内的元素做注解
my_list: list[int] = [1, 2, 3, 4, "hello"]
my_tuple: tuple[str, int, bool] = ("闻家奇", 18, True)
my_dict: dict[str, int] = {
    "姓名": "闻家奇",
    "年龄": 20
}
my_set: set[int] = {1, 2, 3, 4, 5}


def test(d: dict[str, int]):
    print(d)

test({"name", "闻家奇"})
  • my_list: list[int] = [1, 2, 3, 4, "hello"] 虽然对元素做了注解,但是仍然可以把字符串 hello 放进去,因为不是强类型校验。
  • my_dict: dict[str, int] 字典类型的注解有2个,第一个表示 key,第二个表示 value
注释注解
import random

rand = random.randint(1, 10)    # type: int
  • 可以在注释里对变量进行注解。格式 # type: 类型
  • rand = random.randint(1, 10) # type: int 表示 rand 是一个 int 类型。等同于 rand: int = random.randint(1, 10)
实践

类型注解只是一个标记,不是强制性的。

var1: str = "闻家奇"
var2: int = 18
var3: list = [1, 2, 3]
var4: dict = {"money": 100}
  • 这种定义变量的一般不会使用,变量一下子就能知道类型的

    • var1 = "闻家奇"
      var2 = 18
      var3 = [1, 2, 3]
      var4 = {"money": 100}
      
s : Student = func()
  • 这种函数无法知道返回类型的,可以使用类型注解,其他人阅读代码一下子就能知道 s 的类型
Union
from typing import Union

my_list_1: list = [1, 2, 3, 4, 5]
my_list_2: list[int] = [1, 2, 3, 4, 5]
my_list_3: list[int] = [1, 2, 3, 4, "hello"]  				# 不会报错,但不推荐

my_list_4: list[Union[int, str]] = [1, 2, 3, 4, "hello"]
  • 使用需要导包 pip install Union
  • 使用 Union 定义多种类型。my_list_4: list[Union[int, str]] = [1, 2, 3, 4, "hello"] 该 list 里的元素可能是 str 也可能是 int 类型

闭包


def outer(prefix):
    
    def inner(msg):
        print(f"{prefix}: {msg}")

    return inner

inner = outer("阿里巴巴")
inner("我是淘宝")
inner("我是天猫")
  • 调用 outer(prefix) 会得到一个内部的函数 inner(msg),由于先调用 outer(prefix) 所以先确定下来 prefix 的变量。后续调用 inner() 都使用该 prefix
def outer(startNum):
    def inner(step):
        nonlocal startNum
        startNum += step
        print(f"当前的值是: {startNum}")

    return inner


inner = outer(10)
inner(2)
inner(2)
inner(2)
  • 内部函数修改外部函数的值,需要先对该变量加上 nonlocal

优点:无需定义全局变量,可以持续的访问、修改某个值。安全

缺点:由于内部函数持续引用,会一直不释放内存,容易内存泄漏

多线程

PySpark

https://www.bilibili.com/video/BV1qW4y1a7fU/?p=139&vd_source=4a8f6785b4f0d27ffaf69dbb4024042e

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值