Python024闭包

闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
def test(number):
# 内部函数调用访问number
def test_in():
print(number)
# 将内部函数返回
return test_in


xxx = test(100)
print("-"*30)
xxx(1)
xxx(100)
xxx(200)

Python023迭代器

迭代器

先来了解什么是可迭代对象

集合类型

  • list
  • tuple
  • dict
  • set
  • str

generator 生成器

判断是否可以迭代

使用 isinstance()判断一个对象是否是 Iterable对象(可迭代)

1
2
3
4
5
6
7
from collections import Iterable

isinstance([],Iterable) # True
isinstance('abc',Iterable) # True
isinstance({},Iterable) # True
isinstance((x for x in range(10)),Iterable) # True
isinstance(100,Iterable) # False

迭代器可以调用next()

Iterator可迭代对象,可迭代对象才可以使用next

  • 生成器就是可迭代对象
  • 列表不是可迭代对象但是它可以迭代
1
2
3
4
5
6
7
8
9
from collections import Iterator

isinstance((x for x in range(10)),Iterator) # True


isinstance([],Iterator) # False
isinstance('abc',Iterator) # False
isinstance({},Iterator) # False
isinstance(100,Iterator) # False

iter()函数

可以把「非可迭代对象」转换为「可迭代对象」

1
2
3
4
5
isinstance(iter([]),Iterator) # True

isinstance(iter('abc'),Iterator) # True

# 生成器比实际的列表占用空间小

Python022property

property

先看私有属性get和set方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class  Test(object):
def __init__(self):
self.__num = 100
def getNum(self):
return self.__num
def setNum(self,newNum):
self.__num = newNum

# 类 Test有私有属性 num (__属性名,代表私有属性)
# 通过get 和 set方法 可以对私有属性进行操作
t = Test()
print(t.getNum())
t.setNum(50)
print(t.getNum())

需求来了

  • t.num = 100 就调用设置 __num的值为100
  • print(t.num)的时候就直接取__num的值
1
2
3
4
5
6
7
8
class  Test(object):
def __init__(self):
self.__num = 100
def getNum(self):
return self.__num
def setNum(self,newNum):
self.__num = newNum
num = property(getNum,setNum)
1
2
t.num = 9 相当于 t.setNum(9)
t.num 相当于 t.getNum()

如果你在定义类的时候设置了一个私有属性,同时设置了get和set方法,并设置property

  • 相当于把方法进行了封装,开发者在对属性设置数据的时候变得方便

设置property的另一种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Test(object):
def __init__(self):
self.__num = 100

@property
def num(self):
print("----getter----")
return self.__num

@num.setter
def num(self, newNum):
print("----setter----")
self.__num = newNum

t = Test()

t.num = 200 #相当于调用了 t.setNum(200)

print(t.num) #相当于调用了 t.getNum()

Python021==和 is和深浅拷贝

== 和 is

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a = [11,22,33]
b = [11,22,33]
a == b # True 你的苹果6 和我的苹果6型号一样的
a is b # False 你的苹果6 不是我的苹果6

id(a) # 139804120094600
id(b) # 139804120094640

# 此时
c = a # 把a的地址给了c
id(a) # 139804120094600
id(c) # 139804120094600
id(b) # 139804120094640


a is c
True
  • == 是比较两个对象内容是否相等
  • is 是比较两个引用是否指向同一个对象(引用比较)

注意点单纯的值类型(这个问题以后讲) 在一定范围内 a is b 是 True的

1
2
3
4
5
6
7
8
a = 100
b = 100
a == b # True
a is b # True

a = 10000
b = 10000
a is b # False

浅拷贝

1
2
3
4
a = [1,2,3]
b = a
id(a) # 地址1001
id(b) # 地址1001

深拷贝

1
2
3
4
5
6
import copy
a = [1,2,3]
c = copy.deepcopy(a) # 深拷贝 [1,2,3]

id(a) # 地址1001
id(c) # 地址1211

问题1多重嵌套的列表拷贝之后拷贝的是地址还是内容?

1
2
3
4
5
6
7
8
9
10
11
a = [1,2,3]
b = [4,5,6]
c = [a,b] # c是一个二维的列表

d = copy.deepcopy(c) # 深拷贝

c[0] # [1,2,3]
d[0] # [1,2,3]

c[0].append(4) # [1,2,3,4]
d[0] # [1,2,3]

元组同上也会进行深拷贝

