python基础学习

Posted yongfuxue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python基础学习相关的知识,希望对你有一定的参考价值。

递归

递归的经典例子

def fib(n):

    if n < 1:

        raise ValueError

    elif (n == 1) or (n == 2):

        return 1

    else:

        return fib(n - 1) + fib(n - 2)

print(fib(1))  #1

print(fib(2))  #1 

print(fib(3))  #2

print(fib(4))  #3

print(fib(5))  #5

print(fib(6))  #8

 

汉诺塔问题

def move(n, source, target, helper):

    if n == 1:

        print (source + ‘ -> ‘ + target)

    else:

        move(n - 1, source, helper, target)

        print (source + ‘ -> ‘ + target)

        move(n - 1, helper, target, source)

move(4, ‘A‘, ‘B‘, ‘C‘)

迭代器与可迭代对象

定义:

 list,truple,str这些都是可迭代对象,但是他们不一定是迭代器。迭代器本身不知道自己要执行多少次,所以可以理解为不知道有多少个元素,每调用一次next(),就会往下走一步,是惰性的。

迭代器提供了一种不依赖索引取值的方式,这样可以遍历没有索引的可迭代对象,比如字典、集合、文件等等,加载这一个元素至内存中随后释放,相比之下更节省内存,但是我们没有办法获取迭代器的长度,而且只能往后依次取值。

 

只要对象本身有__iter__方法,那它就是可以迭代的。

d={‘a‘:1,‘b‘:2,‘c‘:3}
d.__iter__()

执行对象下的__iter__方法得到的就是迭代器

d={‘a‘:1,‘b‘:2,‘c‘:3}
a=d.__iter__()
print(type(a))
print(next(a))
print(next(a))

 

使用迭代器:

使用内建的工厂函数iter(iterable)可以获取迭代器对象

>>> lst = range(5)

>>> it = iter(lst)

>>> it

<listiterator object at 0x01A63110>

使用next()方法可以访问下一个元素

 

因为迭代器如此普遍,python专门为for关键字做了迭代器的语法糖。在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作。如下

>>> a = (1, 2, 3, 4)

>>> for key in a:

    print key

首先python对关键字in后的对象调用iter函数迭代器,然后调用迭代器的next方法获得元素,直到抛出StopIteration异常。

 

自定义一个迭代器:

class Fibs:

    def __init__(self):   #初始化

        self.a = 0

        self.b = 1

       

    def __next__(self):    #获取下一个条目

        self.a, self.b = self.b, self.a + self.b

        return self.a

   

    def __iter__(self):    #返回迭代器

        return self

 

fibs = Fibs()    #产生一个对象

for f in fibs:    #迭代

    if f > 100:

        break

print(f)

字符反转,常见面试题

def reverse(str_list, start, end):

    while start < end:

        str_list[start], str_list[end] = str_list[end], str_list[start]

        start += 1

        end -= 1

 

setence = ‘ Hello, how are you?   Fine.   ‘

str_list = list(setence)

i = 0

while i < len(str_list):

    if str_list[i] != ‘ ‘:

        start = i

        end = start + 1

        while (end < len(str_list)) and str_list[end] != ‘ ‘:

            end += 1

        reverse(str_list, start, end - 1)

        i = end

    else:

        i += 1

str_list.reverse()

print(‘‘.join(str_list))

>>   Fine.   you? are how Hello,

面向对象

1)self

类中的函数第一个参数必须是self,类中定义的函数叫做“方法”。

self 是个什么鬼呢?它是为了指代它所存在的类Class之中。

比如我们如果有好几个不同的obj被创建成同一个类,

那么有了self,我们的class Foo就能很好的知道哪个指的是自己,不会乱

所以说,这个 self 就是个代指。代指了自己所在的class。你可以由 self 点进所指class本身的函数。由此可见,self 本身作为一个代词,并不一定要叫self。你也可以用个其他什么来代替。只不过,必须得是这个类的所有子方法的第一个参数:

2)访问控制

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问

class Student:

    def __init__(self, name, age):

        self.__name = name

        self.__age = age 

def detail(self):

        print(self.__name)

        print(self.__age)

 

LiLei = Student(‘LiLei‘, 12)

LiLei.__age = 20

LiLei.detail()

>> 

LiLei

12

3)一些方法

Dir(): 如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法

 

getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态:

hasattr(obj, ‘x‘) #有木有属性‘x‘

setattr(obj, ‘y‘, 19) # 设置一个属性‘y‘

