python外包面试题整理

1、请尽可能列举python列表的成员方法,并给出一下列表操作的答案:
(1) a=[1, 2, 3, 4, 5],

a[::2] = [1,3,5]
a[-2:] = [4,5]

(2) 一行代码实现对列表a中的偶数位置的元素进行加3后求和?

from functools import reduce
l2 = reduce(lambda x, y: x + y, map(lambda i: l[i] + 3, list(filter(lambda y: y % 2 == 0, range(len(l))))))
l3 = sum(list(map(lambda i: l[i] + 3, list(filter(lambda y: y % 2 == 0, range(len(l)))))))
print(l2)
print(l3)

(3) 将列表a的元素顺序打乱,再对a进行排序得到列表b,然后把a和b按元素顺序构造一个字典d。

from random import shuffle

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

# 打乱列表a的元素顺序
shuffle(a)

# 对a进行排序得到列表b
b = sorted(a, reverse=True)

# zip 并行迭代,将两个序列“压缩”到一起,然后返回一个元组列表,最后,转化为字典类型。
d = dict(zip(a, b))

print (d)

(4),List = [-2, 1, 3, -6],如何实现以绝对值大小从小到大将 List 中内容排序。

sorted(list,key=abs)

(5)列表sort方法和sorted的区别是什么?

sort 是list的方法,改变list对象的顺序,返回值None
sorted是python的内置方法,适用iterable对象,返回值是新列表,不影响原来的iterable的顺序

2、用python实现统计一篇英文文章内每个单词的出现频率,并返回出现频率最高的前10个单词及其出现次数,并解答以下问题?(标点符号可忽略)
方法一:

# coding = utf -8
import re
 
with open("this.txt", "r", encoding="utf-8") as fd:
    word_list = []     # 存放所有单词,全部小写,并去除,.!等后缀,并去除空格字符串
    word_dict = {}     # 保留{word: count}键值对
    for line in fd.readlines():
        for word in line.strip().split(" "):
            word_list.append(re.sub(r"[.|!|,]", "", word.lower()))
    word_sets = list(set(word_list))   # 确保唯一
    word_dict = {word: word_list.count(word) for word in word_sets if word}
result = sorted(word_dict.items(), key=lambda d: d[1], reverse=True)[:10]
print(result)
备注: 遍历文件,用word_list保留所有的单词,用word_sets保存唯一的单词,方便word_dict来作为键。最后对字典排序,取出前10个,非常巧妙.

方法二:借助collections模块

# coding = utf -8
import re
from collections import Counter
 
with open("this.txt", "r", encoding="utf-8") as fd:
    texts = fd.read()                         # 将文件的内容全部读取成一个字符串
    count = Counter(re.split(r"\W+", texts))  # 以单词为分隔
 
result = count.most_common(10)                # 统计最常使用的前10个
print(result)

(1) 创建文件对象f后,解释f的readlines和xreadlines方法的区别?

直接输出后,readlines结尾是\n,返回值readlines返回列表和xreadlines返回生成器

(2) 追加需求:引号内元素需要算作一个单词,如何实现?

思路:以"分割,转换成列表,取其奇数分割,其偶数不做处理

3、简述python GIL的概念, 以及它对python多线程的影响?编写一个多线程抓取网页的程序,并阐明多线程抓取程序是否可比单线程性能有提升,并解释原因。

Python语言和GIL没有半毛钱关系。仅仅是由于历史原因在Cpython虚拟机(解释器),难以移除GIL。
GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行字节码。
线程释放GIL锁的情况:
在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL
Python 3.x使用计时器(执行时间达到阈值后,当前线程释放GIL)或Python 2.x,tickets计数达到100

Python使用多进程是可以利用多核的CPU资源的。

多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁
因为抓取程序涉及到读取远程网站页面的操作,这个操作中从发出请求到获得内容是需要等待IO的;多线程程序可以利用这个时间进行其他操作,因此可以提高效率。

