注释

单行注释

采用#号进行注释

#这是一个注释

多行注释

采用三个单引号 ''' 或者三个双引号 """ 将注释括起来

'''
这是多行注释,用三个单引号
这是多行注释,用三个单引号
'''

"""
这是多行注释,用三个双引号
这是多行注释,用三个双引号 
"""

变量的定义

在程序设计语言中,变量是一种存储数据的载体,是存储器中存储数据的一块内存空间,变量的值可以被读取和修改,这是所有计算和控制的基础。

变量的命名需要遵循以下这些必须遵守硬性规则和强烈建议遵守的非硬性规则:

  • 硬性规则:
    • 变量名由字母(广义的Unicode字符,不包括特殊字符)、数字和下划线构成,数字不能开头。
    • 大小写敏感(大写的a和小写的A是两个不同的变量)。
    • 不要跟关键字(有特殊含义的单词,后面会讲到)和系统保留字(如函数、模块等的名字)冲突。
  • PEP 8要求:
    • 用小写字母拼写,多个单词用下划线连接。
    • 受保护的实例属性用单个下划线开头。
    • 私有的实例属性用两个下划线开头。
a = 123
print(a)

'''
输出结果:
123

'''

变量的数据类型

计算机能处理的数据有很多种类型,除了数值之外还可以处理文本、图形、音频、视频等各种各样的数据,那么不同的数据就需要定义不同的存储类型。常见的数据类型有:

  • 整型:Python中可以处理任意大小的整数(Python 2.x中有int和long两种类型的整数,但这种区分对Python来说意义不大,因此在Python 3.x中整数只有int这一种了),而且支持二进制(如0b100,换算成十进制是4)、八进制(如0o100,换算成十进制是64)、十进制(100)和十六进制(0x100,换算成十进制是256)的表示法。
  • 浮点型:浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如123.456)之外还支持科学计数法(如1.23456e2)。
  • 字符串型:字符串是以单引号或双引号括起来的任意文本,比如'hello'和"hello",字符串还有原始字符串表示法、字节字符串表示法、Unicode字符串表示法,而且可以书写成多行的形式(用三个单引号或三个双引号开头,三个单引号或三个双引号结尾)。
  • 布尔型:布尔值只有True、False两种值,要么是True,要么是False,在Python中,可以直接用True、False表示布尔值(请注意大小写),也可以通过布尔运算计算出来(例如3 < 5会产生布尔值True,而2 == 1会产生布尔值False)。
  • 复数型:形如3+5j,跟数学上的复数表示一样,唯一不同的是虚部的i换成了j。

格式化输出

代码可以采取格式化输出,其中%表示格式化字符串。%s表示字符串,%d表示整数,%f表示浮点数,%x表示十六进制整数,其中格式化整数和浮点数还可以指定是否补0和整数与小数的位数。

print('%d %d' % (2,8))
#%后面的数字表示数字位数,有数字0表示不足位数则前面补0
print('%4d-%03d' % (3,1))
print('%s %s' % ("hello","world"))
#.2表示保存小数点后两位
print('%.2f' % 3.1415926)

'''
输出结果:
2 8
   3-001
hello world
3.14

'''

如果字符串里面的%是一个普通字符,则用%%进行转义表示一个%

print("%%s是格式化%s输出成字符串类型" % ("hello world"))

'''
输出结果:
%s是格式化hello world输出成字符串类型

