复习总结1

1、如何区别可变数据类型和不可变数据类型

可变数据类型:列表、字典、集合
不可变数据类型:字符串、元组、整数、布尔值、字节

从对象内存地址(id)区分:
可变:在内存地址(id)不变的情况下,值可变在这里插入图片描述
不可变:在内存地址(id)改变的情况下,值也跟着变在这里插入图片描述

2、Python垃圾回收机制

  • 引用计数
    • 引用计数为0的时候,会被回收
    • 查看变量引用计数:sys.getrefcount(变量名)
    • 循环引用:手动回收,gc.collect()
  • 标记清除
  • 分代回收

2.1、Python中会有函数或成员变量包含单下划线前缀和结尾、以及双下划线前缀和结尾,区别是什么

单下划线 _:保护变量(类的对象和子类对象可以访问,不希望被类外部访问)
双下划线 _ _:私有属性/私有成员(只有类对象能访问,子类不能访问)

注意:保护变量以及私有属性都是伪私有,即可以通过一些代码的书写在外部访问到。详情可以见私有属性笔记。

3、如何判断一个对象是函数还是方法

函数(FunctionType)

函数是封装了一些独立的功能,可以直接调用,能将一些数据(参数)传递进去进行处理,然后返回一些数据(返回值),也可以没有返回值。可以直接在模块中进行定义使用。 所有传递给函数的数据都是显式传递的。

方法(MethodType)

方法和函数类似,同样封装了独立的功能,但是方法是只能依靠类或者对象来调用的,表示针对性的操作。
方法中的数据self和cls是隐式传递的,即方法的调用者;方法可以操作类内部的数据

小结:函数在python中独立存在,可直接使用的,而方法是必须被别人调用才能实现的。
表面区别:

区别一

所处的位置:函数是直接写文件中而不是class中,方法是只能写在class中。
在这里插入图片描述
区别二:
定义的方式