4、用python编写一个线程安全的单例模式实现。

import threading
import time


class Foo(object):
    _instance = None
    _lock = threading.RLock()

    def __new__(cls, *args, **kwargs):
        if cls._instance:
            return cls._instance
        with cls._lock:
            if not cls._instance:
                cls._instance = object.__new__(cls)
            return cls._instance


def task():
    obj = Foo()
    print(obj)


for i in range(10):
    t = threading.Thread(target=task)
    t.start()

time.sleep(100)
obj = Foo()
View Code

5. 写一个装饰器,用于打印函数执行时长。

import time
def timmer(f):  # f = login函数名
    def inner(*args,**kwargs):  # args (2, 3)
        start_time = time.time()
        ret = f(*args,**kwargs)  # login() *(2, 3) 2,3
        end_time = time.time()
        print('此函数的执行时间%s' % (end_time - start_time))
        return ret
    return inner

@timmer  # login = timmer(login)  # inner 此login是新变量
def login(a,b):
    print(a,b)
    time.sleep(0.3)
    print('123456...')
    return 666

print(login(2,3))  # inner(2,3)
View Code

6. Python 中 GIL 是什么,有什么作用及影响?线程,进程,协程的区别?

GIL锁是线程锁,锁的是线程,保证同一时刻,一个进程中只有一个线程可以被CPU调度,不能保证安全
进程:
    # 计算机最小的资源分配单位
    数据隔离,利用多核,数据不安全
    IO密集型/计算密集型 提高并发,资源浪费
线程: 
    # 计算机中最小的CPU调度单位
    数据共享,GIL锁,数据不安全
    IO密集型,提高并发,多个线程
协程:
    # 线程的一部分,由用户来调度
    数据共享,数据安全
    IO密集型,提高并发,1个线程
# 并发的本质:切换+保存状态
计算密集型:进程
IO密集型:线程<携程​    

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

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

协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
 1、进程多与线程比较

线程是指进程内的一个执行单元,也是进程内的可调度实体。线程与进程的区别:
1) 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
2) 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
3) 线程是处理器调度的基本单位,但进程不是
4) 二者均可并发执行

5) 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制

  2、协程多与线程进行比较

1) 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。

2) 线程进程都是同步机制,而协程则是异步

3) 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
View Code

5、请回答一下问题:
(1) 阐述一下装饰器,描述符(property)、元类的概念,并列举其应用场景;

浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝
深拷贝:是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,这就是深拷贝
闭包:内层函数对外层函数非全局变量的引用
装饰器:装饰器本质上就是一个函数,在不修改源代码,调用方法的前提下,用来给其他函数添加功能的函数。
元类:创建类的就是元类,type是所有类的元类。
描述符:是一种协议,实现了相应的描述符方法便会有相应的描述符行为,property就是一个特定的描述符类型
装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。

装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。


描述符(__get__,__set__,__delete__)   # 这里着重描述了python的底层实现原理

  1、 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议。
    __get__():调用一个属性时,触发
    __set__():为一个属性赋值时,触发
    __delete__():采用del删除属性时,触发
描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)
描述符通常是使用到装饰器或者元类的大型框架中的一个组件.


元类是类的类,是类的模板

元类是用来控制如何创建类的,正如类是创建对象的模板一样

元类的主要用途是创建API
View Code

(2) 如何动态获取和设置对象的属性。

6.Python中的变量作用域(变量查找顺序)。

LEGB
local 局部变量--->enclosed 闭包作用域 ----> Global 全局---->built-in变量

7.下面这段代码的输出结果将是什么?请解释。

# 1 1 1 继承自父类的类属性x,所以都一样,指向同一块内存地址
# 1 2 1 更改Child1,Child1的x指向了新的内存地址
# 3 2 3 更改Parent,Parent的x指向了新的内存地址

8,python中如何 动态获取和设置对象的属性

if hasattr(Parent,'x'):
    print(getattr(Parent,'x'))
    setattr(Parent,'x',3)
    print(getattr(Parent,'x'))

