当前位置: 首页 > news >正文

Python初学笔记

文章目录

    • 关于input()
      • input().split()
    • output()
      • output()类型敏感!
      • print()行为指定
    • Python中的数学运算
      • 除法
    • python中的变量
      • 变量的数据类型
      • type()和isinstance()
      • String
      • bool
      • 切片操作
      • List
      • Tuple
      • Set
      • Dictionary
      • Bytes类型
    • 正则表达式
    • 推导式
      • 字典推导式
      • 推导式的执行顺序
    • 迭代器和生成器
      • 迭代器
      • 生成器
    • 函数传参
      • 可变对象和不可变对象
      • 关键字参数
      • 不定长参数
      • lambda表达式
    • 装饰器
    • 模块
      • \_\_name__属性
    • OOP

关于input()

在Py中,所有从终端读取的数据都是str类型的,也就是C++中的string,因此我们若是想将其转换为其它类型,需要使用转换函数:

# int()就是将类型转换为int的函数
# 所有的内置类型都有类似的转换函数
a = int(input())

若是需要转换的内容无法转换成对应的类型呢?就会抛出一个错误:

try:a = int(input())b = int(input())print(a + b)
except ValueError:print("Can not change to int")

这个错误是ValueError。

在什么时候这段代码会出现错误呢?这和我们的输入有关:Python中的input()会读取一行的数据,当我们的输入是:

1 2

的时候,就会出错:a = int(“1 2”),这很显然不是能转换成int的类型,但当我们的输入为:

1
2

的时候,就是没问题的。理解了先前为何报错,这里也就很好理解了。

那若是我的输入就是放在一行中,并且是以“空格”作为分隔呢?此时就要对input所读取的字符串进行处理了:

numList = input().split()
a = int(numList[0])
b = int(numList[1])
print(a + b)

在这种情况下,可以对输入在同一行的数据进行处理了,但是若是输入数据之间使用了换行符分隔,就会出现数组越界问题。

input().split()

(method) def split(sep: str | None = None,maxsplit: SupportsIndex = -1
) -> list[str]

这是对于split()的声明,虽然对于这个语法我还十分的陌生,但是也不难理解:它返回一个list,其中存储的类型是str

这里写一个测试代码:

numList = input().split()
print(numList)

运行一下:

# input:
1 2 3
# output
['1', '2', '3']

这样应该就很清晰明了。

output()

output()类型敏感!

做数字反转巩固语法的时候,在本地测试一直都没问题,输出都是对的上的:

origin = input()
output = ""
for i in range(len(origin)-1, -1, -1):output += origin[i]print(output)

但是提交的时候测试用例一直没有通过,后面将输出进行了一点调整就AC了:

origin = input()
output = ""
for i in range(len(origin)-1, -1, -1):output += origin[i]print(float(output))

就是在输出的时候将str转换成了float。

[!原因]
虽然输出时会将大多数对象转换为字符串,但Python仍然会保留对象的类型信息。这是为了确保输出的准确性和一致性。例如,如果将浮点数和字符串直接比较,Python会知道它们是不同的类型,因此会返回False。然而,当它们作为输出的一部分时,Python会将它们都转换为字符串以便显示,但这并不改变它们的原始类型。所以虽然在输出时会看起来相似,但它们的类型仍然是不同的。

因此说,Python是一个强类型语言,需要跟C++一样,特别注意数据类型

print()行为指定

在py中,默认情况下,print是会换行的:

print("换行了?")
print("换行了!")

这个输出的结果会是:

换行了?
换行了!

但我们可以通过print的end参数来指定这一行为:

print("换行了吗?", end="")
print("没换行!")

end中可以是任何东西,它都会在print之后附加在输出流的末尾

Python中的数学运算

在Python的混合运算中,整数会被转换为浮点数,不用想C++那样太担心类型的转换问题。

除法

Python中除法分为整数除法浮点数除法,在C++中只有普通的除法,数据类型根据除数和被除数来判断:

