数据类型(补充) [上一部分]

* 集合
* 时间日历

函数

* 函数的参数
* 返回值
* 偏函数
* 高阶函数
* 匿名函数
* 闭包
* 装饰器
* 生成器

#### 集合

**无序的** ,**不可随机访问的** ,**不可重复**的元素集合

* 与数学中的集合类似,可以进行集合的**交 、并 、差、补**等操作 。
* 分为**可变集合**和**不可变集合**
* set: 可以进行**增、删 、改**操作
* frozenset: 创建好之后,无法再做修改 。

##### 可变集合的表示

```
# 直接表示

s = {1, 2, 3, 4}
print(s, type(s)) # {1, 3, 4, 2} <class 'set'>

# set(Iterable)

s1 = set("abc")
s2 = set([1, 2, 3])

print(s1, s2) # {'a', 'b', 'c'} {1, 2, 3}

# 集合推导
# 参考列表推导

s = {x for x in range(3)}
print(s) # {1, 0, 2}

```

##### 不可变集合

```
# frozenset(iterable)

fs = frozenset("abc")
print(fs) # frozenset({'a', 'c', 'b'})

# 集合推导

fs = frozenset(x**2 for x in range(1, 6) if x % 2)
print(fs) # frozenset({1, 25, 9})

```

##### 注意事项

* 创建空集合

```
# 错误做法
s = {} # 实际上构建了一个空字典

s = set() # 空集合

```

* 集合中的元素必须是**可哈希**的值(不可变类型)。
* 集合中元素若出现重复 ,则会被合并成一个。

```
# 多用于给列表元素进行去重

li = {1, 2, 2, 3, 3}
li = list(set(li))
print(li) # [1, 2, 3]

```

##### 集合的操作

* 单集合操作

```
s = {1, 2, 3}

#-----------------------------------------
# 新增元素
# 1.集合可变 2.新增元素可哈希

s.add(4)
print(s) # {1, 3, 2, 4}

#-----------------------------------------
# 删除元素
# 1.remove(element)
# 删除指定的元素,若无该元素,报错

s.remove(2)
print(s) # {1, 3}

# 2.discard(element)
# 删除指定的元素 ,若无该元素,pass

s.discard(2)
print(s) # {1, 3}
s.discard(666)
print(s) # {1, 3}

# 3.pop(element)
# 删除并返回指定元素,若无该元素 ,报错
# 省略 element,不指定删除元素,进行随机删除;集合为空 ,报错

s.pop(1)
print(s) # {2, 3}

s.pop()
print(s) # {2}

s.pop()
print(s) # set() //空集合的意思

# 4.clear()
# 清空集合,集合依然存在

s.clear()
print(s) # set()

#-----------------------------------------
# 遍历集合
# 1.for in

for v in s:
print(s, sep=' ') # 1 2 3

# 2.迭代器
its = iter(s)

print(next(its)) # 1
print(next(its)) # 2
print(next(its)) # 3

```

* 多集合操作

* **intersection(iterable)**:

```
# 求交集,参数是可迭代类型
s1, s2 = {1, 2, 3, 4, 5}, {9, 8, 8, 5, 4}

res = s1.intersection(s2)
print(res) # {4, 5}
# s1也可以是frozenset ,返回结果也是frozenset

# 可以使用逻辑运算符来完成
print(s1 & s2) # {4, 5}

```

* **intersection_update(iterable)**

```
# 更新调用该方法的对象
s1, s2 = {1, 2, 3, 4, 5}, {9, 8, 8, 5, 4}
s1.intersection_update(s2)
print(s1) # {4, 5}

```

* **union(iterable)**:

```
# 求并集 ,参数是可迭代类型
s1, s2 = {1, 2, 3}, {2, 3, 4}

res = s1.union(s2)
print(res) # {1, 2, 3, 4}

# 可以使用逻辑运算符来完成
print(s1 | s2) # {1, 2, 3, 4}

```

* **update(iterable)**

```
s1, s2 = {1, 2, 3}, {2, 3, 4}
s1.update(s2)
print(s1) # {1, 2, 3, 4}

```

* **difference(iterable)**

```
# 求差集
s1, s2 = {1, 2, 3}, {2, 3, 4}
res = s1.difference(s2)
print(res) # {1}

# 逻辑运算符
print(s1 - s2) # {1}

```

* **difference_update(iterable)**:

```
s1, s2 = {1, 2, 3}, {2, 3, 4}
s1.difference_update(s2)
print(s1) # {1}

```

* **判定操作**

```
# isdisjoint() 两个集合是否不相交
# isuperset() 一个集合是否包含另一个集合
# issubset() 一个集合是否包含于另一个集合

```

#### 时间日历

##### time模块

* 获得当前时间戳

