1.类装饰器
1.类装饰器语法 @函数名
2.类装饰器 @类名
@类名 #comment=类名(comment)
def comment():
pass
# 调用
comment()
1.comment=类名(comment),等号右边是创建对象的语法,实参传递给__init__方法中,init方法中需要以形参接受 原函数,故init方法 等价于 外层函数
2.原函数被装饰之后,comment 就是 该类对象,对象(),会调用类的__call__这个魔法方法,即__call__方法,等价于内层函数
# 定义类装饰器
# 1.定义类,书写init方法,等价外层函数
class LoginCheck(object):
def __init__(self, fn):
self.__fn = fn
# 2.书写__call__方法,等价于内层函数
def __call__(self, *args, **kwargs):
# 3.书写添加的新的功能
print('请先登录...')
# 4.调用原函数
res = self.__fn(*args, **kwargs)
return res
@LoginCheck # comment=LoginCheck(comment)
def comment(info):
print(info)
if __name__ == '__main__':
comment('hello world')
书写带参数类装饰器
class MakeTag():
pass
@MakeTag
def comment(info):
pass
-----------------
分析:
1.MakeTag('div') 创建对象,实参, 'div' 给init方法中的形参,故确定init方法中需要一个形参接收这个参数
2.
@对象
def comment(info):
pass
这个代码等价于 comment=对象(comment),对象(comment)调用__call__方法,__call__方法需要有一个形参,
接受原函数,等价于外层函数
3.__call__f返回内层函数的地址
# ----带参数的类装饰器----
class MakeTag(object):
def __init__(self, tag):
self.tag = tag
def __call__(self, fn):
def inner(*args, **kwargs):
result = fn(*args, **kwargs)
return f'<{self.tag}>+ {result}+{self.tag}'
return inner
@MakeTag('div')
def comment(info):
return info
if __name__ == '__main__':
print(comment('hello world'))
2.propetry属性的介绍
1.property属性就是负债把一个方法当做属性进行使用,这样做可以简化代码使用。
2.定义property属性有两种方式
装饰器方式
类属性方式
# ----property属性------
class Dog(object):
def __init__(self, name, age):
self.name = name
self.age = age
# 定义共有方法,获取对象name属性
def get_name(self):
return self.name
# 定义共有方法,设置对象name属性
def set_name(self, name):
self.name = name
# 通过类属性的方式,给对象添加property属性
# property(获取属性值的方法,设置属性值的方法)
name1 = property(get_name, set_name)
# def get_age(self):
# return self.age
#
# def set_age(self, age):
# self.age = age
#
# name1 = property(get_name, set_name)
@property
def age(self):
return self.age
@age.setter
def age(self, nwe_age):
self.age = nwe_age
if __name__ == '__main__':
# 创建对象
# dog = Dog('小白', 13)
# # 调用对象
# print(dog.get_name())
# dog.set_name('小白白')
# # 调用对象
# print(dog.get_name())
dog = Dog('小白', 13)
print(dog.name)
dog.name = '小白白'
print(dog.name)
print(dog.age)
dog.age = 1
print(dog.age)
写代码的小规则:
在类中,如果是获取属性的方法,一般不用print直接打印,一般会进行return返回这个属性值
如果是设置属性值,一半不需要设置返回值
3.with
# -----------with语句----------
# 使用with语句,不需要书写关闭代码,会自动进行关闭
with open('a.txt','w') as f:
f.write('hello world\n')
f.write('hello python!!')
# with语句,代码除了with缩进之后,会自动的进行关闭
with 上下文管理器对象 as 变量名:
pass
# -----------with语句----------
# 使用with语句,不需要书写关闭代码,会自动进行关闭
# with open('a.txt', 'w') as f:
# f.write('hello world\n')
# f.write('hello python!!')
# with语句,代码除了with缩进之后,会自动的进行关闭
# 实现了__enter__和__exit__这两个魔法方法的类,就是上下文管理器对象类
class File(object): # 实现文件操作
def __init__(self, filename, mode):
self.fp = open(filename, mode, encoding='utf-8')
self.filename = filename
self.mode = mode
# 定义上文方法,__enter__,使用with语句,执行下方代码之前,会自动进入上文方法
def __enter__(self):
print('1.进入上面方法')
self.fp = open(self.filename, self.mode, encoding='utf-8')
return self.fp
# 定义下文方法,with语句执行完成之后,会自动调用
# with 语句中,即使发生异常,也会进入__exit__中
def __exit__(self, exc_type, exc_val, exc_tb):
# exc_type 发生异常时,异常的类型
# exc_val 发生异常时,异常的信息
# exc_tb 异常对象
# 方法返回值,1.如果返回False(代码没有书写返回值,默认返回 None,False),代表发生异常
# 以后,异常会继续向外传递。2.如果返回True,代表异常不在向外传递
if exc_type:
print('发生异常了.....')
else:
print('没有发生异常')
print('2.进入了下文方法')
self.fp.close()
if __name__ == '__main__':
with File('a.txt', 'r') as f:
print('3.我是 with语句中代码')
4.生成器
生成器推导式
列表推导式,快速的生成一组数据,一次性将数据全部生成的
# 变量=[生成数据的规则 for i in ..] 每循环一次,回向列表中根据生成数据的规则添加数据
# ------生成器推导式------------
my_list = ['hello' for i in range(5)]
print(my_list)
# 生成器推导式,语法和列表推导式非常像,只是将[]变为小括号,差异:生成器存储的生成数据的规则
# 使用一个数据就生成一个数据,好处:节省内存
my_gen = (i for i in range(5))
print(my_gen)
# 从生成器中获取数据,next(生成器)
num = next(my_gen) # 0
print(num)
print(next(my_gen)) # 1
print(next(my_gen)) # 2
print(next(my_gen)) # 3
print(next(my_gen)) # 4
# 当生成数据的规则不满足之后StopIteration 异常
# print(next(my_gen)) # 此时,生成数据的规则已经不满足了,如果再次使用 next() 获取数据,会发生异常
# 获取 生成器中的数据,比较好用的方法式 for 循环,for 循环,python已经封装好了 StopIteration的异常
# 处理
for i in my_gen:
print(i)
# 无法运行,已经把生成器数据获取完了
5.yield生成器
只有在def函数里面看到有yield关键字那么就是生成器
# --------yield生成器-----------
def func():
for i in range(5):
print(f'第{i + 1}次循环开始')
# yield 关键字作用 1.类似return ,将会将后边跟的内容进行返回
# 函数代码遇到yield,函数会暂停执行
yield 100 + i
print(f'第{i + 1}次循环结束')
if __name__ == '__main__':
# 1.创建一个生成器对象
my_gen = func() # 此处,不是函数调用,是创建生成器,不会执行函数中 代码
print(my_gen, type(my_gen))
# res = next(my_gen)
# print(res)
# res = next(my_gen)
# print(res)
for i in my_gen:
print(i)
6.斐波那锲数列
# ------------斐波那锲数列------------
def fibonacci(n):
# 参数n代表要生成多少个数列
a = 0
b = 1
for j in range(n):
# 循环一次,就生成一个数据
yield a
a, b = b, a + b
if __name__ == '__main__':
my_list = fibonacci(6)
for i in my_list:
print(i, end=' ')
7.yield实现协程(多任务)
# ----------yield实现协程------------
def sing():
for i in range(5):
print('正在唱歌....')
yield
def dance():
for j in range(5):
print('正在跳舞.....')
yield
if __name__ == '__main__':
my_sing = sing()
my_dance = dance()
is_sing=None
is_dance=None
while True:
try:
next(my_sing)
except StopIteration:
pass
try:
next(my_dance)
except StopIteration:
break
if is_sing and is_dance: # 只有两个都为True,结果为True,才会结束循环
break
8.深拷贝和浅拷贝(理解)
浅拷贝
copy函数是浅拷贝,只对可变类型的第一层对象进行拷贝,对拷贝的对象开辟新的内存空间进行储存,不会拷贝对象内部的子对象
# 浅拷贝,copy.copy() 只会对可变类型的第一层对象进行拷贝,对拷贝的对象开辟内存空间,不会对内部的
# 子对象开辟空间
# 可变类型 list dict set
# 不可变类型 int float str tuple 对于不可变类型,浅拷贝不会开辟空间,拷贝的引用
# int
num = 10
num1 = copy.copy(10)
print(f'num:{id(num)}')
print(f'num1:{id(num)}')
# str
my_str = 'hello world'
my_str1 = copy.copy(my_str)
print(f'my_str:{id(num)}')
print(f'my_str1:{id(num)}')
# tuple
my_tuple = (1, 2, 3, [4, 5])
my_tuple1 = copy.copy(my_tuple)
print(f'my_tuple:{id(num)}')
print(f'my_tuple1:{id(num)}')
# 可变类型:list dict set
my_list = [1, 2, [3, 4]]
my_list1 = copy.copy(my_list)
print(f'my_list:{id(my_list)},my_list[2]:{id(my_list[2])}')
print(f'my_list1:{id(my_list1)},my_list[2]:{id(my_list[2])}')
深拷贝
# ---------深拷贝---------
# copy.deepcopy(),深拷贝进行拷贝的时候,只要发现可变类型,就会对可变类型本身,已经父级对象进行拷贝
# int
num = 10
num1 = copy.deepcopy(10)
print(f'num:{id(num)}')
print(f'num1:{id(num)}')
# str
my_str = 'hello world'
my_str1 = copy.deepcopy(my_str)
print(f'my_str:{id(num)}')
print(f'my_str1:{id(num)}')
# tuple 如果元组中包含可变类型,回对元组本身以及子对象都开辟内存空间
my_tuple = (1, 2, 3, [4, 5])
my_tuple1 = copy.deepcopy(my_tuple)
print(f'my_tuple:{id(my_tuple)},my_tuple:{id(my_tuple[2])}')
print(f'my_tuple1:{id(my_tuple1)},my_tuple:{id(my_tuple1[2])}')
# 可变类型:list dict set
my_list = [1, 2, [3, 4]]
my_list1 = copy.deepcopy(my_list)
print(f'my_list:{id(my_list)},my_list[2]:{id(my_list[2])}')
print(f'my_list1:{id(my_list1)},my_list[2]:{id(my_list[2])}')
9.正则介绍
正则表达式:记录文本规则的字符串。
re 模块使用
# re 模块使用
# 在python代码中,想要使用 正则表达式,需要导入 re模块
import re
# re.match(正则表达式,匹配文字)
# 返回值,匹配成功,返回对象 匹配失效,返回None
# result = re.match('0\d{2}-\d{8}', '010-12345678')
# re.search(正则表达式,匹配文字) 从任意位置进行匹配
result = re.search('0\d{2}-\d{8}', '1 010-12345678')
print(result)
if result:
print(result.group()) # result.group() 查看结果
else:
print('匹配失败')
匹配单个字符
代码 | 功能 |
. | 匹配任意一个字符(除了\n) |
[] | 匹配[]中列举的字符 |
\d | 匹配数字,即0-9 |
\D | 匹配非数字,即不是数字 |
\s | 匹配空白,即空白,tab键 |
\S | 匹配非空白 |
\w | 匹配非特殊字符,即a-z,A-Z,0-9,_,汉字 |
\W | 匹配特殊字符,即非字母,非数字,非汉字 |
# ---匹配单个字符------
import re
# 字母,匹配特定的字母
# result = re.match('hello', 'hello world')
# .匹配任意的非换行字符
# result = re.match('hello.', 'helloworld')
# [] 匹配括号中的任意一个字符
# []
# result = re.match('hello[ab]', 'helloaworld')
# \d 0,1,2,3,4,5,6,7,8,9 [0-9]
# result = re.match('hello[a-z]', 'hellocworld') # 能匹配到a到z的字母
# result = re.match('hello\d', 'hello0world') # 能匹配到a到z的字母
# \s 空白字符 空格 tab键
# result = re.match('hello\s.', 'hello world') # 能匹配到a到z的字母
# \w a-z A-Z 0-9 _汉字
result = re.match('hello\w', 'hello你world') # 能匹配到a到z的字母
if result:
print(result.group())
else:
print('匹配失败')
匹配多个字符
# ----------匹配多个字符------------
import re
# *前边一个字符出现任意次--或者这样写
# result = re.match(".", 'hello world')
# result = re.match(".*", 'hello world') # 默认尽量多的匹配
# result = re.match(".*w", 'hello world')
# ? 前边一个字符出现0次或者是1次
# result = re.match("hl?", 'hello world')
# result = re.match("he{0,1}", 'hello world')
# + 至少出现一次
result = re.match("hel+o", 'hello world')
# {m} 出现m次
result = re.match(".{3}", 'hello world')
# {m,n}出现m到n次
result = re.match(".{3,6}", 'hello world')
if result:
print(result.group())
else:
print('匹配失败')
匹配开头和结尾
代码 | 功能 |
^ | 匹配字符串开头 |
$ | 匹配字符串结尾 |
# 匹配开头和结尾
import re
result = re.search("\d.*", "hello 3 world")
# ^以什么开头
# result = re.search("^\d.*", "hello 3 world")
# $以什么结尾
result = re.search("\d.*$", "hello 3 world")
# [^]出了这些内容外,都匹配
result = re.search("^[^aeiou].*", 'hello 3 world3 a')
result = re.search("^[aeiou].*", 'ahello 3 world3 a')
if result:
print(result.group())
else:
print('匹配失败')
匹配分组相关正则表达式
代码 | 功能 |
| | 匹配左右任意一个表达式 |
(ab) | 将括号中字符作为一个分组 |
\num | 引用分组num匹配到的字符串 |
(?P<name>) | 分组起别名 |
(?P=name) | 引用别名为name分组匹配到的字符串 |
# -----------匹配分组-------------
import re
# |
# result = re.match("163|qq|sina", "163.com")
# result = re.match("163|qq|sina", "qq.com")
# result = re.match("163|qq|sina", "sina.com")
# 分组,() 括号括起来的内容是一组,想要那一部分的数据,就可以给这部分数据的正则加括号
# result = re.match("(163|qq|sina).com", "163.com")
# result = re.match("(163|qq|sina).com", "qq.com")
# result = re.match("(163|qq|sina).com", "sina.com")
# result = re.match("(.*)@(163|qq|sina).com", "nshuling@sina.com")
# 正则中 点 可以匹配任意一个字符,如果匹配单个字符 . ,那么在正则中需要使用转义 \.
# 引用分组 \num
# 案例,匹配, HTML 双标签
# result = re.match("<[a-zA-Z0-9]{1,} .*<[a-zA-Z0-9]{1,}>", "<html> hello </hello>")
# # # 解决方案一:\1 在字符串中\ 是转义字符 \1 将 1进行转义
# result = re.match("<([a-zA-Z0-9]{1,})>.*</\\1>", "<html> hello </html>")
# # result = re.match("<([a-zA-Z0-9]{1,}) .*</\\1>", "<html> hello </div>")
# # 解决方案二:使用原生字符串
# result = re.match("<([a-zA-Z0-9]{1,})>.*</\1>", "<html> hello </html>")
# 解决方案三:给引起名字
result = re.match("<(?P<tag>[a-zA-Z0-9]{1,})>.*</(?P=tag)>", "<html> hello </html>")
if result:
print(result.group())
else:
print('匹配失败')
10.题目练习
题目一:有学生类,Student,类中存在私有属性,name和age:
要求:
使用装饰器的方式定义name属性的property属性
使用类属性的方法定义age属性的property属性
使代码可以完整的运行
class Student(object):
def __init__(self, name, age):
self.__name = name
self.__age = age
@property
def get_name(self):
return self.__name
@get_name.setter
def set_name(self, name):
self.__name = name
# 定义属性
def get_age(self):
return self.__age
# 设置属性
def set_age(self, age):
self.__age = age
age = property(get_age, set_age)
if __name__ == '__main__':
# 创建对象
student = Student('小白', 13)
print(student.age)
student.age = 14
print(student.age)
# 调用名字
print(student.get_name)
student.set_name = '小黄'
print(student.get_name)