记Python学习笔记

一、输入与输出

1. 输出

多种输出方式:

print('hello, python')
print('hello', 'python') # ,会被解释为空格
print(10)
print(1+2)

2. 输入

输入使用input,返回值就是输入的内容,参数就是提示语:

str1 = input('Please input:')
print('Your input is:' , str1)

# Please input:aaa
# Your input is: aaa

二、数据类型与变量

1. 数据类型

  1. 整数

    对于大数字可以用_分割,而且十六进制数也支持,例如0xdead_beef,0x100_999_000

    整数的大小没有限制

  2. 浮点数

    对于很大或者很小的浮点数,必须使用科学计数法,把10用e替代,1.23x109就是1.23e9,或者12.3e8,0.000012可以写成1.2e-5

    浮点数没有大小限制,但是超过一定范围就直接表示为inf(无穷大)

    为什么python中的除法也是精确的?

    python中有两种除法:

    1. / : 这种除法运算结果是浮点数,即使结果刚好整除,
    2. // : 地板除,两个整数的除法任然是整数,这会只保留整数部分,其余部分抛弃
  3. 字符串

    字符串以 ’ 或者 “ 括起来,有以下转义字符表示特殊符号

    \n 换行 \t 制表符 \ 右斜线\

    r’ ’表示不转义,也就是想要输入\就不用输入\

    多行内容用

    print('''hello,
    world
    python
    ''')
    
  4. 布尔值

    布尔值与布尔代数完全一致,有True和False两种值

    布尔值可以通过以下运算符运算

    and 与运算 相当于 &&

    or 或运算 相当于 ||

    not 非运算 相当于 ~

  5. 空值

    空值是python中的特殊值,用None表示,None与0不一样,0是有意义的,而None是一个特殊空值

在计算机内部,可以把任意数据类型看作对象,变量就是用来指向这些对象的,

2. 变量

python是动态语言,定义变量类型的时候不需要显式地指定变量类型

>>> a=1
>>> a="hello"
>>> print(a)
hello

3. 常量

常量就是不能改变的变量,通常python中用全部大写的变量名表示常量(只是约定俗成,但是实际并无限制)

三、字符串

总结字符串标志前缀:

r''  # 不转义内容
b''  # bytes类型数据 由于Python的字符串类型是str,在内存中以Unicode表示,
		 # 一个字符对应若干个字节。如果要在网络上传输,
		 # 或者保存到磁盘上,就需要把str变为以字节为单位的bytes。
f''  # f-string格式化字符串

大多数情况下,计算机在存储数据的时候使用UTF-8编码,显示的时候使用Unicode编码

使用记事本时,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:

image.png

浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器:

image.png

编码与解码

在python3中,字符串以Unicode编码,ord()可以将字符转为整数,chr()将编码转换为对于字符

>>> ord('A')
65
>>> ord('你')
20320
>>> chr(20320)
'你'

以Unicode表示的str通过encode()方法可以编码为指定的bytes

>>> 'aaa'.encode('ascii')
b'aaa'
>>> '你'.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character '\u4f60' in position 0: ordinal not in range(128)
>>> '你'.encode('unicode')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
LookupError: unknown encoding: unicode
>>> '你'.encode('utf-8')
b'\xe4\xbd\xa0'
>>> b'\xe4\xbd\xa0'.decode()
'你'

如果bytes中存在小部分无效字节,可以使用error=’ignore’参数忽略

>>> b'\xe4\xbd\xa0\x87'.decode('utf-8', errors='ignore')
'你'
>>> b'\xe4\xbd\xa0\x87'.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x87 in position 3: invalid start byte

字符串长度

>>> len('aaa')
3
>>> len('你好')
2
>>> len(b'你好')
  File "<stdin>", line 1
    len(b'你好')
             ^
SyntaxError: bytes can only contain ASCII literal characters
>>> len('你好'.encode('UTF-8'))
6

一个中文字符在UTF-8编码之后通常占3字节,1个英文字母占一个字节

为了使Python解释器按UTF-8编码读取,可以在文件头加上:

#!/usr/bin/env python3  # 为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释
# -*- coding: utf-8 -*- # 按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码

格式化字符串

  1. 方法一

    类似于C语言的格式化方式,用%实现

>>> 'hello %s' %  ('World')
'hello World'
>>> a = 1
>>> 'num is %d' % a
'num is 1'

如果不知道用什么,可以尝试使用%s,这回将任何类型转换为字符串,同时%%表示一个%字符

  1. 方法二 使用format()

    >>> 'Hello, {0}! Num is {1}, it\'s {2}'.format('vstral', 19, True)
    "Hello, vstral! Num is 19, it's True"
    >>> 'Hello, {}! Num is {}, it\'s {}'.format('vstral', 19, True)
    "Hello, vstral! Num is 19, it's True"
    
  2. 方法三 f-string