9.(前端基础)
(1) 用CSS如何隐藏一个元素

dispaly:none

(2) 一行CSS实现padding上下左右分别为 1px,2px,3px,4px

padding:1 4 2 3

(3) JavaScript(或jQuery)如何选择一个id为main的容器

$('#main')

(4) JavaScript(或jQuery)如何选择一个class为menu的容器

$('.menu')

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

赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。
浅拷贝: 创建一个新的对象,但它包含的是对原始对象中包含项的引用
(如果用引用的方式修改其中一个对象,另外一个也会修改改变)
{1,完全切片方法;2,工厂函数,如list();3,copy模块的copy()函数}
深拷贝:创建一个新的对象,并且递归的复制它所包含的对象
(修改其中一个,另外一个不会改变){copy模块的deep.deepcopy()函数}

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

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

12.Python中pass语句的作用是什么?

pass语句不会执行任何操作,一般作为占位符或者创建占位程序,
whileFalse:pass

13.介绍一下Python下range()函数的用法?

列出一组数据,经常用在for in range()循环中

14.如何用Python来进行查询和替换一个文本字符串?

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

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

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

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

术语叫贪婪匹配( <.> )和非贪婪匹配(<.?> )

17.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):
返回指定范围内的浮点数。

18.有没有一个工具可以帮助查找python的bug和进行静态的代码分析?

PyChecker是一个python代码的静态分析工具,
它可以帮助查找python代码的bug, 
会对代码的复杂度和格式提出警告
Pylint是另外一个工具可以进行codingstandard检查

19.如何在一个function里面设置一个全局的变量?

解决方法是在function的开始插入一个global声明:
def f()
global x

20.单引号,双引号,三引号的区别

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

21.列举您使用过的python网络爬虫所用到的解析数据包
 

BeautifulSoup、pyquery、Xpath、lxml

22.python常用内置函数:

dir(对象名):返回一个列表,列出该对象所有的属性和方法;
  help(函数名、方法名或对象):查看函数、方法或对象的帮助文档;
  type(对象名):查看该对象的类型;
  isinstance(对象, 类型):判断该对象是否是该类型,返回True或False;
  range、input、print就不用多说了。

23. python中的and、or、not逻辑运算符:

andor、not两边的值会被放到布尔环境下,作比较
  and运算如x and y:
  x和y都为True时,那么返回最后一个值y
  否则返回两个值中的第一个布尔值为假的值,从左往右运算
  or运算如x or y:
  只要有一个为真值,就返回第一个布尔值为真的值
  如果都为假,返回最后一个布尔值为假的值,从左往右运算
  not运算如not x:
  当x的布尔值为True,返回False
  当x的布尔值为False,返回True

 24.参数按值传递和引用传递是怎样实现的?
 

Python中的一切都是类,所有的变量都是一个对象的引用。引用的值是由函数确定的,因此无法被改变。但是如果一个对象是可以被修改的,你可以改动对象。

25. python内置的数据类型有哪些?

list: 链表, 有序的项目, 通过索引进行查找, 使用方括号"[]"
  dict: 字典, 字典是一组键(key)和值(value)的组合, 通过键(key)进行查找, 没有顺序, 使用大括号"{}"
  str:字符串,用单或双引号括起来表示字符串
  tuple: 元组, 元组将多样的对象集合到一起, 不能修改, 通过索引进行查找, 使用括号"()"
  set: 集合,无序, 元素只出现一次, 使用"set([])",可实现列表快速去重,不过注意返回的是一个集合
  int: 整数,如3
  float:浮点数,如2.3
  complex:复数,如complex(1,2) => 1+2j
  可迭代(遍历)对象:list、dict、tuple、set、str
  可变类型:list、dict、set,其余为不可变类型
  list、tuple、str可通过索引获取当中的元素
  set不支持索引查找,因为数据只出现一次, 它只关心数据是否出现, 不关心其位置。

 26. 在 Python 中如何实现多线程?

