精华内容
下载资源
问答
  • python后端开发面试常见问题 (持续更新)

    万次阅读 多人点赞 2021-03-14 15:21:18
    python后端开发面试常见问题   大家好,我叫亓官劼(qí guān jié ),在GitHub和CSDN中记录学习的点滴历程,时光荏苒,未来可期,一起加油~~ 本篇文章将在GitHub和CSDN上持续更新,主要是Python后端开发的...

    python后端开发面试常见问题

      大家好,我叫亓官劼(qí guān jié ),在GitHub和CSDN中记录学习的点滴历程,时光荏苒,未来可期,一起加油~~

    本篇文章将在GitHub和CSDN上持续更新,主要是Python后端开发的一些常见问题,包括Python的一些基础知识,以及面试中常问的计网,数据库,数据结构等一些算法题,总体覆盖面试的大多数问题。

    本文的GitHub地址为:python-development-interview-FAQ

    CSDN地址为:python后端开发面试常见问题 (持续更新)

    如果有帮助的话,可以在GitHub上点个star,支持下。相对来说GitHub更新要比CSDN上更新更快一些。

    创建了个交流群,如果需要可以加群一起交流,Q群545611263(为了避免广告小号,设置了0.1的付费群),也可以加我V:qiguanjie2015


    Python 基础

    0 说明占位符

    • 本文中不特别标注Python版本的,全部默认为Python3

    1 Python类中的方法类型

    在Python类中有四种方法类型,分别是实例方法、静态方法、类方法和普通方法。

    • 实例方法(即对象方法):需要实例化对象之后才能调用,接受的第一个参数self就是对象本身,必须使用实例化对象才可以访问,不能通过类直接访问.
    • 静态方法:可以通过类名直接调用,不需要传递selfcls;也可以在实例化对象后调用
    • 类方法:可以通过类名调用,也可以在实例化对象后调用。类方法需要一个cls参数,在调用时自动传递
    • 普通方法:和正常的函数一样,可以直接调用,但是在类中不建议写这种方法

    测试示例:

    class A(object):
        # 实例方法(对象方法),需要接收一个形参self,即实例对象自己
        def instance_method_fun(self):
            print("instance_method_fun,self is {}".format(self))
        
        # 类方法,需要接收一个形参cls,在调用时自动传递
        @classmethod
        def classmethod_fun(cls):
            print("classmethod_fun, cls is {}".format(cls))
    
        # 静态方法
        @staticmethod
        def staticmethod_fun():
            print("staticmethod_fun")
    
        # 普通方法
        def common_fun():
            print("common_fun")
    
    # A.instance_method_fun() # 报错:TypeError: instance_method_fun() missing 1 required positional argument: 'self'
    A.classmethod_fun() # 输出:classmethod_fun, cls is <class '__main__.A'>
    A.staticmethod_fun() # 输出:staticmethod_fun
    A.common_fun() # 输出:common_fun  (不建议在类中写普通方法)
    
    
    a = A()
    a.instance_method_fun() # 输出:instance_method_fun,self is <__main__.A object at 0x0000018674E1E588>
    a.classmethod_fun()# 输出:classmethod_fun, cls is <class '__main__.A'>
    a.staticmethod_fun()# 输出:staticmethod_fun
    

    2 Python的参数传递类型

    Python中的参数传递是引用传递,即我们可以对传递对象的属性,但是不能改变传递对象的指针。在Python中有一些对象的值是不可以更改的,例如int,float类型。如果在函数体内修改了不可修改对象的值,Python会在一个新的内存地址上创建一个变量,而不是使用原来的变量;如果在函数体内修改一个可修改对象的值,则在原内存地址操作。

    例如:

    def fun1(x):
        x = x + 1
        print("x:{},id(x):{}".format(x,id(x)))
    
    def fun2(x):
        print("b:{},id(b):{}".format(b,id(b)))
        x.append(2)
        print("b:{},id(b):{}".format(b,id(b)))
    
    a = 1
    print("a:{},id(a):{}".format(a,id(a)))
    fun1(a)
    print("a:{},id(a):{}".format(a,id(a)))
    
    b = []
    print("b:{},id(b):{}".format(b,id(b)))
    fun2(b)
    print("b:{},id(b):{}".format(b,id(b)))
    
    # 输出为:
    # a:1,id(a):1860272240
    # x:2,id(x):1860272272
    # a:1,id(a):1860272240
    # b:[],id(b):2262818473288
    # b:[],id(b):2262818473288
    # b:[2],id(b):2262818473288
    # b:[2],id(b):2262818473288
    

    3 协程

    这个是在前不久的面试中才知道有协程这个概念,其实也可以理解为用户线程,相比较内核线程而言,用户线程更加的灵活,并且减少了进出内核态的消耗,缺点是无法利用多核CPU的并行优势。

    4 Python命名中的单下划线(_)和双下划线(__)

    在Python中,双下划线开头和结尾的命名默认为Python的内部变量/方法,用以区分用户变量。例如场景的__init__(),__dict__,__dir__等。

    单下划线开头的命名默认为私有变量,不会在from a import *中被导入

    双下划线开头,但是没有下划线结尾的命名,Python在解释的时候会默认对其进行重命名为_类名__变量

    class A():
        def __init__(self) -> None:
            self._b = "self._b"
            self.__c = "self.__c"
    a = A()
    print(a._b) # 输出:self._b
    # print(a.__c) # 报错:AttributeError: 'A' object has no attribute '__c'
    print(a.__dict__) # 输出:{'_b': 'self._b', '_A__c': 'self.__c'}
    # 我们发现__c变量被自动重命名为_A__c了
    print(a._A__c) # 输出:self.__c
    

    在Python中,当一个文件夹下有一个__init__.py文件,则Python会识别这个文件夹为一个Python包

    5 python字符串传参 %s和format

    %s和format的区别在于,format可以传递列表、元组等类型,而%s不可以传递元组类型(%s可以传递列表类型),所以在日常使用时,使用format更加方便

    6 python 迭代器和生成器

    迭代器是python十分强大的一个功能,迭代器是一个可以记住遍历位置的对象。例如:

    a = [1,2,3,4]
    it = iter(a) # 获取一个迭代器对象
    print(next(it)) # 遍历下一个位置,输出:1
    print(next(it)) # 遍历下一个位置,输出:2
    

    我们也可以使用迭代器来生成一个我们需要的列表,例如:

    a = [i*i for i in range(1,9)] # 使用迭代器生成一个[1,9)的平方的列表
    print(a) # 输出:[1, 4, 9, 16, 25, 36, 49, 64]
    

    在这里如果我们将外面的[]改为(),a获取的将会是一个生成器,而不是迭代器。在python中,使用yield的函数被称为生成器,生成器返回的是一个迭代器的函数,只能用于迭代操作,在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

    生成器不保留所有的数据信息,而是指记录当前运行的信息。因此生成器就不能直接获取某个下表的值,而是要通过next()或者sent(),亦或是迭代器来依次获取值。

    例如:

    a = (i*i for i in range(1,9)) # 使用生成器生成一个[1,9)的平方的列表
    print(a) # 输出:[1, 4, 9, 16, 25, 36, 49, 64]
    # print(a[2]) # 报错TypeError: 'generator' object is not subscriptable
    it = iter(a) # 获取一个迭代器对象
    print(next(a)) # 输出 1
    print(next(a)) # 输出 4
    print(next(a)) # 输出 9
    print(next(a)) # 输出 16
    print("=================")
    for item in a:
        print(item)
    # 输出:
    # 25
    # 36
    # 49
    # 64
    

    生成器常用场景:例如我们需要生成一个有规律向前推进的列表,或者一个从1到1亿的列表等等,当我们列表中元素数量十分大时,内存会爆栈。但是如何我们元素间是有规律的,则我们可以利用生成器来解决这个问题。

    有需要的话可以参考这篇文章:学点简单的Python之Python生成器

    7 python 装饰器

    装饰器是一个十分常用的东西,经常被用在有切面需求的场景,大家耳熟能详的AOP就是这个,装饰器的主要功能就是为已经存在的函数提供一些可复用的定制化功能。

    装饰器包含很多内容,需要系统的去看,这里不展开。如有需要,可以参考这篇文章:学点简单的Python之Python装饰器与闭包

    8 python 变量中的作用域

    python中变量总是默认本地变量,如果没有,则会创建一个本地变量。在函数中如果要使用全局变量,需要使用gloabl进行声明。例如:

    a = 5
    def fun():
        global a
        a = a + 1
    fun()
    print(a)# 输出:6
    

    9 python 闭包

    python闭包与其他语言的闭包的意思是一样的,即我们在函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行。简单来说,就是在函数内定义函数,且函数内部定义的函数中使用了外部函数中的变量,且内部函数可以单独的运行。

    这里用语言来描述还是比较的绕,我们可以通过下面这个小例子来更直观的理解:

    # 定义一个函数extern_func
    def extern_func():
        # 在extern_func函数内定义一个空列表list
        list = []
        # 在extern_func函数内定义一个函数inner_func
        def inner_func(name):
            # inner_func函数的功能是在list列表中添加一个name,然后输出list
            list.append(name)
            print(list)
        # exten_func函数的返回值是inner_func的函数体
        return inner_func
    
    # 调用extern_func函数,返回值赋值给ret1,即ret1为inner_func函数体
    ret1 = extern_func()
    ret1('zhangsan')# 调用ret1,在list中添加一个'zhangsan',并输出list
    ret1('lisi')# 调用ret1,在list中添加一个'lisi',并输出list
    
    # 调用extern_func函数,返回值赋值给ret2,即ret2为inner_func函数体
    ret2 = extern_func()
    ret2('wangwu')# 调用ret2,在list中添加一个'wangwu',并输出list
    
    ret1('qiguanjie')# 调用ret1,在list中添加一个'lisi',并输出list
    

    输出为:

    ['zhangsan']
    ['zhangsan', 'lisi']
    ['wangwu']
    ['zhangsan', 'lisi', 'qiguanjie']
    

    我们发现ret1ret2中虽然都是在list中添加一个name并返回,但是ret1ret2是两次调用extern_func( )返回的函数体,他们作用的list是不同的,他们作用的list可以脱离原函数extern_func()而单独使用。这就是函数闭包的简单使用。简而言之就是我们在函数中定义函数,并且使用了外部函数中的部分变量,我们内部的函数在脱离外部函数之后继续执行,且单独作用于外部函数的部分变量。

    闭包一个常见错误:

    我们看下面这个例子

    def func():
        list = []
        for i in range(3):
            def inner_func():
                return i*i
            list.append(inner_func)
        return list
    re1,re2,re3= func()
    print(re1())
    print(re2())
    print(re3())
    

    大家是不是以为三个输出的结果应该是0,1,4?但实际上输出的结果都是4,这是为什么呢?这里我们的i对于inner_func来说是一个外部函数,我们在list中添加是是inner_func的函数体,里面返回的是i*i,但是当我们i变化到2之后,我们才返回list,所以我们输出的三个值才都是4,那如何避免这种情况呢?

    第一种方法,区分变量

    我们使用_i来区分i

    def func():
        list = []
        for i in range(3):
            def inner_func(_i = i):
                return _i*_i
            list.append(inner_func)
        return list
    re1,re2,re3= func()
    print(re1())
    print(re2())
    print(re3())
    

    这里我们在inner_func的参数中定义_i变量,值为当前的i,这时我们将函数体加入list中,就可以保证值不受i值变化的影响,输出为0,1,4。另一种方法就是我们直接在list中存放计算好的值,而不是函数体(这种方法有一定的局限性,和之前的方法就是两种完全不同的方法了):

    def func():
        list = []
        for i in range(3):
            def inner_func():
                return i*i
            list.append(inner_func())
        return list
    re1,re2,re3= func()
    print(re1())
    print(re2())
    print(re3())
    123456789101112
    

    这里我们这里添加到list中的是inner_func(),一旦有()则表明我们这个函数已经运行了,返回的是一个值。

    第二种方法 nonlocal关键字

    那如果我们要在内部函数中使用外部函数中的变量,并进行修改我们应该如何做呢?

    def extern_func(name):
        print('exter_func name is : %s' % name)
        def inner_func():
            name = 'inner_func ' + name
            print('inner_func name is : %s' % name)
        return inner_func
    
    ret = extern_func('qiguanjie')()
    

    如何我们直接修改的话,我们会发现这里编译会报错:UnboundLocalError: local variable 'name' referenced before assignment

    这里报错的意思即我们这里的name变量在使用前未被分配,这就和我们在函数内使用全局变量时要使用globle关键字一样,这里在内部函数中要使用并更改外部函数中的变量,我们需要使用关键字nonlocal,对程序进行修改:

    def extern_func(name):
        print('exter_func name is : %s' % name)
        def inner_func():
            nonlocal name
            name = 'inner_func ' + name
            print('inner_func name is : %s' % name)
        return inner_func
    
    ret = extern_func('qiguanjie')()
    

    此时程序顺利编译,输出结果为:

    exter_func name is : qiguanjie
    inner_func name is : inner_func qiguanjie
    

    10 python lambda函数

    lambda函数即匿名函数,在很多场合都可以使用。lambda 函数比较轻便,即用即仍,很适合需要完成一项功能,但是此功能只在此一处使用,连名字都很随意的情况下。

    例如在sort函数中指定排序的key:

    a = [{"a":13,"b":25,"c":62},{"a":63,"b":215,"c":612},{"a":3,"b":634,"c":216}]
    a.sort(key=lambda x: x['a'])
    print(a) # 输出: [{'a': 3, 'b': 634, 'c': 216}, {'a': 13, 'b': 25, 'c': 62}, {'a': 63, 'b': 215, 'c': 612}]
    a.sort(key=lambda x: x['b'])
    print(a) # 输出: [{'a': 13, 'b': 25, 'c': 62}, {'a': 63, 'b': 215, 'c': 612}, {'a': 3, 'b': 634, 'c': 216}]
    a.sort(key=lambda x: x['c'])
    print(a) # 输出: [{'a': 13, 'b': 25, 'c': 62}, {'a': 3, 'b': 634, 'c': 216}, {'a': 63, 'b': 215, 'c': 612}]
    
    

    11 python中的深拷贝与浅拷贝

    在浅拷贝时,拷贝出来的新对象的地址和原对象是不一样的,但是新对象里面的可变元素(如列表)的地址和原对象里的可变元素的地址是相同的,也就是说浅拷贝它拷贝的是浅层次的数据结构(不可变元素),对象里的可变元素作为深层次的数据结构并没有被拷贝到新地址里面去,而是和原对象里的可变元素指向同一个地址,所以在新对象或原对象里对这个可变元素做修改时,两个对象是同时改变的,但是深拷贝不会这样,这个是浅拷贝相对于深拷贝最根本的区别。

    在深拷贝时,会只拷贝所有元素的值,包括可变对象,也仅拷贝对象中的值,而不是地址。

    import copy
    a = [1,2,3,4,['a','b','c']]
    b = a # 赋值(引用传递)
    c = copy.copy(a)# 浅拷贝
    d = copy.deepcopy(a) # 深拷贝
    
    a.append(5)
    a[4].append('d')
    print("a:{},  id(a):{}, id(a[4]):{}".format(a,id(a),id(a[4])))
    print("b:{},  id(b):{}, id(b[4]):{}".format(b,id(b),id(b[4])))
    print("c:{},     id(c):{}, id(c[4]):{}".format(c,id(c),id(c[4])))
    print("d:{},          id(d):{}, id(d[4]):{}".format(d,id(d),id(d[4])))
    
    # 输出为:
    # a:[1, 2, 3, 4, ['a', 'b', 'c', 'd'], 5],  id(a):1998224934024, id(a[4]):1998224933896
    # b:[1, 2, 3, 4, ['a', 'b', 'c', 'd'], 5],  id(b):1998224934024, id(b[4]):1998224933896
    # c:[1, 2, 3, 4, ['a', 'b', 'c', 'd']],     id(c):1998224936904, id(c[4]):1998224933896
    # d:[1, 2, 3, 4, ['a', 'b', 'c']],          id(d):1998224935752, id(d[4]):1998224957960
    

    12 Python中*args和**kwargs

    *args表示传一个元组给函数,可以同时传递多个参数,这里的args可以替换为其他名称,前面加一个*即可,例如:*para都可以。

    **kwargs表示传一个字典给函数,可以传多个键值对,这里的kwargs同样也可以替换为其他名称,前面有**即可。

    两者的不同如下所示:

    def fun(*args,**kwargs):
      print("args: ",args)
      print("kwargs: ",kwargs)
    
    fun("hello","world","!","this","is","args",a=1,b=2,c=3)
    
    # 输出为:
    # args:  ('hello', 'world', '!', 'this', 'is', 'args')
    # kwargs:  {'a': 1, 'b': 2, 'c': 3}
    

    13 Python中__new____init__的区别

    __new__是静态方法,会返回一个创建的实例

    __init__是实例方法,无返回值

    14 Python中的单例模式

    单例模式是一种特别重要的设计模式,通过单例模式可以保证系统中一个类只有一个实例并且该实例易于被外界访问,方便控制实例个数并节约系统资源。实现单例模式的常用方法如下:

    1 通过import导入

    在Python中使用import来导入一个对象,则是天然的单例模式。因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。例如:

    # a.py中
    class A(object):
        def fun(self):
            pass
    test_a = A
    
    # b.py中
    from a import test_a
    

    2 使用装饰器

    def Singleton(cls):
        _state = {}
        def _singleton(*args, **kargs):
            if cls not in _state:
                _state[cls] = cls(*args, **kargs)
            return _state[cls]
        return _singleton
    
    
    @Singleton
    class A(object):
        a = 1
        def __init__(self, x=0):
            self.x = x
    
    a1 = A()
    a2 = A()
    
    print("id(a1): ",id(a1))
    print("id(a2): ",id(a2))
    
    print("a1.a: ",a1.a)
    print("a2.a: ",a2.a)
    
    a1.a = 2
    print("a1.a: ",a1.a)
    a2.a = 3
    print("a2.a: ",a2.a)
    
    print("a1.a: ",a1.a)
    
    # 输出为:
    # id(a1):  2973113231736
    # id(a2):  2973113231736
    # a1.a:  1
    # a2.a:  1
    # a1.a:  2
    # a2.a:  3
    # a1.a:  3
    

    3 使用类实现

    使用类实现的时候需要加锁,否则在多线程中无法保证单实例

    import time
    import threading
    class Singleton(object):
        _instance_lock = threading.Lock()
    
        def __init__(self):
            time.sleep(1)
    
        @classmethod
        def instance(cls, *args, **kwargs):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = Singleton(*args, **kwargs)
            return Singleton._instance
    
    
    def task(arg):
        obj = Singleton.instance()
        print(obj)
    for i in range(10):
        t = threading.Thread(target=task,args=[i,])
        t.start()
    time.sleep(20)
    obj = Singleton.instance()
    print(obj)
    
    # 输出:
    # <__main__.Singleton object at 0x0000022E7C561E80>
    # <__main__.Singleton object at 0x0000022E7C561E80>
    # <__main__.Singleton object at 0x0000022E7C561E80>
    # <__main__.Singleton object at 0x0000022E7C561E80>
    # <__main__.Singleton object at 0x0000022E7C561E80>
    # <__main__.Singleton object at 0x0000022E7C561E80>
    # <__main__.Singleton object at 0x0000022E7C561E80>
    # <__main__.Singleton object at 0x0000022E7C561E80>
    # <__main__.Singleton object at 0x0000022E7C561E80>
    # <__main__.Singleton object at 0x0000022E7C561E80>
    

    4 基于__new__方法实现

    当我们实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.new),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以基于这个,实现单例模式

    import threading
    class Singleton(object):
        _instance_lock = threading.Lock()
    
        def __init__(self):
            pass
    
        def __new__(cls, *args, **kwargs):
            if not hasattr(Singleton, "_instance"):
                with Singleton._instance_lock:
                    if not hasattr(Singleton, "_instance"):
                        Singleton._instance = object.__new__(cls)  
            return Singleton._instance
    
    obj1 = Singleton()
    obj2 = Singleton()
    print(obj1)
    print(obj2)
    
    def task(arg):
        obj = Singleton()
        print(obj)
    
    for i in range(10):
        t = threading.Thread(target=task,args=[i,])
        t.start()
    
    # 输出
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    # <__main__.Singleton object at 0x0000017B102EA978>
    

    15 Python中is==的区别

    is是对指针的比较,==是对值的比较。

    a = [1,2,3,4]
    b = [1,2,3,4]
    print(a is b) # 输出 False
    print(a == b) # 输出 True
    

    16 Python3 和Python2的区别

    • Python2的print不用加()而python3需要
    • python2的/表示整除(不加.0的时候),而Python3是除
    • Python3的A / B的返回值类型都是float,而Python2可能是整型
    • python2默认编码是ascii,python3的默认编码是utf-8
    • python3新增了nonlocal关键字,用于实现非局部变量

    等等,这里例举的几个是常见的价格区别。

    17 Python中a += X和a = a + x的区别

    在Python中,a += X和a = a + x的实现机制是不同的,这里分为四种情况。

    • 可变类型
      • a += x:将会在a原地址上进行修改,a的地址不变
      • a = a + x:将会新创建一个对象,名称为a,但是地址与原来的地址不同。
    • 不可变类型
      • a += x:将会新创建一个对象,名称为a,但是地址与原来的地址不同。
      • a = a + x:将会新创建一个对象,名称为a,但是地址与原来的地址不同。

    程序示例:

    a = [1,2,3]
    print("a原地址为:{}".format(id(a)))
    a += [4,5]
    print("进行a += [4,5]操作后的a地址为:{}".format(id(a)))
    a =a + [4,5]
    print("进行a =a + [4,5]操作后的a地址为:{}".format(id(a)))
    
    a = 1
    print("a原地址为:{}".format(id(a)))
    a += 2
    print("进行a += 2操作后的a地址为:{}".format(id(a)))
    a =a + 2
    print("进行a =a + 2操作后的a地址为:{}".format(id(a)))
    

    输出为:

    a原地址为:140591562829000
    进行a += [4,5]操作后的a地址为:140591562829000
    进行a =a + [4,5]操作后的a地址为:140591562984456
    a原地址为:4391820368
    进行a += 2操作后的a地址为:4391820432
    进行a =a + 2操作后的a地址为:4391820496
    

      大家好,我是亓官劼(qí guān jié ),在【亓官劼】公众号、CSDN、GitHub、B站、华为开发者论坛等平台分享一些技术博文,主要包括前端开发、python后端开发、小程序开发、数据结构与算法、docker、Linux常用运维、NLP等相关技术博文,时光荏苒,未来可期,加油~
      如果喜欢博主的文章可以关注博主的个人公众号【亓官劼】(qí guān jié),里面的文章更全更新更快。如果有需要找博主的话可以在公众号后台留言,我会尽快回复消息,其他平台私信回复较慢。
    在这里插入图片描述

    由于学习工作的需要,算法刷题将会逐渐由C++向Python3过度,正在过度中,如实现的不太优美,请见谅。

    本文原创为【亓官劼】(qí guān jié ),请大家支持原创,部分平台一直在恶意盗取博主的文章!!! 全部文章请关注微信公众号【亓官劼】。

    展开全文
  • python后端开发

    千次阅读 2019-08-02 09:46:19
    学习python多线程的缺点进程,线程和协程进程,协程的上下文切换线程和进程的实现方式如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...

    python多线程的缺点

    在这里插入图片描述
    python的多线程的问题:GIL导致PYTHON 无法使用到计算机的多核,仅能使用单核

    JAVA传统的多线程主要解决的问题:
    1、运行于多核CPU上,各线程可分布于CPU的各个核心,让程序真正的并发
    2、因为外设(IO外设)的速度不匹配,导致线程阻塞。所以需要多线程切换来让阻塞的线程让出CPU,让其它线程运行。

    python线程被人诟病的主要原因:
    由于python设计之初,没预料到多核cpu能够得到现在的发展,只考虑到了单核cpu。为了更好的实现多线程之间数据完整性与状态同步,于是设计出了一个全局解析器锁(GIL, global interpreter lock)。
    GIL确保Python进程一次运行一个线程(其它线程处于等待I/O或者睡眠状态),无论当前cpu有多少核心。这就意味着Python虽然可以实现多线程,但是在任意时间点仅有一个核心在执行Python指令(即线程无法并行运算),无法发挥现代多核cpu的性能。
    CPython解析只允许拥有GIL才能运行程序。
    理解GIL的弊端
    write代表互斥锁,作用是防止多个线程一起修改某一共享数据data导致错误
    1)Th1和Th2的下一步都要希望对data进行修改;
    2) Th1在某一时刻同时拿到了GIL与write,准备对data进行修改;
    3) Th1在准备修改前,发生了I/O请求,所以需要让出GIL(如果由于I/O请求让出GIL,该线程不参与GIL的竞争,如果由于持有时间到达上限,可参与竞争),但是write依旧才Th1手上;
    4) Th2获得了GIL,但是由于缺少write也无法对data进行修改,达到持有GIL时间上限后,让出GIL,并参与竞争;
    5) Th1的I/O完成后,参与GIL竞争(由于Th1持有write,所以无论Th2获得多少次GIL都无法对data进行修改,而持有GIL等待write的时间将会被浪费);
    6) 直到Th1获得GIL后,由于Th1拥有GIL、write,所以对data进行修改,然后释放write,进行下一步操作,直到GIL持有时间达到上限或者进程结束,释放GIL(不持有GIL无法运行);
    7) Th2获得Th1释放的write,等待GIL,获得后,修改data,直到GIL持有时间达到上限或者进程结束,释放GIL(不持有GIL无法运行);加粗样式

    进程,线程和协程

    进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。

    线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是的)。

    协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
    协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。

    进程,协程的上下文切换

    cpu保存上一次的任务状态,加载下一个任务这个过程为一次上下文切换
    协程
    协程的切换其实就是cpu 寄存器内容特别是%rip 和 %rsp 的写入和恢复,因为cpu 的寄存器决定了程序从哪里执行(%rip) 和使用哪个地址作为堆栈 (%rsp)

    现有协程库,是怎么去实现context切换的呢,目前主要有以下几种方式:
    使用ucontext系列接口,例如:libtask
    使用setjmp/longjmp接口,例如:libmill
    使用boost.context,纯汇编实现,内部实现机制跟ucontext完全不同,效率非常高,后面会细讲,tbox最后也是基于此实现
    使用windows的GetThreadContext/SetThreadContext接口
    使用windows的CreateFiber/ConvertThreadToFiber/SwitchToFiber接口
    线程
    线程上下文切换的原因
      1.正常时间片完了之后的正常调度。
      2.执行任务时遇到IO阻塞,挂起当前线程加载下一个线程。
      3.多个任务抢占锁资源,当前任务没有抢到锁资源,被调度器挂起,继续下一任务。
      4.用户代码挂起当前任务,让出CPU时间。
      
      减少上下文切换
      1.无锁编程:
      2.CAS:原子类就是啦。
      3.协程:单线程里面实现调度多任务。

    线程和进程的实现方式

    线程
    Java多线程实现的方式有四种
    1.继承Thread类,重写run方法
    2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
    3.通过Callable和FutureTask创建线程
    4.通过线程池创建线程

    前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果
    后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中
    进程的通信方式
    1-1、无名管道(pipe);
     1-2、有名管道 (fifo);
     1-3、信号(signal);
     2-1、共享内存(share memory);
     2-2、消息队列(message queue);
     2-3、信号灯集(semaphore set);
    以上6种进程间通信方式是用在本地一台计算机的不同进程间通信,而 Socket和Streams支持不同主机上的两个进程IPC, 即可用于本地一台计算机的不同进程间通信,但更多的是用于不同主机通过网络来通信。
    3、套接字(socket)

    展开全文
  • PythonBackend:Python后端开发课程,2021年Spring
  • 关于python后端开发所需的技术栈的总结

    python后端开发学习

    最近在学习python后端开发,简单的总结了python后端开发所需的技术栈,希望对自学python的同学有一点帮助.

    1.python语言基础

    • python的语法特点
    • python的高级特性

    2.编程范式

    • 面向对象和函数式编程
    • 常用的设计模式

    3.数据结构和算法

    • 常用的数据结构(如队列, 栈, 二叉树等)
    • 常见的算法(如二分查找,排序算法)

    4.操作系统方面

    • 线程,进程,协程
    • Linux常用的命令

    5.数据库方面

    • 关系型数据库MySQL, 常见的增删改查操作,索引,MySQL调优
    • 非关系型数据库Redis缓存
    • 数据库与python的交互,ORM

    6.网络编程

    • TCP/IP协议族模型
    • socket
    • io复用和异步io

    7.web框架

    • 常用的web框架(Django,flask,Tornador异步框架)
    • restful规范
    展开全文
  • Python,不需要有编程基础!编程零基础,可以学习 Python 吗”,这是很多初学者经常问我的一个问题。,在计算机方面的基础越好,对学习任何一门新的编程语言越有利。但如果你在编程语言的学习上属于零基础,也不用...

    学Python,不需要有编程基础!

    编程零基础,可以学习 Python 吗”,这是很多初学者经常问我的一个问题。,在计算机方面的基础越好,对学习任何一门新的编程语言越有利。但如果你在编程语言的学习上属于零基础,也不用担心,因为无论用哪门语言作为学习编程的入门语言,总是要有一个开始。

    就我个人的观点,Python 作为学习编程的入门语言是再合适不过的。凡是在大学计算机专业学习过 C 语言的同学都感同身受,认为 C 语言不是很好的入门语言,很多曾经立志学习编程的读者,在学习了 C 语言之后,就决心不再学习编程。因此,是否学会 C 语言,好像成为了进入编程行业的筛选标准。

    但是,如果将 Python 作为编程入门语言,就不会出现类似 C 语言的那些窘境问题。目前,逐渐有高校开始使用 Python 作为软件专业大学生(甚至也包含非软件专业)的入门编程语言。

    零基础也能学 Python,目标就是和初学者一起,从零基础开始学习 Python。因此,编程零基础的你,无需犹豫,尽管放胆来学。

    除此之外,很多初学者还面临这样一个问题,那就是教程已经学完啦,教程中的代码也都已经亲自编写并运行通过了,但还是不知道如何开发一个真正的应用程序,面对问题还是不知道如何下手解决。

    如果你深有同感,只能说明你缺乏练习,代码编辑量太少。从编程零基础到专业程序员的过程,除了学习更多的基础知识,更要刻意地去培养自己的编程思维,这没有捷径,只有靠不断积累自己的代码量。

    当然,增加代码量并不是要我们去盲目地编写代码,如果找不到增加代码量的方向,可以从阅读别人的代码开始。需要注意的是,在阅读他人编写的代码时,要边阅读边思考,多问几个为什么,例如代码为什么要这么写,有什么意图,有没有更简单的方法可以实现等等,必要情况下还可以给代码进行必要的注释。不仅如此,在完全理解他人代码的前提下,还可以试图对代码做修改,实现一些自己的想法。做到这些,才能说明你将别人的代码消化吸收了。

    初学者在写代码或者调试代码的过程中,肯定会遇到很多问题,怎么办呢?最好的方法就是借助网络寻找答案,看看类似的问题别人是如何解决的,千万不要总是局限在自己的思维范围中。在这里,给大家推荐一个专门针对编程答疑解惑的网站 Stack OverFlow。

    Python中的9个代码小实例!

    1 串联比较

    2、串联函数调用

    3、复制列表

    4、字典元素值

    5、 按值排序字典

    6、 For Else

    7、列表转换为逗号的字符串

    8、 合并字典

    9、寻找列表中最大和最小元素的索引

    若有不明白的地方,请移步Python视频教程继续学习!!

    廖雪峰python3教程怎么样

    您每个老师的都很不错!

    我现在也正在看Python,个人认为,先找一个能入门的,快速看完际练习一遍,然后在结合其他人的书在看几遍,这样效果比较好。每写书的特点都不一样,因此分类的重点什么的都不太一样。这样多看看多练习一下,能更全面一点!

    视频的话,也类同,不过建议先看书自己来,自己把代码敲一遍,然后在看视频,看看自己出错的地方,老师怎么解决的,自己是怎么解决的,那种方法更好一点!

    共同进步~~~谢谢

    求推荐python3入门教程,适合新手的

    关于Python的课程还是很多的,

    你可以看看猎豹网校的课程,也许会对你有所帮助。

    希望可以对你有帮助

    python后端开发需要学什么?

    第一阶段:Python语言基础

    主要学习Python最基础知识,如Python3、数据类型、字符串、、类、文件操作等。阶段课程结束后,学员需要完成Pygame实战飞机大战、2048等项目。

    第二阶段:Python语言高级

    主要学习Python库、正则表达式、进程线程、爬虫、遍历以及MySQL数据库。

    第三阶段:Python web开发

    主要学习HTML、CSS、JavaScript、jQuery等前端知识,掌握python三大后端框架(Django、 Flask以及Tornado)。需要完成网页界面设计实战;能独立开发网站。

    第四阶段:Linux基础

    主要学习Linux相关的各种命令,如文件处理命令、压缩解压命令、权限管理以及Linux Shell开发等。

    第五阶段:Linux运维自动化开发

    主要学习Python开发Linux运维、Linux运维报警工具开发、Linux运维报警安全审计开发、Linux业务质量报表工具开发、Kali安全检测工具检测以及Kali 密码破解实战。

    第六阶段:Python爬虫

    主要学习python爬虫技术,掌握多线程爬虫技术,分布式爬虫技术。

    第七阶段:Python数据分析和大数据

    主要学习numpy数据处理、pandas数据分析、matplotlib数据可视化、scipy数据统计分析以及python 金融数据分析;Hadoop HDFS、python Hadoop MapReduce、python Spark core、python Spark SQL以及python Spark MLlib。

    第八阶段:Python机器学习

    主要学习KNN算法、线性回归、逻辑斯蒂回归算法、决策树算法、朴素贝叶斯算法、支持向量机以及聚类k-means算法。

    关于python后端开发需要学什么的内容,青藤小编就和您分享到这里了。如果您对python编程有浓厚的兴趣,希望这篇文章可以为您提供帮助。如果您还想了解更多关于python编程的技巧及素材等内容,可以点击本站的其他文章进行学习。

    python运维怎么学

    运维工和开发人员一同属于IT从业人员,很多人认维人员不需要懂开其实不然,不懂开发的运维道路会越走越窄。现阶段,掌握一门Python开发已经成为高级运维工程师的必备技能了,那么Python运维要学习哪些内容,如何才能学好?下面给大家介绍一下:

    1、学习编程不止是学习语法,需要学习算法(计算思维、解决问题的方法、编程思路)。

    何为计算思维:计算思维(Computational Thinking)概念的提出是计算机学科发展的自然产物。

    相关推荐:《Python教程》

    计算思维是运用计算机科学的基础概念去求解问题、设计系统和理解人类的行为;计算思维最根本的内容,即其本质是抽象和自动化。编程思路,其实就是计算思维的具体体现,用语法来表达解决问题的方法、算法。

    2、Python有多种编程范式,面向过程,面向对象,函数式编程等。建议从面向过程学起。

    3、函数抽象、需要掌握大的问题化解为小的问题,每一个小的问题用函数来解决,集成起来大的问题就解决了。

    4、面向对象的类抽象,类就是由属性加方法构成的对象的蓝图。会用面向对象的思想建模。

    5、多看书多实战。

    学习编程需要多看相关书籍,选专业的书籍仔细研读。也可以去网上搜一些视频教程学习,边看边跟着敲代码,千万不要懒,不要认为自己看懂了,就可以省去不用敲代码!这是错误的,只有亲自把代码敲一遍,你才能对代码有一个更深入的认知,在敲的过程中,才能碰到问题。碰到问题,想办法解决,才能提高。

    python最佳入门教程(1): python的安装

    本教程基于python3.x, 是针对初的列python入门教程,在知乎上常有人问算机该怎么学,如学编程,笔者也是通过自学编程而进入IT这一行业的,回顾入行的这几年,从音视频流媒体辗转到人工智能深度学习,机器视觉,我是下了不少苦心的,对于如何学习有自己的一套理论和实践方法,很多人自言学编程不得其门,把学不会归咎于天分,其实芸芸众生,智力无别,你现在所看到的是技术大牛们一个个超凡绝顶(然知此绝顶非彼绝顶),看不到的是曾经的他们,也在每个昼夜里用心苦学。再者学一门技术,需要勤学刻苦,是需要讲究方法和基础的,方法对了就事半功倍,所谓的天才也无不是建立在扎实的基础之上。

    在windows中安装python

    首先打开python官网https://www.python.org/,点击页面downloads导航按钮,下载windows最新的基于web安装的安装器,右键以管理员身份运行 安装包,会出现如下界面:

    将Add Python 3.7 to PATH 进行勾选,勾选此项的目的在于将python解释器加入系统环境变量,则在后续的python开发中可直接在windows 命令行中执行python脚本。所谓的环境变量是系统运行环境的一系列参数,比如这里的系统环境变量是PATH,PATH保存了与路径相关的参数,系统在路径查找中,会对PATH保存的路径进行搜索。

    点击install Now按钮执行python的安装

    打开windows命令行界面(按windows键输入cmd命令),输入python -V,出现python版本的相关输出,即表示安装成功。

    在Linux系统中安装python

    笔者的系统是CentOS, Linux系统默认有安装python,但是其版本是2.x,在这里笔者以源码安装的形式来安装python 3.X。首先进入python源码包页面 点击下载最新的gzip格式的python源码包,上传到服务器然后进行解压,解压后的目录结构如下图所示:

    Linux中的configure与make

    configure是Linux中的脚本配置工具,用来对源码的当前安装环境进行检测,若检测无误,会在当前目录生成一个供源码编译的Makefile脚本文件。

    make是Linux系统下的编译安装工具,用来解释执行makefile文件中的脚本命令,编译命令。

    现在我们开始编译安装python

    (1) 在当前目录执行./configure(2) 输入 make

    版权声明:本站所有文章皆为原创,欢迎转载或转发,请保留网站地址和作者信息。

    展开全文
  • 编程之JAVA后端开发与python后端开发的区别及类的方法技巧[图] 今天总算闲了一会,趁着这个闲暇来写篇文章。 今天我想以个人观点来简单说说Java后端开发和Python后端开发的区别。 Java&PythonBackEnd 公众号老粉...
  • _栗昕源的简历_python后端开发_三年_ .pdf
  • Python后端开发要求

    2017-08-07 15:44:00
    关于Python后端开发要求 一.对Python有兴趣,熟悉Python(标准库) 最好阅读过源码 了解Python的优化(熟悉pypy更佳) 二.至少至少一门语言(不说“精通”) 起码熟悉其他基本语言 C/C++ Lisp Haskell Scheme ...
  • python后端开发学习内容有哪些? 【导语】Python是一个强大的面向对象的程序设计语言,在人工智能领域,在网络爬虫、服务器开发、3D游戏、网络编程、数据分析、Web开发、运维、测试等多个领域都有不俗的表现,但学习...
  • 阿里云钉钉应用python后端开发之安装MySQL数据库 在本系列文章中,项目需要选择MySQL作为默认数据库。 在python后端开发中,可以选择的数据库有PostgreSQL, MariaDB, MySQL, or Oracle等,一般情况下,PostgreSQL是...
  • 更新:2020年5月10号惭愧惭愧,我已经叛逃Python 4年了,加入了Java阵营,主要是大数据领域被Java、Scala占领了。工作中真正的核心竞争力还是写出整洁的代码和架构,面向对象的思维(原则与设计),模式的使用。以及...
  • 阶段一:Python开发基础Python全栈开发与人工智能之Python开发基础知识学习内容包括:Python基础语法、数据类型、字符编码、文件操作、函数、装饰器、迭代器、内置方法、常用模块等。阶段二:Python高级编程和数据库...
  • 不管你用什么语言,PHP、Python 还是 Java,后端都会涉及到这些东西1、计算机基础:操作系统、网络系统(协议)、数据库系统、数据结构与算法2、中间件:Nginx、MQ 等3、开发工具:Git、Docker 等4、架构方面:CAP、...
  • Python后端开发面经

    2019-10-04 18:48:07
    python 后端工程师每天做什么? 网站后台业务逻辑 为网站提供API 为产品、运营提供后台网站工具,比如后台运营系统。 知识储备-上: 面试流程、技巧 通过不断的面试加深自己的面试经验 python语法基础、性能...
  • 想从事Python后端开发的你,不知道如何入门和学习,但首先必须知道什么是“Python后端开发”。 1、什么是“Python后端开发” 刚开始接触软件行业的你,以前可能经常会被人问到:“你以后想走前端还是后端呢?”这...
  • 前两天,在群里收到一个群友...之前有许多读者会在微信上问我,「自学 Python 后端开发 到什么程度才可以出去找工作?」,由于我本人不从事后端开发,所以无法给出合理的建议。正好借着强哥这篇经验分享,希望能给大...
  • 不管你用什么语言,PHP、Python 还是 Java,后端都会涉及到这些东西1、计算机基础:操作系统、网络系统(协议)、数据库系统、数据结构与算法2、中间件:Nginx、MQ 等3、开发工具:Git、Docker 等4、架构方面:CAP、...
  • 不管你用什么语言,PHP、Python 还是 Java,后端都会涉及到这些东西1、计算机基础:操作系统、网络系统(协议)、数据库系统、数据结构与算法2、中间件:Nginx、MQ 等3、开发工具:Git、Docker 等4、架构方面:CAP、...
  • 原标题:python后端开发工程师考证试题python开发工程师考证试题选择题题目关于 Python 程序格式框架的描述,以下选项中错误的是 ( A )A: Python 语言不采用严格的“缩进”来表明程序的格式框架B: Python 单层缩进...
  • 关于POST和GET的请求方法和区别请参考:HTTP协议下GET与POST的区别 GET方法 首先先使用html简单编写一个表单页面 代码如下: GET方法传递数据(runoob.com) 数据值1: 数据值2: 运行示列: 后端python代码: backend_...
  • 作者:硅步来源:zhu327.github.io/2018/07/19/python后端架构演进/来腾讯之前在前公司做了3年的后端开发,经历一款SaaS产品从0到10(还没有到100,...
  • 前两天,在群里收到一个群友...之前有许多读者会在微信上问我,「自学 Python 后端开发 到什么程度才可以出去找工作?」,由于我本人不从事后端开发,所以无法给出合理的建议。正好借着强哥这篇经验分享,希望能给...
  • 本人技术栈为Python后端开发,面经如下:老虎证券(挂)一面python基础部分:1. 迭代器生成器 生成器是如何实现迭代的2. list实现3. import一个包时过程是怎么样的?4. 装饰器实现5. 菱形继承6. 内存垃圾回收:分代...
  • 简单聊聊Python后端开发和Java后端的区别

    千次阅读 多人点赞 2020-10-26 18:00:00
    点击上方“Python进击者”,选择“星标”公众号超级无敌干货每日18:00推送给你!!!前言Hello,我是Kuls.又已经有一段时间没写原创了,今天总算闲了一会,趁着这个闲暇来写篇文...
  • 阿里云钉钉应用python后端开发之安装调用钉钉H5扫码接口 调用钉钉H5扫码接口网页显示效果如下图所示, <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name...
  • python后端开发面试题

    2021-02-22 19:52:51
    一:简述你对Restful风格的理解: 1: 协议 : 2:域名: 3:版本: 4:路径: 5:请求方式(6种): 6: 请求参数: 7: 状态码: 二:概述python的内存管理机制: 三: cookie 与 Session的区别: 四:你了解web开发中...
  • python后端开发工程师考证试题

    千次阅读 2019-05-29 17:54:00
    python开发工程师考证试题 问答题链接 python开发工程师考证试题 选择题 题目 关于 Python 程序格式框架的描述,以下选项中错误的是 ( A ) A: Python 语言不采用严格的“缩进”来表明程序的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,368
精华内容 1,747
关键字:

python后端开发

python 订阅