使用f开头的字符串

>>> print(f'Hello, {name}! Your age is {age}')
Hello, vstarl! Your age is 19

>>> r = 2.5
>>> s = 3.14 * r ** 2
>>> print(f'The area of a circle with radius {r} is {s:.2f}')
The area of a circle with radius 2.5 is 19.62

四、list与tuple类型

list

list是python内置的一种数据类型,是一种有序的集合,可以随时添加或删除其中的数据

>>> cls = ['aaa', 'bbb', 'ccc']
>>> cls
['aaa', 'bbb', 'ccc']

len()可以获得list元素的个数

>>> len(cls)
3

用索引访问对应位置元素,可以使用正负索引

>>> cls[1]
'bbb'
>>> cls[-1]
'ccc'

追加元素到末尾:

>>> cls.append('ddd')
>>> cls
['aaa', 'bbb', 'ccc', 'ddd']

插入到指定位置

>>> cls.insert(2, 'xxx')
>>> cls
['aaa', 'bbb', 'xxx', 'ccc', 'ddd']

删除末尾元素/删除指定位置

>>> cls.pop()
'ddd'
>>> cls
['aaa', 'bbb', 'xxx', 'ccc']
>>> cls.pop(1)
'bbb'
>>> cls
['aaa', 'xxx', 'ccc']

需要替换某个位置的元素可以直接赋值

>>> cls[1] = 'bbb'
>>> cls
['aaa', 'bbb', 'ccc']

list也可以是一个元素(二维)

>>> cls[2] = ['1', '2', '3']
>>> cls
['aaa', 'bbb', ['1', '2', '3']]
>>> cls[2][2]
'3'

tuple

tuple是另外一种有序列表,叫做元组,与list相似,但是tuple一旦初始化就不能修改,

>>> cla=(1, 2, 3)
>>> cla
(1, 2, 3)
>>> cla[1]=5
Traceback (most recent call last):
  File "<python-input-21>", line 1, in <module>
    cla[1]=5
    ~~~^^^
TypeError: 'tuple' object does not support item assignment

注意,当定义一个元素的tuple时,需要一点添加

>>> a=(2) # ()为运算符
>>> a
2
>>> b=(2,) # 添加一个, 以消除歧义
>>> b
(2,)

当一个tuple有一个list元素会怎么样?

内层的list元素的元素是可以改变的!

这就是指向不变的,tuple指向的是list这个对象,而不是内部的每一个元素

>>> a=(1,2, [3,4])
>>> a
(1, 2, [3, 4])
>>> a[2][1] = 1
>>> a
(1, 2, [3, 1])

五、条件判断与循环控制

条件判断

与C语言类型,使用if-else进行判断,对于多个判断使用elif

这一块不再学习

语法结构

if <条件判断1>:
    <执行1>
elif <条件判断2>:
    <执行2>
elif <条件判断3>:
    <执行3>
else:
    <执行4>

模式匹配

类似于swich case结构,python也有match-case结构

score = 'B'

match score:
    case 'A':
        print('score is A.')
    case 'B':
        print('score is B.')
    case 'C':
        print('score is C.')
    case _: # _表示匹配到其他任何情况,类似于default
        print('score is ???.')

复杂条件匹配

通过将一个值增加到一系列值的匹配

age = 15

match age:
    case x if x < 10:
        print(f'< 10 years old: {x}')
    case 10:
        print('10 years old.')
    case 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18:
        print('11~18 years old.')
    case 19:
        print('19 years old.')
    case _:
        print('not sure.')

循环

  1. for-in循环
a = ['aaa', 'bbb', 'ccc']
for i in a:
    print(i)
    
##
aaa
bbb
ccc

range()函数可以生成一个0-10的整数序列,注意range函数为左闭右开

>>> for i in range(1,10):
...     print(i)
...
1
2
3
4
5
6
7
8
9
  1. while循环

while可以一直循环运行,直到遇到退出的指令或者条件不满足

while True:
	print(1)
  1. break

break可以使得循环提前退出

n = 1
while n <= 100:
    if n > 10: # 当n = 11时,条件满足,执行break语句
        break # break语句会结束当前循环
    print(n)
    n = n + 1
print('END')
  1. continue

循环中,可以使用continue语句跳过当前的循环,直接进入下一次循环

n = 1
while n <= 10:
    n = n + 1
    if n % 2 == 0:
        continue
    print(n)
print('END')

3
5
7
9
11
END

六、dict和set

dict

dict是python内置的字典,在其他语言中也被称为map,使用键值对(Key-Value)储存,有极快的查找速度

>>> d = {'aaa':111, 'bbb':222, 'ccc':333}
>>> d['ccc']
333