一个线程就是一个轻量级进程,多线程能让我们一次执行多个线程。我们都知道,Python 是多线程语言,其内置有多线程工具包。
Python 中的 GIL(全局解释器锁)确保一次执行单个线程。一个线程保存 GIL 并在将其传递给下个线程之前执行一些操作,这会让我们产生并行运行的错觉。但实际上,只是线程在 CPU 上轮流运行。当然,所有的传递会增加程序执行的内存压力。

27. 解释一下 Python 中的继承

当一个类继承自另一个类,它就被称为一个子类 / 派生类,继承自父类 / 基类 / 超类。它会继承 / 获取所有类成员(属性和方法)。
继承能让我们重新使用代码,也能更容易的创建和维护应用。Python 支持如下种类的继承:
● 单继承:一个类继承自单个基类
● 多继承:一个类继承自多个基类
● 多级继承:一个类继承自单个基类,后者则继承自另一个基类
● 分层继承:多个类继承自单个基类
● 混合继承:两种或多种类型继承的混合

28, 解释 Python 中的 help() 和 dir() 函数

Help() 函数是一个内置函数,用于查看函数或模块用途的详细说明:
Dir() 函数也是 Python 内置函数,dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。

29. 请写一个 Python 逻辑,计算一个文件中的大写字母数量

import os

os.chdir('C:\\Users\\lifei\\Desktop')
with open('Today.txt') as today:
    count = 0
for i in today.read():
    if i.isupper():
        count += 1
print(count)

30. 如何以就地操作方式打乱一个列表的元素?

from random import shuffle
mylist = [1,2,34]
shuffle(mylist)
mylist

31. 解释 Python 中的 join() 和 split() 函数

Join()能让我们将指定字符添加至字符串中。

Split() 能让我们用指定字符分割字符串。

32. Python 区分大小写吗?

如果能区分像 myname 和 Myname 这样的标识符,那么它就是区分大小写的。也就是说它很在乎大写和小写。

33. Python 中的标识符长度能有多长?

在 Python 中,标识符可以是任意长度。此外,我们在命名标识符时还必须遵守以下规则:
只能以下划线或者 A-Z/a-z 中的字母开头
其余部分可以使用 A-Z/a-z/0-9
区分大小写
关键字不能作为标识符,

34. 怎么移除一个字符串中的前导空格?

字符串中的前导空格就是出现在字符串中第一个非空格字符前的空格。我们使用方法 Istrip() 可以将它从字符串中移除。
1>>> ' Ayushi '.lstrip()

35. 怎样将字符串转换为小写?

我们使用 lower() 方法。
1>>> 'AyuShi'.lower()

36. 在 Python 中有多少种运算符?解释一下算数运算符。

在 Python 中,我们有 7 种运算符:算术运算符、关系运算符、赋值运算符、逻辑运算符、位运算符、成员运算符、身份运算符。

37. 在 Python 中如何使用多进制数字?

我们在 Python 中,除十进制外还可以使用二进制、八进制和十六进制。
二进制数字由 0 和 1 组成,我们使用 0b 或 0B 前缀表示二进制数。
1>>> int(0b1010)
210
2. 使用 bin() 函数将一个数字转换为它的二进制形式。
1>>> bin(0xf)
2‘0b1111’
3. 八进制数由数字 0-7 组成,用前缀 0o 或 0O 表示 8 进制数。
1>>> oct(8)
2‘0o10’
4. 十六进数由数字 0-15 组成,用前缀 0x 或者 0X 表示 16 进制数。
1>>> hex(16)
2‘0x103
4>>> hex(15)
5‘0xf’

38. 怎样获取字典中所有键的列表?

使用 keys() 获取字典中的所有键
1>>> mydict={'a':1,'b':2,'c':3,'e':5}
2>>> mydict.keys()
3dict_keys(['a', 'b', 'c', 'e'])

