上药三品,神与气精

曾因酒醉鞭名马 生怕情多累美人


  • 首页

  • 关于

  • 分类

  • 标签

  • 归档

  • 搜索

分享python面试题2

发表于 2018-03-05 | 分类于 web | 阅读次数:
字数统计: 1.9k | 阅读时长 ≈ 7

1.Python是如何进行内存管理的?

答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制
一、对象的引用计数机制
Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
引用计数增加的情况:
1,一个对象分配一个新名称
2,将其放入一个容器中(如列表、元组或字典)
引用计数减少的情况:
1,使用del语句对对象别名显示的销毁
2,引用超出作用域或被重新赋值
sys.getrefcount( )函数可以获得对象的当前引用计数
多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。
二、垃圾回收
1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。
三、内存池机制
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。
3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

2.什么是lambda函数?它有什么好处?

答:lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数
lambda函数:首要用途是指点短小的回调函数
lambda [arguments]:expression

>>> a=lambdax,y:x+y
>>> a(3,11)

3.Python里面如何实现tuple和list的转换?

答:直接使用tuple和list函数就行了,type()可以判断对象的类型

4.请写出一段Python代码实现删除一个list里面的重复元素

答:
1,使用set函数,set(list)

2,使用字典函数,

>>>a=[1,2,4,2,4,5,6,5,7,8,9,0]
>>> b={}
>>>b=b.fromkeys(a)
>>>c=list(b.keys())
>>> c

5.编程用sort进行排序,然后从最后一个元素开始判断

a=[1,2,4,2,4,5,7,10,5,5,7,8,9,0,3]

a.sort()
last=a[-1]
for i inrange(len(a)-2,-1,-1):
if last==a[i]:
del a[i]
else:last=a[i]
print(a)

6.Python里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)

答:赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。

浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变){1,完全切片方法;2,工厂函数,如list();3,copy模块的copy()函数}

深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变){copy模块的deep.deepcopy()函数}

7.介绍一下except的用法和作用?

答:try…except…except…[else…][finally…]
执行try下的语句,如果引发异常,则执行过程会跳到except语句。对每个except分支顺序尝试执行,如果引发的异常与except中的异常组匹配,执行相应的语句。如果所有的except都不匹配,则异常会传递到下一个调用本代码的最高层try代码中。
try下的语句正常执行,则执行else块代码。如果发生异常,就不会执行
如果存在finally语句,最后总是会执行。
8.Python中pass语句的作用是什么?

答:pass语句不会执行任何操作,一般作为占位符或者创建占位程序,whileFalse:pass
9.介绍一下Python下range()函数的用法?

答:列出一组数据,经常用在for in range()循环中
10.如何用Python来进行查询和替换一个文本字符串?

答:可以使用re模块中的sub()函数或者subn()函数来进行查询和替换,
格式:sub(replacement, string[,count=0])(replacement是被替换成的文本,string是需要被替换的文本,count是一个可选参数,指最大被替换的数量)

