python基础加强笔记.md

文章目录

      • 简单说说Python中的垃圾回收
      • Python中的垃圾回收
      • 对Python语言中的名字(命名)空间的认识
        • 闭包:
      • 参数,位置参数(定位参数),关键字参数, 不定长位置参数与关键字参数
        • 函数式编程思想:
          • 面向对象编程
            • 类与对象的关系
            • 类的设计与创建

简单说说Python中的垃圾回收

Python中的垃圾回收的主要策略:引用计数与分代回收
引用计算:
一旦对象的引用计数为0,该对象立即被回收,对象占用的内存空间将被释放。
import sys#使用工具查看对象被引用次数
sys.getrefcount(对象名)
分代回收:
Python根据内存中对象的存活时间划分为不同的集合,每个集合称为一个代,共3代
分别为年轻代(新加入的对象)(第0代)、中年代(经历0代回收仍然存活的对象)(第1代),老年代(经历0代,1代回收仍然存活的对象)(第2代) 他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。
可以使用gc模块查看当前监视对象的个数,以及触发垃圾回收的阈值

Python中的垃圾回收

迭代器与生成器有什么相似与不同的地方?

python基础加强笔记.md_第1张图片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:
python基础加强笔记.md_第2张图片

分析:

我们发现,make_adder是一个函数,包括一个参数addend,比较特殊的地方是这个函数里面又定义了一个新函数,这个新函数里面的一个变量正好是外部make_adder的参数.
也就是说,外部传递过来的addend参数已经和adder函数绑定到一起了,形成了一个新函数,我们可以把addend看做新函数的一个配置信息,配置信息不同,函数的功能就不一样了,也就是能得到定制之后的函数.

再看看运行结果,我们发现,虽然p和q都是make_adder生成的,但是因为配置参数不同,后面再执行相同参数的函数后得到了不同的结果.这就是闭包.

def makebold(fn):
    def wrapped():
        return "" + fn() + ""
    return wrapped

def makeitalic(fn):
    def wrapped():
        return "" + fn() + ""
    return wrapped

@makebold
@makeitalic
def hello():
    return "hello world"

print(hello())

result:
python基础加强笔记.md_第3张图片简单分析
怎么样?这个程序熟悉吗?这不是传说的的装饰器吗?
对,这就是装饰器,其实,装饰器就是一种闭包,

我们再回想一下装饰器的概念:对函数(参数,返回值等)进行加工处理,生成一个功能增强版的一个函数。再看看闭包的概念,这个增强版的函数不就是我们配置之后的函数吗?区别在于,装饰器的参数是一个函数或类,专门对类或函数进行加工处理。

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)

python基础加强笔记.md_第4张图片

python基础加强笔记.md_第5张图片

由此可以看出,不定长位置参数是一个 元组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)

python基础加强笔记.md_第6张图片

关键字参数,与不定长关键字参数
关键字参数:

python基础加强笔记.md_第7张图片

#关键字参数,与不定长关键字参数
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基础加强笔记.md_第8张图片

匿名函数
python基础加强笔记.md_第9张图片
在这里插入图片描述

python基础加强笔记.md_第10张图片

装饰器
以函数作参数并返回一个替换函数的可执行函数
python基础加强笔记.md_第11张图片

# 使用 @ 语法糖
# @是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()

python基础加强笔记.md_第12张图片

python基础加强笔记.md_第13张图片

函数式编程思想:

函数是第一等公民 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())

python基础加强笔记.md_第14张图片

知识点测试:
某个函数参数前出现了*和**,这是什么意思?
* 表示该参数是可以接收不定长的位置参数, **表示该参数是可以接收不定长的关键字参数

*不定长的位置参数

可变参数就是参数可以传递任意个参数,这些参数在函数调用时自动组装为一个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)

你可能感兴趣的:(Python)