1.函数定义的方式 def关键字 然后接函数名 再是括号 括号里面写形参也可以省略不写形参

 def functionName():
    """这里是函数的注释"""
    print("这一块写函数的内容" 

2.方法定义的方式 首先方法是定义在类中的其他他大体和函数定义差不多,这里需要注意的一点就是方法必须带一个默认参数(即self,相当于this),静态方法除外

class className(super):
    
    def methodName(self):
        """这里是方法的注释
        self相当于this;
        """
        print("这里是方法的内容")

区别三
调用的方式:

1.函数的调用:函数的调用是直接写 函数名(函数参数1,函数参数2,…)

def functionName():
    print("这是一个函数")
 
#调用
functionName()

2.方法的调用:方法是通过对象点方法调用的(这里是指对象方法)


class className:
    
    def method(self):
        print("这是一个方法")
 
#调用---------------------
#实例化对象
c=className()
 
c.method()

区分函数以及方法的代码:

1、使用isinstance()。而判断的类型从types中导入MethodType, FunctionType两个模块,判断是否是函数或者方法类型。

MethodType:方法类型
FunctionType:函数类型

from types import MethodType, FunctionType

isinstance(xx, MethodType):判断xx是否是方法类型
isinstance(xx, FunctionType) :判断xx是否是函数类型

# MethodType:方法类型   FunctionType:函数类型
from types import MethodType, FunctionType


# 这是方法
class num():
    def num(self):
        pass


# 这是函数
def num1():
    pass


print(isinstance(num1, MethodType))         # False
print(isinstance(num1, FunctionType))       # True,代表num1是函数

2、对isinstance(xx, MethodType) 以及 isinstance(xx, FunctionType) 两个方法进行的封装使用的代码。 从 inspect 中导入isfunction, ismethod方法进行方法与函数的判断。

isfunction(xx):判断是否是函数
ismethod(xx) :判断是否是方法
在这里插入图片描述在这里插入图片描述

# isfunction:是FunctionType的封装
# ismethod:是MethodType封装
from inspect import isfunction, ismethod


# 这是方法
class num():
    def num(self):
        pass


# 这是函数
def num1():
    pass


print(isfunction(num1))  # True
print(ismethod(num1))  # False

4、super函数的用法

调用父类中的方法,在子类中重写方法的同时调用父类同名方法的代码。

super使用:super().xxx
xxx:代表调用父类中的方法名

class a():
    def __init__(self):
        print('a')

    def task(self):
        print('task')


class b(a):
    def __init__(self):
        print('b')
        # python3的写法super().继承方法名
        super().__init__()

        # python2的写法super(类名,self).继承方法名
        # super(b,self).__init__()
        
        # 调用父类中的task方法
        super().task()


b()

’‘’
b类的运行结果:b
a
task
‘’‘

_ mro_:了解算法的实现,算法的执行顺序或者继承顺序。即c3算法。

5、使用isinstance和type的区别

功能相同
isinstance:查看对象类型
type:查看对象类型

返回类型不同
isinstance:返回的是布尔值
type:返回的是类型名

a = 1
print(type(a))              # <class 'int'>
print(isinstance(a, int))   # True

继承关系
isinstance:考虑继承关系
type:不考虑继承关系

b继承a类,c是b的类的实例化,那么c肯定是b类的,但是isinstance考虑到了继承所以b继承了a类那么b是a类,而c是b类实例化调用,所以c也是a类。

type则不会考虑。那么c就不是a类。

class a():
    pass


class b(a):
    pass


# 实例化调用
c = b()

print(isinstance(c, b))     # True
print(isinstance(c, a))     # True

print(type(c) is b)         # True
print(type(c) is a)         # False

6、创建大量实例节省内存

关闭动态绑定属性
在类中绑定_ slots_属性 最好使用元组 而不是列表,因为列表容易被修改

_ _slots _ _ = () 元组形式
_ _slots _ _ = [] 列表形式

详情使用见Web课堂笔记2关闭动态绑定部分

7、上下文管理器

with语句中实现一下两个语句
_ _enter _ _:获取资源,需要有返回值
_ _ exit _ _:释放资源

自己创建一个类,完成上下文管理器,那么必须要写入上面两个魔法方法

8、判断一个对象是否具有某个属性

hasattr():判断对象是否具有某个属性,传入的属性以字符串形式写入

class A():
    name = 'jr'

    def task(self):
        print('task')


b = A()
print(hasattr(b, 'name'))       # True
print(hasattr(b, 'names'))      # False
print(hasattr(b, 'task'))       # True

如果name 或者task不用字符串形式而是之间变量名形式传入会报错

9、property动态属性的使用

将类中的方法变成属性进行调用,即“对象.属性”的方式操作操作类属性,除了使用 property() 函数, 还可以 @property 装饰器。

通过 @property 装饰器,可以直接通过方法名来访问方法,不需要在方法名后添加一对“()”小括号。

用法:

@property
def 方法名(self)
    代码块

例:定义一个矩形类,并定义用 @property 修饰的方法操作类中的 area 私有属性

class Rect:
    def __init__(self,area):
        self.__area = area
    @property
    def area(self):
        return self.__area
rect = Rect(30)
#直接通过方法名来访问 area 方法
print("矩形的面积是:",rect.area)

结果是30。
rect.area就是通过对象.属性访问的方式

@property 修饰了 area() 方法,这样就使得该方法变成了 area 属性的 getter 方法。需要注意的是,如果类中只包含该方法,那么 area 属性将是一个只读属性。

也就是说,在使用 Rect 类时,无法对 area 属性重新赋值,即运行如下代码会报错:

rect.area = 90
print("修改后的面积:",rect.area)
“”“
会报错,因为不能重新赋值
”“”

而要想实现修改 area 属性的值,还需要为 area 属性添加 setter 方法,就需要用到 setter 装饰器,它的语法格式如下:

@方法名.setter
def 方法名(self, value):
	   代码块

为 Rect 类中的 area 方法添加 setter 方法,重新赋值rect.area。

@area.setter
def area(self, value):
    self.__area = value
rect.area = 90
print("修改后的面积:",rect.area)

结果就是90。

还可以通过deleter 装饰器来删除指定属性

@方法名.deleter
def 方法名(self):
    代码块
@area.deleter
def area(self):
    self.__area = 0
del rect.area
print("删除后的area值为:",rect.area)

结果就是0

10、如何使用type创建自定义类

type的参数:

  • name:类名
  • bases:继承的父类
  • dict:类属性

type(‘user’, (Baseclass,), {类方法,静态方法,魔法方法等})

# ()类的继承可以不写内容,但是不能没有括号
use = type('Uesr', (), {'name': 'jr'})

print(dir(use))

打印结果:
在这里插入图片描述

11、生成器的创建

生成器创建的两种方式

  • ()
  • yield

11.1 、send方法启动生成器

启动步骤:

  1. 启动生成器:send(None)或next()
  2. 继续使用生成器send(随意写也可以None)或next()

12、TCP和UDP的区别

  1. TCP面向连接(需要对方有回应才会继续,类型打电话)。UDP无连接(只管发送不管对方接收到与否,类似写信)。
  2. TCP是可靠服务。UDP是尽量交付。
  3. UDP实时性好 适合广播通信。TCP是点对点通信。
  4. TCP要求资源比较多。UDP要求资源较少。

13、TCP服务端通信流程

  1. 创建套接字
  2. bind IP和PORT(绑定ip地址和端口)
  3. listen (监听套接字,主动为被动)
  4. accept(等待连接,返回新的套接字和客户端地址)
  5. recv / send (收/发数据)
  6. close(关闭套接字)

类似打电话:
先买手机 ——>插卡——>调成正常状态——>等待别人给你打电话

14、创建线程的两种方式

  • 第一种

  •   iimport threading
      t1=threading.Thread(target=任务 , args=(参数,))
      t1.start()  # 启动
    
  • 第二种(不常用,继承方式)

      import threading
      class A(threading.Thread):
         def run(self):  		# run方法必须写入才能运行
             pass
    

15、解释线程资源竞争以及解决方案

解释线程资源竞争:dis模块。
比如 a+= 1 这个代码分为三步或者更多来执行(大致):
1、加载(获取)变量。
2、进行+1。
3、存储数据。

当线程在一步步执行的时候会进行切换。
一个线程不能保证这三步完全执行完毕后再切换到另一个线程。

解决方法:添加 互斥锁

15.1、死锁出现的原因

两个线程之间相互锁住了对方的资源,没有一方主动释放资源。

如下所示:

线程A
acquire(a) #锁a
acquire(b) #锁b

线程B
acquire(b) #锁b
acquire© #锁a

解决方式:

  • 银行家算法

16、进程之间的通信,以及进程池中的进程通信

进程之间的通信:
import multiprocessing
multiprocessing.Queue

进程池中的进程通信:
import multiprocessing
multiprocessing.Manager().Queue()

17、同步、异步、阻塞、非阻塞

  • 并行:真的多任务,任务数量小于cpu数量
  • 并发:假的多任务,任务数量大于cpu数量
  • 同步:调用IO操作,必须等待IO操作完成才返回调用结果,有先后顺序,必须一个执行完毕后再执行另一个。
  • 异步:调用IO操作,不必等待IO操作完成就返回的调用方式,没有先后顺序,一个在执行过程中有等待环节时候可以执行另一个。
  • 阻塞:代码被卡住了,不能继续向下运行,需要等待。
  • 非阻塞:代码运行没有被卡住,可以继续向下运行,不需要等待。

18、进程、线程、协程对比

  • 进程是资源分配的单位
  • 线程是操作系统调度的单位
  • 进程切换需要的资源很大,效率很低
  • 线程切换需要的资源一般,效率一般
  • 协程切换需要的资源很小,效率高
  • 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中,所以是并发的

19、描述Python GIL的概念以及它对Python多线程的影响

GIL:python的全局解释器锁,用来阻止同一个进程下的多个线程同时执行,即:保证了在同一个进程下同一个时刻多个线程只有一个线程在执行代码

  • python语言和GIL没有关系,是Cpython解释器中的互斥锁。
  • 保证了解释器级别的数据安全

计算密集型:不适合多线程,适合多进程因为没有延迟
IO密集型:适合多线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值