【Python】编程笔记3

一、dict 和 set

1、字典——dict

思想:空间换时间
dict 中的 key 必须是不可变对象

(1)定义、初始化

在其他语言中也称为 map,使用键 - 值(key - value)存储,根据key通过hash算法计算value值,可进行快速查找。

## key-value
d = {'Michael':95, 'Bob':75, 'Tracy':85}
print(d['Michael'])

## 其他初始化方式
d['Adam'] = 67
print(d['Adam'])

输出结果:

95
67

key-value 存储方式:必须根据 key算出 value 的存放位置。

(2)查找中,如果 key 不存在, dict 就会报错

==》检测 key 是否在 dict 中:

  • 方法一:in
  • 方法二:get()方法
## 方法1:
print('Tom' in d)
## 方法2:如果 key 不存在,可以返回 None,或指定的值
print(d.get('Tom'))
print(d.get('Tom', -1))

输出结果

False
None
-1

注意:

  • 返回 None 的时候 Python 的交互式命令行不显示结果。
  • dict 内部存放的顺序和 key 放入的顺序是没有关系的。

(3)删除 key

pop(key) ==》key 和所对应的 value 均被删除。

(4)dict vs. list

和 list 比较, dict 有以下几个特点:

  1. 查找和插入的速度极快,不会随着 key 的增加而增加;
  2. 需要占用大量的内存,内存浪费多。

而 list 相反:

  1. 查找和插入的时间随着元素的增加而增加;
  2. 占用空间小,浪费内存很少。

2、集合——set

(1)定义

set 是一组 key 的集合,不存储 value。且 set 中的元素,没有重复。
==》可看作数学意义上的无序和无重复元素的集合

s = set([1, 1, 8, 2, 9, 2, 3, 3])
print(s)

输出结果

{1, 2, 3, 8, 9}

(2)添加元素——add(key)

s.add(4)
print(s)

输出结果

{1, 2, 3, 4, 8, 9}

(3)删除元素——remove(key)

s.remove(4)
print(s)

输出结果

{1, 2, 3, 8, 9}

(4)其他运算

s1 = set([1, 2, 3])
s2 = set([2, 3, 4])
print(s1 & s2)  	## 交集
print(s1 | s2)  	## 并集

输出结果

{2, 3}
{1, 2, 3, 4}

二、不可变对象

问题:

a = 'abc'
print(a.replace('a','A'))
print(a)

输出结果

Abc
abc

虽然字符串有个 replace()方法,也确实变出了’Abc’,但变量 a 最后仍是’abc’,应该怎么理解呢?

分析

重点:a 是变量,而’abc’才是字符串对象
==》a 指向的对象的内容是 ’abc‘
在这里插入图片描述

调用 a.replace(‘a’, ‘A’) 时,作用在字符串对象 ‘abc’ 上,replace 方法创建了一个新字符串’Abc’并返回,如果我们用变量 b 指向该新字符串,就容易理解了,变量 a 仍指向原有的字符串’abc’,但变量 b 却指向新字符串’Abc’了
==》对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的。
在这里插入图片描述

三、函数

一种代码抽象的方式。

1、调用函数

调用函数的时候,如果传入的参数数量不对或者参数类型错误,会报 TypeError 的错误。

2、数据类型转换函数

print(int('123'))
print(int(12.34))
print(float('12.34'))
print(str(1.23))
print(str(100))
print(bool(1))
print(bool(''))

输出结果

123
12
12.34
1.23
100
True
False

3、函数名

函数名,本质是指向一个函数对象的引用。
==》可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”。

a = abs
print(a(-1))

输出结果

1

4、定义函数

格式:def 函数名(参数):,然后,在缩进块中编写函数体,函数的返回值用 return 语句返回。

如果没有 return 语句,函数执行完毕后也会返回结果,只是结果为 None。return None 可以简写为 return。

(1)空函数——pass语句

pass用于占位符,可以先让代码运行起来,之后再进行补充。

def nop():
	pass

还可以放在其他语句中,eg:if 语句

5、参数检查——TypeError错误

  • 参数个数不对
  • 参数类型不对(内置函数可以检查出来,而自己写的会不完善==》参数类型检查)
def my_abs(x):
	## 参数类型检验
    if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
    if x > 0:
        return x
    else:
        return -x

6、返回多个值

本质:函数可以同时返回多个值,但其实就是一个 tuple。

7、函数的参数

参数包括:必选参数、默认参数、可变参数和关键字参数。
==》处理复杂的参数,还可以简化调用者的代码

(1)位置参数(必选参数)

按照位置顺序依次赋给不同的参数。

(2)默认参数

