python 学习笔记

 注意:该文章摘抄之百度,仅当做学习笔记供小白使用,若侵权请联系删除!


可变与不可变类型

可变类型和不可变类型

1,可变类型有list,dict,set, 不可变类型有string,number,tuple.

2,当进行修改操作时,可变类型传递的是内存中的地址,直接修改内存中的值,并没有开辟新的内存。

3,不可变类型被改变时,并没有改变原内存地址中的值,而是开辟一块新的内存,将原地址中的值复制过去,对这块新开辟的内存中的值进行操作。

eg: python中的元组和列表的区别是什么 列表是可以修改的序列,而元组中的内容是无法进行修改的

 请解释Python中的join()函数

join()用于将指定序列中的元素以指定的字符连接生成一个新的字符串,并返回

 请解释*args和**kwargs的含义

 

1. *args

:这个语法用于传递可变数量的位置参数(positional arguments)给函数。args是一个元组(tuple),其中包含了函数调用时传递的所有位置参数。

使用*args,函数可以接受任意数量的位置参数,而不需要提前指定参数的数量。

2. **kwargs

:这个语法用于传递可变数量的关键字参数(keyword arguments)给函数。kwargs是一个字典(dictionary),其中包含了函数调用时传递的所有关键字参数。

使用**kwargs,函数可以接受任意数量的关键字参数,而不需要提前指定参数的名称。

 

# 示例:
def print_args(*args):
    for arg in args:
        print(arg)
print_args(1, 2, 3)  # 输出:1 2 3
print_args('hello', 'world')  # 输出:hello world
#示例:
def print_kwargs(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")
 
print_kwargs(name='Alice', age=30)  # 输出:name: Alice  age: 30
print_kwargs(city='New York', country='USA')  # 输出:city: New York  country: USA

总结:

在函数定义时使用*args和**kwargs可以使函数更加灵活,因为它们可以接受不固定数量的位置参数和关键字参数。

这在编写一些通用的函数或装饰器时特别有用,允许你处理各种不同的输入情况。

 解释一下Python中的继承

当一个类继承自另一个类,它就被称为一个子类/派生类,继承自父类/基类。 它会继承/获取到父类的所有类属性和类方法。继承能更容易的创建和维护应用。

python继承顺序

Python中多继承的顺序是基于MRO (Method Resolution Order)算法来确定的。 MRO算法会从当前类的类树中按照广度优先的顺序搜索要继承的方法和属性,每个类只会被搜索一次。 出现多个父类时,子类继承属性或方法的优先级是按照类树的拓扑序列来决定的 树的拓扑序列是指对一棵有向无环图(DAG)进行拓扑排序得到的顶点序列。 在树中,每个节点都只有一个父节点,因此它是一种特殊的DAG。 因此,树也可以通过拓扑排序得到其拓扑序列。 拓扑排序是一种线性排序算法,它将一个有向无环图(DAG)中的所有节点按照一定的顺序排列。

 

# 代码
class A:
    def foo(self):
        print("A's foo")
class B(A):
    def foo(self):
        print("B's foo")
class C(A):
    def foo(self):
        print("C's foo")
class D(B, C):
    pass
d = D()
d.foo()
#在这个例子中,D继承了B和C的属性。由于B在类树中排在C的前面,因此D将继承B的foo方法。
#输出结果为"B's foo"。

sort和sorted对列表排序的区别

sort()会对list进行重新排序,排序后会完全改变原有list值的顺序。

sorted()则是临时修改list的元素排列顺序。

Python中类方法、类实例方法、静态方法有何区别?

类方法:

定义:是类对象的方法,在定义时需要在上方使用 @classmethod 进行装饰,形参为cls,表示类对象,通过它来传递类的属性和方法(不能传实例的属性和方法);

调用:实例对象和类对象都可以调用。类方法通常用于创建、修改或操作类的属性和方法。它可以访问和修改类的属性,也可以调用其他类方法或静态方法

优点:通过类方法,可以在不创建实例的情况下对类进行操作,从而提供更灵活的使用方式。

class Circle:
    radius = 5

    @classmethod
    def change_radius(cls, new_radius):
        cls.radius = new_radius

    @classmethod
    def get_radius(cls):
        return cls.radius

# 调用类方法
Circle.change_radius(10)
print(Circle.get_radius())  # Circle.get_radius() 直接调用get_radius()    
# 输出:10

# 通过实例调用类方法也可以
circle = Circle()
circle.change_radius(8)
print(circle.get_radius())  # 输出:8

类实例方法:

类实例方法: 是类实例化对象的方法,只有实例对象可以调用,形参为self,指代对象本身;

定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);