'''

运算符

Python支持多种运算符,下表大致按照优先级从高到低的顺序列出了所有的运算符:

运算符描述
[] [:]下标,切片
**指数
~ + -按位取反, 正负号
* / % //乘,除,模,整除
+ -加,减
>> <<右移,左移
&按位与
^ |按位异或,按位或
<= < > >=小于等于,小于,大于,大于等于
== !=等于,不等于
is is not身份运算符
in not in成员运算符
not or and逻辑运算符
= += -= *= /= %= //= **= &= |= ^= >>= <<=(复合)赋值运算符

如果搞不清楚优先级可以使用括号来确保运算的执行顺序

变量的使用

a = 123
b = 456
print(a + b)
print(a - b)
print(a * b)
print(a / b)
print(a // b)
print(a % b)
print(a ** b)

'''
输出结果:
579
-333
56088
0.26973684210526316
0
123
9925006877209885670083146...
'''

以上代码是将变量a和变量b进行了数学运算并且打印出来,我们还可以使用input函数进行进一步修改,让用户可以输入变量的值

a = int(input('a = '))
b = int(input('b = '))
print('%d + %d = %d' % (a, b, a + b))
print('%d - %d = %d' % (a, b, a - b))
print('%d * %d = %d' % (a, b, a * b))
print('%d / %d = %f' % (a, b, a / b))
print('%d // %d = %d' % (a, b, a // b))
print('%d %% %d = %d' % (a, b, a % b))
print('%d ** %d = %d' % (a, b, a ** b))

'''
输出结果
a = 123
b = 456
123 + 456 = 579
123 - 456 = -333
123 * 456 = 56088
123 / 456 = 0.269737
123 // 456 = 0
123 % 456 = 123
123 ** 456 = 992500687720988567008314620574696...
'''

变量的数据类型转换

上面的代码块中int()表示进行了整数数据类型转换,相关的转换方法还有

  • int():将一个数值或字符串转换成整数,可以指定进制。
  • float():将一个字符串转换成浮点数。
  • str():将指定的对象转换成字符串形式,可以指定编码。
  • chr():将整数转换成该编码对应的字符串(一个字符)。
  • ord():将字符串(一个字符)转换成对应的编码(整数)。

我们可以用type检查变量的数据类型

a = 123
b = 123.456
c = 1 + 2j
d = 'hello, world'
e = True
print(type(a))
print(type(b))
print(type(c))
print(type(d))
print(type(e))

'''
输出结果:
<class 'int'>
<class 'float'>
<class 'complex'>
<class 'str'>
<class 'bool'>
'''

分支结构

从上往下执行的代码为顺序结构,当要表示如果的动作时,我们需要使用分支结构。if、elif、else关键字构成分支结构,如下代码为判断用户密码是否正确

username = input('输入用户名: ')
password = input('输入密码: ')
if username == '' and password == '':
    print('输入不能为空!')
elif username == '' :
    print('用户名输入不能为空!')
elif password == '':
    print('密码输入不能为空!')
elif username == 'wakamizu' and password == '123456':
    print('身份验证成功!')

else:
    print('身份验证失败!')

'''
输出结果:
输入用户名: wakamizu
输入密码: 123456
身份验证成功!

'''

分支结构是可以嵌套的,注意逻辑顺序,当分支结构中匹配到某个条件成立时,同一级的代码将不会执行

x=1
if x >= 1:
    print("if-1")
    if x == 1:
        print("if-1-1")
elif x > 0:
    print("elif-1")
else:
    print('else-1')

'''
输出结果:
if-1
if-1-1

'''

循环结构

需要重复执行的命令可使用循环结构

for-in循环

明确知道循环执行的次数或者是要对一个容器进行迭代,推荐使用for-in循环

sum = 0
for x in range(101):
    sum += x
print(sum)

'''
输出结果:
5050

'''

range方法可以产生一个不变的数值序列:

  • range(101)可以产生一个0到100的整数序列。
  • range(1, 100)可以产生一个1到99的整数序列。
  • range(1, 100, 2)可以产生一个1到99的奇数序列,其中的2是步长,即数值序列的增量。

for-in循环中可嵌套if,以下代码为求100以内中偶数的和

sum = 0
for x in range(1, 101):
    if x % 2 == 0:
        sum += x
print(sum)

'''
输出结果:
2550

'''

while循环

不知道具体循环次数的循环结构,我们推荐使用while循环,while循环通过一个能够产生或转换出bool值的表达式来控制循环,表达式的值为True循环继续,表达式的值为False循环结束。

'''
猜数字
'''
import random

answer = random.randint(1, 11)
counter = 0
while True:
    counter += 1
    number = int(input('输入1~10的数字: '))
    if number < 0 or number >10:
        print("输入正确范围的数字")
    elif number < answer:
        print('大一点')
    elif number > answer:
        print('小一点')
    else:
        print('恭喜你猜对了!')
        break
print('一共猜了%d次' % counter)

'''
输出结果:
输入1~10的数字: 99
输入正确范围的数字
输入1~10的数字: 1
大一点
输入1~10的数字: 2
大一点
输入1~10的数字: 5
大一点
输入1~10的数字: 7
小一点
输入1~10的数字: 6
恭喜你猜对了!
一共猜了6次

'''

上面的代码中使用了break关键字,表示终止其所在的那一级循环。还有一个continue关键字,表示跳过本次接下去循环的代码直接开始下一轮循环

字符串的使用

计算字符串长度

str = 'hello, world!'
print(len(str))

'''
输出结果:
13
'''

将字符串首字母转为大写

str = 'hello, world!'
print(str.capitalize())


'''
输出结果:
Hello, world!
'''

将字符串全部字母转为大写

str = 'hello, world!'
print(str.upper())


'''
输出结果:
HELLO, WORLD!
'''

查找子串的位置

str = 'hello, world!'
print(str.find('or'))
print(str.find('He'))

'''
输出结果:
8
-1
#找不到子串会返回-1
'''

print(str.index('or'))
print(str.index('He'))

'''
输出结果:
Traceback (most recent call last):
  File "H:/代码库/python/test/test.py", line 3, in <module>
    print(str.index('He'))
