End

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.141.23e91.2e-5
  • 字符串:以单引号'或双引号"括起来的任意文本,转义字符为\
  • 字节:bytes类型的数据用带b前缀的单引号或双引号表示,b'ABC'
  • 布尔值:一个布尔值只有TrueFalse两种值,布尔值可以用andornot运算
  • 空值:空值是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 a one-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}

函数

Built-in Functions

基础知识

  • 定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回
  • 如果没有return语句,函数执行完毕后会返回Nonereturn 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的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

为什么要设计strNone这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。

可变参数 *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

posted @ 2018-04-18 13:40  白乾涛  阅读(2609)  评论(0编辑  收藏  举报