调用:只能由实例对象调用。

静态方法:

静态方法: 是一个任意函数,在其上方使用 @staticmethod 进行装饰,可以用对象直接调用,静态方法实际上跟该类没有太大关系

定义:使用装饰器 @staticmethod。参数随意,没有“self”和“cls”参数,因此方法体中不能使用和访问类或实例的任何属性和方法;

调用:实例对象和类对象都可以调用。

class Person:
    def shilifangfa(self):
       print("这是一个实例方法", self)
       
    @classmethod
    def leifangfa(cls):
       print("这是一个类方法", cls)
       
    @staticmethod
    def jingtaifangfa():
       print("这是一个静态方法")
       
p = Person()  # # 通过实例调用类方法
print(p)
p.shilifangfa()
Person.leifangfa()
Person.jingtaifangfa()

# 输出
<__main__.Person object at 0x0000019C4DE13EB0>
这是一个实例方法 <__main__.Person objectat 0x0000019C4DE13EB0>

# 解释:类属性地址和实例方法的地址相同,说明在调用的内容相同,
因此,可以确定p就是Person传入的实例,将self对应的即为实例p,Person object 说明是Person对应的一个实例

这是一个类方法 
# 解释:Person作为了leifangfa中的cls传入
这是一个静态方法
# 解释:并不需要任何参数传入

python2与python3的区别

两个版本所使用的编码不同

        python2使用的是ASCII编码,如果想要支持中文的话,需要更改一下字符集,添加                coding:utf-8

        python3使用的是utf-8编码,是支持中文的

不等运算符

        Python 2.x中不等于有两种写法 != 和 <>

        Python 3.x中去掉了<>, 只有!=一种写法

除法运算

        在 Python 2.x 中 / 除法整数相除的结果是一个整数,把小数部分完全忽略掉。

        在 Python 3.x 中 / 除法不再这么做了,对于整数之间的相除,结果也会是浮点数。         Python 2.x:

        >>> 1 / 2 # 结果 0

        >>> 1.0 / 2.0 # 结果 0.5

异常机制

        Python2:可以用 , (逗号)也可以用as

        Python3:只能用as # 注:把信息赋给一个标识符的时候

        try:

                print("ok")

        except Exception,e: # python2中用, python3中用as

                print("exception error")

range与xrange

        Python2:

                range(4),结果是一个列表生成[0,1,2,3];

                xrange返回一个生成器,使用的时候再创建对象

        Python3:

                range就是Python2的xrange # 注:自己本身没有xrange函数

描述下什么是私有属性和私有方法

想要在类中定义到专属于类内部的私有属性与私有方法,则可以通过在属性或方法的名称前添加__来表示。 私有属性和私有方法无法在类外部被调用,也无法被实例化对象调用。 私有属性和私有方法的使用,只限于在类本身之中,如果想要获取这些私有内容,则需要通过公有方法来调用,或者通过return将私有属性返回,达到外部使用的目的。

==和is的区别是什么

==比较两个对象或值的相等性。 is用于检查两个对象是否属于同一内存对象。

解释以下什么是闭包?

在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。

闭包(closure)指的是在函数内部定义了另外一个函数,并返回了这个内部函数作为函数对象,同时还保存了外层函数的状态信息。这个内部函数可以依赖外层函数的变量和参数,而且外层函数返回的是这个内部函数的引用。这种在函数内部定义函数并返回的方式称为闭包。

def outer(x):
    def inner(y):
        return x+y
    return inner
f=outer(5)
print(f(3))

优点:

1可以保留外层函数的状态信息:由于内层函数保留了外层函数的状态信息,因此闭包可以用来创建一些在多次调用中保持状态的对象,例如装饰器。

