python 基础语法
目录
python 基础语法
Python使用缩进
来组织代码块,约定俗成的习惯是使用4个空格
的缩进
文件头
我们通常在文件开头写上这两行:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
- 第1行注释是为了在
Linux/OS X
系统将此文件当做一个Python可执行程序
,Windows
系统会忽略这个注释 - 第2行注释是为了告诉Python解释器,按照
UTF-8
编码读取源代码
数据类型
Python可以把任何数据
都看成一个对象
,而变量就是在程序中用来指向
这些数据对象的,对变量赋值就是把数据和变量给关联
起来。
- 整数:Python的整数没有大小限制,而某些语言(如Java)的整数受限于其存储长度是有大小限制的
- 浮点数:浮点数也没有大小限制,但是超出一定范围就直接表示为
inf
(无限大),3.14
,1.23e9
,1.2e-5
- 字符串:以单引号
'
或双引号"
括起来的任意文本,转义字符为\
- 字节:
bytes
类型的数据用带b
前缀的单引号或双引号表示,b'ABC'
- 布尔值:一个布尔值只有
True
、False
两种值,布尔值可以用and
、or
和not
运算 - 空值:空值是Python里一个特殊的值,用
None
表示 - 其他:列表、字典、自定义数据类型...
数据类型转换函数
int('123')
int(12.34)
float('12.34')
str(1.23)
bool(1)
bool('')
变量和常量
变量
- 可以把
任意数据类型
赋值给变量,同一个变量可以反复赋值,而且可以是不同类型
的变量。 - 这种变量本身类型不固定的语言称之为
动态语言
,与之对应的是静态语言
。
常量
- 所谓常量就是不能变的变量,在Python中,通常用
全部大写
的变量名表示常量。 - 但事实上Python根本没有任何机制保证一个常量不会被改变,而用全部大写的变量名表示常量,只是一个习惯上的用法。
字符串 str
Python的字符串类型是str
,在内存中以Unicode
表示,一个字符对应若干个字节。
转义与换行
Python允许用r'...'
表示'...'
内部的字符串默认不转义
print('白\\\\乾涛') # 【白\\乾涛】
print(r'白\\\\乾涛') # 【白\\\\乾涛】
print(r'白\\乾涛') # 【白\\乾涛】
Python允许用'''多行内容'''
的格式表示多行内容,多行字符串还可以在前面加上r
表示内部的字符串默认不转义
print('''白
乾涛
你好''')
注意:在交互式命令行内输入时,在输入多行内容时,提示符由
>>>
变为...
,提示你可以接着上一行输入,当输入完结束符和括号)
后,执行该语句并打印结果。
编码
ord()
:获取字符
的整数表示 Return the Unicode code point for aone-character string
chr()
:把编码转换为对应的字符encode()
:把字符串编码为bytes
,无法显示为ASCII字符的字节,用\x##
显示decode()
:把字节解码为字符串,如果包含无法解码的字节会报UnicodeDecodeError
,可以传入errors='ignore'
忽略错误的字节
print(ord('A'), ord('1'), ord('中')) # 65 49 20013
print(chr(66), chr(50), chr(25991)) # B 2 文
print('\u4e2d\u6587') # 中文
print('ABC'.encode('ascii'), 'ABC'.encode('utf-8')) # b'ABC'
print('中文'.encode('utf-8')) # b'\xe4\xb8\xad\xe6\x96\x87'
print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')) # 中文
print(b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')) # 中
长度
len()
:计算字符串的字符数,或bytes
的字节数 Return the number of items in a container
print(len('ABC'), len(b'ABC'), len('中文'), len('中文'.encode())) # 3 3 2 6
输入输出
输出 print
print()
函数可以接受多个参数,打印时遇到逗号会输出一个空格
print("白", "乾涛", 30, True) # 白 乾涛 30 True
在Python中,采用的格式化方式和C语言是一致的,用%
实现。如果只有一个%?
,括号可以省略;可以用%%
来表示一个%
。
占位符 | 替换内容 |
---|---|
%d | 整数,可以指定是否补0 |
%f | 浮点数,可以指定小数的位数 |
%s | 字符串,%s 永远起作用,它会把任何数据类型转换为字符串 |
%x | 十六进制整数 |
print('%2d+%2d+%02d' % (111, 2, 3)) # 【111+ 2+03】
print('%.2f_%.3f' % (3.1415, 3.1415)) # 【3.14_3.142】
print('增长 %d %%' % 7) # 【增长 7 %】
输入 input
input()
可以让用户输入字符串,并存放到一个变量里
name = input('please enter your name: ')
print('hello,', name)
s = input('你的年龄: ') # 返回的数据类型是str
print(int(s) + 1)
语句
条件判断 if:
if判断条件只要是非零数值、非空字符串、非空list
等,就判断为True
,否则为False
if age >= 18:
print('adult')
elif age >= 6:
print('teenager')
else:
print('kid')
if age:
print('非零数值')
循环 for/in while:
在循环过程中,break
语句可以提前退出循环,continue
语句可以跳过当前的这次循环,直接开始下一次循环
for x in range(10):
print(x)
x = 0
while x < 10:
x += 1
print(x)
集合
list []
list是一种有序
的集合
mlist = ['白乾涛', '包青天', 'bqt']
print(len(mlist), mlist[0], mlist[-1], mlist[-2]) # 3 白乾涛 bqt 包青天
mlist.append("a") # 追加元素到末尾
mlist.insert(1, '哈哈') # 把元素插入到指定的位置
print(mlist) # ['白乾涛', '哈哈', '包青天', 'bqt', 'a']
mlist.pop() # 删除末尾的元素
mlist.pop(-2) # 删除指定位置的元素
mlist[0] = 30 # 修改元素的值,元素的数据类型可以不同
mlist[1] = ["a", "b"] # list的元素也可以是另一个list
mlist[1][1] = [] # 如果一个list中一个元素也没有,就是一个空的list
print(mlist) # [30, ['a', []], 'bqt']
print(mlist[1][0], len(mlist[1][1])) # a 0
r = range(5) # range()函数可以生成一个整数序列
print(r) # range(0, 5)
l = list(r) # list()函数可以将一个整数序列转换为list
print(l) # [0, 1, 2, 3, 4]
tuple ()
tuple和list非常类似,但是tuple一旦初始化,其元素
就不能改变(注意,这里的意思是:tuple的元素的指向不变)!
t = (1, "bqt") # 定义tuple时,tuple的元素就必须被确定下来
print(t, len(t), t[0], t[-1]) # (1, 'bqt') 2 1 bqt
t[0] = 2 # TypeError: 'tuple' object does not support item assignment
t = (1) # 这种形式定义的不是一个tuple,是1这个数
print(t, isinstance(t, tuple), isinstance(t, int)) # 1 False True
t = (1,) # 定义只有1个元素的tuple时必须加一个逗号来消除歧义,显示时也会加一个逗号
print(t, isinstance(t, tuple), isinstance(t, int)) # (1,) True False
t = () # 定义一个空的tuple
print(t) # ()
t = ('a', ['A']) # 虽然tuple的元素的指向不变,但是变量t可以指向其他对象
t[1][0] = 'B' # 这里改变的并不是tuple的元素,tuple的元素是一个list,而list的指向并没有变
t[1].append(3)
print(t) # ('a', ['B', 3])
dict {}
dict
是字典dictionary
的简称,在其他语言中也称为map
,使用键-值对
存储,具有极快的查找速度
dict
是用空间换时间
的一种方法:查找和插入的速度极快,不会随着key的增加而变慢,但需要占用大量的内存dict
内部存放的顺序和key放入的顺序是没有关系的dict
根据key来计算value的存储位置,这个通过key计算位置的算法称为哈希hash
算法dict
的key必须是不可变对象,字符串、整数等都是不可变的,适合作为key
d = {'Michael': 90, 'Bob': 80, 'Tracy': 70}
d['Bob'] = 60 # 如果key存在,效果为修改
d['Adam'] = 50 # 如果key不存在,效果为增加
print(d.pop('Michael')) # 90,移除一个key及其对应的value
print(d) # {'Bob': 60, 'Tracy': 70, 'Adam': 50}
print("bqt" in d, 'Bob' in d) # False True
print(d.get("bqt")) # 如果key不存在,这种方式会返回【None】
print(d["bqt"]) # 如果key不存在,这种方式会报【KeyError】
set ([])
set和dict的唯一区别仅在于没有存储对应的value
,但是,set的原理和dict一样,所以,同样不可以放入可变对象
,因为无法判断两个可变对象是否相等,也就无法保证set内部不会有重复元素
。
s = set([2, 1, 1, 3, 3]) # 通过一个list创建set
s.add(3) # This has no effect if the element is already present
s.remove(3) # If the element is not a member, raise a KeyError
print(s) # {1, 2} 打印的顺序不表示set是有序的,且和key放入的顺序也没有关系
t = (2, 3) # 这个tuple的元素都是不可变的,所以tuple也不会改变,因此可以放入set中
l = ['a', 1, t]
s = set(l)
s.add(2)
print(s, len(s)) # {(2, 3), 1, 2, 'a'} 4
try:
s.add(l) # 因为list是可变的,放入set中会报TypeError: unhashable type: 'list'
except Exception as e:
print("Exception", e) # unhashable type: 'list'
t = ([(4, 5)], 6) # 因为tuple的元素是可变的,所以导致tuple也会改变,因此不可以放入set中
s.add(t) # TypeError: unhashable type: 'list'
set可以看成数学意义上的无序和无重复元素的集合,因此,两个set可以做数学意义上的交集、并集等操作:
s1 = set([1, 2, 3])
s2 = set([2, 3, 4])
print(s1 & s2, s1 | s2) # {2, 3} {1, 2, 3, 4}
函数
基础知识
- 定义一个函数要使用
def
语句,依次写出函数名、括号、括号中的参数和冒号:
,然后,在缩进块中编写函数体,函数的返回值用return
语句返回 - 如果没有
return
语句,函数执行完毕后会返回None
,return None
可以简写为return
- 用
from file_name import function_name
可以导入file_name.py
中的function_name
函数 - 用
import math
可以导入math
包,并允许后续代码引用math包里的sin、cos等函数
def hello(x):
return "hello, " + str(x)
a = hello # 函数名其实就是指向一个函数对象的引用,所以可以把函数名赋给一个变量
print(a("白乾涛")) # 所以也可以通过a调用hello函数
def my_abs(x):
if not isinstance(x, (int, float)): # 数据类型检查
raise TypeError('类型错误,只能传递int或float类型')
pass # pass语句什么都不做,可以用来作为占位符
def move(x, y):
return x + 1, y + 2
a, b = move(1, 1) # 如果要接收多个返回值,必须用相同数量的变量
t = move(1, 1) # 返回值其实是一个tuple,在语法上,返回一个tuple时可以省略括号
c, d = t # 多个变量可以同时接收一个tuple,按位置赋给对应的值
print(a, b, c, d, t, type(t)) # 2 3 2 3 (2, 3) <class 'tuple'>
位置参数/必选参数
调用函数时根据函数定义的参数位置来传递参数
- 参数定义的顺序必须是:必选参数、
默认参数
、可变参数
、命名关键字参数和关键字参数 - 虽然可以组合多达5种参数,但不要同时使用太多的组合,否则函数接口的可理解性很差
默认参数
用于定义函数,为参数提供默认值,调用函数时可传可不传该默认参数的值。
def power(x, n="n", k="k"): # 位置参数在前,默认参数在后
print(x, n, k)
power(5) # 5 n k
power(5, "nn") # 按顺序提供默认参数 5 nn k
power(5, "nn", "kk") # 5 nn kk
power(5, k="kk", n="nn") # 把参数名写上可以不按顺序提供默认参数 5 nn kk
power(5, k="kk") # 也可以不按顺序提供部分默认参数 5 n kk
默认参数必须指向不变对象
def add_end(L=[]):
L.append('END')
return L
print(add_end([1, 2]), add_end(["x", "y"])) # [1, 2, 'END'] ['x', 'y', 'END']
print(add_end()) # ['END']
print(add_end(), add_end()) # ['END', 'END', 'END'] ['END', 'END', 'END']
Python函数在定义的时候,默认参数
L
的值就被计算出来了,即[]
,因为默认参数L
也是一个变量,它指向对象[]
,每次调用该函数,如果改变了L
的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]
了。
为什么要设计str
、None
这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改
,这样就减少了由于修改数据导致的错误。
可变参数 *args
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple
def calc(x, y="y", z="z", *args): # 顺序必须为:位置参数 -- 默认参数 -- 可变参数
print(x, y, z, args) # args在这里是一个tuple, <class 'tuple'>
nums = [1, 2]
calc("xx") # xx y z ()
calc("xx", *nums) # xx 1 2 ()
calc("xx", "yy", *nums) # xx yy 1 (2,)
calc("xx", 1, 2) # xx 1 2 ()
# 注意下面两个语法
calc("xx", z="zz") # xx y zz ()
calc("xx", y="yy", *nums) # 运行报错 TypeError: got multiple values for argument 'y'
calc("xx", y="yy", 1, 2) # 编译报错 Positional argument after keyword argument
关键字参数 **dict
关键字参数允许你传入0个或任意个含参数名的参数
,这些关键字参数在函数内部自动组装为一个dict
def person(name, **kw):
print(name, kw) # kw 的类型为 <class 'dict'>
person('bqt') # bqt {}
person('bqt', age="30") # bqt {'age': '30'}
person('bqt', age="30", city="sz") # bqt {'age': '30', 'city': 'sz'}
extra = {"age": "30", "city": "sz"}
person('bqt', **extra) # bqt {'age': '30', 'city': 'sz'}
**extra
表示把extra
这个dict的所有key-value
用关键字参数传入到函数的**kw
参数,kw
将获得一个dict
注意
kw
获得的dict是extra
的一份拷贝,对kw
的改动不会影响到函数外的extra
命名关键字参数 =
- 函数的调用者可以传入任意
不受限制
的关键字参数,如果要限制关键字参数的名字,就可以用命名关键字参数 - 命名关键字参数需要一个特殊分隔符
*
,*
后面的参数被视为命名关键字参数,否则定义的将是位置参数 - 如果函数定义中已经有了一个
可变参数
,后面跟着的命名关键字参数就不再需要一个特殊分隔符*
了 - 命名关键字参数必须传入
参数名
- 必须传递所有的命名关键字参数,除非命名关键字参数有缺省值
def person(name, *, age=20, city):
print(name, age, city)
person('bqt', city="sz", age=30) # bqt 30 sz
person('bqt', city="sz") # bqt 20 sz
extra = {"age": 30, "city": "sz"}
person('bqt', **extra) # bqt 30 sz
def person(name, *args, age, city): # 有一个可变参数,不再需要一个特殊分隔符*
print(name, args, age, city)
递归函数
如果一个函数在内部调用自身本身,这个函数就是递归函数
所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出
。在计算机中,函数调用是通过栈stack
这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧
,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
def fact(n):
if n == 1:
return 1
return n * fact(n - 1)
print(fact(998)) # 不堆栈溢出的最大数
print(fact(999)) # RecursionError: maximum recursion depth exceeded in comparison
案例:汉诺塔
s = input('输入个数: ')
file = open("result.txt", "w")
def move(n, a, b, c):
if n == 1:
print(a, '-->', c) # 如果只有一个盘子,直接从a柱移动到c柱
file.write(a + " --> " + c + "\n")
else:
move(n - 1, a, c, b) # 将a柱上的n-1个盘子通过c柱移动到b柱
print(a, '-->', c) # 移动完n-1个盘子之后,a柱剩下的最大盘子直接从a柱移到c
file.write(a + " --> " + c + "\n")
move(n - 1, b, a, c) # b柱上的n-1个盘子通过a柱移动到c柱
move(int(s), 'a', 'b', 'c')
file.close()
2018-04-18
本文来自博客园,作者:白乾涛,转载请注明原文链接:https://www.cnblogs.com/baiqiantao/p/8874285.html