为什么dict查找速度这么快?

在list中,查找原理就是从前往后地依次遍历,list越大,查找越慢

而在dict中,给定一个名字 ’aaa’ ,dict就会在内部计算出这个 ‘aaa’ 对应数据的内存地址,直接取出来

dict查找原理:

基于哈希表,这是一种效率极高的数据结构,平均情况下时间复杂度为O(1)

  1. 当执行num[key]的时候,python会调用内置hash(key)计算key得hash值,hash值是一个整数

  2. 计算索引:hash通常是一个很大的整数,所以需要通过取模运算来进行映射

    假设数组大小为n:(index = hash(key) % n)

  3. 检查槽位index位置

    1. 槽位为空:不存在这个健:抛出KeyError异常
    2. 槽位不为空:
      1. 键匹配:存在键值对,而且与查找的key相同(使用 == 比较),返回值,查找完成
      2. 键不匹配:发生hash冲突。即两个不同的健经过hash函数计算后得到相同的数组索引。就需要处理hash冲突(二次探查)

判断一个值是否在dict中

  1. 使用 in 判断

    >>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
    >>> 'Bob' in d
    True
    >>> 'aaa' in d
    False
    
  2. 使用get方法,如果key不存在,返回None(交互环境不显示结果),或者自定义返回值

>>> d.get('Bob')
75
>>> d.get('Bob',-1)
75
>>> d.get('aaa',-1)
-1

删除一个Key

使用pop方法,对应的Value也会被删除

>>> d.pop('Bob')
75
>>> d
{'Michael': 95, 'Tracy': 85}

dict的特性

与list相比,有以下特点:

  1. 查找和插入速度极快,不会随Key增加而变慢
  2. 需要暂用大量内存,内存浪费多

所以dict是一种空间换时间的方法,切记dict的Key是不可变对象,因为dict是根据Key来计算对应Value的存储位置

七、函数

常用函数

函数名 功能
abs 返回绝对值
help 查看函数作用
int 将其他数据类型转换为整数

函数的定义

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

空函数(用来做占位函数,待实现功能)

def nop_func():
	pass

返回多个值(实际上是一个tuple元组)

import math

def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny
    
x, y = move(100, 100, 60, math.pi / 6)
print(x, y)

151.96152422706632 70.0

默认参数:当没有设置这个参数值的时候使用默认参数

def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s
    
def enroll(name, gender, age=6, city='Beijing'):
    print('name:', name)
    print('gender:', gender)
    print('age:', age)
    print('city:', city)
    
enroll('Adam', 'M', city='Tianjin') # 只更改需要更改的默认参数

注意点:默认参数必须指向不变对象!

可变参数

顾名思义,可变参数就是传入的参数是可变的,可以是1个,2个…还可以是0个

def calc(*num):
    total = 0
    for i in num:
        total += i
    return total