2可以让函数的参数更加灵活:某些函数的参数可能是固定的,但是有时候需要在函数调用过程中更改参数的值。闭包可以通过保存外层函数的参数和变量,让函数的参数更加灵活。

3可以简化大型程序的代码结构:通过使用闭包,可以将大型程序拆分为多个小函数,并且它们之间可以共享变量和参数。

生成器,迭代器的区别?

迭代器

迭代器是遵循迭代协议的对象。用户可以使用 iter() 以从任何序列得到可迭代对象(如 list, tuple,dict, set 等)。

eg: result=iter(list) print(next(result))) 要获取下一个元素,则使用成员函数 next() (python2) __next()__ (python3)

当没有元素时,则引发 StopIteration 此例外。若要实现自己的迭代器,则只要实现 next()

# 调用如下
>>> f = iter([1,2,3,5,6])
>>> f # 此时生成器还没有运行

>>> print(next(f))
1
>>> print(next(f)) # 记录上一次返回的位置
2

生成器 —— Generator ,只是在需要返回数据的时候使用yield语句。每次next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值) 区别: 生成器能做到迭代器能做的所有事,而且因为自动创建iter()和next()方法,生成器显得特别简洁,而且生成器也是高效的, 使用生成器表达式取代列表解析可以同时节省内存。 除了创建和保存程序状态的自动方法,当生成器终结时,还会自动抛出StopIteration异常 生成器本质上就是一个函数,它记住了上一次返回时在函数体中的位置。 对生成器函数的第二次(或第n次)调用,跳转到函数上一次挂起的位置。 而且记录了程序执行的上下文。Yield

# 通过`yield`来创建生成器
def func():
   for i in range(10):
       yield i

# 通过列表来创建生成器
[i for i in range(10)]

(3)区别:

①生成器是生成元素的,迭代器是访问集合元素的一种方式

②迭代输出生成器的内容

③迭代器是一种支持next()操作的对象 生成器 如果一个函数包含yield关键字,这个函数就会变为一个生成器。 生成器并不会一次返回所有结果,而是每次遇到yield关键字后返回相应结果,并保留函数当前的运行状态,等待下一次的调用。 由于生成器也是一个迭代器,那么它就应该支持next方法来获取下一个值。

 回调函数,如何通信的?

回调函数是把函数的指针(地址)作为参数传递给另一个函数,将整个函数当作一个对象,赋值给调用的函数。
把一个函数,作为参数,传给另一个函数使用。这个参数,就被称为回调函数
# 代码如下
def c_sign(x: int, y: int):
    return x - y

def my_sign(x: int, y: int, func):
    num = func(x, y)
    print(num)

if __name__ == '__main__':
    my_sign(1, 2, c_sign)

谈谈你对面向对象的理解?

面向对象是相当于面向过程而言的, 面向过程语言是一种基于功能分析的,以算法为中心的程序设计方法, 而面向对象是一种基于结构分析的,以数据为中心的程序设计思想。 在面向对象语言中有一个很重要的东西,叫做类。面向对象有三大特性:封装、继承、多态。

用Python匹配HTML tag的时候, 和 有什么区别

第一个代表贪心匹配,第二个代表非贪心; ? 在一般正则表达式里的语法是指的"零次或一次匹配左边的字符或表达式"相当于{0,1} 而当?后缀于*,+,?,{n},{n,},{n,m}之后,则代表非贪心匹配模式,也就是说,尽可能少的匹配左边的字符或表达式,这里是尽可能少的匹配.(任意字符) 所以:第一种写法是,尽可能多的匹配,就是匹配到的字符串尽量长,第二中写法是尽可能少的匹配,就是匹配到的字符串尽量短。 比如tag>tag>end,第一个会匹配tag>tag>,第二个会匹配

系统编程---进程总结 

进程:程序运行在操作系统上的一个实例,就称之为进程。

进程需要相应的系统资源:内存、时间片、pid。

创建进程:首先要导入multiprocessing中的Process:

创建一个Process对象; 创建Process对象时,可以传递参数;

p = Process(target=XXX,args=(tuple,),kwargs={key:value})
target = XXX 指定的任务函数,不用加(),
args=(tuple,)  kwargs={key:value}给任务函数传递的参数

使用start()启动进程

结束进程