getattr(obj, ‘y‘) # 获取属性‘y‘

getattr(obj, ‘z‘, 404) # 获取属性‘z‘,如果不存在,返回默认值404

4)实例属性和类属性

 

实例属性:

class Student(object):

    def __init__(self, name):

        self.name = name

 

s = Student(‘Bob‘)

s.score = 90

 

类属性:

class Student(object):

    name = ‘Student‘

 

s = Student() # 创建实例s

print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性

 

s.name = ‘Michael‘ # 给实例绑定name属性

print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性

 

总结:

从上面的例子可以看出,在编写程序的时候,千万不要把实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。

5)super()

 

文件读写

1) 直接读入

read()将文本文件所有行读到一个字符串中。

readline()是一行一行的读

readlines()是将文本文件中所有行读到一个list中,文本文件每一行是list的一个元素。优点:readline()可以在读行过程中跳过特定行。

2) 文件迭代器,用for循环的方法

file = open("output.txt","w")

for line in open("test.txt"):

      #这里可以进行逻辑处理

    file.write(‘"‘+line[:s]+‘"‘+",")

3)文件上下文管理器

with open(‘somefile.txt‘, ‘r‘) as f:

4)二进制文件读写

f = open(‘DegangGuo.txt‘, ‘rb‘)

# 读入郭德纲老师的作文, 但是郭老师用的是参合着错别字的繁体编码,假设叫个"DeyunCode"

# 那么你读入以后,就需要解码它

u = f.read().decode(‘DeyunCode‘)

文件目录操作

os.path.join(‘/Users/EDC‘, ‘Pictures‘)

# 这里你得到的是一个字符串,代表了新的文件夹是这个位置:/Users/EDC/Pictures/

# 自己也可以拼起来,但是怕不同操作系统下的区分符问题,最好是用OS接口

# 但是你还并没有创建任何的文件

 

# 需要用mkdir创建:

os.mkdir(‘/Users/EDC/Pictures/‘)

 

# 同理,删除一个文件夹

os.rmdir(‘/Users/EDC/Pictures/‘)

os.path.split(‘/Users/EDC/Pictures/AJiao.avi‘)

# (‘/Users/EDC/Pictures/‘, ‘AJiao.avi‘)

 

os.path.splitext(‘/Users/EDC/Pictures/AJiao.avi‘)

# (‘/Users/EDC/Pictures/AJiao‘, ‘.avi‘)

 

#复制文件

import shutil 

shutil.copyfile(‘/path/to/file‘, ‘/path/to/other/file‘) 

匿名函数

python 使用 lambda 来创建匿名函数。

lambda只是一个表达式,函数体比def简单很多。

lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。

lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。

虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

语法:lambda [arg1 [,arg2,.....argn]]:expression

 

Reduce:

传给reduce中的函数func() (必须是一个二元操作函数)先对集合中的第1,2个数据进行操作,得到的结果再与第三个数据用func()函数运算,最后得到一个结果。

from functools import reduce

l = [1,2,3,4,5]

print(reduce(lambda x,y: x+y, l))

# 这里代表着,把list中的值,一个个放进lamda的x,y中

 

# 如果你给出一个初始值,可以放在list后面

print(reduce(lambda x,y: x+y, l, 10))

# 这样,x开始的时候被赋值为10,然后依次

 

Map:

格式:map(func, seq1[, seq2...] )

Python函数式编程中的map()函数是将func作用于seq中的每一个元素,并用一个列表给出返回值。

l = [1,2,3]

new_list = list(map(lambda i: i+1, l))

print(new_list)

# Py3里,外面需要套个list:

# 这是为了让里面的值给显示出来,要不然你会得到这是个map函数

# 而不是里面的值。

# Py2的童鞋不虚

 

# 我们也可以把两个数组搞成一个单独的数组

l2 = [4,5,6]

new_list = list(map(lambda x,y: x+y, l, l2))

print(new_list)

[2, 3, 4]

[5, 7, 9]

 

Filter:

和map()类似,filter()也接收一个函数和一个序列。和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

l = [100, 20, 24, 50, 110]

new = list(filter(lambda x: x<50, l))

# 同理,py3得套个list来转化成list函数,便于打印出来

print(new)   [20, 24]

进程和线程

概念梳理

进程:

一个程序的执行实例就是一个进程。每一个进程提供执行程序所需的所有资源。(进程本质上是资源的集合)

每个进程有自己的内存空间、数据栈等,只能使用进程间通讯,而不能直接共享信息。

 

线程:

所有线程运行在同一个进程中,共享相同的运行环境。

每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。每条线程可以执行多个任务。

线程的运行可以被抢占(中断),或暂时被挂起(睡眠),让其他线程运行(让步)。

一个进程中的各个线程间共享同一片数据空间。

 

进程和线程的区别:

1.同一个进程中的线程共享同一内存空间,但是进程之间是独立的。

2.同一个进程中的所有线程的数据是共享的(进程通讯),进程之间的数据是独立的。

3.对主线程的修改可能会影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。

4.线程是一个上下文的执行指令,而进程则是与运算相关的一簇资源。

5.同一个进程的线程之间可以直接通信,但是进程之间的交流需要借助中间代理来实现。

6.创建新的线程很容易,但是创建新的进程需要对父进程做一次复制。

7.一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。

8.线程启动速度快,进程启动速度慢(但是两者运行速度没有可比性)。

多线程

常用方法:

start()                 线程准备就绪,等待CPU调度

setName()             为线程设置名称

getName()             获取线程名称

setDaemon(True)   设置为守护线程, 使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,因此当主进程结束后,子线程也会随之结束。所以当主线程结束后,整个程序就退出了。

join()                    逐个执行每个线程,执行完毕后继续往下执行

run()                     线程被cpu调度后自动执行线程对象的run方法,如果想自定义线程类,直接重写run方法就行了

 

GIL:

在非python环境中,单核情况下,同时只能有一个任务执行。多核时可以支持多个线程同时执行。但是在python中,无论有多少核,同时只能执行一个线程。究其原因,这就是由于GIL的存在导致的。

GIL是一把全局排他锁,同一时刻只有一个线程在运行。毫无疑问全局锁的存在会对多线程的效率有不小影响。甚至就几乎等于Python是个单线程的程序。

multiprocessing库的出现很大程度上是为了弥补thread库因为GIL而低效的缺陷。它完整的复制了一套thread所提供的接口方

便迁移。唯一的不同就是它使用了多进程而不是多线程。每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争

抢。

 

线程锁和互斥锁和递归锁和信号量:

1)由于线程之间是进行随机调度,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期,我们也称此为“线程不安全”。

2)为了方式上面情况的发生,就出现了互斥锁(Lock)。

3)RLcok类的用法和Lock类一模一样,但它支持嵌套,,在多个锁没有释放的时候一般会使用使用RLcok类。

4)互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据

def run(n):

    lock.acquire()  #获取锁

    global num

    num += 1

    lock.release()  #释放锁

lock = threading.Lock()     #实例化一个锁对象

num = 0

t_obj = [] 

for i in range(20000):

    t = threading.Thread(target=run, args=("t-%s" % i,))

    t.start()

    t_obj.append(t)

for t in t_obj:

    t.join()

 

print "num:", num

 

信号量

def run(n):

    semaphore.acquire()   #加锁

    time.sleep(1)

    print("run the thread:%s " % n)

    semaphore.release()     #释放

semaphore = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行

事件(Event类)

python线程的事件用于主线程控制其他线程的执行,事件是一个简单的线程同步对象。

事件处理的机制:全局定义了一个“Flag”,当flag值为“False”,那么event.wait()就会阻塞,当flag值为“True”,那么event.wait()便不再阻塞。

 

#利用Event类模拟红绿灯

import threading

import time

 

event = threading.Event()

 

def lighter():

    count = 0

    event.set()     #初始值为绿灯

    while True:

        if 5 < count <=10 :

            event.clear()  # 红灯,清除标志位

            print("33[41;1mred light is on...33[0m")

        elif count > 10:

            event.set()  # 绿灯,设置标志位

            count = 0

        else:

            print("33[42;1mgreen light is on...33[0m")

 

        time.sleep(1)

        count += 1

 

def car(name):

    while True:

        if event.is_set():      #判断是否设置了标志位

            print("[%s] running..."%name)

            time.sleep(1)

        else:

            print("[%s] sees red light,waiting..."%name)

            event.wait()

            print("[%s] green light is on,start going..."%name)

 

light = threading.Thread(target=lighter,)

light.start()

 

car = threading.Thread(target=car,args=("MINI",))

car.start()

 

定时器

定时器,指定n秒后执行某操作

from threading import Timer

def hello():

    print("hello, world")

 

t = Timer(1, hello)

t.start()  # after 1 seconds, "hello, world" will be printed

多进程

在linux中,每个进程都是由父进程提供的。每启动一个子进程就从父进程克隆一份数据,但是进程之间的数据本身是不能共享的。