print(1 / 3)  # 浮点数除法
print(1 // 3) # 整数除法

上面这两个是完全不同的意思,不多说,运行下就明白了。

python中的变量

python中的基本数据类型,我就想再记下多变量赋值

num1, num2 = 1, 2temp1 = temp2 = 100

两种都是多变量赋值的方式。

变量的数据类型

Python中的标准数据类型有:

数据类型是否可变
Number
String
Tuple
List
Dictionary
Set

其中,Number中包括了许多种数学类型:int,float,bool,complex都是,Python中的int就是长整型,它没有long和long long这么一说。

type()和isinstance()

这两个函数的内容在菜鸟教程#Number中说的很清楚,我这里就标记一下而不赘述了。

String

字符串的截取操作是我很容易忘记的点,这里记录下强化记忆吧:

[!字符串的截取操作]
在C++中,字符串的截取通常是指使用子串操作,例如std::string::substr函数。如果你使用substr从位置pos开始截取长度len的字符串,那么它将从位置pos开始,包括位置pos的字符,截取len-1个字符。所以如果有一个字符串str = “abcdef”,使用str.substr(2, 3)将截取从位置2开始的长度为3的子串,结果是"cde",包括位置2的字符c,但不包括位置5的字符f(因为在C++中,索引是从0开始的)。

在Python中,字符串切片操作s[start:end]也是包含起始索引start的字符,但不包括结束索引end的字符。所以如果对字符串s = “abcdef"使用切片操作s[2:5],结果是"cde”,包括位置2的字符c,但不包括位置5的字符f。

所以,无论是C++还是Python,字符串的截取或切片操作都是从起始位置开始,到结束位置的前一个字符结束在两种语言中,结束位置的字符都不包括在内

Python中的String是很以用的一种数据类型,主要说两个符号:加号(+)和星号(*)

  • 加号:可以直接进行字符串拼接,很多语言都能做到这一点
  • 星号:复制当前字符串,我的理解就是简单的乘法:
    res = "Hello"
    print(res * 2)
    
    这将会输出两个连续的Hello

和C/C++不同的是,Python的String是不可变的

res = "Hello"
res[0] = "N"

这段代码是会直接报错的:

Traceback (most recent call last):File "c:\Users\Lenovo\Desktop\study\Python\test.py", line 14, in <module>res[0] = "N"~~~^^^
TypeError: 'str' object does not support item assignment

下文中提到的切片操作虽然对于String也适用,但是却是不能对字符串进行实际上的改变,字符串切片实际上是创建了一个新的字符串对象

bool

Python中的布尔值是大写的:TrueFalse,其它的点和C++的基本一致,包括数值转换。

切片操作

Python中的截取被称为切片操作:

res = "Hello World"
subStr = res[6:]
print(subStr)

它的语法就是:变量[头下标 : 尾下标 : 步长],其中的部分注意事项在上面的[[#String|引用]]中已经提过了,这里说说它更复杂的用法:

# 列表切片
l = [0, 1, 2, 3, 4, 5]# 获取索引1到索引4之间的元素(不包括索引4)
sub_l = l[1:4]  # 结果是[1, 2, 3]# 步长为2的切片
sub_l = l[::2]  # 结果是[0, 2, 4]# 负步长,从右向左切片
sub_l = l[::-1]  # 结果是[5, 4, 3, 2, 1, 0]

也就是说,切片的时候其中的值可以是负数,这会有不同的效果

List

Python中的列表就类似于其它语言中的数组,但是还是有很多的差别,Python中的数组更加的灵活。

  1. List中的元素可以是不同类型的
  2. 它可以使用切片操作
  3. 和String一样,它也实现了”+“和”*“
  4. 定义的时候使用的是”[]“,其中的元素使用”,“隔开

需要注意的是:String是不可变的,而List是可变的,这点需要特别注意,因为其它编程语言的原因,我总是以为它们是差不多的。

我觉得我主要需要记忆的就是有关它的方法:

函数名作用
append(element)向列表末尾添加一个元素
extend(iterable)将可迭代对象中的元素添加到列表末尾(拼接,但不限于列表
insert(index, element)在指定位置插入一个元素
remove(element)删除列表中第一个出现的指定元素
pop([index])删除并返回指定位置的元素,如果不指定索引,则删除并返回列表最后一个元素
index(element)返回列表中第一个出现的指定元素索引
count(element)返回指定元素在列表中出现的次数
sort()对列表进行排序
reverse()反转列表中元素的顺序
clear()清空列表中的所有元素
copy()返回列表的一个浅拷贝
len(list)返回列表的元素个数

上面的函数很多都是只有最基础的用法,多多使用就会更清楚了

Tuple

元组是Python特有的数据结构,刚看到它的时候以为它就是set,但其实还是有很大差别的:

  • 元组是不可修改啊,而set是可修改的
  • 元组创建的时候使用的是“()”,而set创建的时候使用的是“{}”
  • 元组是有序的,set是无序的(这个有序无序体现在使用的时候是否能用下标进行索引)

元组中的函数跟Srting的差不多,这里就不重复了,若是使用的时候遇到特殊的再添加。
需要强调的是元组的创建,在创建空元组和单元素元组的时候有特殊的语法:

my_tuple = () # 创建空元组
my_tuple = (41, ) # 创建单元素元组

需要强调的是创建单元素的时候,后面这个“,"是不能省略的,若是省略了,编译器会认为这是一个number。

Set

集合用于存储不会重复的元素,它的原理跟C++中的unordered_map一样,是哈希表,它是一种无序的数据结构,因此在使用print输出的时候可能输出的顺序会出人意料,但是总归是有道理的。
在Python中,集合使用”{}“进行创建,元素之间使用”,“进行分隔,和Tuple一样,在创建的时候也有地方需要注意:

my_set = set() # 创建空集合my_set = {} # 错误,创建的是字典

我们不能直接使用“{}”创建集合,因为“{}”被用来创建字典
集合的使用比C++更加灵活,它能够实现交并补操作:

set1 = {1, 2, 3}
set2 = {3, 4, 5}print(set1 & set2)
print(set1 | set2)
print(set1 ^ set2)

除了使用符号,也有相应的函数实现这三个操作:

set1 = {1, 2, 3}
set2 = {3, 4, 5}print(set1.union(set2))  # set1 | set2
print(set1.intersection(set2))  # set1 & set2
print(set1.difference(set2))  # set1 - set2
print(set1.symmetric_difference(set2))  # 对称差集(不同时存在的元素) set1 ^ set2
函数名作用
add(element)向集合中添加元素
update(iterable)将一个可迭代对象的元素添加到集合中
remove(element)从集合中删除指定元素,若是集合中不存在该元素,将会引发KeyError错误
discard(element)也是从集合中删除指定元素,但是不会引发错误
pop()随机移除集合中的一个元素并返回它
clear()清空集合
copy()复制该集合
issubset(other_set)判断该集合是否是other_set的子集
issuperset(other_set)判断该集合是否是other_set的父集

Dictionary

这就是C++中的map,它是无序的,其中存储的元素是键值对,其中所有的值通过来进行存取:

my_dict = {}  # 创建空字典
dict1 = {"key" : 1, }

在使用的时候我们还能使用它的构造函数进行构造:

my_dict = dict('none'=0, 'one'=1)
函数名作用
dict[key]获取指定的键的值
dict.get(key, default=None)获取指定键的值,如果键不存在返回默认值
dict.keys()返回字典中的所有的键
dict.values()返回字典中所有键值对的元组
dict.items()返回字典中所有键值对的元组
dict[key]=value添加或更新指定键的值
dict.update(other_dict)将other_dict的键值对添加到当前字典中
del dict[key]删除指定键的键值对
dict.pop(key)弹出指定键值对的值,并返回该值
dict.clear()清空字典

Bytes类型

这个类型用于二进制转换,我还没怎么看懂,等我看懂了我再写吧

正则表达式

使用正则表达式需要使用模块re

推导式

有很多的数据结构支持推导式:

  • 字典
  • 集合
  • 列表
  • 元组
  • [[#生成器]]
[表达式 for 变量 in 列表] 
[out_exp_res for out_exp in input_list]或者 [表达式 for 变量 in 列表 if 条件]
[out_exp_res for out_exp in input_list if condition]

推导式是直接根据要求生成一个新的变量,原来的变量实际上是没有变过的

set1 = {'a', 'ab', 'abc', 'abcd'}
set2 = [temp for temp in set1 if len(temp) > 1]
print(set1)
print(set2)

列表生成元素表达式是不能够省略的,因为推导式在生成元素的时候会使用该表达式对元素进行处理,若是省略了会直接报错,在上面的代码中我是直接对set1进行了一个简单的过滤操作,若是我将其改为0,则set2中的元素将会全为0,表达式可以是一个有返回值的函数

字典推导式

字典推导式的使用有点不太一样:

{ key_expr: value_expr for value in collection }{ key_expr: value_expr for value in collection if condition }

也就是说,需要分别对进行处理,两者之间跟定义的时候一样,是使用“:"进行分隔的。

推导式的执行顺序

  1. 执行if部分进行元素过滤
  2. 执行exp部分进行元素处理

迭代器和生成器

迭代器

跟C++中的迭代器不太一样,Python中的迭代器只能前进不能后退,它只有两个基本的操作iter()和next()

str = 'Hello World'
it = iter(str)for temp in it:print(temp, end=" ")

iter()获取的是对象的第一个元素,这就跟C++迭代器的begin()是一样的,然后next()就是使迭代器移动到下一个位置,当没有下一个元素的时候,会抛出StopIteration异常
在Python中,迭代器本身就是可迭代的,上面的代码就体现了这一点,这是因为迭代器在设计的时候就定义了_iter_()和_next_()两个函数,在Python中,一个类中只要有这两个函数的实现,那么这个类就是可迭代的

当使用for循环对迭代器进行使用的时候,我们会发现StopIteration这个异常并没有被抛出,这也是Python语言设计的原因,但当我们不使用for循环而使用迭代器的时候,就需要手动处理异常了:

my_iterator = iter([1, 2, 3])
try:while True:item = next(my_iterator)print(item)
except StopIteration:print("迭代结束")

若是我们不对这个异常进行处理,就会出现很奇怪的报错:

  File "c:\Users\Lenovo\Desktop\study\Python\temptlceyka.py", line 1except StopIteration:^^^^^^
SyntaxError: invalid syntax

在实现我们自己的类的时候,为了防止出现死循环的情况,我们也需要在实现next()的时候让其会抛出异常:

class MyNumbers:def __iter__(self):self.a = 1return selfdef __next__(self):if self.a <= 20:x = self.aself.a += 1return xelse:raise StopIterationmyclass = MyNumbers()
myiter = iter(myclass)for x in myiter:print(x)

生成器

[!菜鸟教程]
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回

然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果。

调用一个生成器函数,返回的是一个迭代器对象

def countdown(n):while n > 0:yield nn -= 1# 创建生成器对象
generator = countdown(5)# 通过迭代生成器获取值
print(next(generator))  # 输出: 5
print(next(generator))  # 输出: 4
print(next(generator))  # 输出: 3# 使用 for 循环迭代生成器
for value in generator:print(value)  # 输出: 2 1

所以说,使用了yield的函数就是自己实现了一个迭代器的使用,它通向需要搭配next()进行使用,该函数就相当于自己实现了一个iter()

函数传参

可变对象和不可变对象

函数的定义这块已经很熟了,就是Python中,它函数传参的行为很有意思,想单独记一下。
首先,在Python中,没有值传递和引用传递的概念,只有传可变对象和不可变对象两种,两种对象的传递有不同的行为:

# 函数传参
def func(mult, unmult):print(f"mult's id:{id(mult)}, before change")mult[0] = 1print(f"mult's id:{id(mult)}, after change")print(f"unmult's id:{id(unmult)}, before change")unmult = 100print(f"unmult's id:{id(unmult)}, after change")if __name__ == "__main__":mult = [0, 2, 3, 4]unmult = 1func(mult, unmult)

能够看到,可变对象的地址在函数中是一直没变过的,但是不可变对象的地址在对不可变对象进行修改之后发生了改变,也就是说,在发生改变的时候产生了该不可变对象的副本

关键字参数

Python中允许函数在使用的时候传入的参数顺序和声明的时候不一致,但是这一点需要通过关键字参数进行实现:

def func(num1, num2):print(f"num1 = {num1}")print(f"num2 = {num2}")if __name__ == "__main__":func(num2=2, num1=1)

不定长参数

在Python中,传入不定长参数的形式有两种:

  1. “*”:在传入参数的时候是以元组的形式
  2. “**”:在传入参数的时候以字典的形式

举例说明下:

def func1(*args):# 输出args的类型print(f"func1's args:{type(args)}")def func2(**args):print(f"func2's args:{type(args)}")if __name__ == "__main__":func1(1, 2)func2(a=1, b=2)

由于func2的参数是字典,所以在传入参数的时候,相对应的也需要使用字典的语法。

func1's args:<class 'tuple'>
func2's args:<class 'dict'>

lambda表达式

匿名函数,具体来说就应该叫lambda表达式,因为Python中的lambda和C++中的有点不太一样,Python中的lambda后面跟着的是表达式而不是函数体,它仅仅能封装有限的逻辑。

lambda arg1 [, arg2, ..., argn] : experssion

lambda表达式其实就是一种简单的创建函数对象的方式,但是它不能够代替普通的函数。

[!lambda表达式的使用]
为了保持程序的可读性,推荐仅在逻辑简单、只需少量代码的情况下使用 lambda 表达式。对于复杂逻辑和长代码块,最好使用普通的函数来增强可读性和维护性。
建议避免将 lambda 表达式赋值给变量,而是应该使用 def 关键字来定义函数

# 错误,因为lambda表达式不是函数,它不能使用return
func = lambda num1, num2 : return num1 + num2if __name__ == "__main__":print(func(1, 2))

上面的写法是错误的,因为lambda表达式中的逻辑部分只是表达式而不是函,,因此不能使用retrun

func = lambda num1, num2 : num1 + num2if __name__ == "__main__":print(func(1, 2))

这么写虽然能正确运行,但是编译器可能会报错,这是因为将lambda给了一个变量,从而创建了一个函数对象,但是Python中是不推荐这个行为的:

num = 5
print((lambda num: num ** 2)(num))

这么使用也是可以的。

装饰器

没看懂,现在似乎也用不上,先pass

模块

这就类似C/C++中的头文件:

import module  # 将整个模块导入
# 使用
module.func()

除此之外,还能指定导入模块中的某一函数:

from module import funcfunc()

这种做法有可能会出现命名冲突的问题,此时我们能够通过给模块或调用函数起别名的方式来避免这种麻烦,切记不能出现以下代码!

from module import func
module.func()

当导入模块的时候指定函数了,就不能再通过模块来指定函数了,此时会报错:模块module为定义,若是此时出现了命名冲突呢?

from module import func as my_func
from module import func1 as alias1, func2 as alias2
import module1 as m1, module2 as m2

还能够使用通配符导入模块中的所有内容,但是很容易出现命名冲突的问题,所以是不推荐使用的,在VsCode中甚至会有报错提示,这里就不写了。

__name__属性

在引入模块的时候,被引入的模块的主程序会运行,如何控制模块的控制语句?就是通过该属性。
这里编写一个模块文件mod.py:

def func():print("func called")if __name__ == "__main__":print("this is main")
else:print("this is a module")

在main.py中,如下:

from mod import func as my_func
my_func()

程序的执行结果为:

this is a module
func called

OOP

(好像没什么跟C++不一样的地方)

相关文章:

  • 从零实现ChatGPT:第二章使用注意力Dropout减少过拟合
  • CMS与AI的融合:构建万能表单小程序系统
  • linux的一些知识点分享-------关于操作维护的一些知识点
  • 【通信原理】数字频带传输系统
  • 数据加密技术起到了什么作用?一分钟带你详细了解!
  • openGauss学习笔记-299 openGauss AI特性-AI4DB数据库自治运维-DBMind的AI子功能-SQLdiag慢SQL发现
  • 本地GPT-window平台 搭建ChatGLM3-6B
  • Oracle最终会扼杀MySQL?(译)
  • 最新下载:CorelDraw 2023【软件附加安装教程】
  • Ecovadis审核的内容
  • CG-85C 振弦式土压力计厂家 结构物内部土压力变化量如何测量?
  • 高考志愿填报秘籍:个人篇
  • getDay 与 getUTCDay 本质区别
  • 基于 Delphi 的前后端分离:之三,使用 HTMX
  • H323 截包分析辅流问题
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • eclipse的离线汉化
  • iOS编译提示和导航提示
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • java8 Stream Pipelines 浅析
  • JavaScript实现分页效果
  • JAVA之继承和多态
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • LeetCode29.两数相除 JavaScript
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • mac修复ab及siege安装
  • markdown编辑器简评
  • python_bomb----数据类型总结
  • React Native移动开发实战-3-实现页面间的数据传递
  • Vue.js-Day01
  • Vue组件定义
  • 对超线程几个不同角度的解释
  • 基于webpack 的 vue 多页架构
  • 跳前端坑前,先看看这个!!
  • 微服务核心架构梳理
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 新书推荐|Windows黑客编程技术详解
  • 再次简单明了总结flex布局,一看就懂...
  • 【云吞铺子】性能抖动剖析(二)
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • ​字​节​一​面​
  • "无招胜有招"nbsp;史上最全的互…
  • # Kafka_深入探秘者(2):kafka 生产者
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (done) 声音信号处理基础知识(2) (重点知识:pitch)(Sound Waveforms)
  • (k8s)Kubernetes本地存储接入
  • (ros//EnvironmentVariables)ros环境变量
  • (二)pulsar安装在独立的docker中,python测试
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (十六)Flask之蓝图
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (转)shell中括号的特殊用法 linux if多条件判断
  • ./和../以及/和~之间的区别