给子进程指定函数传递参数Demo

注意:进程间不共享全局变量

import os
from mulitprocessing import Process
import time
def pro_func(name,age,**kwargs):
    for i in range(5):
        print("子进程正在运行中,name=%s,age=%d,pid=%d"%(name,age,os.getpid()))
        print(kwargs)
        time.sleep(0.2)        
if __name__ =="__main__":
    #创建Process对象
    p = Process(target=pro_func,args=('小明',18),kwargs={'m':20})
    #启动进程
    p.start()
    time.sleep(1)
    #1秒钟之后,立刻结束子进程
    p.terminate()
    p.join()

谈谈你对多进程,多线程,以及协程的理解,项目是否用?

进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位, 进程拥有自己独立的内存空间,所有进程间数据不共享,开销大。 线程: cpu调度执行的最小单位,不能独立存在,依赖进程存在,一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。 协程: 又称微线程。是一种用户态的轻量级线程,协程的调度完全由用户控制,只不过比线程更小占用更小执行单元 协程拥有自己的寄存器上下文和栈。协程调度时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈, 直接操中栈则基本没有内核切换的开销,所以上下文的切换非常快。 线程是并发还是并行,进程是并发还是并行? 线程是并发,进程是并行;协程是在一个线程中 所以是并发

进程之间互相独立,是系统分配资源的最小单位,同一个线程中的所有线程共享资源。

协程

# 代码
def work1():
    while True:
        print("---work1---")
        yield
def work2():
    while True:
        print("---work2---")
        yield
def main():
    w1 = work1()
    w2 = work2()
    while True:
        next(w1)
        next(w2)
if __name__ == '__main__':
    main()

# 输出        
---work2---
---work1---
---work2---
......

多线程

setDaemon(True)

当我们使用setDaemon(True)时,这是子线程为守护线程,主线程一旦执行结束,则全部子线程被强制终止,默认False

 

import threading
import time
def thread():
    time.sleep(2)
    print('---子线程结束---')
def main():
    t1 = threading.Thread(target=thread)
    t1.start()
    print('---主线程--结束')
if __name__ =='__main__':
    main()
#执行结果
---主线程--结束
---子线程结束---

join(线程同步)

join 所完成的工作就是线程同步,即主线程任务结束以后,进入堵塞状态,一直等待所有的子线程结束以后,主线程再终止。

当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序,所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和,

简单的来说,就是给每个子线程一个timeout的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。

没有设置守护线程时,主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,

但是并没有杀死子线程,子线程依然可以继续执行,直到子线程全部结束,程序退出。

 

import threading
import time
def thread():
    time.sleep(2)
    print('---子线程结束---')
def main():
    t1 = threading.Thread(target=thread)
    t1.setDaemon(True)
    t1.start()
    t1.join(timeout=1)          #1 线程同步,主线程堵塞1s 然后主线程结束,子线程继续执行
    print('---主线程结束---')    #2 如果不设置timeout参数就等子线程结束,主线程再结束
                        #3 如果设置了setDaemon=True和timeout=1主线程等待1s后会强制杀死子线程,然后主线程结束
if __name__=='__main__':
    main()

map函数和reduce函数?

map(lambda x: x * x, [1, 2, 3, 4]) # 使用 lambda
# [1, 4, 9, 16]
reduce(lambda x, y: x * y, [1, 2, 3, 4]) # 相当于 ((1 * 2) * 3) * 4
# 24
一句话解决阶乘函数?
reduce(lambda x,y : x*y,range(1,n+1))

什么是lambda函数? 有什么好处?

lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数 1.lambda函数比较轻便,即用即仍,很适合需要完成一项功能,但是此功能只在此一处使用,连名字都很随意的情况下 2.匿名函数,一般用来给filter,map这样的函数式编程服务 3.作为回调函数,传递给某些应用,比如消息处理

 深拷贝和浅拷贝的区别:

深拷贝是将对象本身复制给另一个对象。这表示对对象的副本进行更改时不会影响原对象,使用 deepcopy()函数进行深拷贝
浅拷贝是将对象的引用复制给另一个对象。当对副本改变时会影响原对象,使用copy()函数进行浅拷贝

import copy

