温故而知新--day1
变量类型#
变量是计算机存储数据的内存空间,由于计算机可以处理不同的数据,不同的数据就要定义不同的数据类型。python的数据类型很多,还可以自定义数据类型,常用的一般数据类型有以下几种:
- 整型:
- 在python2版本中有long和int之分,但到了python3中就只有int了。
- 除此之外,整型还有进制的概念:二进制:
0b10
表示十进制2,八进制:0o10
表示十进制8,十进制:10
,十六进制:0x10
表示十进制16
- 浮点型:
- 即float,也就是小数,称之为浮点型是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的。
- 字符串
- 以
"
或'
括起来的字符,比如:"hello, world"。 - 在表示多行字符串时,可以使用三个单引号(
'''
)/双引号("""
)括起来
- 以
- 布尔型
- 表示的是真或假,通常使用True或False表示。
- 一些表达式的结果也可以表示真假,如:
1 != 2
- 空的数据类型(
""、[]、{}
)和None
和0
表示False,反之为True
- 复数
- 如3+5j,跟数学上的复数表示一样,唯一不同的是虚部的i换成了j,了解即可。
函数#
基本概念#
计算机的函数实质上就是一段有特定功能的代码,使用函数可以有效的减少代码的耦合度,同时提高代码的可读性和易维护性。
函数的写法#
计算机的函数和数学的函数有一定的相似性:
- 有参数,相当于数学函数的自变量
- 有返回值,相当于数学函数的因变量
python 的函数使用def
关键词定义,需要写上函数名称,而参数值和返回值需要根据需求考虑是否填写。
如:
def foo(num): return num + 1
参数#
前面说过,参数就相当于数学函数的自变量,主要是一些在函数体中用到的值,python的参数可以指定默认的参数。
def pow(num, count=2): """计算多少次方""" return num ** count if __name__ == "__main__": print(pow(2)) # 4 print(pow(2, 3)) # 8
上面的函数的count参数即指定了默认参数count=2
,对于某些对于参数不确定的函数还可以使用不定长参数,其方式一般为*args
或**kwargs
,这两个参数接收的值的类型分别为list
和dict
。
def foo(*args, **kwargs): for a in args: print(a) for k, v in kwargs.items(): print(k, v) if __name__ == "__main__": foo(1, 2, 3, **{"a": 4, "b": 5, "c": 6}, d=7)
需要注意的是:在传入参数时,可以根据函数参数的位置传参,也可以根据根据参数的关键字传参。二者可以结合使用,但位置参数一定要在关键字参数之前。
比如对于def foo(a, b, c)
来说,既可以foo(1, 2, 3)
也可以foo(b=2, a=1, c=3)
还可以foo(1, c=3, b=2)
但不能foo(c=3, 1, 2)
。
返回值#
使用返回值需要用到一个关键词return
,一个函数的返回值可以是一个或多个值,也可以是一个函数。
导入模块#
由于python没有函数重载的概念,所以假如定义了相同函数名的函数时,前一个函数会被后一个函数所覆盖:
def foo(): print("foo1") def foo(): print("foo2")
在日常的开发过程中,假如是一个人开发的话可以为不同的函数取不同的名字,但假如是多人开发的话就有可能使用相同的函数名。多人开发时通常使用模块(module)开发,在使用时可以使用import关键字导入某个指定的模块。
m1.py
:
def foo(): print("foo1")
m2.py
:
def foo(): print("foo2")
在使用时:
import m1 import m2 # 使用 m1.foo() m2.foo()
需要注意的是:导入模块时会将模块的内容执行一遍,假如不想这样的话,可以使用一个判断语句,使代码主动执行时运行,而不是导入时也运行。
def foo(): print("foo") if __name__ == "___main__": foo()
__name__
是Python中一个隐含的变量它代表了模块的名字,只有被Python解释器直接执行的模块的名字才是__main__。
作用域#
作用域就相当于一个变量可以使用的范围,该作用域的变量只能本作用域和子作用域可用。有了作用域这个概念就有了全局变量和局部变量这两者变量,全局变量即声明在全局作用域中的变量,而局部变量则不是声明在全局的变量,一般来说是一些函数内部声明的变量。
n = 2 # 全局变量 def foo(): m = 3 # 局部变量
根据python的规则,变量会优先找本作用域的,假如找不到会依次往外找,直至找到,当找不到时就会报错。
age = 19 def main(): print(age) main()
但假如要修改外部作用域的变量时,必须使用global
和nonlocal
这两个关键字声明一下,否则报错。因为python会认为修改的这个动作其实是声明,也就是说python没有朝外找变量,假如使用变量在声明变量之前的话,就会报错:UnboundLocalError: local variable 'xxx' referenced before assignment
。
# 这是错误的示范 age = 18 def main(): print(age) age = 20 main() print(age)
正确的方法:
- global
age = 18 def main(): global age print(age) age = 20 main() print(age)
如果我们希望函数内部的函数能够修改嵌套作用域中的变量,可以使用nonlocal
关键字来指示变量来自于嵌套作用域。
2. nonlocal
def test1(): count = 0 def test2(): nonlocal count count += 1 return count return test2() print(test1())
练习#
-
实现计算求最大公约数和最小公倍数的函数。
几个整数中公有的约数,叫做这几个数的公约数;其中最大的一个,叫做这几个数的最大公约数。例如:12、16的公约数有1、2、4,其中最大的一个是4,4是12与16的最大公约数。
-
实现判断一个数是不是素数的函数
# 第一题 求最大公约数和最小公倍数 def gcd(x, y): """最大公约数""" (x, y) = (y, x) if x > y else (x, y) for i in range(x, 0, -1): if x % i == 0 and y % i == 0: return i def lcm(x, y): """最小公倍数""" return x * y // gcd(x, y) # 第二题 def is_prime(num): """判断一个数是不是素数""" for factor in range(2, int(num ** 0.5) + 1): if num % factor == 0: return False return True if num != 1 else False
常用数据结构#
字符串 str#
字符串实质上就是由字符组成的有序序列。前面说过字符串是以引号括起来的,引号里面的内容可以使用\
进行转义,使一般的字符特殊化,如:"\n"
表示换行,"\\"
表示反斜杠\
,除此之外转义符还可以跟八进制(\141
)、十六进制(\x61
)和Unicode编码。
一些常用的转义符
字符 | 含义 |
---|---|
\ |
在行尾时是续行符 |
\\ |
反斜杠符号 |
\' |
单引号 |
\" |
双引号 |
\a |
响铃 |
\b |
退格 |
\e |
转义 |
\000 |
空 |
\n |
换行 |
\v |
纵向制表符 |
\t |
横向制表符 |
\r |
回车 |
\f |
换页 |
除了转义以外,字符串还有很多使用方法。
- 切片
s = "hello, world" print(s[1:4])
如上所述,切片实质上就是拿中括号写成[开头:结尾:步长]
的形式(步长可以省略,且默认为一),把需要截取的一部分内容取出来,不过需要注意的是:切片里面的数不能超过要切片的范围,python的索引以0开始。假如要取开头([:n]
)或结尾([n:]
)的话,可以空着。
- 其他方法
python的字符串还有很多的其他方法,这些方法本质上就是一些函数,使用时以"".xxx()
的形式调用。
s = "hello world" # 大写 print(s.upper()) # HELLO WORLD # 首字母大写 print(s.title()) # Hello World # 小写 print(s.lower()) # hello world # 替换 print(s.replace("world", "world!")) # hello world! # 分割 print(s.split(" ")) # ['hello', 'world'] # join print(" ".join(["hello", "world"])) # hello world # 两边去空 print(" hello world ".strip()) # hello world # 查找 # 找的是第一个的位置,用rfind可以找最后一个 print(s.find("l")) # 2 # print(s.index("t")) # 找不着时会报错 # 判断开头、结尾 print(s.startswith("hello")) # True print(s.endswith("ld")) # True
列表 list#
列表也是python的一种常用的数据结构,上面例子中split
方法的结果就是一个列表。列表由一个个元素组成,各个元素的类型可以各不相同,与字符一样,列表可以切片、也有一些特定的方法,不一样的是,列表可以直接通过索引对元素进行修改,而字符串则不可以。
fruits_list = ["apple", "pear", "peach", "banana"] print(fruits_list[1:]) # ['pear', 'peach', 'banana'] # 修改值 fruits_list[2] = "orange" # ['apple', 'pear', 'orange', 'banana'] # 追加 fruits_list.append("pear") # ['apple', 'pear', 'orange', 'banana', 'pear'] # 插入 # 第一个参数是位置,第二个参数是要插入的元素 fruits_list.insert(0, "cherry") # ['cherry', 'apple', 'pear', 'orange', 'banana', 'pear'] # 迭代添加一个列表 fruits_list.extend(["watermelon", "lemon"]) # ['cherry', 'apple', 'pear', 'orange', 'banana', 'pear', 'watermelon', 'lemon'] # 删除 # 按索引位置删除 fruits_list.pop(0) # ['apple', 'pear', 'orange', 'banana', 'pear', 'watermelon', 'lemon'] # 删列表中的第一个指定值 fruits_list.remove("pear") # ['apple', 'orange', 'banana', 'pear', 'watermelon', 'lemon'] # 排序 # 可以跟匿名函数lambda:fruits_list.sort(key=lambda x: len(x)) fruits_list.sort() # ['apple', 'banana', 'lemon', 'orange', 'pear', 'watermelon'] # 查找 # 第一个指定值的位置 print(fruits_list.index("pear")) # 4 # 清空 fruits_list.clear() # []
元组 tuple#
元组是一种类似于列表的数据结构,它以小括号()
括起来为一个元组,元组的元素同样可以是任意的。但是需要注意的是,元组的元素并不能被改变,这一种特性这某些场合中适用,如某些重要的数据、不允许改变的类属性(__slots__
)和函数的多返回值。由于元组不能被修改,所以我们只需要关注其定义和使用即可。
# 定义元组 fruits_tuple = ("apple", "pear", "peach", "banana") # 也可以使用tuple从其他可迭代数据转换过来 fruits_tuple = tuple(["apple", "pear", "banana", "peach", "banana"]) print(fruits_tuple) # 遍历 for f in fruits_tuple: print(f) # 计数 print(fruits_tuple.count("banana")) # 2 # 查找 print(fruits_tuple.index("banana")) # 2
元组在内存上比列表更小,换句话说使用元组可以节省内存,使用sys.getziseof
函数可以返回该对象的字节数。
import sys print(sys.getsizeof(("apple", "pear", "peach", "banana"))) # 72 print(sys.getsizeof(["apple", "pear", "peach", "banana"])) # 88
字典 dict#
字典是由一个个键值对组成的数据结构,它以大括号({}
)括起来为一个数据,一般的形式为:{"key": "value}
。需要注意的是,字典的键不能重复,也就是说,假如再次给已经存在的键赋值时,原来的值会被替换;而且键是可以被哈希的数据,一般来说,python不可变的内置类型都可以被哈希,而列表和字典是可变的,不可被哈希,所以不能作为集合的元素。。
data = { "name": "lczmx", "age": 18, "address": "xxx", } # 获取 # 1. 使用中括号,类似于索引的方法,假如没有该键的话会报错 print(data["name"]) # lczmx # 2. 使用get方法,没有该键时,返回另一个参数 print(data.get("name", "none")) # lczmx # 3. 获取键值对 for k, v in data.items(): print(f"key: {k} value: {v}") # 4. 获取键或值 for k in data.keys(): print(f"key: {k}") for v in data.values(): print("value: %s" % v) # 更新 # 1. update data.update({"score": 99, "student": True}) # 写法一 data.update(score=99, student=True) # 写法二 # {'name': 'lczmx', 'age': 18, 'address': 'xxx', 'score': 99, 'student': True} # 2. fromkeys # 将一个可迭代的数据的元素作为键,为多个键创建统一的值 # 注意,这是dict的方法 d2 = dict.fromkeys(["a", "b", "c"], "123") print(d2) # {'a': '123', 'b': '123', 'c': '123'} # 3. setdefault # 存在取对应的值,不存在则新增键值对 print(data.setdefault("name", "lczmx")) # lczmx # 删除 # 1. 随机删除,返回被删除的键值对 print(data.popitem()) # ('student', True) # 2. 删除键对应的值,不存在时返回的二个参数 print(data.pop("name", "already delete")) # lczmx # 3. 清空 data.clear() print(data) # {}
集合 set#
python的集合与数学上的集合是一样的,有交集、差集、并集、补集等操作,而且元素是唯一无序的。注意:元素的类型不可变的,准确的说:可以被哈希的数据类型可成为元素。根据集合的这些特性,一般来说其用途一般有两个方面:1. 关系测试(相交等)、2. 去重。
fruits1 = {'cherry', 'pear', 'banana', 'watermelon', 'lemon'} fruits2 = set(['apple', 'pear', 'banana', 'orange']) # 添加 fruits2.add("lemon") # 交差并集可以用方法实现,也可以用符号实现 # 交集 print(fruits1.intersection(fruits2)) print(fruits1 & fruits2) # {'banana', 'lemon', 'pear'} # 差集 print(fruits1.difference(fruits2)) print(fruits1 - fruits2) # {'watermelon', 'cherry'} # 并集 print(fruits1.union(fruits2)) print(fruits1 | fruits2) # {'banana', 'orange', 'pear', 'cherry', 'watermelon', 'lemon', 'apple'} # 删除 # 1. remove # 删除指定元素,不存在则报错 fruits1.remove("banana") # 2. discard # 删除指定元素,不存在不报错 fruits1.discard("apple")
假如定义的时候用forzenset
定义的话,则该集合不可变。
推导式#
推导式是一种构建数据的快捷方式,假如用得好可以简化代码,提高可读性。但假如滥用推导式,就有可能降低代码可读性。一般来说,超过两个for循环的代码,就不适合用推导式了,而直接用多个循环写了。
列表推导式#
顾名思义,即生成列表的推导式,和定义列表一样,列表推导式用中括号包裹着表达式。
假如有这样一个需求:
把num = [18, 22, 23, 50]
里面的数加一,我们固然可以,使用一个for循环把每个元素加一,然后放回原来的列表中。但使用列表推到式只需要一行代码即可:num = [n + 1 for n in num]
。
上面的例子只有一个循环,但假如多个循环该怎么做,如果现在有num和code两个列表:
num = [1, 2, 3, 4, 5] code = ["A", "B", "C", "D"]
要求他们相互组合成['A1', 'A2', 'A3', 'A4', 'A5', 'B1', 'B2', 'B3', 'B4', 'B5', 'C1', 'C2', 'C3', 'C4', 'C5', 'D1', 'D2', 'D3', 'D4', 'D5']
。
很简单:
num = [1, 2, 3, 4, 5] code = ["A", "B", "C", "D"] result = [c + str(n) for c in code for n in num] print(result)
python2.7的版本中使用列表推导式有可能有变量泄露的风险,但在python3中则没有该顾虑,可以放心使用。
生成器表达式#
虽然可以使用列表推导式初始化元组等其它序列类型,但是生成器表达式是更好的选择。由于生成器遵循迭代器协议,可以在用到时才生成元素,可以减少内存开销。生成器表达式在书写上与列表推导式仅仅是把中括号换成了小括号。
比如同样是上面的那个例子:
import sys num = [1, 2, 3, 4, 5] code = ["A", "B", "C", "D"] result_list = [c + str(n) for c in code for n in num] result_tuple = tuple([c + str(n) for c in code for n in num]) result_gen = (c + str(n) for c in code for n in num) print(sys.getsizeof(result_list), sys.getsizeof( result_tuple), sys.getsizeof(result_gen)) # 256 200 112
使用生成器除了可以用生成器表达式,也可以用yeild
关键字:
def gen_result(): num = [1, 2, 3, 4, 5] code = ["A", "B", "C", "D"] for c in code: for n in num: yield c + str(n) for i in gen_result(): print(i)
字典推导式#
自python2.7以来,列表推导式和生成器表达式的概念就移植到了字典上(集合也一样),因此就有了字典推导式。使用字典推导式可以将可迭代的数据作为键值对构建出字典。
例子:
temp = ["A1", "B2", "C3", "D4"] result_dict = {c: n for c, n in temp} print(result_dict) # {'A': '1', 'B': '2', 'C': '3', 'D': '4'}
假如是由两个可迭代数据组成字典的话,可以使用zip
函数:
num = ["1", "2", "3", "4"] code = ["A", "B", "C", "D"] result_dict = dict(zip(code, num)) print(result_dict) # {'A': '1', 'B': '2', 'C': '3', 'D': '4'}
集合推导式#
集合推导式跟列表推导式用起来差不多,下面举个简单的例子即可:
num = ["1", "2", "3", "4"] code = ["A", "B", "C", "D"] result_set = {c + str(n) for c in code for n in num} print(result_set) # {'D3', 'C3', 'A2', 'D1', 'C1', 'C2', 'B4', 'B2', 'B3', 'C4', 'A1', 'D2', 'D4', 'A3', 'B1', 'A4'}
练习#
- 在屏幕上显示跑马灯文字。
import time def main(): string = "放飞你的青春,奔洒你的热情。 " while True: print("\r%s" % string, end="") string = string[1:] + string[0] # 把第一个字符放到最后一个,以达到运动的效果 time.sleep(0.2) if __name__ == '__main__': main()
- 设计一个函数产生指定长度的验证码,验证码由大小写字母和数字构成。
import random def veri_code(count=4): chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' temp = "" for _ in range(count): temp += random.sample(chars, 1)[0] return temp def main(): print(veri_code()) if __name__ == '__main__': main()
- 设计一个函数返回给定文件名的后缀名。
def get_suffix(filename): if "." in filename: return filename.split(".")[-1] else: return ""
- 设计一个函数返回传入的列表中最大和第二大的元素的值。
def get_max(data: list): max1 = 0 # 最大 max2 = 0 # 第二大 for d in data: if d > max1: max2 = max1 max1 = d else: if d > max2: max2 = d return max1, max2
- 打印杨辉三角。
def triangles(): L = [1] while True: yield L L = [sum(i) for i in zip([0] + L, L + [0])] # zip和sum结合,不过要在两边加0
作者:忞翛
出处:https://www.cnblogs.com/lczmx/p/14255940.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
欢迎各位大佬评论交流。可以的话,不妨点一下推荐。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具