39. 为何不建议以下划线作为标识符的开头

因为 Python 并没有私有变量的概念,所以约定速成以下划线为开头来声明一个变量为私有。所以如果你不想让变量私有,就不要使用下划线开头。

40. 怎样声明多个变量并赋值?

一共有两种方式:
1>>> a,b,c=3,4,5 #This assigns 3, 4, and 5 to a, b, and c respectively
2>>> a=b=c=3 #This assigns 3 to a, b, and c

41. 元组的解封装是什么?

首先我们来看解封装:
1>>> mytuple=3,4,5
2>>> mytuple
3(3, 4, 5)
这将 3,4,5 封装到元组 mytuple 中。
现在我们将这些值解封装到变量 x,y,z 中:
1>>> x,y,z=mytuple
2>>> x+y+z
得到结果 12.

42、Python是如何进行内存管理的?

Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。

43、垃圾回收机制

当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。

44、引用计数机制

PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除、引用超出作用域或被重新赋值,它的ob_refcnt就会减少.引用计数为0时,该对象生命就结束了。
优点:
1. 简单
2. 实时性
缺点:
1. 维护引用计数消耗资源
2. 循环引用

45、标记-清除

基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。

46、分代回收

分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。
Python默认定义了三代对象集合,索引数越大,对象存活时间越长。
举例:
当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。

47、内存池机制

Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。
对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。

48、函数参数

普通参数
即在调用函数时必须按照准确的顺序来进行参数传递。
def fun(name):
print('Hello', name)

fun('World')#Hello World
默认参数
即参数含有默认值,在调用函数时可以进行参数传递,若没有进行参数传递则使用默认值,要注意,默认参数必须在普通参数的右侧(否则解释器无法解析)
def fun(name, age=1):
print('Hello', name, age, '')

fun('World') # Hello World 1 年
元组参数,即 *args
参数格式化存储在一个元组中,长度没有限制,必须位于普通参数和默认参数之后
def fun(name, age=1, *args):
print('Hello', name, age, '') # Hello World 1 年
print(args) # ('I', 'love', 'it')
for i in args:
print(i)

fun('World', 1, 'I', 'love', 'it') 
输出结果:
I 
love 
it


字典参数,即 **kwargs
参数格式化存储在一个字典中,必须位于参数列表的最后面
def fun(name, age=1, *args, **kwargs):
print('Hello', name, age, '') # Hello World 1 年
print(args) # ('I', 'love', 'it')
for i in args:
print(i)
print(kwargs) # {'my': 'jack', 'like': 'girl'}
for m in kwargs:
print(m, ':', kwargs[m])

fun('World', 1, 'I', 'love', 'it', my='jack', like='girl')
输出结果:
Hello World 1 年
('I', 'love', 'it')
I
love
it
{'my': 'jack', 'like': 'girl'}
my : jack
like : girl
View Code

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

赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。
浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变){1,完全切片方法;2,工厂函数,如list();3,copy模块的copy()函数}
深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变){copy模块的deep.deepcopy()函数}

copy 仅拷贝对象本身,而不拷贝对象中引用的其它对象。
deepcopy 除拷贝对象本身,而且拷贝对象中引用的其它对象。
代码实例
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象

b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝

a.append(5) #修改对象a
a[4].append('c') #修改对象a中的['a', 'b']数组对象

print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d

输出结果:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]

50、Python中重载

函数重载主要是为了解决两个问题:
1. 可变参数类型
2. 可变参数个数
解释一:
那么对于情况 1 ,函数功能相同,但是参数类型不同,python 如何处理?答案是根本不需要处理,因为 python 可以接受任何类型的参数,如果函数的功能相同,那么不同的参数类型在 python 中很可能是相同的代码,没有必要做成两个不同函数。
那么对于情况 2 ,函数功能相同,但参数个数不同,python 如何处理?大家知道,答案就是缺少参数。对那些缺少的参数设定为缺少参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。
鉴于情况 1 跟 情况 2 都有了解决方案,python 自然就不需要函数重载了。