# 创建一个列表
lst1 = [1, 2, [3, 4]]
# 深拷贝列表
lst2 = copy.deepcopy(lst1)
# 浅拷贝列表
lst3 = copy.copy(lst1)
# 修改原始列表中嵌套的列表元素
lst1[2][0] = 5

# 打印结果
print(lst1)  # 输出:[1, 2, [5, 4]]
print(lst2)  # 输出:[1, 2, [3, 4]]
print(lst3)  # 输出:[1, 2, [5, 4]]

python 如何实现多线程

线程是轻量级的进程,多线程容许一次执行多个线程。 GIL(全局解释器锁)确保一次执行单个线程。 一个线程保存GIL并在将其传递给下一个线程之前执行一些操作。

 GIL

GIL是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。

多进程中因为每个进程都能被系统分配资源,相当于每个进程有了一个python解释器,所以多进程可以实现多个进程的同时运行,缺点是进程系统资源开销大

 装饰器的含义及作用

装饰器是为已经存在的函数或者对象添加额外的功能。
本质上是一个闭包函数(闭包函数:本质是个嵌套函数,内层函数引用外层函数的变量并且返回外层函数,外层函数返回内层函数)
①不修改已有函数的源代码   ②不修改已有函数的调用方式   ③为已有函数添加额外的功能
好处:
扩展功能,代码复用,日志记录,访问控制

# 定义一个简单的装饰器函数
def decorator(func):
    def wrapper(*args, **kwargs):
        print("执行装饰器逻辑")
        result = func(*args, **kwargs)  # 调用原函数
        result1 = result + ',I am a decorateor'
        return result1
    return wrapper

# 应用装饰器到函数
@decorator
def greet(name):
    return f"Hello, {name}!"

# 使用被装饰的函数
message = greet("Alice")
print(message)

__new__ 和 __init__ 的区别

[同] 二者均是Python面向对象语言中的函数,__new__比较少用,__init__则用的比较多 [异) __new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象,是个静态方法 __init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值,通常用在初始化一个类实例的时候。是一个实例方法。 __new__是一个静态方法,而 __init__ 是一个实例方法 __new__方法会返回一个创建的实例,而 __init__ 什么都不返回 只有在__new__ 返回一个cls的实例时,后面的__init__ 才能被调用 当创建一个新实例时调用__new__,初始化一个实例时用__init__

 进程与线程的区别

1. 进程是CPU资源分配的基本单位,线程是独立运行和独立调度的基本单位(CPU上真正运行的是线程)。 2. 进程拥有自己的资源空间,一个进程包含若干个线程,线程与CPU资源分配无关,多个线程共享同一进程内的资源。 3. 线程的调度与切换比进程快很多。 一个进程可以包含多个线程,一个线程也可以包含多个协程,也就是说,一个线程内可以有多个那样的特殊函数在运行 冒泡排序的时间复杂度:最好情况是“O(n)”,最坏情况是“O(n2)”。快速排序的的时间复杂度:最好情况是“O(nlog2n)”,最坏情况是“O(n2)”。堆排序的时间复杂度是“O(nlog2n)

 三次握手

  • 第一次握手:客户端向服务端发送一个 SYN 报文(SYN = 1),并指明客户端的初始化序列号 ISN(x),此时客户端处于 SYN_Send 状态。
  • 第二次握手:服务器收到客户端的 SYN 报文之后,会发送 SYN 报文作为应答(SYN = 1)。同时会把客户端的 ISN + 1 作为确认号 ack 的值,此时服务器处于 SYN_REVD 的状态。
  • 第三次握手:客户端收到服务器端响应的 SYN 报文之后,会发送一个 ACK 报文,此时客户端处于 Establised 状态。服务器收到 ACK 报文之后,也处于 Establised 状态,至此,双方建立起了 TCP 连接。

 四次挥手

  • 第一次挥手:客户端发送一个 FIN 报文(请求连接终止:FIN = 1)。此时客户端处于 FIN_WAIT1 状态,等待服务端的确认。
  • 第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,此时服务端处于 CLOSE_WAIT状态。此时的 TCP 处于半关闭状态,客户端到服务端的连接释放。FIN-WAIT-2 - 从远程TCP等待连接中断请求;
  • 第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发送FIN 报文。此时服务端处于 LAST_ACK 的状态,等待客户端的确认。

LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认;

  • 第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答(ack = w+1)此时客户端处于 TIME_WAIT(时间等待)状态。

 

 cookie 和session 的区别:

 1.cookie: cookie是保存在浏览器端的键值对,可以用来做用户认证 2.session:将用户的会话信息保存在服务端,key值是随机产生的字符串,value值时 session的内容 1、cookie数据存放在客户的浏览器上,session数据放在服务器上。 2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗 考虑到安全应当使用session。 3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。 4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。 5、所以个人建议: 将登陆信息等重要信息存放为SESSION 其他信息如果需要保留,可以放在COOKIE中

 请描述数据库优化查询方法

答: (1)使用索引: 应尽量避免全表扫描,首先考虑在where 以及 order by ,group by 涉及的列上建立索引 (2)优化SQL语句: 1>通过explain(查询优化神器)用来查看SQL语句的执行效果。通常我们可以对比较复杂的尤其是涉及到多表的SELECT语句,把关键字explain加到前面,查看执行计划,例如: explain select * from news; 2>任何地方都不要使用select * from ,用具体的字段列表代替“*”,不要返回用不到的任何字段。 3>-- SQL 优化:能使用 EXISTS 就不要使用 IN (3)优化数据库对象 1>.优化表的数据库类型 使用procedure analyse()函数对表进行分析 2>.使用中间表来提高查询速度

数据库优化方案 可以从数据库服务器部署、表设计、表查询等方面考虑。 1、创建数据表时把固定长度的放在前面 2、将固定数据放入内存: 例如: choice字段 (django中有用到,数字1、2、3...对应相应内容) 3、char 和 varchar 的区别(char可变,varchar不可变 ) 4、联合索引遵循最左前缀(从最左侧开始检索) 5、避免使用 select * 6、读写分离 - 实现: 两台服务器同步数据 - 利用数据库的主从分离:主,用于增加、删除、更新,从,用于查询: 7、分库 - 当数据库中的表太多,将某些表分到不同的数据库,例如:1w张表时 - 代价:连表查询 8、分表 - 水平分表:将某些列拆分到另外一张表,例如:博客+博客详情 - 垂直分表:讲些历史信息分到另外一张表中,例如:支付宝账单

 说明OS,SYS模块不同,并列举常用的模块方法

 答: os:提供一种方便的使用操作系统函数的方法 sys:提供访问由解释器使用或维护的变量和在与解释器交互使用到的函数 os模块常用方法: os.remove()删除文件 os.rename()重命名文件 os.walk()生成目录树下的所有文件名 os.chdir()改变目录 sys模块的常用方法: sys.argv命令行参数List,第一个元素是程序本身路径 sys.modules.keys()返回所有已经导入的模块列表sys.exc_info() 获取当前正在处理的异常类

 SQL语句什么是左连接、右连接、内连接?

 1、左连接 以左表为基础,根据ON后给出的两表的条件将两表连接起来。结果会将左表所有的查询信息列出,而右表只列出ON后条件与左表满足的部分。 左表(table1)全部保留,右表(table2)关联不上用null表示。 SELECT * FROM table1 LEFT JOIN table2 ON table1.a=table2.b 2、右连接 与 左连接相反。 右表(table2)全部保留,左表(table1)关联不上的用null表示。 SELECT * FROM table1 RIGHT JOIN table2 ON table1.a=table2.b 3、内连接 保留两个表共有的部分。 SELECT * FROM table1 inner JOIN table2 ON table1.a=table2.b

 MongoDB和MySQL的区别

 关系型数据库-MySQL 1、在不同的引擎上有不同的存储方式。 2、查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。 3、开源数据库的份额在不断增加,mysql的份额页在持续增长。 4、缺点就是在海量数据处理的时候效率会显著变慢。 非关系型数据库-MongoDB 非关系型数据库(nosql)属于文档型数据库。先解释一下文档的数据库,即可以存放xml、json、bson类型系那个的数据。 这些数据具备自述性,呈现分层的树状数据结构。数据结构由键值(key=>value)对组成。 1、存储方式:虚拟内存+持久化。 2、查询语句:是独特的MongoDB的查询方式。 3、适合场景:事件的记录,内容管理或者博客平台等等。

 Linux查看进程命令  

