属性与方法
1、类属性与实例属性
类:模板定义属性和方法的封装
实例:具体的类对象,是类的表现
(1)实例属性会根据实例的不同而不同,类属性由类决定
(2)实例属性通常在构造函数__init__中赋值
(3)类属性属于类,实例属性属于实例。实例确定,实例属性确定。实例可以调用类属性,类不可以调用实例属性(Good.addr报错)
class Good:
# 类属性
name = "tea"
def __init__(self, addr):
# 实例属性
self.addr = addr
g1 = Good("fujian")
g2 = Good("guangdong")
print(g1.addr, g2.addr)
print(Good.name, g1.name)
2、类方法、静态方法、实例方法
类方法:需要第一个参数为cls, 并且使用@classmethod声明
静态方法:需要使用@staticmethod声明
实例方法:需要第一个参数为self
(1)类可以调用 类方法、静态方法
(2)实例可以调用 类方法、静态方法、实例方法
class Good:
"""
这是一个商品类
"""
def __init__(self, name):
self.name = name
def getname(self):
return self.name
@classmethod
def getinfo(cls):
print(cls.__doc__)
@staticmethod
def pprint():
print("hello world")
g1 = Good("tea")
print(g1.getname())
g1.getinfo()
g1.pprint()
3、对比
(1)类属性 类方法属于类,只占一份内存
(2)实例方法 实例方法,浪费内存
4、属性编写
class Good:
def __init__(self, _name):
self.name = _name
@property
def gname(self):
return self.name
@gname.setter
def gname(self, _name):
self.name = _name
g1 = Good("tea")
print(g1.name) # tea
print(g1.gname) # tea
g1.gname = "coffee"
print(g1.gname) # coffee
Python是动态语言
1、定义
动态语言:是在运行时可以改变其结构的语言,Python是动态语言,不需要编译,直接由解释器解释执行,效率低下。
2、动态添加
import types
class Good:
# 通过__slots__限制动态添加内容
__slots__ = ["name", "addr", "geti"]
def __init__(self, _addr):
self.addr = _addr
g1 = Good("fujian")
# 动态添加实例属性
g1.name = "tea"
# 添加类属性
Good.name = "tea"
print(g1.name) # tea
def getinfo(self):
print(self.addr)
# 动态添加实例方法
g1.geti = types.MethodType(getinfo, g1)
g1.geti() # fujian
@classmethod
def getdoc(cls):
print(cls.__doc__)
# 添加类方法
Good.getd = getdoc
Good.getd() # None
@staticmethod
def get():
print("staticmethod")
# 添加静态方法
Good.get = get
Good.get()
# 删除方法
delattr(Good, "get")
# 判断方法是否存在
if hasattr(Good, "get"):
print("存在get")
生成器
1、什么是生成器
一种边循环边计算的机制,称为生成器:generator
2、生成器的创建
(1)把一个列表生成式的[] 改成()
import sys
# 普通列表生成式
list1 = [x for x in range(100000)]
print(sys.getsizeof(list1))
# 824464
# 使用生成器
list2 = (x for x in range(100000))
print(sys.getsizeof(list2))
# 120
# 得到生成器内容
print(list2.__next__())
# 0
print(next(list2))
# 1
# 遍历生成器
for i in list2:
print(i)
# 通过异常捕获遍历生成器
while True:
try:
print(next(list2))
except StopIteration as e:
print(e)
break
(2)使用函数来创建
def fun():
yield 1
yield 2
yield 3
return "hello world"
# 获得生成器内容
print(next(fun()))
# 1
for i in fun():
print(i)
# 1 2 3
# 获得函数返回值
f = fun()
try:
print(next(f))
print(next(f))
print(next(f))
print(next(f))
except StopIteration as e:
print(e)
(3)使用生成器打印斐波那契数列
def fun(num):
a = 0
b = 1
count = 0
yield a
yield b
while count < num:
a, b = b, a+b
yield b
count += 1
return "hello world"
result = fun(10)
for i in result:
print(i, end=" ")
# 0 1 1 2 3 5 8 13 21 34 55 89
3、生成器的特点
(1)节约内存
(2)迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即在整个所有函数调用的参数都是第一次用时保留的,而不是新创建的。
迭代器
1、可迭代对象
iterable:可以用于for循环的对象。
2、迭代器
iterator:可以被next()调用并不断返回下一个值的对象。
from collections.abc import Iterable, Iterator
list1 = [1, 2, 3]
print(isinstance(list1, Iterable))
# True
print(isinstance(list1, Iterator))
# False
list2 = (x for x in range(10))
print(isinstance(list2, Iterable))
# True
print(isinstance(list2, Iterator))
# True
3、iter()函数
# iter()函数可以将可迭代对象转换为迭代器
list1 = iter(list1)
print(next(list1), isinstance(list1, Iterator))
# 1 True
闭包
1、什么是闭包
函数的内部再声明一个函数
外部函数返回内部函数的引用
内部函数可以访问外部函数局部变量
2、例子
def fun1(a):
def fun2(b):
nonlocal a
return a + b
return fun2
f = fun1(10)
print(f(20))
# 30
装饰器
作用:在不改变原函数的情况下给函数增加功能。
1、使用装饰器
"""
解释器解释到有装饰器的函数:会改变函数结构
把函数作为参数传给装饰器,并且执行装饰器的返回值(装饰器返回的为内部函数)
把装饰器内部函数赋给被装饰函数
"""
def check(fun):
print("最先执行")
def ck(*args):
# print(type(fun), fun.__name__)
# <class 'function'> selectgoods
# 在查询商品之前需要输入权限验证
user = input("请输入用户名: ")
if user == "liuhaoran":
fun(*args)
else:
print("无权限")
return ck
@check
def showlist():
for i in range(10):
print(i)
@check
def showdetail(num):
print("当前为第%s页" % (num))
showlist()
showdetail(10)
深 浅拷贝
1、"="
"""
"=" 是一般意义的复制,相当于引用
内层外层均拷贝引用
"""
list1 = [1, 2, 3, [4, 5]]
list2 = list1
print(list2 is list1)
# True
print(list2[3] is list1[3])
# True
list1.insert(3, 3.5)
print(list1, list2)
# [1, 2, 3, 3.5, [4, 5]] [1, 2, 3, 3.5, [4, 5]]
list1[4].insert(1, 4.5)
print(list1, list2)
# [1, 2, 3, 3.5, [4, 4.5, 5]] [1, 2, 3, 3.5, [4, 4.5, 5]]
2、浅拷贝
"""
浅拷贝
外层拷贝值,内层拷贝引用
"""
import copy
list1 = [1, 2, [3, 4]]
list2 = copy.copy(list1)
print(list1 is list2)
# False
print(list1[2] is list2[2])
# True
list1.insert(2, 2.5)
print(list1, list2)
# [1, 2, 2.5, [3, 4]] [1, 2, [3, 4]]
list1[3].insert(1, 3.5)
print(list1, list2)
# [1, 2, 2.5, [3, 3.5, 4]] [1, 2, [3, 3.5, 4]]
3、深拷贝
"""
深拷贝
外层拷贝值,内层拷贝值
"""
import copy
list1 = [1, 2, 3, [4, 5]]
list2 = copy.deepcopy(list1)
print(list1 is list2)
# False
print(list1[3] is list2[3])
# False
list1.insert(2, 3.5)
print(list1, list2)
# [1, 2, 3.5, 3, [4, 5]] [1, 2, 3, [4, 5]]
list1[4].insert(1, 4.5)
print(list1, list2)
# [1, 2, 3.5, 3, [4, 4.5, 5]] [1, 2, 3, [4, 5]]
元类
1、什么是元类
元类就是用来创建类的东西。
2、使用type创建类
"""
使用type可以动态的创建类
type(类名,由父类名称组成的元组,包含属性的字典)
"""
AI = type("AI", (), {"hp": 100})
print(AI)
# <class '__main__.AI'>
print(AI.__class__)
# <class 'type'>
ai = AI()
print(ai.__class__)
# <class '__main__.AI'>
# 定义普通方法
def speak(self):
print("hello")
# 定义静态方法
@staticmethod
def attack():
print("attack")
# 定义类方法
@classmethod
def dead(cls):
print("dead")
NPC = type("NPC", (AI,), {"canMove": False, "speak": speak, "attack": attack, "dead": dead})
npc = NPC()
npc.speak()
npc.attack()
npc.dead()
3、自定义元类
"""
元类就是用来创建类的东西
使用元类的好处:
拦截类的创建
修改类
返回修改之后的类
"""
# 实现所有的属性均需要以类名开始
def renameattr(classname, parentclass, attrs):
newattr = {}
for k, v in attrs.items():
# print(k, v)
if not k.startswith("__"):
k = classname.lower()[0] + "_" + k
print(k)
newattr[k] = v
return type(classname, parentclass, newattr)
class Good(metaclass=renameattr):
id = None
name = None
g = Good()
print(hasattr(Good, "name"))
print(hasattr(g, "g_name"))
垃圾回收
python采用引用计数机制为主,标记-清理和分代收集为辅的策略。
1、引用计数
(1)引用计数+1的情况
对象被创建时,例如a = “hello world”
对象被copy引用时,例如b = a,此时a引用计数+1
对象被作为参数,传入到一个函数中时
对象作为一个子元素,存储到容器中时,例如list = [a, b]
(2)引用计数-1的情况
对象别名被显示销毁,例如del a
对象引用被赋予新的对象,例如b = c, 此时b引用计数-1
一个函数离开他的作用域,例如函数执行完成
对象所在容器被销毁,或者从容器中删除
优点:简单、直观、实时性
缺点:维护引用计数需要消耗一定的资源、循环应用时,无法回收。
2、标记-清除
a=[1,2]#假设此时a的引用为1
b=[3,4]#假设此时b的引用为1
#循环引用
a.append(b)#b的引用+1=2
b.append(a)//a的引用+1=2
标记删除第一步: 对执行删除操作后的每个引用-1, 那么a的引用就是0, b的引用为1, 将a放到死亡容器, 将b放到存活容器。
标记删除第二步: 循环存活容器, 发现b引用a, 复活a: 将a放到存活容器内。
标记删除第三步: 删除死亡容器内的所有对象。
3、分代收集
(1) 新创建的对象做为0代
(2) 每执行一个【标记-删除】 , 存活的对象代数就+1
(3)代数越高的对象(存活越持久的对象) , 进行【标记-删除】 的时间间隔就越长。 这个间隔, 江湖人称阀值。
4、小整数对象池与intern机制
(1) 小整数[-5, 257): 共用对象, 常驻内存
(2) 单个字符: 共用对象, 常驻内存
(3)单个单词等不可变类型, 默认开启intern机制, 共用对象, 引用计数为0时销毁。
内建函数
1、dir
import dir
print(dir(math))
2、range
a = range(5)
list(a)
3、map
根据提供的函数对指定序列做映射
def fun1(x, y):
return (x, y)
list1 = [0, 1, 2, 3, 4, 5]
list2 = ["one", "two", "three", "four"]
result = map(fun1, list1, list2)
print(list(result))
# [(0, 'one'), (1, 'two'), (2, 'three'), (3, 'four')]
4、filter
对指定序列执行过滤操作
def fun(x):
if x >3:
return True
else:
return False
list1 = [1, 2, 3, 4, 5]
result = filter(fun, list1)
print(list(result))
# [4, 5]
5、reduce
对参数序列中元素进行累积
from _functools import reduce
def fun(x, y):
return x + y
list1 = [1, 2, 3, 4, 5]
result = reduce(fun, list1)
print(result)
# 15
6、sorted
对指定的序列排序
list1 = [1, 3, 5, 7, 2]
result = sorted(list1, reverse=1)
print(result)
# [7, 5, 3, 2, 1]