copy模块的方法

  • copy.copy(xxx) 如果是可变类型仅进行一层拷贝,如果是不可变类型不进行拷贝(浅拷贝)
  • copy.deepcopy(xxx) 递归的进行拷贝无论多少层

copy的坑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
a = [1,2,3]
b = [4,5,6]
c = [a,b] # c是一个二维的列表
d = copy.copy(c)

# 仅进行第一层拷贝
id(c) # 地址100
id(d) # 地址110

c[0].append(4) # [1,2,3,4]
d[0] # [1,2,3,4]

# 元组又有例外
a = [1,2,3]
b = [4,5,6]
c = (a,b)
d = copy.copy(c)

id(c) # 地址1100
id(d) # 地址1100

copy.copy去拷贝一个不可变类型时不进行拷贝,可变类型拷贝一层

Python013set_list_tuple

set 的简单应用以后会更复杂。。。。。。

set 集合

跟列表一样,但是它不重复

1
2
3
4
5
6
7
8
9
10
a = [11,22,33,44,55,11]

b = set(a)
# {11,22,33,44}
type(b)
# set


c = list(b)
# [33,11,44,22] 集合转成列表虽然去重但是是无序的

set list tuple相互可以转化

1
2
3
4
5
6
a = (11,22,33,44,55,11)
b = set(a)
# {11,22,33,44}

c = tuple(b)
# (11,22,33,44)

Python012列表推导式

列表推到式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a = [x for x in [11,22,33,44,55]]
# [11,22,33,44,55]

# 生成1-100的列表
b = [x for x in range(1,101)]

# 生成1-100的奇数列表
b = [x for x in range(1,101,2)]


# 生成1-100的偶数列表
b = [x for x in range(2,101,2)]
# 生成1-100的偶数列表
c = [x+1 for x in range(1,101,2)]

# 生成1-100的偶数列表 只能写一个条件
d = [x for x in range(1,101) if x%2==0]

列表推到式,循环嵌套

1
2
3
4
5
6
7
8
9
10
11
e = [x for x in range(1,4) for y in range(1,3)]

# x是外层循环 循环3次
# y是内层循环 循环2次

# [1,1,2,2,3,3]


# 想要既取到x也取到y 生成元组
e = [(x,y) for x in range(1,4) for y in range(1,3)]
# [(1,1),(1,2),(2,1),(2,2),(3,1),(3,2)]

Python011模块

模块

1
2
3
4
import 模块名
# 引入模块
import random
random.randint(0,2)

自定义模块

1
2
3
4
5
6
7
8
9
# test.py内容如下

def test:
print('test')


# 在你的模块里引入并使用
import test
test.test()

导入模块的过程实际就是把模块里的内容执行一遍

你的模块需要自测,但是不想在被引入的地方调用

1
2
3
4
5
6
__name__  代表模块的名字 test.py

单独执行test.py
print(__name__) # __main__
在其他模块里导入 test.py
会打印 __test__

实现自测才调用的效果

1
2
3
4
5
6
7
def test():
print('haha')

#测试
if __name__ == "__main__":
print(__name__)
test()

模块导入路径问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import random 
random.randint(1,3)
# 每次都有random命名空间是不是很不爽


# 太极端会把random里所有方法导入进来
from random import *
randint(1,3)


# 单独导入一个
from random import randint
randint(1,3)

# 导入多个
from random import randint,randrange

定位模块

如果第三方模块在当前执行目录则没有关系,如果模块拆的比较碎同时不在同一目录,就会有路径问题

  1. 当前目录
  2. 如果不在当前目录,搜索shell改变了pythonpath下的每个目录
  3. 如果不在以上目录,python会查看默认路径 UNIX下默认路径为/usr/local/lib/python
  4. 模块搜索路径存储在system模块的sys.path变量里。它是一个列表,包含以上目录
1
2
3
4
5
6
7
import sys
# 将你的模块路径插入到最前面
sys.path.insert(0,"test.py的路径")
# 将你的模块路径插入到最后, 如果加载失败一定是 sys.path里有同名的test模块覆盖了你的test
# sys.path.append("test.py的路径")
def test():
print('haha')

all变量

1
模块中的__all__

当你有test.py文件

1
2
3
4
5
6
7
8
9
class Test(object):
def test(def):
print("class defined method")

def test1():
print("test1")

def test2():
print("test2")
1
2
from test import *
这时你可以调用test模块所有东西

