学了一年多的Python,去年做了一段时间的爬虫项目,近来在做数据分析和机器学习的东西,抽空整理一下以前学的Python基础知识点,有借鉴与总结。具体知识点后续会分段展开深入。
1.到底什么是Python?你可以在回答中与其他技术进行对比(据说是某面试题)。答案:下面是一些关键点: l Python是一种解释型语言。这就是说,与C语言和C的衍生语言不同,Python代码在运行之前不需要编译。其他解释型语言还包括PHP和Ruby。 l Python是动态类型语言,指的是你在声明变量时,不需要说明变量的类型。你可以直接编写类似x=111和x="I'm a string"这样的代码,程序不会报错。 l Python非常适合面向对象的编程(OOP),因为它支持通过组合(composition)与继承(inheritance)的方式定义类(class)。Python中没有访问说明符(access specifier,类似C++中的public和private),这么设计的依据是“大家都是成年人了”。 l 在Python语言中,函数是第一类对象(firstclassobjects)。这指的是它们可以被指定给变量,函数既能返回函数类型,也可以接受函数作为输入。类(class)也是第一类对象。 l Python代码编写快,但是运行速度比编译语言通常要慢。好在Python允许加入基于C语言编写的扩展,因此我们能够优化代码,消除瓶颈,这点通常是可以实现的。numpy就是一个很好地例子,它的运行速度真的非常快,因为很多算术运算其实并不是通过Python实现的。 l Python用途非常广泛——网络应用,自动化,科学建模,大数据应用,等等。它也常被用作“胶水语言”,帮助其他语言和组件改善运行状况。 l Python让困难的事情变得容易,因此程序员可以专注于算法和数据结构的设计,而不用处理底层的细节。
2.这两个参数是什么意思:*args,**kwargs?我们为什么要使用它们?答案:如果我们不确定要往函数中传入多少个参数,或者我们想往函数中以列表和元组的形式传参数时,那就使要用*args;如果我们不知道要往函数中传入多少个关键词参数,或者想传入字典的值作为关键词参数时,那就要使用**kwargs。args和kwargs这两个标识符是约定俗成的用法,你当然还可以用*bob和**billy,但是这样就并不太妥。
3.简要描述Python的垃圾回收机制(garbage collection)。答案:这里能说的很多。你应该提到下面几个主要的点: l Python在内存中存储了每个对象的引用计数(reference count)。如果计数值变成0,那么相应的对象就会小时,分配给该对象的内存就会释放出来用作他用。 l 偶尔也会出现引用循环(reference cycle)。垃圾回收器会定时寻找这个循环,并将其回收。举个例子,假设有两个对象o1和o2,而且符合o1.x == o2和o2.x == o1这两个条件。如果o1和o2没有其他代码引用,那么它们就不应该继续存在。但它们的引用计数都是1。 l Python中使用了某些启发式算法(heuristics)来加速垃圾回收。例如,越晚创建的对象更有可能被回收。对象被创建之后,垃圾回收器会分配它们所属的代(generation)。每个对象都会被分配一个代,而被分配更年轻代的对象是优先被处理的。
4.|说说你对zen of python的理解,你有什么办法看到它?答案:Python之禅,Python秉承一种独特的简洁和可读行高的语法,以及高度一致的编程模 式,符合“大脑思维习惯”,使Python易于学习、理解和记忆。Python同时采用了一条 极简主义的设计理念,了解完整的Python哲学理念,可以在任何一个Python交互解释器 中键入import this命令,这是Python隐藏的一个彩蛋:描绘了一系列Python设计原则。 如今已是Python社区内流行的行话"EIBTI",明了胜于晦涩这条规则的简称. 在Python 的思维方式中,明了胜于晦涩,简洁胜于复杂。
5.是否遇到过python的模块间循环引用的问题,如何避免它?答案:这是代码结构设计的问题,模块依赖和类依赖 如果老是觉得碰到循环引用,很可能是模块的分界线划错地方了。可能是把应该在一起的东西硬拆开了,可能是某些职责放错地方了,可能是应该抽象的东西没抽象 总之微观代码规范可能并不能帮到太多,重要的是更宏观的划分模块的经验技巧,推荐uml,脑图,白板等等图形化的工具先梳理清楚整个系统的总体结构和职责分工采取办法,从设计模式上来规避这个问题,比如: 1. 使用 “__all__”白名单开放接口 2. 尽量避免 import
6.有用过with statement吗?它的好处是什么?with open('text.txt') as myfile: ... while True: ... line = myfile.readline() ... if not line: ... break ... print line, #with语句使用所谓的上下文管理器对代码块进行包装,允许上下文管理器实现一些设置和清理操作。 # 例如:文件可以作为上下文管理器使用,它们可以关闭自身作为清理的一部分。 # NOTE:在PYTHON2.5中,需要使用from __future__ import with_statement进行with语句的导入
7.Python里面search()和match()的区别>>> import re >>> re.match(r'python','Programing Python, should be pythonic') >>> obj1 = re.match(r'python','Programing Python, should be pythonic') #返回None >>> obj2 = re.search(r'python','Programing Python, should be pythonic') #找到pythonic >>> obj2.group() 'python' #re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;#re.search匹配整个字符串,直到找到一个匹配。
8.Python程序中文输出问题怎么解决在Python3中,对中文进行了全面的支持,但在Python2.x中需要进行相关的设置才能使用中文。否则会出现乱码。 Python默认采取的ASCII编码,字母、标点和其他字符只使用一个字节来表示,但对于中文字符来说,一个字节满足不了需 求。为了能在计算机中表示所有的中文字符,中文编码采用两个字节表示。如果中文编码和ASCII混合使用的话,就会导致解码错误,从而才生乱码。 解决办法: 交互式命令中:一般不会出现乱码,无需做处理 py脚本文件中:跨字符集必须做设置,否则乱码 1. 首先在开头一句添加: # coding = utf‐8 # 或 # coding = UTF‐8 # 或 # ‐*‐ coding: utf‐8 ‐*‐ 2. 其次需将文件保存为UTF‐8的格式! 3. 最后: s.decode('utf‐8').encode('gbk')
9.什么是lambda函数函数使用: 1. 代码块重复,这时候必须考虑到函数,降低程序的冗余度 2. 代码块复杂,这时候必须考虑到函数,降低程序的复杂度 Python有两种函数,一种是def定义,一种是lambda函数() 当程序代码很短,且该函数只使用一次,为了程序的简洁,及节省变量内存占用空间,引入了匿名函数这个概念 >>> nums = range(2,20) >>> for i in nums: nums = filter(lambda x:x==i or x % i,nums) >>> nums [2, 3, 5, 7, 11, 13, 17, 19]
10.Python里面如何拷贝一个对象切片S[:] # 注不能应用于字典 深浅宝贝 # 能应用于所有序列和字典 1. 浅拷贝D.copy()方法 2. 深拷贝deepcopy(D)方法 11.Python中pass语句的作用是什么pass语句什么也不做,一般作为占位符或者创建占位程序
12.Python是如何进行内存管理的python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。所有这些都是自动完成,不需要像C一样,人工干预,从而提高了程序员的效率和程序的健壮性。
13.Python异常处理介绍一下程序中出现异常情况时就需要异常处理。比如当你打开一个不存在的文件时。当你的程序中有一些无效的语句时,Python会提示你有错误存在。下面是一个拼写错误的例子,print写成了Print 下面是异常最常见的几种角色 1. 错误处理 >>>可以在程序代码中捕捉和相应错误,或者忽略已发生的异常。 >>>如果忽略错误,PYTHON默认的异常处理行为将启动:停止程序,打印错误信息。 >>>如果不想启动这种默认行为,就用try语句来捕捉异常并从异常中恢复。 2. 事件通知 >>>异常也可用于发出有效状态的信号,而不需在程序间传递结果标志位。或者刻意对其进行测试 3. 特殊情况处理 >>>有时,发生了某种很罕见的情况,很难调整代码区处理。通常会在异常处理中处理,从而省去应对特殊情况的代码 4. 终止行为 >>>try/finally语句可确保一定会进行需要的结束运算,无论程序是否有异常 5. 非常规控制流程
14.介绍一下Python中的filter方法filter就像map,reduce,apply,zip等都是内置函数,用C语言实现,具有速度快,功能强大等 优点。 用于过滤与函数func()不匹配的值, 类似于SQL中select value != 'a' 相当于一个迭代器,调用一个布尔函数func来迭代seq中的每个元素,返回一个是bool_seq返 回为True的序列 >>>第一个参数: function or None, 函数或None >>>第二个参数: sequence,序列
15.介绍一下except的用法和作用try/except: 捕捉由PYTHON自身或写程序过程中引发的异常并恢复 except: 捕捉所有其他异常 except name: 只捕捉特定的异常 except name, value: 捕捉异常及格外的数据(实例) except (name1,name2) 捕捉列出来的异常 except (name1,name2),value: 捕捉任何列出的异常,并取得额外数据 else: 如果没有引发异常就运行 finally: 总是会运行此处代码
16.inspect模块有什么用inspect模块提供了一系列函数用于帮助使用自省。 检查对象类型 is{module|class|function|method|builtin}(obj): 检查对象是否为模块、类、函数、方法、内建函数或方法。 isroutine(obj): 用于检查对象是否为函数、方法、内建函数或方法等等可调用类型。 获取对象信息 getmembers(object[, predicate]): 这个方法是dir()的扩展版,它会将dir()找到的名字对应的属性一并返回。 getmodule(object): 它返回object的定义所在的模块对象。 get{file|sourcefile}(object): 获取object的定义所在的模块的文件名|源代码文件名(如果没有则返回None)。 get{source|sourcelines}(object): 获取object的定义的源代码,以字符串|字符串列表返回。 getargspec(func): 仅用于方法,获取方法声明的参数,返回元组,分别是(普通参数名的列表, *参数名, **参数名, 默认值元组)。
17.Python列表与元组的区别是什么?分别在什么情况下使用?Python中列表和元组是序列,因此都能进行添加,删除,更新,切片等操作。但列表是可变对象,元祖是不可变对象。 元祖主要用于函数赋值,字符串格式化等。但列表中的方法更多些,也是PYTHON中更常用的数据结构。
18.解释一下python的and-or语法0 and *不需要再考虑*是0还是1,结果是0 1 and *需要考虑*是0还是1来决定结果。 1 or *不需要考虑后面的*,结果为1 0 or *需要考虑后面的*来决定结果 这个语法看起来类似于 C 语言中的 bool ? a : b 表达式。整个表达式从左到右进行演算,所以先进行 and 表达式的演算。 1 and 'first' 演算值为 'first',然后 'first' or 'second' 的演算值为 'first'。 0 and 'first' 演算值为False,然后 0 or 'second' 演算值为 'second'。 and‐or主要是用来模仿三目运算符 bool?a:b的,即当表达式bool为真,则取a否则取b。 and‐or 技巧,bool and a or b 表达式,当a 在布尔上下文中的值为假时,不会像 C 语言表达式 bool ? a : b 那样工作。
19.在Python中, list, tuple, dict, set有什么区别, 主要应用在什么样的场景?解答:定义list: 链表, 有序的项目, 通过索引进行查找, 使用方括号"[]"; tuple: 元组, 元组将多样的对象集合到一起, 不能修改, 通过索引进行查找, 使用括号"()"; dict: 字典, 字典是一组键(key)和值(value)的组合, 通过键(key)进行查找, 没有顺序, 使用大括号"{}"; set: 集合,无序, 元素只出现一次, 自动去重, 使用"set([])"; 应用场景: list, 简单的数据集合, 可以使用索引; tuple, 把一些数据当做一个整体去使用, 不能修改; dict, 使用键值和值进行关联的数据; set, 数据只出现一次, 只关心数据是否出现, 不关心其位置; 代码: mylist = [1, 2, 3, 4, 'Oh'] mytuple = (1, 2, 'Hello', (4, 5)) mydict = {'Wang' : 1, 'Hu' : 2, 'Liu' : 4} myset = set(['Wang', 'Hu', 'Liu', 4, 'Wang'])
20. 静态函数, 类函数, 成员函数的区别?解答: 定义: 静态函数(@staticmethod): 即静态方法,主要处理与这个类的逻辑关联; 类函数(@classmethod): 即类方法, 更关注于从类中调用方法, 而不是在实例中调用方法, 可以用作方法重载, 传入参数cls; 成员函数: 实例的方法, 只能通过实例进行调用; 具体应用: 日期的方法, 可以通过实例化(__init__)进行数据输出, 传入参数self; 可以通过类的方法(@classmethod)进行数据转换, 传入参数cls; 可以通过静态方法(@staticmethod)进行数据验证; 代码: # -*- coding: utf-8 -*- #eclipse pydev, python 3.3 #by C.L.Wang class Date(object): day = 0 month = 0 year = 0 def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year
def display(self): return "{0}*{1}*{2}".format(self.day, self.month, self.year)
@classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('-')) date1 = cls(day, month, year) return date1
@staticmethod def is_date_valid(date_as_string): day, month, year = map(int, date_as_string.split('-')) return day <= 31 and month <= 12 and year <= 3999
date1 = Date('12', '11', '2014') date2 = Date.from_string('11-13-2014') print(date1.display()) print(date2.display()) print(date2.is_date_valid('11-13-2014')) print(Date.is_date_valid('11-13-2014'))
21. a=1, b=2, 不用中间变量交换a和b的值解答: 两种形式: 加法或异或 代码: a = 1 b = 2 a = a + b b = a - b a = a - b print ('a = {0}, b = {1}'.format(a, b)) a = a ^ b b = a ^ b a = a ^ b print ('a = {0}, b = {1}'.format(a, b))
22. 写一个函数, 输入一个字符串, 返回倒序排列的结果: 如: string_reverse(‘abcdef’), 返回: ‘fedcba’(请采用多种方法实现, 并对实现方法进行比较)解答: 5种方法的比较: 1. 简单的步长为-1, 即字符串的翻转; 2. 交换前后字母的位置; 3. 递归的方式, 每次输出一个字符; 4. 双端队列, 使用extendleft()函数; 5. 使用for循环, 从左至右输出; 代码: string = 'abcdef' def string_reverse1(string): return string[::-1] def string_reverse2(string): t = list(string) l = len(t) for i,j in zip(range(l-1, 0, -1), range(l//2)): t[i], t[j] = t[j], t[i] return "".join(t) def string_reverse3(string): if len(string) <= 1: return string return string_reverse3(string[1:]) + string[0] from collections import deque def string_reverse4(string): d = deque() d.extendleft(string) return ''.join(d) def string_reverse5(string): #return ''.join(string[len(string) - i] for i in range(1, len(string)+1)) return ''.join(string[i] for i in range(len(string)-1, -1, -1)) print(string_reverse1(string)) print(string_reverse2(string)) print(string_reverse3(string)) print(string_reverse4(string)) print(string_reverse5(string))
23.介绍一下python的异常处理机制解答:Python的异常处理机制: try: 尝试抛出异常; raise: 引发异常; except: 处理异常; finally: 是否发生异常都需要做的事情; 创建新的异常类型, 需要继承Exception类, 可以定义类的属性, 便于处理异常; 开发体会: 异常主要处理读取文件, 也可以使用with的方法读取文件; 还可以用于网络连接, 异常可以包含大量的错误信息, 进行错误处理.
代码: class ShortInputException(Exception): def __init__(self, length, atleast): Exception.__init__(self) self.length = length self.atleast = atleast
while True: try: text = raw_input('Enter somthing-->') if len(text) < 3: raise ShortInputException(len(text), 3) except EOFError: print('Why did you do an EOF on me') except ShortInputException as ex: print('ShortInputException The input was {0} long, \ excepted at least {1}. '.format(ex.length, ex.atleast)) else: print('No exception was raised. ') finally: print('Over')
24.Python自省这个也是python彪悍的特性.自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时能够获得对象的类型.比如type(),dir(),getattr(),hasattr(),isinstance().
25.Python中重载函数重载主要是为了解决两个问题。 l 可变参数类型。 l 可变参数个数。 另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两个函数的功能其实不同,那么不应当使用重载,而应当使用一个名字不同的函数。 好吧,那么对于情况 1 ,函数功能相同,但是参数类型不同,python 如何处理?答案是根本不需要处理,因为python 可以接受任何类型的参数,如果函数的功能相同,那么不同的参数类型在 python 中很可能是相同的代码,没有必要做成两个不同函数。 那么对于情况 2 ,函数功能相同,但参数个数不同,python 如何处理?大家知道,答案就是缺省参数。对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。 好了,鉴于情况 1 跟 情况 2 都有了解决方案,python 自然就不需要函数重载了。 26.__new__和__init__的区别这个__new__确实很少见到,先做了解吧. l __new__是一个静态方法,而__init__是一个实例方法. l __new__方法会返回一个创建的实例,而__init__什么都不返回. l 只有在__new__返回一个cls的实例时后面的__init__才能被调用. l 当创建一个新实例时调用__new__,初始化一个实例时用__init__. ps: __metaclass__是创建类时起作用.所以我们可以分别使用__metaclass__,__new__和__init__来分别在类创建,实例创建和实例初始化的时候做一些小手脚.
|
|