```
# 获得从 1970年1月1日到现在的时间秒数

import time
t = time.time()

yearSpan = t / (60 * 60 * 24 * 365)
print(yearSpan) # 48.6441059296045

```

* 获得时间元组

```
# 根据所给的时间戳,返回当时的时间信息

import time
t = time.time()

res = localtime(t)
print(res) # time.struct_time(tm_year=2018, tm_mon=8, tm_mday=12, tm_hour=10, tm_min=22, tm_sec=4, tm_wday=6, tm_yday=224, tm_isdst=0)

```

* 获得格式化的时间

```
# 根据所给定的时间戳,返回一个更加可读的时间

import time
t = time.time()

res = time.ctime(t)
print(res) # Sun Aug 12 10:33:58 2018

```

* 获得格式化的时间字符串

```
# time.strftime(格式字符串, 时间元组)

res = time.strftime("%y-%m-%d %H:%M:%S", time.localtime())
print(res) # 18-08-12 10:39:28

res = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
print(res) # 2018-08-12 10:39:50

```

* 获取当前cpu时间

```
# 常用来统计一段代码的执行时间
import time

# IDLE环境测试

start = time.clock()
for i in range(0, 10)
print(i, end=' ')
end = time.clock()

print(end - start) # 0.02806393769252448

```

* 休眠

```
# 线程休眠

# 每隔一秒打印一个数字
import time

n = 0
while True:
print(n)
time.sleep(1) # 参数单位是秒

```

##### datetiem模块

模块内部有多个**类**:**datetime**、**date**、**time** 。使用时选择合适的类进行操作就行了

* 获取当天的日期

```
import datetime
t = datetime.datetime.now()

print(type(t)) # <class 'datetime.datetime'>
print(t) # 2018-08-12 11:04:12.982890
print(t.year) # 2018
print(t.month) # 8

```

* 计算n天之后的日期

```
import datetime

t = datetime.datetime.today()
res = t + datetime.timedelta(days=7)
print(t, res, sep='|') # 2018-08-12 11:10:31.995501|2018-08-19 11:10:31.995501

```

* 获得两个日期的时间差

```
import datetime

first = datetime.datetime(2018, 9, 10, 12, 0, 0)
second = datetime.datetime(2018, 10, 1, 0, 0, 0)

res = second - first
print(res) # 20 days, 12:00:00

```

#### 函数

* 将一段代码集中到一块 ,起一个名字,下次可以根据这个名字再次使用这个代码块。
* 作用
* 方便代码重用
* 分解任务,简化程序逻辑
* 使代码更加模块化

##### 函数的参数

所有的传参方式都是传**引用** ,注意**列表**做参数和**数值**做参数容易出现的问题。

* 单个参数

* 多个参数

```
# 定义方式
def funName(arg1, arg2, arg3...):

# 调用方法
funName(arg1, arg2, arg3...) # 形参和实参一一对应
funName(arg2=v1, arg3=v3, arg1=v1) # 指明形参的名称,不用严格按照顺序

```

* 不定长参数

```
# 1\. 利用元组的拆包装包
def mySum(*args):
print(type(args)) # <class 'tuple'>
print(args) # (1, 2, 3, 4)
print(*args) # 拆包操作 1, 2, 3, 4

for v in args:
# todo ...
# 装包,将传入的参数装入一个元组中 ,args就成了一个元组对象
# 拆包,将一个元组中的元素拆分出来,*args就成了参数序列

# 2\. 利用字典的键值对
def myInfo(**args):
print(type(args)) # <class 'dict'>

# todo ...

myInfo(name="rity", age=12)

```

* 默认参数

```
# 调用某些函数时 ,可以省略某些参数,采用定义时指定的值
# 若不省略,则以调用时输入的为准

def sorted(iterable, reverse=False):
# todo...

sorted([1, 3, 2, 5], reverse=True)

```

##### 返回值

* 返回语句标志着函数的结束 ,一个函数最好只有一处返回语句
* 如果想**返回多个数据** ,可以把数据包装成一个集合,整体返回(列表,元组 ,字典...)

```
def funName():
# todo...
return data

```

##### 偏函数

* 对于一个默认值较多的函数,有时我们需要重复用到其中的部分默认值,每次指定默认值比较麻烦 。
* 可以将其中的默认值先赋值好 ,然后封装成一个新的函数,这就是偏函数。

```
import functools

numStr = "100010"
res = int(numStr, base=2)
print(res) # 34

int2 = functools.partial(int, base=2) # 重新封装,构成偏函数
print(int2(numStr)) # 34

```

##### 高阶函数

* 一个函数的参数可以是另外一个函数

```
def calculate(a, b, cal_fun):
print(cal_fun(a, b))

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

def sub(a, b):
return a - b

calculate(2, 3, sum) # 5
calculate(2, 3, sub) # -1

```

##### 匿名函数