查看进程: 1、ps 命令用于查看当前正在运行的进程。 grep 搜索例如: ps -ef | grep java表示查看所有进程里 CMD 是 java 的进程信息 -a 与任何用户标识和终端相关的进程 -e 所有进程(包括守护进程) -p pid 与指定PID相关的进程 -u userid 与指定用户标识userid相关的进程 -ef 显示所有用户进程,完整输出 -a 显示所有非守护进程 -t 仅显示所有守护进程 2、ps -aux | grep java-aux 显示所有状态ps 3. kill 命令用于终止进程 例如: kill -9 [PID]-9 表示强迫进程立即停止通常用 ps 查看进程 PID ,用 kill 命令终止进程

 数据库三范式?范式的定义?

范式:改造关系模式,通过分解关系模型来消除其中不合适的数据依赖,以消除插入异常,删除异常,数据冗余等异常情况。 1NF(Normal Form):R 的所有属性都不能再分解为更基本的数据单位。 2NF:R 的所有非主属性都依赖于 R 的关键属性,所有列都依赖于任意一组候选关键字。 3NF:每一列都与任意候选关键字直接相关,没有传递依赖

 简述关系的三类完整性约束

实体完整性:这项规则要求每个数据表都必须有主键,而作为主键的所有字段,其属性必须是独一即非空值 参照完整性:是指两个表的主关键字和外关键字的数据应一致,保证了表之间数据的一致性,防止了数据丢失或无意义的数据在数据库 中扩散。 用户自定义完整性:对特定关系数据库的约束条件,反映某一具体应用必须满足的语义要求

 主键和外键

主键就是一个代表这个表的唯一属性,有且只有一个,并且不能为空,外键是存在于此表中的,另一张表的主键。

 索引和键的区别?

索引是存储在数据库中的一个物理结构,是实际存在的,相当于一本书的目录。 键是一个逻辑概念,不是数据库的物理部分。键分为主键和外键。

 索引的作用?和它的优点缺点是什么?

答:索引就是一种特殊的查询表,数据库的搜索引擎可以利用它加速对数据的检索。 它很类似与现实生活中书的目录,不需要查询整本书内容就可以找到想要的数据。 索引可以是唯一的,创建索引允许指定单个列或者是多个列。 缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小 

 触发器的作用?

答:触发器是一种特殊的存储过程,主要是通过事件来触发而被执行的。 它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化。

 什么是事务?事务有那些性质?事务和程序的区别?

事务就是被绑定在一起作为一个逻辑工作单元的 SQL 语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态。 为了确保要么执行,要么不执行,就可以使用事务。事务包含四个特性:原子性,一致性,隔离性和持久性。 事务和程序是两个概念:在关系数据库中,一个事务可以是一条 SQL 语句,一组 SQL 语句或整个程序;一个应用程序通常包含多个事务。 原子性 Atomicity:一个事务被视为一个最小单元,要么全部提交,要么全部回滚 一致性 Consistency:事务总是由一种状态转换为另一种状态,数据库事务只会是执行前的状态或是执行后的状态,不会出现执行中的状态。 即如果一个事务执行了十秒,那么第一秒读到的结果和第九秒得到的应该是相同的。 隔离性 Isolation:一个事务的执行不会被另一个事务影响,互不干扰。 持久性Durability:事务只要提交了,那么数据库中的数据也永久的发生了变化。

 什么是死锁和活锁,如何预防?死锁的解决的方法有哪些?

活锁指的是任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试—失败—尝试—失败的过程。 处于活锁的实体是在不断的改变状态,活锁有可能自行解开。 避免活锁的简单方法就是采用先来先服务的策略。 死锁:是指两个以上的事务分别请求封锁对方已经封锁的数据,导致长期等待而无法继续运行下去的现象叫做死锁. 死锁预防:一次封锁法,顺序封锁法 死锁诊断解除:超时法,等待图法

试述 SQL 语言的特点。 