ValueError: substring not found
8
#找不到子串会引起异常
'''

检查字符串是否以指定的字符串开头

str = 'hello, world!'
print(str.startswith('He'))  
print(str.startswith('hel'))


'''
输出结果:
False
True
'''

检查字符串是否以指定的字符串结尾

str = 'hello, world!'
print(str.endswith('!')) 

'''
输出结果:
True
'''

指定字符串宽度并在两侧填充指定的字符

str = 'hello, world!'
print(str.center(20, '*'))


'''
输出结果:
***hello, world!****
'''

指定宽度靠右放置并在左侧填充指定的字符

str = 'hello, world!'
print(str.rjust(20, ' '))


'''
输出结果:
       hello, world!
'''

获取指定下标的字符

str = 'hello, world!'
print(str[2])


'''
输出结果:
l
'''

字符串切片

str = 'hello, world!'
print(str[0:5]) #取下标为0~4的字符
print(str[7:]) #取从下标为7开始到末尾的字符
print(str[2::2]) #取从下标2开始到末尾,每次步进两个单位的字符
print(str[::2]) #取从下标1开始到末尾,每次步进两个单位的字符
print(str[::-1]) #字符左右倒序排列
print(str[-3:-1]) #取从下标为-3到末尾(-1)的字符


'''
输出结果:
hello
world!
lo ol!
hlo ol!
!dlrow ,olleh
ld
'''

检查字符串是否由数字构成

str = 'hello, world!'
print(str.isdigit())


'''
输出结果:
False
'''

检查字符串是否以字母构成

str = 'hello, world!'
print(str.isalpha())

'''
输出结果:
False
'''

检查字符串是否以数字和字母构成

str = 'hello, world!'
print(str.isalnum())

'''
输出结果:
False
'''

裁剪字符串两侧空格

str = ' hello, world! '
print(str.strip())

'''
输出结果:
hello, world!
'''

列表的使用

列表由[]符号定义

输出列表

list = [1,2,3,4,5]
print(list)
list = ['string']*3
print(list)

'''
输出结果:
[1, 2, 3, 4, 5]
['string', 'string', 'string']
'''

计算列表长度

list = [1,2,3,4,5]
print(len(list))

'''
输出结果:
5
'''

索引列表元素

list = [1,2,3,4,5]
print(list[0])
print(list[4])
print(list[-1])
print(list[-2])

'''
输出结果:
1
5
5
4
'''

列表添加元素

list = [1,2,3,4,5]
list.append(99)
print(list)
list += [1000,2000]
print(list)

'''
输出结果:
[1, 2, 3, 4, 5, 99]
[1, 2, 3, 4, 5, 99, 1000, 2000]
'''

列表插入元素

list = [1,2,3,4,5]
list.insert(1,0)
print(list)

'''
输出结果:
[1, 0, 2, 3, 4, 5]
'''

列表删除元素

list = [1,2,3,4,5]
list.remove(2)
print(list)
del list[0]
print(list)

'''
输出结果:
[1, 3, 4, 5]
[3, 4, 5]
'''

清空列表元素

list = [1,2,3,4,5]
list.clear()
print(list)

'''
输出结果:
[]
'''

列表切片

list = [1,2,3,4,5]
print(list[-3:-1])
print(list[::-1])
print(list[0::2])

'''
输出结果:

[3, 4, 5]
[5, 4, 3, 2, 1]
[1, 3, 5]
'''

列表排序

list1 = ['a', 'cd', 'bzh', 'ssa', 'odd']
#正向排序
list2 = sorted(list1)
#反向排序
list3 = sorted(list1, reverse=True)
#以元素字符长度为基准排序
list4 = sorted(list1, key=len)
print(list1)
print(list2)
print(list3)
print(list4)


'''
输出结果:
['a', 'cd', 'bzh', 'ssa', 'odd']
['a', 'bzh', 'cd', 'odd', 'ssa']
['ssa', 'odd', 'cd', 'bzh', 'a']
['a', 'cd', 'bzh', 'ssa', 'odd']
'''

元组的使用

元组与列表类似,不同之处在于元组的元素不能修改。元组在创建时间和占用的空间上面都优于列表。元组由()定义。

获取元组

tuple=(1, 2, 3, 4, 5)
print(tuple)

print(tuple[0])

'''
输出结果:
(1, 2, 3, 4, 5)
1
'''

元组转换成列表

tuple=(1, 2, 3, 4, 5)
print(list(tuple))

'''
输出结果:
[1, 2, 3, 4, 5]
'''

列表转换成元组

list=[1, 2, 3, 4, 5]
print(tuple(list))

'''
输出结果:
(1, 2, 3, 4, 5)
'''

集合的使用

集合跟数学上的集合是一致的,不允许有重复元素,而且可以进行交集、并集、差集等运算。集合由{}定义。

获取集合

set = {1, 2, 3, 3, 3, 2}
print(set)

'''
输出结果:
{1, 2, 3}
'''

添加元素

set = set(range(1, 5))
set.add(9)
set.update([99, 100])
print(set)

set = set(range(1, 5))
set.add(9)
set.update([99, 100])
print(set)

'''
输出结果:
{1, 2, 3, 4, 99, 100, 9}
'''

删除元素

set1 = {1, 2, 3, 3, 3, 2}
set1.discard(1)
print(set1)

'''
输出结果:
{2, 3}
'''

#remove的元素如果不存在会引发KeyError
set1 = {1, 2, 3, 3, 3, 2}
if 4 in set:
    set.remove(4)
print(set)

'''
输出结果:
Traceback (most recent call last):
  File "H:/代码库/python/test/test.py", line 2, in <module>
    if 4 in set:
TypeError: argument of type 'type' is not iterable
'''

集合运算(运算符和方法意义一致)

set1 = {1, 2, 3 ,4}
set2 = {3 ,4 ,5 ,6}
print(set1 & set2)
# print(set1.intersection(set2))
print(set1 | set2)
# print(set1.union(set2))
print(set1 - set2)
# print(set1.difference(set2))
print(set1 ^ set2)
# print(set1.symmetric_difference(set2))
# 判断子集和超集
print(set2 <= set1)
# print(set3.issubset(set1))
print(set1 >= set2)
# print(set1.issuperset(set2))

'''
输出结果:
{3, 4}
{1, 2, 3, 4, 5, 6}
{1, 2}
{1, 2, 5, 6}
False
False
'''

将元组转换成集合

tuple = (1, 2, 3, 3, 3, 2)
print(set(tuple))

'''
输出结果:
{1, 2, 3}
'''

字典的使用

可以存储任意类型对象,与列表、集合不同的是,字典的每个元素都是由一个键和一个值组成的“键值对”,键和值通过冒号分开。由{:}定义。

获取键值

dictory = {'a':1, 'b':2, 'c':3}
print(dictory['a'])
for x in dictory:
    print('%s--->%d' % (x,dictory[x]))

'''
输出结果:
1
a--->1
b--->2
c--->3
'''

更新字典元素

dictory = {'a':1, 'b':2, 'c':3}
dictory['a'] = 3
dictory.update(c=2)
print(dictory)

'''
输出结果:
{'a': 3, 'b': 2, 'c': 2}
'''

设置默认值

dictory = {'a':1, 'b':2, 'c':3}
print(dictory.get('d'))
print(dictory.get('d',2))

'''
输出结果:
None
2
'''

删除元素

dictory = {'a':1, 'b':2, 'c':3}
print(dictory.popitem())
print(dictory)

'''
输出结果:
('c', 3)
{'a': 1, 'b': 2}
'''

dictory = {'a':1, 'b':2, 'c':3}
print(dictory.pop('b'))
print(dictory)

'''
输出结果:
2
{'a': 1, 'c': 3}
'''

清空字典

dictory = {'a':1, 'b':2, 'c':3}
print(dictory.clear())

'''
None
'''

列表生成式语法和生成器语法

列表生成式语法由[]组成,直接输出变量返回运算的具体经过;生成器语法由()组成,直接输出变量返回生成器对象。因为生成式语法运行后直接返回结果,相对会占用较多的内存空间,而生成器语法仅返回对象,需要数据的时候通过内部再进行运算(需要花费较多的时间)。

import sys


#生成式语法
f = [x ** 2 for x in range(1, 10)]
print(sys.getsizeof(f))  # getsizeof()查看对象占用内存的字节数
print(f)
#当if...else在for后面的时候不能加上else,在for前面的时候必须加上else
#[x for x in range(1, 11) if x % 2 == 0]
#[x if x % 2 == 0 else -x for x in range(1, 11)]


#生成器语法
f = (x ** 2 for x in range(1, 10))
print(sys.getsizeof(f))  
print(f)
for val in f:
    print(val)

'''
输出结果:
184
[1, 4, 9, 16, 25, 36, 49, 64, 81]
112
<generator object <genexpr> at 0x0000026DD6971DD0>
1
4
9
16
25
36
49
64
81
'''

还有另外一种定义生成器的方式,就是通过yield关键字将一个普通函数改造成生成器函数。

def fib(n):
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
        yield a

def main():
    for val in fib(10):
        print(val)

if __name__ == '__main__':
    main()

'''
输出结果:
1
1
2
3
5
8
13
21
34
55
'''

函数和模块

解决代码重复,将重复的代码封装到一个称之为”函数“的模块,在有需求的代码块进行调用即可。

函数通过def关键字定义,命名规则和变量的命名规则一致。函数名后的原括号可放置参数传递给函数,函数执行后可通过return返回值。

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

#函数名(参数)表示使用函数
add(1,2)
add(5,6)

#设置默认参数为a=2,b=1,调用函数参数为空时则采用默认参数
def add(a=2,b=1):
    print(a+b)

add()
add(b=2,a=3)
add(5,6)

#在参数名前添加*表示参数为可变参数
def add(*args):
    sum = 0
    for n in args:
        sum += n
    print(sum)

add()
add(1,2)
add(5,6)

'''