注意:

  • 必选参数在前,默认参数在后。
  • 多参数时,将变化大的参数放在前面,变化小的参数放在后面,变化小的参数可以作为默认参数。
  • 当不按顺序提供部分默认参数时,需要把参数名写上。
    ==》降低调用函数的难度。
def add_end(L = []):
    L.append('END')
    return L

print(add_end([1,2,3]))
print(add_end(['x','y','z']))
print(add_end())
print(add_end())
print(add_end())

输出结果

[1, 2, 3, 'END']
['x', 'y', 'z', 'END']
['END']
['END', 'END']
['END', 'END', 'END']

原因

  • 默认参数 L 是一个变量,它指向对象[],每次调用该函数,如果改变了 L 的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了
    ==》默认参数必须指向不变对象

修改版本

def add_end(L = None):
    if L is None:
        L = []
    L.append('END')
    return L

print(add_end([1,2,3]))
print(add_end(['x','y','z']))
print(add_end())
print(add_end())
print(add_end())

输出结果

[1, 2, 3, 'END']
['x', 'y', 'z', 'END']
['END']
['END']
['END']

(3)可变参数

传入的参数个数是可变的。0 个 或 任意个
==》可变参数在函数调用时自动组装为一个 tuple

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

## 直接调用
print(calc(1,2))
print(calc())   ## 可以 0 个参数

## 调用已有的list或tuple元素
## *nums 表示把 nums 这个 list 的所有元素作为可变参数传进去。
nums = [1,2,3]
print(calc(*nums))

(4)关键字参数

传入 0 个或任意个含参数名的参数
==》这些关键字参数在函数内部自动组装为一个 dict。
==》用于扩展函数的功能,eg:选填参数

def person(name, age, **kw):
    print('name:',name, 'age:',age, 'others:',kw)

## 直接调用
person('Michael', 30)
person('Bob', 35, city='Beijing')
person('Adam', 45, gender='M', job='Engineer')

## 调用已有的dict元素
extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra)

extra 表示把 extra 这个 dict 的所有 key-value 用关键字参数传入到函数的kw 参数, kw 将获得一个 dict,注意 kw 获得的 dict 是 extra 的一份拷贝,对 kw 的改动不会影响到函数外的 extra。

(5)命名关键字参数

关键字参数检查

调用时,仍可传入不受限制的关键字参数

def person(name, age, **kw):
    if 'city' in kw:
        pass
    if 'job' in kw:
        pass
    print('name:',name, 'age:',age, 'others:',kw)

person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)

输出结果

name: Jack age: 24 others: {'city': 'Beijing', 'addr': 'Chaoyang', 'zipcode': 123456}
命名关键字参数——只接受特定的关键字参数

命名关键字参数需要一个特殊分隔符 ** 后面的参数被视为命名关键字参数。

def person(name, age, *,city, job):
    print(name, age, city, job)

person('Jack', 24, city='Beijing', job='Enigneer')

## 命名关键字参数可以有缺省值
def person(name, age, *,city = 'Beijing', job):
    print(name, age, city, job)

注意:

  • 命名关键字参数必须传入参数名,这和位置参数不同。
  • 命名关键字参数可以有缺省值;

(6)参数组合

参数定义顺序
必选参数、默认参数、可变参数/命名关键字参数和关键字参数。其中可变参数无法与命名关键字参数混合。

def f1(a, b, c=0, *args, **kw):
	print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
	print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
f1(1, 2)
f1(1, 2, c=3)
f1(1, 2, 3, 'a', 'b')
f1(1, 2, 3, 'a', 'b', x=99)
f2(1, 2, d=99, ext=None)

## 通过 tuple 和 dict 调用
args1 = (1,2,3,4)
kw1 = {'d':99,'x':'#'}
f1(*args1, **kw1)
args2 = (1,2,3)
kw2 = {'d':99,'x':'#'}
f2(*args2, **kw2)

输出结果

a = 1 b = 2 c = 0 args = () kw = {}
a = 1 b = 2 c = 3 args = () kw = {}
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
a = 1 b = 2 c = 3 d = 99 kw = {'x': '#'}

对于任意函数,都可以通过类似 func(*args, **kw)的形式调用它,无论它的参数是如何定义的。

四、递归函数

如果一个函数在内部调用自身本身,这个函数就是递归函数。

优点:简单、逻辑清晰

1、递归过程

注意:防止栈溢出

在计算机中,函数调用是通过栈( stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
==》解决方法:尾递归
==》尾递归:在函数返回的时候,调用自身本身,并且, return 语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。

def fact(n):
    return fact_iter(n, 1)
def fact_iter(num, product):
    if num == 1:
        return product
    return fact_iter(num - 1, num * product)

遗憾的是,大多数编程语言没有针对尾递归做优化, Python 解释器也没有做优化,所以,即使把上面的 fact(n)函数改成尾递归方式,也会导致栈溢出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值