多进程

进程间通信

1)queue():

from multiprocessing import Process, Queue

import time

def write(q):

    for i in [‘A‘,‘B‘,‘C‘,‘D‘,‘E‘]:

        print(‘Put %s to queue‘ % i)

        q.put(i)

        time.sleep(0.5)

 

def read(q):

    while True:

        v = q.get(True)

        print(‘get %s from queue‘ %v)

        if(v == ‘E‘): break;

 

if __name__ == ‘__main__‘:

    q = Queue()

    pw = Process(target=write,args=(q,))

    pr = Process(target=read,args=(q,))

    pw.start()

    pr.start()

    pr.join()

    pr.terminate()

2)pipe():

Pipe的本质是进程之间的数据传递,而不是数据共享,这和socket有点像。pipe()返回两个连接对象分别表示管道的两端,每端都有send()和recv()方法。

from multiprocessing import Process, Pipe

def f(conn):

    conn.send([42, None, ‘hello‘])

    conn.close()

if __name__ == ‘__main__‘:

    parent_conn, child_conn = Pipe()

    p = Process(target=f, args=(child_conn,))

    p.start()

    print(parent_conn.recv())   # prints "[42, None, ‘hello‘]"

    p.join()

进程锁

数据输出的时候保证不同进程的输出内容在同一块屏幕正常显示,防止数据乱序的情况。

from multiprocessing import Process, Lock

 

def f(l, i):

    l.acquire()

    try:

        print(‘hello world‘, i)

    finally:

        l.release()

 

if __name__ == ‘__main__‘:

    lock = Lock()

    for num in range(10):

        Process(target=f, args=(lock, num)).start()

进程池

由于进程启动的开销比较大,使用多进程的时候会导致大量内存空间被消耗。为了防止这种情况发生可以使用进程池,(由于启动线程的开销比较小,所以不需要线程池这种概念,多线程只会频繁得切换cpu导致系统变慢,并不会占用过多的内存空间)

 

进程池中常用方法:

apply()          同步执行(串行)

apply_async()       异步执行(并行)

terminate()     立刻关闭进程池

join()                   主进程等待所有子进程执行完毕。必须在close或terminate()之后。

close()                  等待所有进程结束后,才关闭进程池。

 

进程池内部维护一个进程序列,当使用时,去进程池中获取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。在上面的程序中产生了10个进程,但是只能有5同时被放入进程池,剩下的都被暂时挂起,并不占用内存空间,等前面的五个进程执行完后,再执行剩下5个进程。

from multiprocessing import Pool

import time

 

def f(x):

    print x*x

    time.sleep(2)

    return x*x

if __name__ == ‘__main__‘:

    ‘‘‘定义启动的进程数量‘‘‘

    pool = Pool(processes=5)

    res_list = []

 

    for i in range(10):

        ‘‘‘以异步并行的方式启动进程,如果要同步等待的方式,可以在每次启动进程之后调用res.get()方法,也可以使用Pool.apply‘‘‘

        res = pool.apply_async(f,[i,])

        print(‘-------:‘,i)

        res_list.append(res)

    pool.close()

    pool.join()

    for r in res_list:

        print "result",(r.get(timeout=5))

>>> 

0

4

1

9

16

(‘-------:‘, 0)

(‘-------:‘, 1)

(‘-------:‘, 2)

(‘-------:‘, 3)

(‘-------:‘, 4)

(‘-------:‘, 5)

(‘-------:‘, 6)

(‘-------:‘, 7)

(‘-------:‘, 8)

(‘-------:‘, 9)

25

36

49

64

81

result 0

result 1

result 4

result 9

result 16

result 25

result 36

result 49

result 64

result 81

魔术方法

1. __doc__

表示类的描述信息

class Foo:

    """ 描述类信息 """

    def func(self):

        pass

 

print(Foo.__doc__)

#输出:类的描述信息

2. __module__ 和 __class__

__module__ 表示当前操作的对象在那个模块

__class__ 表示当前操作的对象的类是什么

 

test.py文件

# -*- coding:utf-8 -*-

class Person(object):

    def __init__(self):

        self.name = ‘laowang‘

 

main.py文件

from test import Person

obj = Person()

print(obj.__module__)  # 输出 test 即:输出模块

print(obj.__class__)  # 输出 test.Person 即:输出类

3. __del__

当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,__del__的调用是由解释器在进行垃圾回收时自动触发执行的。

 

class Foo:

    def __del__(self):

        pass

