文章目录
简单说说Python中的垃圾回收
Python中的垃圾回收的主要策略:引用计数与分代回收
引用计算:
一旦对象的引用计数为0,该对象立即被回收,对象占用的内存空间将被释放。
import sys#使用工具查看对象被引用次数
sys.getrefcount(对象名)
分代回收:
Python根据内存中对象的存活时间划分为不同的集合,每个集合称为一个代,共3代
分别为年轻代(新加入的对象)(第0代)、中年代(经历0代回收仍然存活的对象)(第1代),老年代(经历0代,1代回收仍然存活的对象)(第2代) 他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。
可以使用gc模块查看当前监视对象的个数,以及触发垃圾回收的阈值
Python中的垃圾回收
迭代器与生成器有什么相似与不同的地方?
iter()
iter() 函数用来生成迭代器。
iter(object)
Python官方文档对于这种形式的解释很容易理解。
此时,object必须是集合对象,且支持迭代协议(iteration protocol)或者支持序列协议(sequence protocol)。
说白了,也就是实现了__iter__()方法或者__getitem__()方法。
>>>lst = [1, 2, 3]
>>> for i in iter(lst):
... print(i)
...
1
2
3
对Python语言中的名字(命名)空间的认识
名称到对象的映射的容身之处就是名称空间。名称空间是一个字典对象,键为名字(变量名,标识符),值是名字对应的对象。
各个命名空间是独立没有关系的,一个命名空间中不能有重名,但是不同的命名空间可以重名而没有任何影响
Python中共有四类名字空间:
内置命名空间(Built-in):也叫Python自带电池,任何模块均可以访问,放着内置的函数和异常(比如:input,print,str,list,tuple…)。
全局命名空间(Global):每个模块加载执行时创建的,记录在该模块中定义的变量,包括模块中定义的函数、类、其他导入的模块、模块级的变量与常量。
闭包(Closure):当函数被函数所嵌套时,所引用的其外部函数使用域上的变量,即闭包。
局部命名空间(Local):每个函数所拥有的命名空间,记录了函数中定义的所有变量,包括函数的入参、内部定义的局部变量。
闭包:
def make_adder(addend):
def adder(augend):
return augend + addend
return adder
p = make_adder(23)
print(p)
q = make_adder(44)
print(q)
print(p(100))
print(q(100))
result:
分析:
我们发现,make_adder是一个函数,包括一个参数addend,比较特殊的地方是这个函数里面又定义了一个新函数,这个新函数里面的一个变量正好是外部make_adder的参数.
也就是说,外部传递过来的addend参数已经和adder函数绑定到一起了,形成了一个新函数,我们可以把addend看做新函数的一个配置信息,配置信息不同,函数的功能就不一样了,也就是能得到定制之后的函数.
再看看运行结果,我们发现,虽然p和q都是make_adder生成的,但是因为配置参数不同,后面再执行相同参数的函数后得到了不同的结果.这就是闭包.
def makebold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
def makeitalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makebold
@makeitalic
def hello():
return "hello world"
print(hello())
result:
简单分析
怎么样?这个程序熟悉吗?这不是传说的的装饰器吗?
对,这就是装饰器,其实,装饰器就是一种闭包,
我们再回想一下装饰器的概念:对函数(参数,返回值等)进行加工处理,生成一个功能增强版的一个函数。再看看闭包的概念,这个增强版的函数不就是我们配置之后的函数吗?区别在于,装饰器的参数是一个函数或类,专门对类或函数进行加工处理。
python里面的好多高级功能,比如装饰器,生成器,列表推到,闭包,匿名函数等,开发中用一下,可能会达到事半功倍的效果!
参数,位置参数(定位参数),关键字参数, 不定长位置参数与关键字参数
def myadd(a,b,c,d,*parms):
print(type(parms))
print('parms:',parms)
print('a,b,c,d:',a,b,c,d)
return sum(parms)
myadd(1,2,3,4,5,6)
由此可以看出,不定长位置参数
是一个 元组tuple
#参数:位置参数(定位参数),与不定长位置参数
def myadd2(a,b):
return a+b
def myadd3(a,b,c):
return a+b+c
def myadd4(a,b,c,d):
print(d)
def myadd(arg,*args):
print(type(args))
print(args)
return sum(args)
myadd(18,1,2,3)
# myadd4(6,3,5,3)
# myadd4(3,4,5,5)
# myadd(1,3,7,7,7,7,7,7,7,7,5,7,7,7,7,77,8,2)
关键字参数,与不定长关键字参数
关键字参数:
#关键字参数,与不定长关键字参数
def myadd0(args,lastnum=1000):
return args+lastnum
myadd0(7)
def myaddkw(**names):
print(type(names))
print(list(names.values()))
return list(names.values())
myaddkw(name='david',gender='male',age=0)
myadd0(args=5, lastnum=6)
匿名函数
装饰器
以函数作参数并返回一个替换函数的可执行函数
# 使用 @ 语法糖
# @是python装饰器的简便写法,是Python的语法糖
import datetime
def outer_fun(fun):
#do something you want here
str1='This is string from outer'
def inner():
print(2)
print(str1)
print('from inner to execute:',fun.__name__)
print('the',fun.__name__,'result:',fun()) # 这里使用传进来的参数 fun 加上() 从而调用了fun()
print('extra:',datetime.datetime.now())
return inner
#装饰器语法糖在要被包裹的函数前声明。
#@后面的函数名,是把下边函数进行包裹的函数的名字outer_fun
@outer_fun#为fun1函数添加一个装饰器函数叫outer_fun
def fun1():
return 'this is fun1 function--'
@outer_fun#为fun1函数添加一个装饰器函数,叫outer_fun
def fun2():
return 'this is fun2 function--'
# 装饰器在Python使用如此方便都要归因于
# Python的函数能像普通的对象一样能作为参数传递给其他函数
# 可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内
#装饰器是AOP思想的体现。Aspect Oriented Programming(面向切面编程)
fun1()
print('---'*23)
fun2()
函数式编程思想:
函数是第一等公民 First Class
函数式编程是一种编程范式,是如何编写程序的方法论。
把运算过程尽量变成一系列函数的调用。属于结构化编程
特点:
允许函数作为参数,传入另一个函数
返回一个函数
作用域,嵌套函数,闭包与LEGB规则
要认识一个新的作用域E,就涉及到了闭包
#而每当进入一个函数时,就会新产生一个locals()
g_1='global value in Global'
def func1():
print(locals() is globals())#此时的loclas()就仅指func1内
func1_name='local values in func1'
print('locals in func1: ', locals())
return locals() is globals()
func1()
#分别定义位于LEGB四个不同zuoyong的,相同名字value1的变量
__builtins__.value1='B value stored in __builtins__'#B
value1='G value stored in Global'#G
del value1
#而当出现嵌套函数inner时,也会新产生一个locals(),而如果inner此时还引用了在outter这个函数作用域内出现的变量时,就是闭包
def outter():
# value1='E value stored in enclosure'#Values store in Enclosure
def inner():
# value1='L value stored in locals'
# Can't find value1 in local
print(value1,' referenced from outter')#此时的value1是inner1这个函数外层函数的变量
return inner
outter()()
##快速理解闭包:函数记住其外层作用域的事实
面向对象编程
类 class
与对象 object
对属于同一类事物的抽象叫类class
比如汽车,门,猫。
之前学习使用的都是Python自带的数据类,这节课我们学习自己定义类class
某类事物中的一个具体的实例叫对象Object
比如我家的那辆汽车,张伟办公室的大门,隔壁丽丽家的那只小花猫。
类与对象的关系
类定义封装了数据与方法,类就是对象的模板,可以批量生产出许多的对象。
比如a=7,7其实是整形数字int类的一个实例。
那int这个类还可以’复刻’出许许多多的整形对象。这些对象共有的特征就是:整数性。
类(class)的变量是所有对象共享使用, 只有一个拷贝, 所有对象修改, 都可以被其他对象所见;
对象(object)的变量由类的每个对象所拥有, 每个对象都包含自己的一份拷贝, 不会影响其他对象;
类的设计与创建
#学生类设计
#总学生的人数,全部学生的姓名,已经毕业的学生的数量
#考试功能,分数大于60分,pass,,计入总分,否则 fail
#查分功能,如果考试次数
#查所有已经毕业学员的姓名。
class Student():
student_total = 0
student_graduated=0
student_namelist=[]
student_graduated_name_list=[]
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
self.__score=0
self.times=0#考试次数
Student.student_total+=1
Student.student_namelist.append(name)
def exam(self,examscore):#def函数在类中定义叫方法method,以和类外部定义的函数区分
if self.times==8:
return 'you already qualified,winner,no need to take exam again'
if examscore<60:
print('sorry,better luck next time!')
elif examscore>100:
print('you are cheating!')
else:
self.__score+=examscore
self.times+=1
if self.times==8 and self.__score/self.times>80:#如果参加了八次考试,且平均分数大于80分,即可毕业
Student.student_graduated+=1
Student.student_graduated_name_list.append(self.name)
def check(self,):
if self.times<8:
return f'you need to do more {8-self.times} tests to graduate!'
elif self.__score/self.times<80:
return f'sorry,you are not qualified in julyedu.com,your mean score is {self.__score/self.times}'
else:
return 'you alreay graduated,winner!'
@classmethod
def get_graducated_student(cls,):
return Student.student_graduated
@classmethod
def get_graducated_student_list(cls,):
return Student.student_graduated_name_list
使用类初始化实例
no1=Student('cwf408528649',22,'male')
no2=Student('tianyang',24,'male')
# type(no21)
# print(id(no22),id(no23))
no1.exam(90)
no1.exam(80)
no1.exam(80)
no1.exam(80)
no1.exam(80)
no1.exam(80)
no1.exam(80)
类成员详解
数据成员
- 类变量与实例变量
方法成员
- 类方法与实例方法
#私有成员:对类内部的属性及方法,通过在在标识符前加双 下划线__来实现的私有化
#即使是在成员名面前加了__,依旧可以访问到。
#因为python使用一种 name mangling 技术,将 __membername替换成 _classname__membername
no2._Student__score
# dir(no22)
类中的关键字与装饰器
#关键字
# cls
# cls是指向类的指针,在类方法中第一个形参要命名为cls.
# self
# self是指向每个独立对象的指针.在实例方法中第一个形参被命名为self,以区别其它函数。
# 对象方法以self参数,类方法以cls参数来传递。
# 装饰器
# @staticmethod:类静态方法
# @classmethod:类方法
#@property—把函数调用伪装成对属性的访问,数据描述符属性的优先级高于实例名称空间中的同名成员。
# 使用@property,不用再像java中使用getter,setter方法去设置和访问类变量
# 这时,也只有设置了@property,才能对实例变量进行访问或设置,保护了变量
class Student1():
def __init__(self,name,age): ###__init__实例初始化
self.name = name ####self:实例变量,变量的名字叫name
self.__age=age
@property #getter
def name1(self):
return self.name
@name1.setter # setter
def name1(self,newname):
self.name = newname
@property #getter
def age(self):
return 0
@age.setter # setter
def age(self,newage):
self.__age = newage
# 上面这样设置的是类变量可以被类实例随意访问,修改。
# 注意,这里的name1,如果和实例变量name重名会导致,无限递归!!!
# RecursionError: maximum recursion depth exceeded while calling a Python object
# 但如果想让@property和类实例变量同名呢?
# 将实例变量设置为私有(像age一样)就不会导致重名引发递归死机了
s1=Student1('jack',33)
s1.name1
s1.age#getter
s1.age=22#setter
s1.age
继承与多态?
class Cinema():
salesTotal = 0
def __init__(self,name,location,sales):
self.name = name
self.location = location
self.sales = sales
Cinema.salesTotal += sales
def saleTickets(self, total):
self.sales += total
Cinema.salesTotal += total
@classmethod # 类方法
def getSales(cls,):
return Cinema.salesTotal
cinema1 = Cinema("万达影院","万达广场",100)
cinema1.saleTickets(200)
print(Cinema.getSales())
cinema2 = Cinema("DMG影院","房山南路",50)
cinema2.saleTickets(100)
print(Cinema.getSales())
print('---'*23)
# 定义一个mini类,继承上面的Cinema类,同时重写 saleTickets 方法
class MiniCinema(Cinema):
def saleTickets(self, total):
if total > 100:
total*=0.9
super().saleTickets(total) # Python中的super().是代表调用父类中的成员。
minicinema1 = MiniCinema("万达影院","万达广场",100)
minicinema1.saleTickets(200)
print(MiniCinema.getSales())
知识点测试:
某个函数参数前出现了*和**,这是什么意思?
*
表示该参数是可以接收不定长的位置参数, **
表示该参数是可以接收不定长的关键字参数
*
不定长的位置参数
可变参数就是参数可以传递任意个参数,这些参数在函数调用时自动组装为一个tuple。,比如:
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
calc(1, 2)
nums = [1,2,3,4,5]
calc(*nums) # *nums 表示把 nums 这个 list 的元素拆包后,传到calc函数。作为可变参数传递
**
不定长的关键字参数
关键字参数就是传入任意个含参数名的参数,这些参数自动组装为一个dict。如:
def calc(a, b, **kw):
print('a', a, 'b', b, 'others', kw)
calc(45, 11, lol='lol')
谈谈对Python中的装饰器的理解
装饰器是一个带有函数作为参数并返回一个新函数的闭包,本质上装饰器也是函数。
装饰器的作用是对已有的函数的功能进行修改或者增加。
简化函数重复定义的繁琐编程,加强对函数的可利用部分的重复使用。
Python 使用 @ 语法糖来提供装饰器功能:
以下是一个比较常见的形式:
from functools import wraps
def use_logging(level): # 装饰器带参数
def decorator(func):
@functools.wraps(func) # 把原始函数的文档和签名复制到wrapper()函数中
def wrapper(*args, **kwargs): # 通用参数传递形式
if level == "warn":
logging.warn("%s is running" % func.__name__)
elif level == "info":
logging.info("%s is running" % func.__name__)
return func(*args)
return wrapper
return decorator
@use_logging(level="warn")
def foo(name='foo'):
print("i am %s" % name)
foo()
类装饰器则依靠 call 方法:
Python闭包出现的条件是哪些?
出现嵌套函数(nested function)
嵌套函数引用了定义在外层函数(the enclosing function)的变量
外层函数返回嵌套函数
简述LEGB规则
L-Local(function) : 局部名字空间
E-Enclosing function locals :外部嵌套函数所引用的自由变量所在名字空间(比如闭包)
G-Global(module):函数定义所在模块(文件)的名字空间
B-Builtin(Python):Python内置模块的名字空间
LEGB就是用来规定命名空间查找顺序的规则:L -> E -> G -> B
请设计一个人员类(Person)该类具有姓名,年龄,性别等信息
class Person:
def __init__(self,name,age,sex):
self.name=name
self.__age=age
self.sex=sex
def getname(self,):
return self.name
def setage(self,newage):
self.__age=newage
再设计一个继承自人员类的教师类(Teacher)该类有教师职称,学历,工作年数,工资信息
并能计算出总收入(总收入计算为=工资+工作年数x100),要求对该类构造函数进行重载。
class Teacher(Person):
def __init__(self,name,age,sex,title,eduction,workyears,salary):
super().__init__(name,age,sex)
self.title=title
self.eduction=eduction
self.workyears=workyears
self.salary=salary
self.totalsal=salary+workyears*100
t=Teacher("zhangsan",30,"male","doctor","doctor",5,20000)
print(t.name)
print(t.totalsal)