答: (1)综合统一。SQL 语言集数据定义语言 DDL 、数据操纵语言 DML、数据控制语言DCL 的功能于一体。 (2)高度非过程化。用 SQL 语言进行数据操作,只要提出“做什么”,而无需指明“怎么做” (3)面向集合的操作方式。SQL 语言采用集合操作方式,操作对象、结果都是集合

 ORM的实现原理?

概念: 对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping), 是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。 ORM技术特点: 1.提高了开发效率。由于ORM可以自动对Entity对象与数据库中的Table进行字段与属性的映射,所以我们实际可能已经不需要一个专用的、庞大的数据访问层。 2.ORM提供了对数据库的映射,不用sql直接编码,能够像操作对象一样从数据库获取数据。

 变量的三要素

name = 'tony' 1. 变量值 2. 内存地址编号 3. 数据类型 """ 一个变量名只能指向一个内存地址 一个内存地址可以有多个变量指向 """

 垃圾回收机制

1. 什么是垃圾数据? # 就是没有变量指向的数据 2. python开发出了一套自动回收方案 ①. 引用计数 # 当有变量指向内存中得数据时候,会同时加一个计数,当计数为零的时候,就说明是垃圾数据 ②. 标记清楚 # 当内存快被沾满的时候,那么python就会终止程序的运行,从头到位进行扫描数据,对垃圾数据进行标记,之后,统一进行清除 ③. 分代回收 # 通过分不同的时间段,来降低被监管的频率

 global与nonlocal关键字的使用

""" 局部修改全局的 1. 修改的是不可变类型,必须使用global关键字声明一下 2. 修改的是可变类型,就不用global声明了,直接可以改 内部的局部修改外部的局部 1. 如果是不可变类型,必须使用nonlocal关键字声明一下 2. 如果是可变类型,就不需要使用nonlocal关键字声明一下 """

 Python 是单线程的,多线程有意义嘛

import threading
import time


def test1():
    for i in range(100000000):
        a = 100 - i
def test3():
    time.sleep(10)
def test2():
    threads = []
    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test1)
    t3 = threading.Thread(target=test1)
    t4 = threading.Thread(target=test1)
    threads.append(t1)
    threads.append(t2)
    threads.append(t3)
    threads.append(t4)

    threads[0].start()
    threads[1].start()
    threads[2].start()
    threads[3].start()

    threads[0].join()
    threads[1].join()
    threads[2].join()
    threads[3].join()


if __name__ == '__main__':
    t1 = time.time()
    test1()
    print('单线程一次:', time.time() - t1)  # 单线程一次: 3.872997760772705
    test1()
    print('单线程两次:', time.time() - t1)  # 单线程两次: 7.738230466842651
    test1()
    print('单线程三次:', time.time() - t1)  # 单线程三次: 11.609771013259888
    test1()
    print('单线程四次:', time.time() - t1)  # 单线程四次: 15.493367433547974
    t2 = time.time()
    test2()
    print('多线程四次:', time.time() - t2)  # 多线程四次: 15.55045747756958

 如上输出结果单线程和多线程的时间几乎一样的。

总结

其实python的多线程不是来解决多核利用率问题的,而是解决IO阻塞问题和IO占用时CPU闲置问题 如:多线程中,三线程中test1 需要5s,test2需要10s,test3需要15s,其采用多线程中总花费时间15s 结论:多线程中使程序交替轮番执行,不会对后面的程序产生阻塞(多线程的根本目的) 总结:对于I/O密集型应用更适合多线程,对于计算密集型应用更适合多进程以便让其他的内核来执行

 Python中的多线程没有真正实现多线程,也就是经常说的伪多线程!

为什么这么说,我们了解一个概念,全局解释器锁(GIL)。

Python代码的执行由Python虚拟机(解释器)来控制,Python在设计之初就考虑要在主循环中,同时只有一个线程在执行,就像单CPU的系统中运行多个进程那样,内存中可以存放多个程序,但任意时刻,只有一个程序在CPU中运行。 同样地,虽然Python解释器可以运行多个线程,只有一个线程在解释器中运行。 对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同时只有一个线程在运行。在多线程环境中,Python虚拟机按照以下方式执行。 1.设置GIL。 2.切换到一个线程去执行。 3.运行。 4.把线程设置为睡眠状态。

你可能感兴趣的:(python,学习,笔记,python)