4. __call__

对象后面加括号,触发执行。

注:__init__方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

 

class Foo:

    def __init__(self):

        pass

 

    def __call__(self, *args, **kwargs):

        print(‘__call__‘)

 

 

obj = Foo()  # 执行 __init__

obj()  # 执行 __call__

5. __dict__

类或对象中的所有属性

类的实例属性属于对象;类中的类属性和方法等属于类,即:

 

 

class Province(object):

    country = ‘China‘

 

    def __init__(self, name, count):

        self.name = name

        self.count = count

 

    def func(self, *args, **kwargs):

        print(‘func‘)

 

# 获取类的属性,即:类属性、方法、

print(Province.__dict__)

# 输出:{‘__dict__‘: <attribute ‘__dict__‘ of ‘Province‘ objects>, ‘__module__‘: ‘__main__‘, ‘country‘: ‘China‘, ‘__doc__‘: None, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Province‘ objects>, ‘func‘: <function Province.func at 0x101897950>, ‘__init__‘: <function Province.__init__ at 0x1018978c8>}

 

obj1 = Province(‘山东‘, 10000)

print(obj1.__dict__)

# 获取 对象obj1 的属性

# 输出:{‘count‘: 10000, ‘name‘: ‘山东‘}

 

obj2 = Province(‘山西‘, 20000)

print(obj2.__dict__)

# 获取 对象obj1 的属性

# 输出:{‘count‘: 20000, ‘name‘: ‘山西‘}

6.魔术方法之运算方法

举例:__add__

 

class Rectangle(object):

    def __init__(self, length, width):

        self.length = length

        self.width = width

 

    def get_area(self):

        return self.length * self.width

 

    def __add__(self, other):  #__add__魔术方法,相加

        add_length = self.length + other.length

        add_width = self.width + other.width

        return add_length, add_width

 

rec1 = Rectangle(10,8)

rec2 = Rectangle(20,15)

print(rec1 + rec2)

运行结果:

(30, 23)

 

到底是怎么回事呢?

>>> a = 1

>>> b =2

>>> a + b

3

>>> b.__add__(a)  #实际a + b 就等同于 b.__add__(a)  这里a, b均是两个类

3

 

魔术方法之运算方法:

__add__(self,other) # x+y

__sub__(self,other) # x-y

__mul__(self,other) # x*y

__mod__(self,other)      # x%y

__iadd__(self,other)      # x+=y

__isub__(self,other)      # x-=y

__radd__(self,other)      # y+x

__rsub__(self,other)      # y-x

__imul__(self,other)      # x*=y

__imod__(self,other)     # x%=y

7. __str__

如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

class Foo:

    def __str__(self):

        return ‘laowang‘

 

obj = Foo()

print(obj)

# 输出:laowang

8、__getitem__、__setitem__、__delitem__

用于索引操作,如字典。以上分别表示获取、设置、删除数据

# -*- coding:utf-8 -*-

class Foo(object):

    def __getitem__(self, key):

        print(‘__getitem__‘, key)

 

    def __setitem__(self, key, value):

        print(‘__setitem__‘, key, value)

 

    def __delitem__(self, key):

        print(‘__delitem__‘, key)

 

obj = Foo()

 

result = obj[‘k1‘]      # 自动触发执行 __getitem__

obj[‘k2‘] = ‘laowang‘   # 自动触发执行 __setitem__

del obj[‘k1‘]           # 自动触发执行 __delitem__

9、__getslice__、__setslice__、__delslice__

该三个方法用于分片操作,如:列表

# -*- coding:utf-8 -*-

class Foo(object):

    def __getslice__(self, i, j):

        print(‘__getslice__‘, i, j)

 

    def __setslice__(self, i, j, sequence):

        print(‘__setslice__‘, i, j)

 

    def __delslice__(self, i, j):

        print(‘__delslice__‘, i, j)

 

obj = Foo()

 

obj[-1:1]                   # 自动触发执行 __getslice__

obj[0:1] = [11,22,33,44]    # 自动触发执行 __setslice__

del obj[0:2]                # 自动触发执行 __delslice__

数组List的操作

a = [1,2,3,4,5,6,7]

b = [11,22,33]

a[ : 1] = b

则a = [11,22,33,2,3,4,5,6,7] 






以上是关于python基础学习的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记:python3,代码片段(2017)

Python 函数声明和调用

[vscode]--HTML代码片段(基础版,reactvuejquery)

Python学习(22):模块

python基础学习(十三)

python基础学习笔记(十三)