• day4.python基础下


    1. 类和对象

      1. 索引\切片\迭代协议
        1. 当对象被索引的时候,python究竟会怎么做?
        python会调用__ getitem __ (self,index)的魔法方法
        __ getitem __(self, index):该方法节能响应单个下标的缩影操作,又能支持代表范围的切片索引方式
        class C:
        def __getitem__(self,index):
            print(index)
        c = C()
        c[2]
        c[2:7]
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        注意:
        • 其实与’获取’相关的操作都会被拦截
        class D:
            def __init__(self,data):
                self.data = data
            def __getitem__(self,index):
                return self.data[index]*2
        d = D([1,2,3,4])
        for i in d:
        print(i,end=' ')#2 4 6 8
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • [切片操作] 其实是python的一个语法糖,调用的是slice(start,end = None,step)的函数
        s = 'hello world ! ni hao '
        # 等价于
        print(s[slice(2,7)])
        print(s[7:])
        print(s[slice(7,None)])
        
        • 1
        • 2
        • 3
        • 4
        • 5
        1. 当索引被赋值的时候呢?
        python会调用__ setitem __ ()魔法方法拦截缩影或切片的操作,
        class D:
            def __init__(self,data):
                self.data = data
            def __getitem__(self,index):
                return self.data[index]
            def __setitem__(self,index,value):
                self.data[index] = value
        d = D([1,2,3,4])
        print(d[1])
        d[1] = 6
        print(d[1])
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        1. 针对可迭代对象的魔法方法
        • __ iter __ (self) : 对应iter()函数
          根据python的迭代协议来说,如果一个对象定义了__ iter __ () 魔法方法,那么它就是一个可迭代对象;如果一个可迭代对象定义了__ next() __ 魔法方法,那么它就是一个迭代器
          当我们在进行for循环时,首先会将参数传入内置函数iter()中,并由此得到一个迭代器,因此才会有需要的__ next() __ 魔法方法.接着第二补利用__ next __()魔法方法进行真正的迭代操作
        • __ next __(self):对应next()函数
        list1  =[1,2,3,4,5]
        # 第一步先调用iter()获取迭代器
        _ = iter(list1)
        # 第二步使用__next__()进行迭代操作
        while True:
            try:
                i = _.__next__()
            except StopIteration:
                break
            print(i,end=' ')
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        应用:自己创建一个迭代器:
        class Double:
            def __init__(self,start,stop):
                self.value = start -1
                self.stop = stop
            def __iter__(self):
                # __iter_-方法返回的是一个迭代器
                return self
            def __next__(self):
                if self.value == self.stop:
                    raise StopIteration
                self.value += 1
                return self.value*2
        
        d = Double(1,5)
        for i in d:
            print(i,end=' ')
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
      2. 容器类型魔法方法

      在介绍容器的魔法方法之前,要首先知道python中常见的容器类型:

      • 字典
      • 元组
      • 列表
      • 字符串
        因为他们都可以作为迭代对象,都实现了容器协议.
      python容器类型的协议

      1、协议(Protocols)与其他编程语言中的接口恒相似,它规定你哪些地方必须要定义,然而在python中的协议就显得不那么正式,事实上,在python中,协议更像是一种指南

      2、序列类型和映射类型(元组,字典,字符串,列表)等都属于容器类型,关于容器类型的协议如下:

      (1)如果你希望定制的容器是不可变的话(元组,字符串等),你只需定义__len__()和__getitem__()方法;

      (2)如果你希望定制的容器是可变的话,你除了定义__len__()和__getitem__()方法之外,还需要定义__setitem__()和__delitem__()方法。

      魔法方法名作用备注
      __ contains __(self,item)主要用于成员关系的监测,对应的运算符是 in 和 not in当使用了in 或者 not in 但又没有实现__ contains __(),就会使用 __ iter __()和 __ next __()作为代偿的魔法方法
      __ getitem __(self, key)定义获取容器中指定元素的操作 ,相当于 self[key];当找不到__ iter ()和 next ()方法时,就会去找 getitem __()方法,起到代偿的作用
      __ setitem__(self, key, value)定义设置容器中指定元素的操作相当于 self[key] = value
      __ delitem__(self, key)定义删除容器中指定元素的操作相当于 del self[key];
      __ len__(self)定义当被 len() 调用时的操作(返回容器中元素的个数)
      __ iter__(self)定义迭代容器中的元素的操作;
      __ reversed__(self)定义当被 reversed() 调用时的操作

      基本用法代码示例:

          # 自己实现一个list
          class Mylist:
              #自己设计一个list
              def __init__(self,values = None):
                  self.values = values
                  self.index = 0
              def __setitem__(self,index,value):
                  self.values[index] = value
              def __getitem__(self,index):
                  return self.values[index]
              def __delitem__(self,index):
                  del self.values[index]
              def __len__(self):
                  return len(self.values)
              def __iter__(self):
                  #将实例生成可迭代对象
                  return self
              def __next__(self):
                  #迭代实现的具体细节
                  #如果__iter__返回的是self,就必须实现该方法.因为此时self是生成器,必须由next()方法
                  if self.index >= len(self.values):
                      raise StopIteration()
                  value = self.values[self.index]
                  self.index += 1
                  return value
              def __contains__(self,value):
                  return value in self.values
              def __reversed__(self):
                  #反转
                  return list(reversed(self.values))
              def __str__(self):
                  #return "This is my own List!"
                  return str(self.values)
              def __repr__(self):
                  return self.values
      
          mylist = Mylist([1,2,3,4,5,6])
          print(mylist)
          print(mylist[0])
          mylist[0] = 7#__setitem__
          print(mylist[0])#getitem
          print(1 in mylist)#__contains__
          print(len(mylist))#__len__
          print([i for i in mylist])#__iter__
          print(mylist)
          f = reversed(mylist)#__reversed__
          print(f)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47

      代偿代码示例:

      class C:
          def __init__(self,data):
              self.data = data
          def __contains__(self,item):
              return item in self.data
      c = C([1,2,3,4,5,6])
      print(3 in c)
      print(0 in c)
      # 当__contains__不存在时,会找__ iter __和__next__
      class C:
          def __init__(self,data):
              self.data = data
          def __iter__(self):
              print('Iter',end= "->")
              self.i = 0
              return self
          def __next__(self):
              print("next",end = "->")
              if self.i == len(self.data):
                  raise StopIteration
              item = self.data[self.i]
              self.i += 1
              return item
      c = C([1,2,3,4,5,6])
      print(3 in c)
      # 当__contains__不存在时,__ iter __和__next__也不存在时,会找getitem方法
      class C:
          def __init__(self,data):
              self.data = data
          def __getitem__(self,index):
              print("GetItem",end='->')
              return self.data[index]
      c = C([1,2,3,4,5,6])
      print(3 in c)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      1. 表示类的魔法方法

      关于类的表示相关的魔法方法,主要包括__str__()__repr__()两种。这两个方法都是用来描述类或对象信息的,比如你直接实例化了一个对象,打印出来的是这个对象的地址。而要是重新在类中定义了这两个方法,那打印对象的结果就是方法返回的信息。

      # class D:
      #     def __init__(self):
      #         super().__init__()
      # d = D()
      # print(d)#<__main__.D object at 0x000002142D900CA0>
      # 如果在类中定义了__str__()和__repr__()方法,那打印对象就是输出该方法的返回信息
      class D:
          def __init__(self):
              super().__init__()
          def __repr__(self):
              return '我也是描述对象状态信息的魔法方法,但我是给解释器看的,只有在没有__str__定义是调用我'
          def __str__(self):
              return '我是说明对象状态信息的魔法方法,如果不写默认输出对象的地址'
      d = D()
      print(d)#我是说明对象状态信息的魔法方法,如果不写默认输出对象的地址
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

      注意:
      __ str __和 __ repr __魔法都是描述类或对象的信息.定义两个的目的是:

      • __ repr __的作用是准确,是为了给python解释器看的
      • __ str __ 的作用可读性,是为了编程人员看的
        一般的,也可以只定义__str__而不定义__repr__
      1. 比较操作类魔法方法

      比较操作的魔法方法主要包括以下几种:
      __ eq __ ():可以判断亮哥哥对象是否相等
      __ ne __ ():判断两个对象是否不相等,这个和__eq__()方法基本一样
      __ lt __ ():比较对象的大小,__ lt__ 表示小于
      __ gt __ ():比较对象的大小,__ gt__ 表示大于
      代码示例:

      # 比较操作类魔法方法
      class Person():
          def __init__(self,uid):
              self.uid = uid
      
          def __eq__(self,other):
              #截断不相等
              return self.uid == other.uid
          def __ne__(self,other):
              #判断不等于
              return self.uid != other.uid
          def __lt__(self,other):
              return self.uid < other.uid
          def __gt__(self,other):
              return self.uid > other.uid
      p1 = Person(1)
      p2 = Person(2)
      p3 = Person(2)
      
      print(p1 != p2)
      print(p3 == p2)
      print(p2 > p1)
      print(p1 < p2)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      1. 可调用对象类魔法方法(重要)
        在Python中,方法也是一种高等的对象。这意味着他们也可以像其他对象一样被传递到方法中,这是一个非常惊人的特性。 Python中有一个特殊的魔术方法可以让类的实例的行为表现的像函数一样,你可以调用他们,将一个函数当做一个参数传到另外一个函数中等等。这个魔法方法就是__call__(self, [args…]):当执行对象当做函数使用时,就相当于调用 __ call __

      代码示例:

      # __call__
      class Circle:
          def __init__(self,radious):
              self.radious = radious
          def __call__(self,radious):
              self.radious = radious + 1
      a = Circle(3)
      print(a.radious)#3
      
      a(10)#此时a这个对象相当于一个方法,这是__call__的作用,当执行对象当做函数使用时,就相当于调用 __ call __
      print(a.radious)#11
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    2. 布尔测试

    3. 类和对象

      1. 类属性,实例属性

      类属性顾名思义就是类所拥有的属性,分为共有属性和私有属性,私有属性通过__属性名称的方法进行定义。对于公有的类属性,可以在类外进行访问,私有属性则不可以,代码如下:

      # 类属性,实例属性
      class People:
          name = 'Me',#共有的类属性
          __age = 24#私有属性
          def __init__(self):
              pass
      p = People()
      # print(p.name)#('Me',)
      # print(People.name)#('Me',)
      p.name = 'you'
      print(p.name)#you
      print(People.name)#('Me',)
      
      # print(p.__age)   #错误,不能在类外通过实例对象访问私有的类属性
      print(p._People__age)#24
      p._People__age = 18
      print(p._People__age)#24
      print(People._People__age)
      # print(People.__age)        #错误,不能在类外通过类对象访问私有的类属性
      People._People__age = 20
      print(People._People__age)#20
      print(p._People__age)#28
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

      注意:

      • 类属性是声明在类的内部,实例方法的外部的属性,即在class内,init(self)方法之前
      • 实例属性是属于实例对象的属性,也称"实例变量",但使用需要注意以下几点:
        1. 实例属性一般在__init__()方法中通过如下代码定义: self.实例属性名 = 初始值
        2. 在本类的其他实例方法中,也是通过self进行访问: self.实例属性名
          3.创建实例对象后,可通过实例对象访问, obj = 类名() 创建和初始化对象,调用__init__()初始化属性 ,obj.实例属性名 = 值 可以给已有属性赋值,也可以新加属性
          4.实例属性可修改、新增、删除。
      • 如果在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用修改,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性。当类属性与实例属性同名时,一个实例访问这个属性时实例属性会覆盖类属性,但类访问时不会。示例代码见上面代码
      1. 实例方法,类方法和静态方法
      • 实例方法

      在类中以def关键词定义的都可以称之为实例方法.实例方法最大的特点是:最少要包含一个self参数,用于绑定调用此方法的实例对象(Python 会自动完成绑定)。实例方法通常会用类对象直接调用。此外,类的初始方法(__ init __)理论上也属于实例方法,不过它更加特殊.

      • 类方法

      Python 类方法和实例方法相似,它最少也要包含一个参数,只不过类方法中通常将其命名为 cls,类方法是类对象所拥有的方法,需要用修饰器@classmethodcls来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以’cls’作为第一个参数,可以通过实例对象和类对象去访问。类方法的常见应用就是对类属性进行修改.
      实例代码如下:

      class People:
      country = "China"
      
      #类方法,用classmethod装饰器
      @classmethod
      def getCountry(cls):
          return cls.country
      @classmethod
      def setCountry(cls,country):
          cls.country = country
      p = People()
      print(p.getCountry())#可以用过实例对象引用China
      print(People.getCountry())#可以通过类对象引用China
      
      p.setCountry('UK')
      print(p.getCountry())#UK
      print(People.getCountry())#UK
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 静态方法

      通过修饰器@staticmethod来修饰的的函数.静态方法属于类中的函数.主要作用是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护.例如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数:

      import time
      class TimeTest:
          def __init__(self,hour,minute,second):
              self.hour = hour
              self.minute = minute
              self.second = second
      
          @staticmethod
          def showTime():
              return time.strftime("%H:%M:%S",time.localtime())
      # 使用类调用静态方法
      print(TimeTest.showTime())
      # 实例化对象
      t = TimeTest(1,10,2)
      print(t.showTime())
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

      如上,使用了静态方法,然而静态方法实现中并没使用实例的属性和方法(但可以通过类名调用类属性和类方法)。若要获得当前时间的字符串时,并不一定需要实例化对象。当然,我们也可以在类外面写一个同样的函数来做这些事,但是这样做就打乱了逻辑关系,也会导致以后代码维护困难。

      1. 抽象类

      在面向对象的特征多态,有抽象类的概念,即父类只写接口,以保证子类必须实现这些方法.通过装饰器@abc.abstractmethod在父类引入抽象类的概念来硬性限制子类必须有某些方法名.

      import abc
      # 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
      class Animal(metaclass = abc.ABCMeta):
          @abc.abstractmethod#该装饰器限制紫烈必须又一个talk方法
          def talk(self):#抽象方法,无需实现具体功能
              pass
      class Cat(Animal):#只要继承了抽象类就必须实现抽象方法
          def talk(self):#若子类中没有一个名为talk的方法,则会掏出异常TypeError,无法实例
              pass
      cat = Cat()
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      1. 鸭子类型

      实际上,多态的概念是应用于JavaC#这一类强类型语言中,而Python崇尚的是“鸭子类型”
      Duck typing:“如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子”。
      比起继承的方式,鸭子类型在某种程度上实现了程序的松耦合度,如下:

      # 鸭子类型
      # 定义的类型和运行的类型不一样,就是多态的体现,python崇尚的是鸭子类型,只要有鸭子的方法,就是鸭子
      class Cat:
          def say(self):
              print('I am a Cat')
      class Dog:
          def say(self):
              print("I am a Dog")
      class Duck:
          def say(self):
              print("I am a Duck")
      animals_list = [Cat,Dog,Duck]# 这里将三个封装好的类分别作为animals_list的三个元素
      for animal in animals_list:
          animal().say()# animal()是实例化对象的过程,然后分别调用 Cat, Dog, Duck的say方法
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

      如上述代码所示,如果定义的若干个对象都有同一个方法,(比如下面的say方法),那么无论他们是否继承同一个父类,他们都可以统一通过方法的调用(say方法的调用)实现。
      在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。 鸭子类型的好处就在于能够避免一些类的重写与继承,无需大量复制相同的代码

    4. python中的模块制作和介绍

      在python中模块(module)的概念跟C语言\Java中的包很类似.要使用某个模块下的函数,就必须先使用import关键字导入模块.例如,导入math模块,就可以使用math.sqrt()函数

      1. 导入方式:
        1. 基本导入

        import 模块名

        1. 部分导入
        但在很多时候,我们只需要使用模块中的部分函数,不需要完整的包.可以通过:

        from 模块名 import 函数名
        此时,就可以直接使用函数名了,例如:

        from math import sqrt
        print(sqrt(4))
        
        • 1
        • 2
        1. 全部导入
        把一个模块的所有内容全都导入到当前的命名空间也是可行的,此时,使用模块中的函数名也只需要使用函数名即可,但不建议过多的使用这个方法.导入方式只需使用如下声明:

        from 模块名 import *

        1. 重命名导入

        import 模块名 as 新的名字

        import math as m
        print(m.sqrt(4))
        
        • 1
        • 2
      2. 制作模块
        在python中每个python文件都可以作为一个模块,模块的名字就是文件的名字.
        例如,在test.py中定义了add()函数,代码如下:
      def add(x,y):
         return x+y
      
      • 1
      • 2

      那么在其他文件中就可以通过导入的方式使用,代码如下:

      from test  import add
        print(add(1,2))
      
      • 1
      • 2

      但是,在实际开发中,一个模块开发完了,可能会在这个.py文件中添加一些测试模块,用来检验模块的正确性.例如:

      def add(x,y):
        return x+y
      print(add(1,2))
      
      • 1
      • 2
      • 3

      如果此时引入代码,test.py中的print(add(1,2))也会执行.这就给导入带了麻烦.
      因此,我们更希望的是字啊python导入模块的时候,只指定脚本中调用的模块函数,而其他函数不应该被执行.为了解决这个问题,python字啊执行一个文件时,会print(__name__),如果在本文件中被执行会打印:_ _ mian _ _,如果该文件被调用了则会打印:__模块名__.
      因此,在实际代码开发中,我们经常会看到代码:

      if _ _ name _ _ = “_ _ main _ _”

      用这种方法来选择性执行被导入的模块代码.例如:

         def add(x,y):
       return x+y
       print(__name__)
          if __name__ == '__main__':
      print(add(1,2))
      
      • 1
      • 2
      • 3
      • 4
      • 5
    5. python中的包和库

    实际开发中,一个大型的项目往往需要使用成百上千的 Python 模块,如果将这些模块都堆放在一起,势必不好管理。而且,使用模块可以有效避免变量名或函数名重名引发的冲突,但是如果模块名重复怎么办呢?因此,Python提出了包(Package)的概念。

    什么是包呢?简单理解,包就是文件夹,只不过在该文件夹下必须存在一个名为“__init__.py” 的文件,包将有联系的模块组织在一起,即放到同一个文件夹下。

    其中,每个包的目录下都必须建立一个 __init__.py 的模块,可以是一个空模块,可以写一些初始化代码,其作用就是告诉 Python 要将该目录当成包来处理。不过,这是 Python 2.x 的规定,而在 Python 3.x 中,init.py 对包来说,并不是必须的。

    另外,init.py 不同于其他模块文件,此模块的模块名不是init,而是它所在的包名。例如,在 settings 包中的__init__.py 文件,其模块名就是 settings。包是一个包含多个模块的文件夹,它的本质依然是模块,因此包中也可以包含包。

    至于Python 库:相比模块和包,库是一个更大的概念,例如在 Python 标准库中的每个库都有好多个包,而每个包中都有若干个模块

    1. Python的pip命令

    pip 是 python 自带的一个软件,相当于手机里的应用市场,可以用来安装、卸载、搜索 python 的常见模块。

    直接输入 pip 后回车,可以查看 pip 命令的所有可用参数。常见的操作如下:

    • 安装模块

    pip install 被安装模块名

    • 卸载模块

    pip uninstall 被卸载模块名

    • 搜索模块

    pip search 模块名

    Tips:

    看到pip的作用同学们可能会想起conda命令,也可以进行包的下载安装卸载和查询。两者的主要区别是:pip是Python包的通用管理器 conda是一个与语言无关的跨平台环境管理器。pip可以在任何环境中安装python包(只能按照python相关的包,例如C,JAVA其他语言是不行的);conda需要安装在conda环境中装任何包(需要下载Anaconda)。

    conda功能其实比pip更多。pip几乎就是个安装包的软件,conda是个环境管理的工具。conda自己可以用来创建环境,pip不能。这意味着你能用conda安装python解释器,pip不行。这一点我觉得是conda很有优势的地方,用conda env可以很轻松地管理很多个版本的python。

    其次,conda和pip对于环境依赖的处理不同,总体来讲,conda比pip更加严格,conda会检查当前环境下所有包之间的依赖关系,pip可能对之前安装的包就不管了.这样做的话,conda基本上安上了就能保证工作,pip有时候可能装上了也不work。不过我个人感觉这个影响不大,毕竟主流包的支持都挺不错的,很少遇到broken的情况。这个区别也导致了安装的时候conda算依赖项的时间比pip多。

    最重要的是conda作为环境管理工具,可以为不同的任务创建不同的环境,即conda具有环境隔离功能。 对于绝大多数朋友,只是在自己的个人电脑上,其实用pip和conda下载包的区别不大。如果是搞研究或者开发,在一台服务器上多人共享使用,我建议最好是conda。再者,用版本迭代很快的库,我也建议使用conda。

  • 相关阅读:
    如果重回大一学软件工程,你会做什么?
    Leetcode 652. 寻找重复的子树
    大学生没有项目经验该怎么拿测开岗位的office?
    html 使用input file上传图片并显示
    互联网医院|医疗系统新模式改善看病效率
    人机融合有助于解决P-NP问题的理解与解决
    在springboot工程中修改使用quartz创建的定时任务
    二叉搜索树
    nginx版本号隐藏(405 not allowed解决办法)
    FPGA project : ROM_VGA
  • 原文地址:https://blog.csdn.net/qq_45801179/article/details/127697953