* lambda表达式
* 没有名字的函数

```
res = (lambda x, y : x + y)(1, 2)
print(res) # 3

fun = lambda x, y : x + y
print(fun(2, 3)) # 5

# 更多的是配合 map(), reduce()等函数进行使用

```

##### 闭包

* 在函数嵌套定义的前提下
* 内层函数引用了外层函数的变量
* 外层函数把内层函数当做返回值

```
def line_config(content, length):

define line():
print(content * length)

return line

line1 = line_config("-", 5);
line2 = line_config("*", 6)

line1(); # -----
line2(); # ******

```

* 作用域问题:内层函数要修改外层函数的变量,要使用**nonlocal**进行声明 ,否则变量属于内层函数。

```
def test():
num = 10

def test2():
nonlocal num # test中的 num被修改
num = 666

return test2

```

* 当内层函数使用外层的变化量时,注意值得情况

```
def test():
funs = []
for i in range(1, 4):

def test2():
print(i)

funs.append(test2)
return funs

myFuns = test()

myFuns[0]() # 3 // 函数在运行时才会去确定变量的值
myFuns[1]() # 3 // 运行时,索引 i的值已经发生变化了
myFuns[2]() # 3

```

##### 装饰器

* 在调用目标函数之前 ,对这个函数对象进行**装饰**(增加一些其他功能) 。
* 函数的**名字不能改变**。
* 函数体内部的**代码不能发生改变**。

```
def check(func):

def inner():
print("登录验证...")
func()

return inner()

# 在 fss()和 ftp()执行之前,都会送入 check()进行包装

@check
def fss():
print("发说说")

# 上面三行等价于 fss = check(fss)

@check
def ftp():
print("发图片")

# 上面三行等价于 ftp = check(ftp)

# 主业务逻辑如下:

flag = 1
if flag == 1:
fss() # 登录验证...
else: # 发说说
ftp()

```

* 多个装饰器的调用顺序

```
def one(func):
print('----1----')
def two():
print('----2----')
func()
return two

def a(func):
print('----a----')
def b():
print('----b----')
func()
return b

@one
@a
def demo():
print('----3----')

demo()

# 运行结果 //从下到上装饰,从上到下执行 ,分析略
# 装饰的过程就相当于你把一件礼物一层一层的进行包装 ,先包装内层
# 执行的过程就是把礼物拆开,最外面的包装先被拆开
----a----
----1----
----2----
----b----
----3----

```

* 对**带有参数**的函数进行装饰

```
def zsq(funcs):

def inner(*args, **kwargs): # 装包
print("-" * 5)
func(*args, **kwargs) # 拆包
return inner

@zsq
def fun1(n1, n2, n3):
print(n1, n2, n3)

@zsq
def fun2(n):
print(n)

fun1(1, 2, n3=8) # 1 2 8
fun2(3) # 3

```

* 对带**有返回值的**函数进行装饰

```
def zsq(funcs):

def inner(*args, **kwargs): # 装包
print("-" * 5)
res = func(*args, **kwargs) # 拆包
return res

@zsq
def fun1(n1, n2, n3):
return sum(n1, n2, n3)

fun1(1, 2, 3)

```

* 带有参数的装饰器

```
def getzsq(char):

def zsq (func):

def inner():
print(char * 5)
func()

return inner

return zsq

@getzsq("*")
def f(): # *****
print("666") # 666

@getzsq("-")
def f1(): # -----
print("666") # 666

```

##### 生成器

* 是一个特殊的迭代器
* 特性:
* 惰性计算数据,节省内存
* 能够记录状态 ,通过`next()`函数,访问下一个状态
* 使用方式

```
# 生成器表达式
l = (i for i in range(1, 10000000) if i % 2)
print(type(l)) # <class 'generator'> // 不是元组推导,没有元组推导式

print(next(l)) # 1
print(next(l)) # 3

for i in l:
print(i) # 循环打印出所有满足条件的值

# 生成器函数
def test():
for i in range(1, 9):
yield i

g = test()
print(next(g)) # 1
print(next(g)) # 2
```
#####推荐一下我建的python学习交流扣扣qun:850973621 ,群里有免费的视频教程,开发工具 、
#####电子书籍、项目源码分享 。一起交流学习,一起进步!
![QQ截图20201205144328.png](https://upload-images.jianshu.io/upload_images/25205170-73b3c9e6ec60cc66.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

作者:MetaT1an
链接:https://www.jianshu.com/p/ba8b9bdea10a
来源:简书
著作权归作者所有。商业转载请联系作者获得授权 ,非商业转载请注明出处。

文章来源于网络,如有侵权请联系站长QQ61910465删除
本文版权归趣快排营销www.seoguRubloG.com 所有,如有转发请注明来出,竞价开户托管,seo优化请联系✚Qq61910465