解释二:
简单来说,Python中为什么不需要重载,重载要解决的是参数类型和参数个数的问题,对于类型,python不像是c语言整型要写int,字符串要写str,,,这些python都不需要。

那么需要解决的就是传递参数个数问题,此时python可以传递列表呀,字典呀,可以使用*arg和**args呀,所以python根本不需要重载。

51、Python中单下划线和双下划线

__foo__:一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突.
_foo:一种约定,用来指定变量私有.程序员用来指定私有变量的一种方式.
__foo:这个有真正的意义:解析器用_classname__foo来代替这个名字,以区别和其他类相同的命名.

52、 __new__和__init__的区别

1. __new__是一个静态方法,而__init__是一个实例方法.
2. __new__方法会返回一个创建的实例,而__init__什么都不返回.
3. 只有在__new__返回一个cls的实例时,后面的__init__才能被调用.
4. 当创建一个新实例时调用__new__,初始化一个实例时用__init__.

53、单例模式


该模式的主要目的是确保某一个类只有一个实例存在
使用模块
其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。


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


当我们实现单例时,为了保证线程安全需要在内部加入锁,未加锁部分并发执行,加锁部分串行执行,速度降低,但是保证了数据安全


import
threading import time class Foo(object): _instance = None _lock = threading.RLock() def __new__(cls, *args, **kwargs): if cls._instance: return cls._instance with cls._lock: if not cls._instance: cls._instance = object.__new__(cls) return cls._instance def task(): obj = Foo() print(obj) for i in range(10): t = threading.Thread(target=task) t.start() time.sleep(100) obj = Foo()

54、创建字典的方法

直接创建
dict = {'name':'earth', 'port':'80'}
工厂方法
items=[('name','earth'),('port','80')]
dict2=dict(items)
fromkeys()方法
dict1={}.fromkeys(('x','y'),-1)
dict={'x':-1,'y':-1}
dict2={}.fromkeys(('x','y'))
dict2={'x':None, 'y':None}

55、数组和元组之间的区别是什么?

相同点
首先,列表与元组都是容器,是一系列的对象;
其次,二者都可以包含任意类型的元素甚至可以是一个序列。
不同点
列表和元组的“技术差异”是,列表是可变的,而元组是不可变的。

56、Python都有那些自带的数据结构?

Python自带的数据结构分为可变的和不可变的。
可变的有:
集合
字典
数组
不可变的有:
字符串
元组
数字

57、推导式

列表(list)推导式
功能:是提供一种方便的列表创建方法,所以,列表解析式返回的是一个列表
例子:
>>> li=[i*2 for i in range(10) if i % 2 == 0]
>>> print li
[0, 4, 8, 12, 16]
列表解析式最擅长的方式就是对整个列表分别做相同的操作,并且返回得到一个新的列表
字典(dict)推导式

集合(set)推导式
功能:集合推导式跟列表推导式差不多,都是对一个列表的元素全部执行相同的操作,但集合是一种无重复无序的序列
区别:跟列表推到式的区别在于:1.不使用中括号,使用大括号;2.结果中无重复;3.结果是一个set()集合,集合里面是一个序列
>>> squared={i*2 for i in [1,1,2]}
>>> print squared
set([2, 4])

58、Python是如何进行类型转换的?

Python提供了将变量或值从一种类型转换成另一种类型的内置函数。比如int函数能够将符合数学格式数字型字符串转换成整数。否则,返回错误信息。

59、Python是如何被解释的?

Python是一种解释性语言,Python解释器会将源代码转换成中间语言,之后再翻译成机器码再执行。

60、.Python中的负索引是什么?

Python中的序列索引可以是正也可以是负。如果是正索引,0是序列中的第一个索引,1是第二个索引。如果是负索引,(-1)是最后一个索引而(-2)是倒数第二个索引。

61、Python的参数传递是值传递还是引用传递