在test.py里添加如下内容后

1
__all__ = ["Test","test1"]
1
2
3
from test import *
这时你可以调用test模块里的 Test类 和 test1
调用 test2报错

all仅仅影响的是 from test import 里的 「

1
2
3
4
from test import *
from test from test2
test1 ()
test2() #不报错

Python010异常

异常

try … except…

1
2
3
4
5
6
try:
print(a) #a没有定义直接打印报错
except:
print('hahahaha')

# 打印 hahahaha

异常有多种应该怎样捕获

1
2
3
4
5
6
7
8
9
10
11
try:
xxxxxxxxxx1
xxxxxxxxxx2
xxxxxxxxxx3
xxxxxxxxxx4
except 车胎扎了:
补胎
except 链子掉了:
挂上
except 闸坏了:
换车闸

一次捕获多个异常

1
2
3
4
5
6
7
8
9
try:
xxxxxxxxxx1
xxxxxxxxxx2
xxxxxxxxxx3
xxxxxxxxxx4
except (车胎扎了,链子掉了,闸坏了):
处理

# python2 里不用加括号

打印错误的基本信息

1
2
3
4
5
6
7
8
9
10
try:
print(a)
except NameError as ffff:
print('产生了一个异常%s'%ffff)

# 多种异常
try:
print(a)
except (NameError,FileNotFoundError) as ffff:
print('产生了一个异常%s'%ffff)

捕获所有异常

1
2
3
4
5
6
7
8
9
try:
print(a)
except:
print('产生了一个异常')

try:
print(a)
except Exception as ffff:
print('产生了一个异常%s'%ffff)

异常之else

1
2
3
4
5
6
7
8
9
10
11
try:
#如果产生了一个异常,但是except没有捕获,那么就会按照这个异常默认的处理方式进行
open("aaa.txt")
a = 100
print(a)
except NameError:
#如果在try中的代码产生了一个NameError时,才会执行的异常处理
print("捕获到了一个异常")
else:
#在try中的代码都没有产生异常的时候,才会执行的代码
print("-----1-----")

异常之finally

1
2
3
4
5
6
7
8
9
10
11
12
13
try:
#如果产生了一个异常,但是except没有捕获,那么就会按照这个异常默认的处理方式进行
open("aaa.txt")
a = 100
print(a)
except NameError:
#如果在try中的代码产生了一个NameError时,才会执行的异常处理
print("捕获到了一个异常")
else:
#在try中的代码都没有产生异常的时候,才会执行的代码
print("-----1-----")
finally:
print("-----最后执行的实行-0----")

异常的传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def test1():
print("------1-1------")
print(num)
print("------1-2------")


def test2():
print("------2-1------")
test1()
print("------2-2------")

def test3():
try:
print("------2-1------")
test1()
print("------2-2------")
except Exception as result:
print("捕获到了异常:%s"%result)


test3()

自定义异常

1
2
3
4
5
6
7
8
9
10
11
class Test(Exception):
def __init__(self, length, atleast):
self.length = length
self.atleast = atleast

try:
raise Test(1,2)
except Test as result:
print("---f-f-f-f-f----")
print(result.length)
print(result.atleast)

Python008类属性实例属性静态方法

类属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class 士兵:
#类属性
血量 = 100
def __init__(self,name):
self.name = name
#方法
def run(self):
print('士兵奔跑')


a = 士兵('a')
b = 士兵('b')

a.血量 # 100
b.血量 # 100

如果实例属性里定义了 血量 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
class 士兵:
#类属性
血量 = 100
def __init__(self,name):
self.name = name
self.血量 = 200
#方法
def run(self):
print('士兵奔跑')


a = 士兵('a')
a.血量 # 200

类方法

要用修饰器 @classmethod来标识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Test:
#类属性
num = 0
def __init__(self):
#实例属性
self.age = 20
@classmethod
def setNum(cls,newNum):
cls.num = newNum

a = Test()
print(Test.num) # 0

Test.setNum(100)
print(Test.num) # 100

a.setNum(200)
print(Test.num) # 200

# 类方法既可以通过 类调用 也可以通过 实例对象

静态方法

要用修饰器 @staticmethod来标识

1
2
3
4
5
6
7
8
9
10
11
12
class Test:
def __init__(self):
#实例属性
self.age = 20

@staticmethod
def test():
print('我是Test类的静态方法')

a = Test()
a.test()
Test.test()