print(calc(1, 2))
print(calc(1, 2, 3)

这里传入函数内部的num是一个tuple类型

当想要将一个list或者一个tuple传入到函数的时候,可以使用*

num = {1, 2, 3, 4}

def calc(*nums):
    total = 0
    for n in nums:
        total += n
    return total

print(calc(*num))

关键字参数

可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

def output(name, age, **say):
    print(say)
    print(f'Name: {name}, Age: {age}. say: {say}')

output('Alice', 30, hobby='reading', city='New York')

{'hobby': 'reading', 'city': 'New York'}
Name: Alice, Age: 30. say: {'hobby': 'reading', 'city': 'New York'}

注意:这里的say参数表示把函数外部的这个dict的所有传入到了函数内,并且是一份拷贝,所以函数内的改动并不会影响函数外部

八、高级特性

切片

如何只取出lsit或者tuple中的部分元素?

L = ['Michael', 'Sarah', 'Tracy']
print(L[0:2])
# ['Michael', 'Sarah']

str = "abcdefj"
print(str[1:4])
# bcd

# 倒数第一个元素的索引是-1
str = "abcdefj"
print(str[-4:-1])
# def

str = "abcdefj"
print(str[-4:])
# defj

# 每两个取一个
str = "abcdefj"
print(str[::2])
# acej

练习:利用切片和递归去除字符串首尾的空格

def trim(s):
    if (s[:1] == ' '):
        return trim(s[1:])
    elif (s[-1:] == ' '):
        return trim(s[:-1])
    else:
        return s

# 测试:
if trim('hello  ') != 'hello':
    print('测试失败!')
elif trim('  hello') != 'hello':
    print('测试失败!')
elif trim('  hello  ') != 'hello':
    print('测试失败!')
elif trim('  hello  world  ') != 'hello  world':
    print('测试失败!')
elif trim('') != '':
    print('测试失败!')
elif trim('    ') != '':
    print('测试失败!')
else:
    print('测试成功!')

迭代

如果给定一个list或者tuple,我们就可以通过for循环来遍历这个list或者tuple,这种遍历称为迭代(Iteration)

在python中,迭代通过for-in来完成,C语言的迭代通过遍历每一个下标值来完成,而python的for循环抽象程度高于C的for,因为python的for还可以用在其他可迭代对象上例如dict、字符串等

要想实现类似Java的下标循环,可以使用内置的enumerate将list转换为索引-元素对,这样就可以同时迭代索引和元素本身

a = ['aaa', 'bbb', 'ccc']

for i, v in enumerate(a):
    print(i, v)
    
0 aaa
1 bbb
2 ccc

列表生成式

列表生成式即LIst Comperhensions,是python内置用来创建list的生成式

例如:

  1. 生成1-9的序列
l = list(range(10))
print(l)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  1. 生成12,22,3^2 …
l = []
for i in range(10):
    l.append(i * i)
print(l)

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

或者

l = [x * x for x in range(10)]
print(l)

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

进一步:

l = [x * x for x in range(10) if x % 2 != 0]
print(l)

[1, 9, 25, 49, 81]

还可以两层循环,生成全排列

l = [x+y for x in 'abc' for y in 'cde']
print(l)

['ac', 'ad', 'ae', 'bc', 'bd', 'be', 'cc', 'cd', 'ce']

将list中所有字符转小写

L = ['Hello', 'World', 'IBM', 'Apple']
print([s.lower() for s in L])  

['hello', 'world', 'ibm', 'apple']

列表生成式中的if-else应用

L = [x if x % 2 == 0 else -x for x in range(10)]
print(L)

[0, -1, 2, -3, 4, -5, 6, -7, 8, -9]

生成器 generator

通过列表生成式可以直接创建一个列表,但是当我们想要创建一个很大的列表的时候,而且只需要前面几个元素,就会造成很大的内存浪费

所以可以使用生成器,生成器相当于是保存了列表规律的算法,他会循环推演出后续的元素,这样一边循环一边计算

创建一个generator,有很多方法:

  1. 只需要将一个列表生成式的{ }改为( )
L1 = [i for i in range(10)]
L2 = (i for i in range(10))

print(L1)
print(L2)
print(next(L2))

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
<generator object <genexpr> at 0x0000025363676740>
0
L2 = (i for i in range(10))

print(L2)
for i in L2:
    print(i)

当需要创建一些复杂一点的生成器的时候,单单for就很难实现,但是使用函数就会很容易,比如斐波拉契数列

def fb(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return "done"

fb(6)

1
2
3
5
8
13

这就是定义generator的另一种方法,如果一个函数定义中包含yield关键词,那么这个函数就不再是一个普通函数而是一个generator函数,调用一个generator函数将会返回一个generator

yield函数的执行流程与普通函数不同普通函数是按顺序执行,直到遇到return或者全部执行完毕返回,而yield函数在每次调用next的时候执行,直到遇到yield返回,再次执行时从上一次yield的地方开始

def fb(max):
    n, a, b = 0, 0, 1
    while n < max:
        a, b = b, a + b
        n = n + 1
        yield(b)

f = fb(6)
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))

1
2
3
5
8

注意:调用generator会创建一个generator对象,多次调用generator会创建多个相互独立的generator

在实际使用中一般不会用next来获得下一个返回值,而是使用for循环迭代

但是用for循环调用generator时,发现拿不到return的返回值因为return的返回值在StopIteration错误中

杨辉三角实现:

def triangles():
    L = [1]
    while True:
        yield L[:]
        temp = L[:]
        for i in range(len(L) - 1):
            L[i + 1] = temp[i] + temp[i + 1]
        L.append(1)

# 期待输出:
# [1]
# [1, 1]
# [1, 2, 1]
# [1, 3, 3, 1]
# [1, 4, 6, 4, 1]
# [1, 5, 10, 10, 5, 1]
# [1, 6, 15, 20, 15, 6, 1]
# [1, 7, 21, 35, 35, 21, 7, 1]
# [1, 8, 28, 56, 70, 56, 28, 8, 1]
# [1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
n = 0
results = []
for t in triangles():
    results.append(t)
    n = n + 1
    if n == 10:
        break

for t in results:
    print(t)

注意一个易错点:返回yield的时候要返回L[:]这是为什么呢?

L[:}指的是对L做一次切片拷贝,拷贝和原来的占用不同的内存,为什么不能直接yield L,因为后面使用的是append,实际上是对同一个list对象的引用,下一次修改的时候会导致前面也被修改

posted @ 2025-08-26 17:29  vstral  阅读(11)  评论(0)    收藏  举报