1).Python的参数传递有:
位置参数
默认参数,
可变参数,
关键字参数

2).函数的传值到底是值传递还是引用传递,要分情况
a.不可变参数用值传递:
像整数和字符串这样的不可变对象,是通过拷贝进行传递的,因为你无论如何都不可能在原处改变不可变对象
b.可变参数是用引用传递的

比如像列表,字典这样的对象是通过引用传递,和C语言里面的用指针传递数组很相似,可变对象能在函数内部改变.

62、Xrange和range的区别是什么?

xrange 函数说明:用法与range完全相同,所不同的是生成的不是一个数组,而是一个生成器。
>>> range(5)
[0, 1, 2, 3, 4]

>>> xrange(5)
xrange(5)
>>> list(xrange(5))
[0, 1, 2, 3, 4]

63、单引号,双引号,三引号的区别

1),单引号和双引号主要用来表示字符串
区别:
若你的字符串里面本身包含单引号,必须用双引号
比如:"can't find the log\n"
2).三引号
三单引号:'''python ''',也可以表示字符串一般用来输入多行文本,或者用于大段的注释
三双引号:"""python""",一般用在类里面,用来注释类

64、类和实例
https://www.cnblogs.com/crazyrunning/p/6945183.html

65、类变量和实例变量

实例变量是对于每个实例都独有的数据,而类变量是该类所有实例共享的属性和方法。
class Dog:
kind = 'canine' # class variable shared by all instances

def __init__(self, name):
self.name = name # instance variable unique to each instance
类Dog中,类属性kind为所有实例所共享;
实例属性name为每个Dog的实例独有。

66、类对象和实例对象

类对象
类对象仅支持两个操作:
实例化;使用instance_name = class_name()的方式实例化,实例化操作创建该类的实例。
属性引用;使用class_name.attr_name的方式引用类属性。
实例对象
实例对象是类对象实例化的产物,实例对象仅支持一个操作:
属性引用;与类对象属性引用的方式相同,使用instance_name.attr_name的方式。

67、属性绑定

我们说的属性绑定,首先需要一个可变对象,才能执行绑定操作,使用objname.attr = attr_value的方式,为对象objname绑定属性attr。
这分两种情况:
若属性attr已经存在,绑定操作会将属性名指向新的对象;
若不存在,则为该对象添加新的属性,后面就可以引用新增属性。
类属性绑定
类属性的绑定发生在两个地方:
类定义时;
运行时任意阶段。

在类定义中,类属性的绑定并没有使用objname.attr = attr_value的方式,这是一个特例,其实是等同于后面使用类名绑定属性的方式。
因为是动态语言,所以可以在运行时增加属性,删除属性。
实例属性绑定
与类属性绑定相同,实例属性绑定也发生在两个地方:
类定义时;
运行时任意阶段。

类实例有两个特殊之处:
__init__在实例化时执行
Python实例调用方法时,会将实例对象作为第一个参数传递
因此,__init__方法中的self就是实例对象本身

68、属性引用

类属性引用
类属性的引用,肯定是需要类对象的,属性分为两种:
数据属性
函数属性
实例属性引用
使用实例对象引用属性稍微复杂一些,因为实例对象可引用类属性以及实例属性。但是实例对象引用属性时遵循以下规则:
总是先到实例对象中查找属性,再到类属性中查找属性;
属性绑定语句总是为实例对象创建新属性,属性存在时,更新属性指向的对象。

69、Python 中的 is 和 ==

is比较内存地址是否相同,==比较数值是否相同

30、isinstance 和 type 的区别

class A:
pass

class B(A):
pass

isinstance(A(), A) # returns True
type(A()) == A # returns True
isinstance(B(), A) # returns True
type(B()) == A # returns False

区别就是:
type()不会认为子类是一种父类类型。
isinstance()会认为子类是一种父类类型。

 

posted on 2019-02-28 14:12  liangliang123456  阅读(951)  评论(0编辑  收藏  举报

导航