四,函数作用域和匿名函数
匿名函数
lambda:
-
方法:lambda 参数:表达式 (可以带或不带参数)
注意:复杂逻辑不用
匿名函数应用场景:
简单函数: 简单的函数,可以不用使用def定义一个函数,使用匿名函数即可
函数调用:类似于filter、map等函数里面,可以使用匿名函数来处理
提高开发效率:匿名函数的合理利用能够让那个代码更加简洁
1.全局变量,局部变量
num = 100 全局变量;函数外定义的变量
def f():
num = 200 局部变量;函数内部定义的变量,函数外无法调用
print("2",num)
print("1",num)
f()
#1 100
#2 200
2.局部变量改变全局变量:
global:
def f():
global num 此处改变了全局变量
num = 200 此处改变了全局变量
print("2",num)
nonlocal
函数内部:函数内部的变量,作用域只在函数内部,函数内部不可以直接更改函数外部的变量
global: 函数内部如果需要改变全局变量,就需要使用global修饰变量
nonlocal:在函数嵌套函数的情况下,同样也有函数作用域的问题,但是python3中提供了方便,只需要使用nonlocal就可以在里层函数内部修改外部函数变量(下面有详细)
闭包
闭包是函数里面嵌套函数,外层函数返回里层函数,这种情况称之为闭包
闭包是概念,不是某种函数类型,和递归的概念类似,就是种特殊的函数调用
闭包可以得到外层函数的局部变量,是函数内部和函数外部沟通的桥梁
嵌套:
def f1():
print("sss")
def f2()
print("dddd")
return f2
y=f1()
y()
1,直接调用f1函数,此时,执行了print ,定义了一个f2函数同时反回了f2的函数名
2,用变量y接收f2函数名
3,变量名+(),实现了函数的调用
函数名即变量
函数嵌套
函数嵌套时,内层函数想要使用外部函数变量,nonlocal
def f1():
num = 88
def f2():
nonlocal num
num += 1
return num
return f2() 此处表示调用f2()函数
y=f1()
print(y)
递归函数
函数里调用自身
求阶乘:
def f(n):
if n==1:
return 1 此为终止条件
return n*f(n-)
慎用递归这不利于电脑的运行
五,类定义、属性、初始化
类,实例(面向对象编程)
类 抽象的模版 是一个独立存放变量(属性/方法)的空间
实例:根据类创建出来的一个个具体的对象,拥有相同的标志但是各自的数据不同
定义:类的定义使用关键字 class 大驼峰命名法:每个单词的首字母大写
class Cat:
pass
实例化对象:
kitty = Cat( )
属性:(句点法给实例赋值)
kitty.color = 'white'
kitty.eat = 'milk'
color eat就是我们kitty对象的实例属性
属性
class Cat:
count = 0 #类属性,记录你实例化对象的次数
def_init_(self,color,eat):
self.color = color #实例属性
self.eat = eat
Cat.count +=1 #类名,类属性名,内部调用
kitty = Cat("white","milk")
print(kitty.color)
print("创建了".format(Cat.count)) #外部调用1 类名.类属性名
print(kitty.count) #外部调用2 实例名.类属性名
print(kitty.color) #实例调用实例属性
注意:类是不能调用实例属性
实例可以访问实例属性,实例可以访问类属性
类只能访问类属性
私有属性:
在python中有两私有属性,分别是在属性前加 一个下换线(_) 和 两个下划线(__)
单下划线开头:告诉别人这是私有属性,依然可以使用
双下划线开头:外部不能使用
class Cat:
def__init__(self,color,eat,age):
self.color = color
self._eat = eat #外部可以访问
self.__age = age #外部不可访问
kitty = Cat("whlit","mlik",5)
print(kitty.coclor)
print(kitty._eat)
#print(kitty.__age) 此会报错
方法
方法----和某个特定的类相关联的函数
类方法:类中的方法,就是函数
self:Self 代表的是实例本身
调用:方法的调用和属性调用一样,通过点操作符调用,传参和函数传参一样
class Cat:
def add_cat(cat):
print("{} {}".format(cat.color, cat.age)) 注意也可在此调用私有方法
kitty = Cat()
kitty.color = "white"
kitty.age = 3
Cat.add_cat(kitty) #类名.方法名() 函数调用1
结果 :white-3
kitty.add_cat() #结果一样 函数调用2
六,继承,多继承,魔术方法
继承
子类(派生类)只继承了一个父类(基类)
class A:
def f(self):
print("A")
class B:
def f(self): E分别继承C,D。C继承A D继承B
print("B")
class C(A):
def f(self):
print("C")
class D(B):
def f(self):
print("D")
class E(C,D):
def f(self):
print("E")
e = E() #实例化对象
e.f() # 得到E 调用方法,self始终指向的是实例对象e,所以方法选择的优先级始终从E类开始
E--->C--->A--->D--->B 方法选择优先级
多继承
子类继承了多个父类
class F:
def f(self):
print("F")
class A(F):
def f(self):
print("A")
class B(F):
def f(self): #E分别继承C,D。C继承A,D继承B A,B继承了F
print("B") #E--->C--->A---D--->B-->F
class C(A):
def f(self):
print("C")
class D(B):
def f(self):
print("D")
class E(C,D):
def f(self):
print("E")
类名.mor() 查看所有继承关系的方法
类名.__ bases__ 查看继承所有父类
魔术方法
__str__ 把一个类的实例变成字符串
__repr__ __str__的备胎,如果有__str__,print会先执行__str__
class A:
pass
a=A()
print(a) #对象地址
class A:
def __str__(self) #返回必须是字符串
return "str"
a=A()
print(a)
__call__ 正常情况下,实例是不能像函数一样被调用,要想能调用使用这个
class A:
def __init__(self, num):
self.num =num
def __add__(self, other): #魔术方法 +
res = self.num + other.num
return res
def __call__(self):
prnit("成功")
one = A(55)
two = A(66)
print(one + two) #121
one() #调用成功
七,描述器和装饰器
__new__方法
相同的东西 不必在重新创建
__new__:单例模式
class A(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, 'instance'): # 判断是不是已经有实例存在了
cls.instance = super().__new__(cls) # 新建一个实例
return cls.instance
def __init__(self):
self.name = "DMC"
one = A()
print(one, id(one))
two = A()
print(two, id(two))
# 数据库连接池
定制属性访问
class Rectangle(object):
def __init__(self, length, width):
self.length = length
self.width = width
def __getattr__(self, item): # 当属性不存在时,调用此魔术方法,实现不报错
print("没有这种方法")
def area(self):
areas = self.length * self.width
# print(areas)
return "面积是:{}".format(areas)
a = Rectangle(66, 88)
对象属性的增删改查
增,无则增,有则改
a.num = 6 #第一种改方法
setattr(a, "num", 6) #第二种改方法
a.__setattr__("num", 6) #此为第二种的对应的魔术方法
print(a.num)
a.num = 8
setattr(a, "num", 10)
a.__setattr__("num", 12)
print(a.num)
# 查
print(hasattr(a, "num")) # bool值
print(getattr(a, "num")) # 获取属性值
print(a.__getattribute__("num")) # 获取属性值
# 删
# del a.num #直接删除这种属性
# delattr(a, "num") #与上同理
a.__delattr__("num")
a.num #没有这种方法 调用实现不报错
# 魔术方法,给了我们一个自定义的接口,函数执行的底层其实就是去调用了魔术方法,我们只需要修改一下对应的魔术方法,实现自定义
描述符
class A:
def __get__(self, instance, owner):
print("__get__")
def __set__(self, instance, value):
print("__set__")
def __delete__(self, instance):
print("__delete__")
class B:
a = A() # 把A的实例对象拿来做了B的类属性,描述符
def __init__(self):
self.name = "句号"
b = B() # 类的实例化
print(b.name) # 输出对象内容
b.a # 获取B的类属性(A的实例),会去执行__get__
b.a = 88 # 重新赋值, 会去执行__set__
del b.a # 删除,会去执行__delete__
装饰器
装饰器的本质还是一个闭包
def outer(func):
def inner():
print("前增功能")
func()
print("后增功能")
return inner
@outer # 1.执行outer函数,并将下方的函数名作为参数赋值给了outer函数2.将outer函数的返回值重新赋值给了下方的函数
def f1():
print("原功能")
f1()
# f1 = outer(f1)
# f1()
@outer
def f2():
print("原功能f2")
@outer
def f3():
print("原功能f3")
# .......
@outer
def f100():
print("原功能f100")
一个装饰器去装饰不同参数个数的不同函数
# 为了方便接收不同参数个数的每个函数,*args, **kwargs
def outer(func):
def inner(*args, **kwargs):
print("前增")
func(*args, **kwargs)
print("后增")
return inner
@outer
def f1():
print("没有参数")
f1()
@outer
def f2(a):
print(a)
f2(6)
@outer
def f3(a, b):
print(a + b)
f3(4, 6)
@outer
def f4(a, b, c):
print(a + b + c)
f4(4, 5, c=6)
多个装饰器
def outer_0(func):
def inner(*args, **kwargs): # 为了方便接收不同参数个数的每个函数,*args, **kwargs
print("start")
func(*args, **kwargs)
print("end")
return inner
# 多个装饰器装饰同一个函数
def outer(func):
def inner(*args, **kwargs):
print("前增")
func(*args, **kwargs)
print("后增")
return inner
@outer_0
@outer
def f1():
print("原功能")
f1()
类做装饰器
class TestClass:
"""这是一个用来做装饰器的类"""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print('__call__')
print("前增")
self.func()
print("后增")
@TestClass
def f():
print("原功能")
f()
内置装饰器
class Cat:
name = "猫"
def __init__(self, color, eat):
self.color = color
self.eat = eat
@property # (方法变属性)
def print_cat(self):
print("{},{}".format(self.color, self.eat))
@classmethod
def func1(self, cls):
print("ok")
print(cls.name)
@staticmethod # 静态方法(解绑)
def func():
print("不需要self参数也能运行")
print("不需要实例化也能运行")
kitty = Cat('white', "food")
# kitty.print_cat()
# kitty.color
kitty.print_cat #white,food
kitty.func() #不需要self参数也能运行 不需要实例化也能运行
Cat.func() #不需要self参数也能运行 不需要实例化也能运行
八,文件
文件基本操作
打开 读取 关闭 和 with
#打开 r
f = open(r"C:\Users\JiaNeng\Desktop\test.txt", "r", encoding="utf-8")
print(f.read())
f.close() #关闭
f = open("test.txt", "r", encoding="utf-8")
print(f.read())
f.close()
#读取 w
f = open("test1.txt", "w", encoding="utf-8") # 无,新建
f.write("dante\n")
f.close()
f = open("test.txt", "w", encoding="utf-8") # 有,覆盖
f.write("dante\n")
f.writelines("nero\n")
f.writelines(["viger\n", "2", "5"]) # 写入字符串或者字符串序列
# f.flush()
f.close()
f = open("test.txt", "r", encoding="utf-8")
print(f.read()) #读写入的内容
f.close()
with 可以自动关闭 比较保险 下面有用法实例
tell():以bytes为单位,从文件头到当前指针的位置
seek():以bytes为单位,指针的偏移量
print("源氏\n".encode("utf-8")) # b'\xe5\x8f\xb6\xe8\x90\xbd\n'
with open("test.txt", "r", encoding="utf-8") as f:
print("1:", f.tell())
print(f.read())
print("2:", f.tell())
f.seek(0)
print("3:", f.tell())
f.seek(2)
print("4:", f.tell())
#print(f.read()) 这个报错 一个中文utf-8是三个字节,移动两个字节,字被拆开了
总结
#r和w
#r只读
with open("test.txt", "r", encoding="utf-8") as f:
print(f.tell())
print(f.read())
#w只写,文件不存在新建并写入,文件存在就直接重写
#不存在新建
with open("test1.txt", "w", encoding="utf-8") as f:
f.write("新建并写入")
#存在覆盖
with open("test.txt", "w", encoding="utf-8") as f:
f.write("覆盖")
非文本的读取和写入
# rb和wb,只读和只写,非文本的读取和写入
img = ""
with open("任意的图片.png", "rb")as f:
img = f.read()
with open(" .png", "wb")as f:
f.write(img)
a追加
# a追加:在文件末尾增加
文件不存在,新建,再写入
with open("test2.txt", "a", encoding="utf-8")as f:
f.write("haha")
# 文件存在,在文件末尾增加
with open("test.txt", "a", encoding="utf-8")as f:
print(f.tell())
f.write("追加")
r+ w+ a+
r+:读写,指针在文件开头
w+:读写,不存在新建,存在覆盖
a+:读写,不存在新建,存在文件末尾追加
用法实例:
with open("test.txt", "r+", encoding="utf-8") as f:
print("1:", f.tell())
print(f.read())
print("2:", f.tell())
f.write("1")
print("3:", f.tell())
print(f.read())
with open("test.txt", "w+", encoding="utf-8") as f:
print("*"*50)
print("1:", f.tell())
print(f.read())
print("2:", f.tell())
f.write("新建并写入")
print("2:", f.tell())
f.seek(0)
print(f.read())
print("*"*50)
with open("test.txt", "a+", encoding="utf-8")as f:
print(f.tell())
f.write("追加")
f.seek(0)
print(f.read())
read() readline() readlines()
read():光标到文件末尾,字符串
readline():读一行,字符串
readlines():列表。[“第一行”, “第二行”。。。。]
用法实例:
with open("test.txt", "r", encoding="utf-8") as f:
file = f.read()
print(file.strip()) # 新建并写入追加
print(type(file)) # <class 'str'>
with open("test.txt", "r", encoding="utf-8") as f:
line = f.readline()
# print(line)
print(type(line)) # <class 'str'>
while line:
print(line.strip())
line = f.readline()
with open("test.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
print(lines) # ['新建\n', '并\n', '写入\n', '追加']
print(type(lines)) # <class 'list'>
上下文管理工具
# __enter__/__exit__
from datetime import datetime
class Runtime:
def __enter__(self):
self.start_time = datetime.now()
print("程序开始运行的时间:{}".format(self.start_time))
return self.start_time
def __exit__(self, exc_type, exc_val, exc_tb):
self.end_time = datetime.now()
print("程序结束运行的时间:{}".format(self.end_time))
print("程序运行的时间:{}".format(self.end_time - self.start_time))
run = Runtime()
with run as a: # 上下文管理器
print("a:", a)
for i in range(10000000):
type("helloTZ")
# isinstance("helloTZ", str)
# a 是__enter__的返回值,with会把这个返回值通过as赋值给a
IO流
使用时先导入模块
###StringIO(字符流):
import io
sio = io.stringIO() #实例化,创建了一个对象,进行保存读取的
sio .write("hello") #写
print(sio.getvalue()) #读
sio.close()
###BytesIO(字节流):
bio = io.BytesIO() #同上
bio.write(b'abcd') #转义
print(type(b'abcd')) #<class 'bytes'>
print(bio.grtvalue())
bio.close()
使用工具
os模块仅作了解
import os
os.system("pwd") # 需连虚拟机
路径拼接
url1 = os.path.join('home', 'pyvip', 'project')
print(url1)
os.mkdir('test') # 创建文件夹,如果已经存在,报错
os.rename('test', 'test1') # 修改文件夹名
模块 shutil
import shutil
将文件移动到目标文件夹
shutil.move('homework.py', 'test1') # 相对路径
shutil.move(r'C:\Users\JiaNeng\Desktop\test.txt', r'E:\fei\讲义\1-基础班') # 绝对路径
复制,将前一个复制到后一个
shutil.copytree(r"test1", r"..\lesson16\test1")
删除
shutil.rmtree(r"E:\fei\basic45\lesson16\test")
shutil.rmtree(r"E:\fei\basic45\lesson16\test1")
九,异常
异常的种类
NameError SyntaxError TypeError
异常本身就是异常类的实例
异常处理
try:
先执行,异常,捕获异常,执行except里面的代码
先执行,无异常,不再执行except里面的代码
except:
捕获异常时,执行的功能块
扩展:捕获具体的异常:让你捕获你想要捕获的异常,不想捕获的正常抛出异常
try:
1/0
# 5 - "a"
except TypeError:
print("类型错误")
except FileNotFoundError:
print("文件错误")
except Exception as e: #e输出了Exception 里的错误描述
print("其他的普通异常")
print(e)
1/0 # ZeroDivisionError: division by zero
自动抛出异常
raise
try:
raise TypeError("主动抛出的类型错误") # 自制异常
except TypeError:
print("类型错误")
except FileNotFoundError:
print("文件错误")
except Exception as e:
print("其他的普通异常")
print(e)
# 自定义异常类型
class ZiDingYiError(Exception):
pass
def func(name):
if name == 'Dante':
print("允许登录")
else:
raise ZiDingYiError("你不是Dante,不许登录!!!!")
try:
func("Dante")
except Exception as e:
print(e)
断言 assert
a = 1
b = 2
print(a > b) # False
print(a < b) # True
assert a < b
assert a > b # 条件不满足时,抛出AssertionError异常,后续程序终止
print("ok") # 条件满足,正常执行
比较
def func(name):
if name == "viger":
raise TypeError("黑名单用户,拒绝访问")
# func("viger")
def func(name):
assert name != "Nero" # ====>"Nero" != "Nero"
func("Nero") # AssertionError