>>>import re
>>>p=re.compile(‘blue|white|red’)
>>>print(p.sub(‘colour’,'blue socks and red shoes’))
colour socks and colourshoes
>>>print(p.sub(‘colour’,'blue socks and red shoes’,count=1))
colour socks and redshoes

subn()方法执行的效果跟sub()一样,不过它会返回一个二维数组,包括替换后的新的字符串和总共替换的数量

11.Python里面match()和search()的区别?

答:re模块中match(pattern,string[,flags]),检查string的开头是否与pattern匹配。
re模块中research(pattern,string[,flags]),在string搜索pattern的第一个匹配值。

>>>print(re.match(‘super’, ‘superstition’).span())
(0, 5)
>>>print(re.match(‘super’, ‘insuperable’))
None
>>>print(re.search(‘super’, ‘superstition’).span())
(0, 5)
>>>print(re.search(‘super’, ‘insuperable’).span())
(2, 7)

12.用Python匹配HTML tag的时候,<.>和<.?>有什么区别?

答:术语叫贪婪匹配( <.> )和非贪婪匹配(<.?> )
例如:
test
<.> :
test
<.
?> :

13.Python里面如何生成随机数?

答:random模块
随机整数:random.randint(a,b):返回随机整数x,a<=x<=b
random.randrange(start,stop,[,step]):返回一个范围在(start,stop,step)之间的随机整数,不包括结束值。
随机实数:random.random( ):返回0到1之间的浮点数
random.uniform(a,b):返回指定范围内的浮点数。
14.有没有一个工具可以帮助查找python的bug和进行静态的代码分析?

答:PyChecker是一个python代码的静态分析工具,它可以帮助查找python代码的bug, 会对代码的复杂度和格式提出警告
Pylint是另外一个工具可以进行codingstandard检查
15.如何在一个function里面设置一个全局的变量?

答:解决方法是在function的开始插入一个global声明:
def f()
global x
16.单引号,双引号,三引号的区别

答:单引号和双引号是等效的,如果要换行,需要符号(),三引号则可以直接换行,并且可以包含注释
如果要表示Let’s go 这个字符串
单引号:s4 = ‘Let\’s go’
双引号:s5 = “Let’s go”
s6 = ‘I realy like“python”!’
这就是单引号和双引号都可以表示字符串的原因了

python装饰器全解

发表于 2018-03-03 | 阅读次数:
字数统计: 1k | 阅读时长 ≈ 4

python装饰器的作用 使得函数包装和方法包装变得更容易阅读和理解

1.一般语法和可能的实现

  • 作为一个函数
  • 作为一个类
  • 参数化装饰器
  • 保存内省的装饰器

2.用法和有用的例子

  • 参数检查
  • 缓存
  • 代理
  • 上下文提供者

Python 函数不同于其他编程语言,它可以作为第一类对象使用,这是关键。因为装饰器本质上还是函数

很多人对装饰器难以理解,原因是由于以下三点内容没有搞清楚:

关于函数“变量”(或“变量”函数)的理解

关于高阶函数的理解

关于嵌套函数的理解

那么如果能对以上的问题一一攻破,同时遵循装饰器的基本原则,相信会对装饰器有个很好的理解的。那么我们先来看以下装饰器的目的及其原则。

1、装饰器

装饰器实际上就是为了给某程序增添功能,但该程序已经上线或已经被使用,那么就不能大批量的修改源代码,这样是不科学的也是不现实的,因为就产生了装饰器,使得其满足:

  • 不能修改被装饰的函数的源代码
  • 不能修改被装饰的函数的调用方式
  • 满足1、2的情况下给程序增添功能
    那么根据需求,同时满足了这三点原则,这才是我们的目的。因为,下面我们从解决这三点原则入手来理解装饰器。

等等,我要在需求之前先说装饰器的原则组成:

< 函数+实参高阶函数+返回值高阶函数+嵌套函数+语法糖 = 装饰器 >

这个式子是贯穿装饰器的灵魂所在!

2、需求实现

improt time
def test():
    time.sleep(2)
    print("test is running!")
test()

给程序添加统计运行时间(2 second)功能

如何进行呢?

很显然,函数和变量是一样的,都是“一个名字对应内存地址中的一些内容”
那么根据这样的原则,我们就可以理解两个事情:

test1表示的是函数的内存地址

test1()就是调用对在test1这个地址的内容,即函数

如果这两个问题可以理解,那么我们就可以进入到下一个原因(关于高阶函数的理解)

那么对于高阶函数的形式可以有两种:

把一个函数名当作实参传给另外一个函数(“实参高阶函数”)

返回值中包含函数名(“返回值高阶函数”)

那么这里面所说的函数名,实际上就是函数的地址,也可以认为是函数的一个标签而已,并不是调用,是个名词。如果可以把函数名当做实参,那么也就是说可以把函数传递到另一个函数,然后在另一个函数里面做一些操作,根据这些分析来看,这岂不是满足了装饰器三原则中的第一条,即不修改源代码而增加功能。那我们看来一下具体的做法:

还是针对上面那段代码:

improt time

def test():
    time.sleep(2)
    print("test is running!")

def deco(func):  
    start = time.time()
    func() #2
    stop = time.time()
    print(stop-start)

deco(test) #1

装饰有参数的函数

improt time

def timer(func)
    def deco(*args, **kwargs):  
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print(stop-start)
        return res 
    return deco

@timer
def test(parameter): #8
    time.sleep(2)
    print("test is running!")   
    return "Returned value"
test()     

带参数的装饰器

import time

def timer(parameter):

    def outer_wrapper(func):

        def wrapper(*args, **kwargs):
            if parameter == 'task1':
                start = time.time()
                func(*args, **kwargs)
                stop = time.time()
                print("the task1 run time is :", stop - start)
            elif parameter == 'task2':
                start = time.time()
                func(*args, **kwargs)
                stop = time.time()
                print("the task2 run time is :", stop - start)

        return wrapper

    return outer_wrapper

@timer(parameter='task1')
def task1():
    time.sleep(2)
    print("in the task1")

@timer(parameter='task2')
def task2():
    time.sleep(2)
    print("in the task2")

task1()
task2()    

分享python面试题

发表于 2018-03-03 | 分类于 web | 阅读次数:
字数统计: 509 | 阅读时长 ≈ 2

1.is和==有什么区别?

python当中对象包含三要素,分别是id(身份标识)、type(数据类型)、value(值)

==是python的比较运算符,用于比较value值是否相等

is是同一性运算符,比较的是id是否相同

a、b值相同

只有数值型和字符串型时, a is b 为true
是tuple list dict 或者 set时,a is b 为false

2.解释装饰器

写代码要遵循开发封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,

def w1(func):
    def inner():
        # 验证1
        # 验证2
        # 验证3
        return func()
    return inner

@w1
def f1():
    print 'f1'
@w1
def f2():
    print 'f2'
@w1
def f3():
    print 'f3'
@w1
def f4():
    print 'f4'

如上例@w1内部会执行以下操作:

  • 执行w1函数,并将 @w1 下面的 函数 作为w1函数的参数,即:@w1 等价于 w1(f1)

所以,内部就会去执行:

def inner:
    #验证
    return f1()   # func是参数,此时 func 等于 f1
return inner     # 返回的 inner,inner代表的是函数,非执行函数

其实就是将原来的 f1 函数塞进另外一个函数中

  • 将执行完的 w1 函数返回值赋值给@w1下面的函数的函数名

w1函数的返回值是:

def inner:
    #验证
    return 原来f1()  # 此处的 f1 表示原来的f1函数

然后,将此返回值再重新赋值给 f1,即:

新f1 = def inner:
        #验证
        return 原来f1() 

所以,以后业务部门想要执行 f1 函数时,就会执行 新f1 函数,在 新f1 函数内部先执行验证,再执行原来的f1函数,然后将 原来f1 函数的返回值 返回给了业务调用者。

如此一来, 即执行了验证的功能,又执行了原来f1函数的内容,并将原f1函数返回值 返回给业务调用者

normal-library

发表于 2018-03-03 | 阅读次数:
字数统计: 1.4k | 阅读时长 ≈ 5
  1. 我做运维的时候,使用Python完成了一些打包和备份的脚本,也就是把某个目录压缩成各种格式(tar.gz、tar.bz2、zip)。 这个脚本其实打包压缩的部分还是比较复杂的。直到我看到了这个:

    In : from shutil import make_archive
    In : make_archive(‘archive_xxx’, ‘bztar’)
    Out: ‘archive_xxx.tar.bz2’

有兴趣的可以翻一下源码。你想要的说不定标准库里面已经实现。当然,有标准库不满足的额外需求,也可以参照它实现。

  1. 你可能接触过定时任务(crontab),它管理的任务很规矩,到点执行(当然精确度不那么高)。现在设想你有更复杂的任务需求:这个任务是动态的,也就是不一定啥时候就来排上队约定一个事件等着执行。这时候你可以想,这可以使用队列(Queue模块)啊,嗯也不错。难度再提高:加上优先级策略并能取消某个指定的已经放入队列的任务。现在思考下,这个怎么实现?其实很多工程实践的最好范例都在标准库中。sched模块中的scheduler类就是一个这样的通用的事件调度类。你可以学习它的实现。你问我它的实现多复杂?整个模块加上大幅的注释才134行。

  2. 学习Python的过程中,一开始我对于装饰器contextmanager+yield怎么都不懂。直到我看了contextmanager的源代码, 其实非常简单就懂了。它的docstring清楚地不能再清楚了:


Typical usage:                                                                               

@contextmanager                                                                          
def some_generator(<arguments>):                                                         
    <setup>                                                                              
    try:                                                                                 
        yield <value>                                                                    
    finally:                                                                             
        <cleanup>                                                                        

This makes this:                                                                             

with some_generator(<arguments>) as <variable>:                                          
    <body>                                                                               

equivalent to this:                                                                          

<setup>                                                                                  
try:                                                                                     
    <variable> = <value>                                                                 
    <body>                                                                               
finally:                                                                                 
<cleanup>
  1. 我之前使用多线程编程都这样用,在好长一段时间里面对于多进程和多线程之前怎么选择都搞得不清楚。看多了开源项目代码,我发现了好多人在用multiprocessing.dummy这个子模块,「dummy」这个词本身好奇怪,我决定去看多进程(multiprocessing)库的代码。「咦!怎么和多线程的接口一样呢」。后知后觉的我看到文档中这样说:

multiprocessing.dummy replicates the API of multiprocessing but is no more than a wrapper around the threading module.
恍然大悟!!!如果分不清任务是CPU密集型还是IO密集型,我就用如下2个方法分别试:

from multiprocessing import Pool
from multiprocessing.dummy import Pool
哪个速度快就用那个。从此以后我都尽量在写兼容的方式,这样在多线程/多进程之间切换非常方便。

  1. 13-14年间,Flask还没怎么火,那时候装饰器风格的Web框架还有一个Bottle。我当时就直接想去看Bottle代码,发现一上来import了一堆模块,你先感受下bottle/bottle.py at master · bottlepy/bottle · GitHub ,第一感觉就是懵啊,这都是干什么的啊,为什么要用啊?这就是促使我去看标准库实现最重要的原因:学会了我才能更好的看懂别人写的代码。

但是不是所有的标准库都要一视同仁的看呢?你可以设置优先级,先看那些不可不知道的模块。我在这里列一下,并对它的用途和其中重要的类、函数的作用加以说明等。要是每个都写例子实在太多太密集,怕大家看不下去,我都用外部链接了。

  1. argparse。 用来替代optparse的命令行解析库。如果你考虑用更直观的,推荐docopt,它使用docstring所见即所得实现命令行解析。
  2. collections。 包含了一些额外的数据类型。其中的OrderedDict(有序列的字典)、defaultdict(带有默认值的字典)、namedtuple(通过创建带有字段属性的元组子类)和deque(高效实现插入和删除操作的双向列表)非常常用。
  3. functools。 这个模块有一些非常有用的工具,其中的partial(偏函数)、wraps(将被包装函数的信息拷贝过来)、total_ordering(只需要定义2个XX方法就可实现对象对比的类装饰器)、cmp_to_key(将老式的比较函数转化为关键字函数)非常常用。
  4. glob。 文件名的shell模式匹配,你不用遍历整个目录判断每个文件是不是符合,使用glob一句话就解决。
  5. multiprocessing。多进程模块,这重要性就不说了。
  6. os。应该是日常工作最常用的模块了,你是否了解它里面所有的函数和实现呢?举个例子,获取环境变量,我之前这样用:
    In : os.environ.get(‘PYTHONPATH’)
    读完源码之后我学了一招:
    os.getenv(‘PYTHONPATH’)
    好吧,省了5个字符。

  7. Queue。这个模块用于多线程编程,它是一个线程安全的FIFO(先进先出)的队列实现。如果是多进程编程,选用multiprocessing.queues中的Queue、SimpleQueue、JoinableQueue这三个队列实现。

  8. SimpleHTTPServer。最简单地HTTP Server实现。不使用Web框架,一句:

    python -m SimpleHTTPServer PORT
    

    就可以运行起来静态服务。平时用它预览和下载文件太方便了。

  9. subprocess。 如果你还被某些书籍引导使用os.system或者os.popen等模块,现在是放弃它们的时候了,这个模块会满足你绝大多数的系统命令执行、执行结果获取和解析等需求。其中最有用的是call(执行系统命令)、check_call(执行结果不为0则抛出异常)、check_output(最方便的获取执行的输出的函数)、Popen+PIPE(支持管道的多命令执行)。

  10. threading。多线程模块,重要性也不必说。

python-fp

发表于 2018-03-03 | 阅读次数:
字数统计: 660 | 阅读时长 ≈ 2

函数式编程

函数式编程源自于数学理论,它似乎也更适用于数学计算相关的场景,因此本文以一个简单的数据处理问题为例,逐步介绍 Python 函数式编程从入门到走火入魔的过程。

问题:计算 N 位同学在某份试卷的 M 道选择题上的得分(每道题目的分值不同)。

首先来生成一组用于计算的伪造数据:

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
48
49
50
51
52
53
54
55
56
57

# @file: data.py
import random
from collections import namedtuple

Student = namedtuple('Student', ['id', 'ans'])

N_Questions = 25
N_Students = 20

def gen_random_list(opts, n):
return [random.choice(opts) for i in range(n)]

# 问题答案 'ABCD' 随机
ANS = gen_random_list('ABCD', N_Questions)
# 题目分值 1~5 分
SCORE = gen_random_list(range(1,6), N_Questions)

QUIZE = zip(ANS, SCORE)
students = [
# 学生答案为 'ABCD*' 随机,'*' 代表未作答
Student(_id, gen_random_list('ABCD*', N_Questions))
for _id in range(1, N_Students+1)
]

print(QUIZE)
# [('A', 3), ('B', 1), ('D', 1), ...
print(students)
# [Student(id=1, ans=['C', 'B', 'A', ...

```


常规的面向过程编程风格,我们需要遍历每个学生,然后遍历每个学生对每道题目的答案并与真实答案进行比较,然后将正确答案的分数累计:


```python

import data
def normal(students, quize):
for student in students:
sid = student.id
score = 0
for i in range(len(quize)):
if quize[i][0] == student.ans[i]:
score += quize[i][1]
print(sid, '\t', score)

print('ID\tScore\n==================')
normal(data.students, data.quize)
"""
ID Score
==================
1 5
2 12
...
"""

通过创建嵌套两个 for 循环来遍历所有题目答案的判断和评分,这完全是为计算机服务的思路,虽然说 Python 中的 for 循环已经比 C 语言更进了一步,通常不需要额外的状态变量来记录当前循环的次数,但有时候也不得不使用状态变量,如上例中第二个循环中比较两个列表的元素。函数式编程的一大特点就是尽量抛弃这种明显循环遍历的做法,而是把注意集中在解决问题本身,一如在现实中我们批改试卷时,只需要将两组答案并列进行比较即可:

from data import students, QUIZE

student = students[0]

# 将学生答案与正确答案合并到一起
# 然后过滤出答案一致的题目
filtered = filter(lambda x: x[0] == x[1][0], zip(student.ans, QUIZE))

print(list(filtered))  
# [('A', ('A', 3)), ('D', ('D', 1)), ...]

正确题目的分数进行累加:

from functools import reduce

reduced = reduce(lambda x, y: x + y[1][1], filtered, 0)  
print(reduced)      

接下来进行推广:

def cal(quize):  
    def inner(student):
        filtered = filter(lambda x: x[0] == x[1][0], zip(student.ans, quize))
        reduced = reduce(lambda x, y: x + y[1][1], filtered, 0)
        print(student.id, '\t', reduced)
    return inner
map(cal(QUIZE), students)      
1…929394…109
John Cheung

John Cheung

improve your python skills

543 日志
33 分类
45 标签
RSS
GitHub Email
© 2020 John Cheung
本站访客数:
|
主题 — NexT.Pisces v5.1.4
博客全站共226.3k字