输出结果:
3
11
3
5
11
0
3
11
'''

Python中每个文件代表一个模块,不同的模块可以有相同的函数名,使用函数的时候import关键字导入模块即可

from file1 import foo
foo() #执行的是file1的foo函数
from file2 import foo
foo() #执行的是file2的foo函数,也可以看出如果导入模块的语法放在代码首行,后续执行的是最后一个模块的函数

#也可以将模块重命名
import file1 as f1
import file2 as f2
f1.foo
f2.foo

当导入其他模块时不需要直接运行模块的代码,那么模块代码需这样设计,这样直接执行该模块可以运行所有函数,导入则不会:

#file1
def foo():
    pass

def bar():
    pass

#__name__是Python中一个隐含的变量它代表了模块的名字,只有被Python解释器直接执行的模块的名字才是__main__
if __name__ == '__main__':
    foo()
    bar()

作用域

  • 局部作用域:变量作用于一个函数内部,外部访问不到则为局部作用域
  • 嵌套作用域:当对于一个函数内部的函数来说,此时变量为嵌套作用域
  • 全局作用域:当定义一个在任何函数之前的全局变量,其作用于任何一个函数为全局作用域
  • 内置作用域:Python内置的那些隐含标识符min、len等都属于内置作用域

Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索。

使用global可将变量提升为全局作用域,使用nonlocal关键字来指示变量来自于嵌套作用域

#使用global
def foo():
    global a
    a = 200
    print(a)  # 200


if __name__ == '__main__':
    a = 100
    foo()
    print(a)  # 200

'''
输出结果:
200
200
'''

#使用nonlocal
def foo():
    a = 200
    def bar():
        nonlocal a
        a = 100
    bar()
    print(a)

if __name__ == '__main__':
    foo()

'''
输出结果:
100
'''

在实际开发中,我们应该尽量减少对全局变量的使用,因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用,除此之外全局变量比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被垃圾回收。

减少对全局变量的使用,也是降低代码之间耦合度的一个重要举措,同时也是对迪米特法则的践行。减少全局变量的使用就意味着我们应该尽量让变量的作用域在函数的内部,但是如果我们希望将一个局部变量的生命周期延长,使其在函数调用结束后依然可以访问,这时候就需要使用闭包。

闭包

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

f=lazy_sum(1,2,3)
print(f())

'''
输出结果:
6
'''

上面的代码在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变

def count():
    fs = []
    for i in range(1, 4):
        def f():
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
print(f1(),f2(),f3())

'''
f1(),f2(),f3()返回的是9,9,9,原因在于返回的函数引用了变量i后并非立刻执行,而是等到3个函数都返回时,引用的变量i已经变成了3才执行。
当修改一下以上代码再创建一个函数时则返回1,4,9
'''

def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
    return fs

f1, f2, f3 = count()
print(f1(),f2(),f3())

匿名函数

当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便,匿名函数由关键字lambda定义。

print(list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])))
#map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个


'''
输出结果:
[1, 4, 9, 16, 25, 36, 49, 64, 81]
'''

匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。

List of learning reference documents

  • https://github.com/lovevantt/Python-100-Days
  • https://www.liaoxuefeng.com/wiki/1016959663602400