> 文档中心 > 你真的了解Python吗?Python一些常见问题总结(一)

你真的了解Python吗?Python一些常见问题总结(一)

你真的了解Python吗?Python一些常见问题总结(一)

  • 前言
  • Python40问
  • 参考链接

前言

本文整理和解答了关于python的一些常见问题,由于水平有限,难免出现错漏,敬请批评改正。

Python40问

  1. 什么是 Python?
  • Python-百度百科
  • Python官网
  • Python3 菜鸟教程
  • Python 是一种解释型语言。这就是说,与 C 语言和 C 的衍生语言不同,Python 代码在运行之前不需要编译。其他解释型语言还包括 PHP 和 Ruby。
  • Python 是动态类型语言,指的是你在声明变量时,不需要说明变量的类型。你可以直接编写类似 x=111 和 x="I’m a string"这样的代码,程序不会报错。
  • Python 非常适合面向对象的编程(OOP),因为它支持通过组合(composition)与继承(inheritance)的方式定义类(class)。
  • Python 中没有访问说明符(access specifier,类似 C++中的 public 和 private),这么设计的依据是“大家都是成年人了”。
  • 在 Python 语言中,函数是第一类对象(first-class objects)。这指的是它们可以被指定给变量,函数既能返回函数类型,也可以接受函数作为输入。类(class)也是第一类对象。
  • Python 代码编写快,但是运行速度比编译语言通常要慢。好在 Python 允许加入基于 C语言编写的扩展,因此我们能够优化代码,消除瓶颈,这点通常是可以实现的。numpy 就是一个很好地例子,它的运行速度真的非常快,因为很多算术运算其实并不是通过 Python 实现的。
  • Python 用途非常广泛——网络应用,自动化,科学建模,大数据应用,等等。它也常被用作“胶水语言”,帮助其他语言和组件改善运行状况。
  • Python 让困难的事情变得容易,因此程序员可以专注于算法和数据结构的设计,而不用处理底层的细节。
  1. 什么是 PEP8?
  • PEP8 是一个Python 代码风格指南、编程规范,内容是一些关于如何让你的程序更具可读性的建议,本文档所提供的编码规范,适用于主要的Python发行版中组成标准库的Python代码。
  • PEP8 官网
  1. 什么是 pickling 和 unpickling?
  • Pickle 模块读入任何 Python 对象,将它们转换成字符串,然后使用 dump 函数将其转储到一个文件中——这个过程叫做 pickling。
  • pickle.dump(obj, file, [,protocol])
  • 从存储的字符串文件中提取原始 Python 对象的过程,叫做 unpickling
  • pickle.load(file)
import pickle# 使用pickle模块将数据对象保存到文件data1 = {'a': [1, 2.0, 3, 4+6j],  'b': ('string', u'Unicode string'),  'c': None}data2 = (1,2,3)selfref_list = [1, 2, 3]selfref_list.append(selfref_list)output = open('data.pkl', 'wb')# Pickle字典使用协议0pickle.dump(data1, output)# Pickle使用协议1pickle.dump(data2, output)# 使用可用的最高协议Pickle列表pickle.dump(selfref_list, output, -1)output.close()#使用pickle模块从文件中重构python对象pkl_file = open('data.pkl', 'rb')data1 = pickle.load(pkl_file)print(data1)data2 = pickle.load(pkl_file)print(data2)data3 = pickle.load(pkl_file)print(data3)pkl_file.close()
{'a': [1, 2.0, 3, (4+6j)], 'b': ('string', 'Unicode string'), 'c': None}(1, 2, 3)[1, 2, 3, [...]]
  1. Python 是如何被解释的?
  • Python 是一种解释性语言,它的源代码可以直接运行。Python 解释器会将源代码转换成中间语言,之后再翻译成机器码再执行。
  1. Python 是怎样管理内存的?
  • Python 的内存管理是由私有 heap 空间管理的。所有的 Python 对象和数据结构都在一个私有 heap 中。程序员没有访问该 heap 的权限,只有解释器才能对它进行操作。
  • Python 的 heap 空间分配内存是由 Python 的内存管理模块进行的,其核心 API 会提供一些访问该模块的方法供程序员使用。
  • Python 有自带的垃圾回收系统,它回收并释放没有被使用的内存,让它们能够被其他程序使用。
  1. 有哪些工具可以帮助 debug 或做静态分析?
  • PyChecker 是一个静态分析工具,它不仅能报告源代码中的错误,并且会报告错误类型和复杂度。
  • Pylint 是检验模块是否达到代码标准的另一个工具。
  1. 什么是 Python 装饰器?
  • Python 装饰器是 Python 中的特有变动,可以使修改函数变得更容易。
  • 装饰器(Decorators)是 Python 的一个重要部分。
  • 简单地说:他们是修改其他函数的功能的函数(封装函数)。他们有助于让我们的代码更简短。
def a_new_decorator(a_func):     def wrapTheFunction(): print("I am doing some boring work before executing a_func()") a_func() print("I am doing some boring work after executing a_func()")    return wrapTheFunction def a_function_requiring_decoration():    print("I am the function which needs some decoration to remove my foul smell")a_function_requiring_decoration()# 现在a_function_requiring_decoration被wrapTheFunction()包装了a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)print('装饰后:')a_function_requiring_decoration()
I am the function which needs some decoration to remove my foul smell装饰后:I am doing some boring work before executing a_func()I am the function which needs some decoration to remove my foul smellI am doing some boring work after executing a_func()

上面,这正是 python 中装饰器做的事情!它们封装一个函数,并且用这样或者那样的方式来修改它的行为。现在你也许疑惑,我们在代码里并没有使用 @ 符号?那只是一个简短的方式来生成一个被装饰的函数。这里是我们如何使用 @ 来运行之前的代码:

from functools import wrapsdef decorator_name(f):    @wraps(f)    def decorated(*args, **kwargs): if not can_run:     return "Function will not run" return f(*args, **kwargs)    return decorated @decorator_name # 装饰器,相当于decorator_name(func)def func():    return("Function is running") can_run = Trueprint(func())# Function is running can_run = Falseprint(func()) # Function will not run
Function is runningFunction will not run

注意:@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint)。它们被大量使用于Flask和Django web框架中。

日志是装饰器运用的另一个亮点。例如:

from functools import wraps def logit(func):    @wraps(func)    def with_logging(*args, **kwargs): print(func.__name__ + " was called") return func(*args, **kwargs)    return with_logging @logit # 装饰器,相当于logit(addition_func)def addition_func(x):    return x + x result = addition_func(4)# addition_func was calledprint(result)
addition_func was called8
  1. 数组和元组之间的区别是什么?
  • 数组和元组之间的区别:数组内容是可以被修改的,而元组内容是只读的。另外,元组可以被哈希,比如作为字典的关键字。
hash((0,1,2)) # 元组可以被哈希,得到对应的哈希值
1267305975155491464
  1. 参数按值传递和引用传递是怎样实现的?
  • Python 中的一切都是类,所有的变量都是一个对象的引用。引用的值是由函数确定的,因此无法被改变。但是如果一个对象是可以被修改的,你可以改动对象。

  • 可更改(mutable)与不可更改(immutable)对象

    • 在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

      • 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a。

      • 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

  • python 函数的参数传递:

    • 不可变类型:类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。

    • 可变类型:类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响

  • python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

def change(a):    print(id(a))   # 指向的是同一个对象    a=10    print(id(a))   # 一个新对象a=1print(id(a))change(a) # 传不可变对象实例
135945849613594584961359458784

可以看见在调用函数前后,形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,形参指向的是不同的 id。

  • 传可变对象实例

可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。例如:

# 可写函数说明def change2(mylist):    "修改传入的列表"    mylist.append([1,2,3,4])    print ("函数内取值: ", mylist)    print("函数内id(mylist):",id(mylist))    return # 调用change2函数mylist = [10,20,30]print("函数外id(mylist):",id(mylist))change2(mylist)print ("函数外取值: ", mylist)
函数外id(mylist): 2594297892744函数内取值:  [10, 20, 30, [1, 2, 3, 4]]函数内id(mylist): 2594297892744函数外取值:  [10, 20, 30, [1, 2, 3, 4]]
  1. 字典推导式和列表推导式是什么?
  • 它们是可以轻松创建字典和列表的语法结构。

  • 列表推导式 - 计算 30 以内可以被 3 整除的整数:

multiples = [i for i in range(30) if i % 3 == 0]print(multiples)
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
  • 字典推导式 - 提供三个数字,以三个数字为键,三个数字的平方为值来创建字典:
dic = {x: x**2 for x in (2, 4, 6)}print(dic)print(type(dic))
{2: 4, 4: 16, 6: 36}
  1. Python 都有哪些自带的数据结构?
  • Python 自带的数据结构分为可变的和不可变的。
    • 可变的有:数组、集合、字典;
    • 不可变的有:字符串、元组、数
  1. 什么是 Python 的命名空间?
  • 在 Python 中,所有的名字都存在于一个空间中,它们在该空间中存在和被操作——这就是命名空间。
  • 它就好像一个盒子,每一个变量名字都对应装着一个对象。当查询变量的时候,会从该盒子里面寻找相应的对象
  • 命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。
  • 命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。
# var1 是全局名称var1 = 5def some_func():    # var2 是局部名称    var2 = 6    def some_inner_func(): # var3 是内嵌的局部名称 var3 = 7
  1. Python 中的 lambda 是什么?
  • 这是一个常被用于代码中的单个表达式的匿名函数。
  • 所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。
  • lambda 只是一个表达式,函数体比 def 简单很多。
  • lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
  • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
x = lambda a : a + 10 print(x(5)) # x(a)
15
# 可写函数说明sum = lambda arg1, arg2: arg1 + arg2 # 调用sum函数print ("相加后的值为 : ", sum( 10, 20 ))print ("相加后的值为 : ", sum( 20, 20 ))
相加后的值为 :  30相加后的值为 :  40
def myfunc(n):    return lambda a : a * n mydoubler = myfunc(2)mytripler = myfunc(3) print(mydoubler(11))print(mytripler(11))
2233
  1. 为什么 lambda 没有语句?
  • 匿名函数 lambda 没有语句的原因,是它被用于在代码被执行的时候构建新的函数对象并且
    返回。
  1. Python 中的 pass 是什么?
  • Pass 是一个在 Python 中不会被执行的语句。在复杂语句中,如果一个地方需要暂时被留白,它常常被用于占位符。
# 输出 Python 的每个字母for letter in 'Python':    if letter == 'h': pass print ('这是 pass 块')    print ('当前字母 :', letter)print ("END!")
当前字母 : P当前字母 : y当前字母 : t这是 pass 块当前字母 : h当前字母 : o当前字母 : nEND!
  • pass 语句不会执行任何操作,一般作为占位符或者创建占位程序,如
while False:    pass
  1. Python 中什么是遍历器?
  • 遍历器用于遍历一组元素,比如列表这样的容器。
  1. Python 中的 unittest 是什么?
  • 在 Python 中,unittest 是 Python 中的单元测试框架。它拥有支持共享搭建、自动测试、在测试中暂停代码、将不同测试迭代成一组,等等的功能。
  • unittest模块不像 doctest模块那么容易使用,不过它可以在一个独立的文件里提供一个更全面的测试集:
import unittestclass TestStatisticalFunctions(unittest.TestCase):    def test_average(self): self.assertEqual(average([20, 30, 70]), 40.0) self.assertEqual(round(average([1, 5, 7]), 1), 4.3) self.assertRaises(ZeroDivisionError, average, []) self.assertRaises(TypeError, average, 20, 30, 70)unittest.main() # 从命令行调用将调用所有测试
E======================================================================ERROR: C:\Users\TFX\AppData\Roaming\jupyter\runtime\kernel-1e1a7ebb-89d6-4e47-9989-8c6a327199db (unittest.loader._FailedTest)----------------------------------------------------------------------AttributeError: module '__main__' has no attribute 'C:\Users\TFX\AppData\Roaming\jupyter\runtime\kernel-1e1a7ebb-89d6-4e47-9989-8c6a327199db'----------------------------------------------------------------------Ran 1 test in 0.001sFAILED (errors=1)An exception has occurred, use %tb to see the full traceback.SystemExit: TrueE:\Users\TFX\Anaconda3\envs\tensorflow24\lib\site-packages\IPython\core\interactiveshell.py:3351: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.  warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
  1. 在 Python 中什么是 slicing?
  • Slicing 是一种在有序的对象类型中(数组,元组,字符串)节选某一段的语法
  • slice() 函数实现切片对象,主要用在切片操作函数里的参数传递。
myslice = slice(5)    # 设置截取5个元素的切片print(myslice)arr = range(10)print(arr)print(arr[myslice])# 截取 5 个元素
slice(None, 5, None)range(0, 10)range(0, 5)
  1. 在 Python 中什么是构造器?
  • 生成器是实现迭代器的一种机制。它功能的实现依赖于 yield 表达式,除此之外它跟普通的函数没有两样。
# 创建一个迭代器class MyNumbers:    '''    __iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。    __next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。    创建一个返回数字的迭代器,初始值为 1,逐步递增 1:    '''    def __iter__(self): self.a = 1 return self    def __next__(self): x = self.a self.a += 1 return xmyclass = MyNumbers()myiter = iter(myclass) print(next(myiter))print(next(myiter))print(next(myiter))print(next(myiter))print(next(myiter))
12345
class MyNumbers:    def __iter__(self): self.a = 1 return self    def __next__(self): if self.a <= 20:     x = self.a     self.a += 1     return x else:     raise StopIterationmyclass = MyNumbers()myiter = iter(myclass) for x in myiter:    print(x)
1234567891011121314151617181920
  1. Python 中的 docstring 是什么?
  • Python 中文档字符串被称为 docstring,它在 Python 中的作用是为函数、模块和类注释生成文档
  1. 如何在 Python 中拷贝一个对象?
  • 赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。
  • 浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变),例如,完全切片方法;工厂函数,如 list();copy 模块的 copy()函数。
  • 深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变),例如,copy 模块的 deep.deepcopy()函数。
  • 如果要在 Python 中拷贝一个对象,大多时候你可以用 copy.copy()或者 copy.deepcopy()。但并不是所有的对象都可以被拷贝。
import copya = [1,2,3]b = ac = a.copy()d = copy.deepcopy(a)print("id(a)",id(a))print("id(b)",id(b))print("id(c)",id(c))print("id(d)",id(d))
id(a) 2594298381064id(b) 2594298381064id(c) 2594298155144id(d) 2594298124040
  1. Python 中的负索引是什么?
  • Python 中的序列索引可以是正也可以是负。如果是正索引,0 是序列中的第一个索引,1是第二个索引。如果是负索引,(-1)是最后一个索引而(-2)是倒数第二个索引。
  1. 如何将一个数字转换成一个字符串?
  • 你可以使用自带函数 str()将一个数字转换为字符串。如果你想要八进制或者十六进制数,可以用 oct()或 hex()
num = 1print(str(num))print(oct(num))print(hex(num))
10o10x1
  1. Xrange 和 range 的区别是什么?
  • Xrange 用于返回一个 xrange 对象,而 range 用于返回一个数组。不管那个范围多大,Xrange 都使用同样的内存。
  • xrange() 函数用法与 range 完全相同,所不同的是生成的不是一个数组,而是一个生成器。
  • 注意:python3 取消了 xrange() 函数,并且和 range() 函数合并为 range()。
  1. Python 中的模块和包是什么?
  • 在 Python 中,模块是搭建程序的一种方式。每一个 Python 代码文件都是一个模块,并可以引用其他的模块,比如对象和属性。一个包含许多 Python 代码的文件夹是一个包。一个包可以包含模块和子文件夹
  1. Python 是如何进行内存管理的?
  • 从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制。
    1. 对象的引用计数机制

      • Python 内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
        • 引用计数增加的情况:
          • 一个对象分配一个新名称
          • 将其放入一个容器中(如列表、元组或字典)
        • 引用计数减少的情况:
          • 使用 del 语句对对象别名显示的销毁
          • 引用超出作用域或被重新赋值
      • sys.getrefcount( )函数可以获得对象的当前引用计数
      • 多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。
    2. 垃圾回收

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

      • Python 提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
        • Pymalloc 机制。为了加速 Python 的执行效率,Python 引入了一个内存池机制,用于管理对小块内存的申请和释放。
        • Python 中所有小于 256 个字节的对象都使用 pymalloc 实现的分配器,而大的对象则使用系统的 malloc。
        • 对于 Python 对象,如整数,浮点数和 List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
  1. 什么是 lambda 函数?它有什么好处?
  • lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数
  • lambda 函数:首要用途是指点短小的回调函数
  • lambda [arguments]:expression
a=lambda x,y:x+ya(3,11)# lambda(3,11):3+11,此表达式只是为了方便说明,语法是错误的
14
  1. Python 里面如何实现 tuple 和 list 的转换?
  • 直接使用 tuple 和 list 函数就行了,type()可以判断对象的类型
a = (1,2,3)b = [1,2,3]print(a,b)print(list(a),tuple(b))
(1, 2, 3) [1, 2, 3][1, 2, 3] (1, 2, 3)
  1. Python 代码实现删除一个 list 里面的重复元
    1. 使用 set 集合函数,set(list),利用集合元素不重复的性质
a=[1,2,4,2,4,5,6,5,7,8,9,0,10,2,4,6]set(a)
{0, 1, 2, 4, 5, 6, 7, 8, 9, 10}
    1. 使用字典函数,利用字典的关键字不重复的性质
a=[1,2,4,2,4,5,6,5,7,8,9,0,10,2,4,6]b={}b=b.fromkeys(a)list(b.keys())
[1, 2, 4, 5, 6, 7, 8, 9, 0, 10]
  1. 用 sort 进行排序,然后从最后一个元素开始判断,去重
a=[1,2,4,2,4,5,6,5,7,8,9,0,10,2,4,6]a.sort()last=a[-1]for i in range(len(a)-2,-1,-1):    if last==a[i]: del a[i]    else: last=a[i]print(a)
[0, 1, 2, 4, 5, 6, 7, 8, 9, 10]
  1. except 的用法和作用?
  • try…except…except…[else…][finally…]
  • 执行 try 下的语句,如果引发异常,则执行过程会跳到 except 语句。对每个 except 分支顺序尝试执行,如果引发的异常与 except 中的异常组匹配,执行相应的语句。
  • 如果所有的 except 都不匹配,则异常会传递到下一个调用本代码的最高层 try 代码中。
  • try 下的语句正常执行,则执行 else 块代码。如果发生异常,就不会执行。
  • 如果存在 finally 语句,最后总是会执行。
  1. range()函数的用法?
  • 列出一组数据,经常用在 for in range()循环中
for i in range(10):    print(i,end=" ")
0 1 2 3 4 5 6 7 8 9 
  1. 如何用 Python 来进行查询和替换一个文本字符串?
  • 可以使用 re 模块中的 sub()函数或者 subn()函数来进行查询和替换,
  • 格式:sub(replacement, string[,count=0])
  • replacement 是被替换成的文本,string 是需要被替换的文本,count 是一个可选参数,指最大被替换的数量.
import rep=re.compile('blue|white|red')print(p.sub('colour','blue socks and red shoes'))print(p.sub('colour','blue socks and red shoes',count=1))
colour socks and colour shoescolour socks and red shoes
  • subn()方法执行的效果跟 sub()一样,不过它会返回一个二维数组,包括替换后的新的字符串和总共替换的数量
import rep=re.compile('blue|white|red')print(p.subn('colour','blue socks and red shoes'))print(p.subn('colour','blue socks and red shoes',count=1))
('colour socks and colour shoes', 2)('colour socks and red shoes', 1)
  1. Python 里面 match()和 search()的区别?
  • re 模块中 match(pattern,string[,flags]),检查 string 的开头是否与 pattern 匹配。
  • re 模块中 re.search(pattern,string[,flags]),在 string 搜索 pattern 的第一个匹配值。
import reprint(re.match('super', 'superstition').span())print(re.match('super', 'insuperable'))print(re.search('super', 'superstition').span())print(re.search('super', 'insuperable').span())
(0, 5)None(0, 5)(2, 7)
  1. 用 Python 匹配 HTML tag 的时候,和有什么区别?
  • 贪婪匹配( )和非贪婪匹配( )
import res = 'Title'print(re.match('', s).group())
Title
import res = 'Title'print(re.match('', s).group())
  1. 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):返回指定范围内的浮点数。
import randomrandom.randint(0,10)
10
random.randrange(0,10,2)
2
random.random()
0.3569320956561295
random.uniform(0,1)
0.5371507256725325
  1. 有没有一个工具可以帮助查找 python 的 bug 和进行静态的代码分析?
  • PyChecker 是一个 python 代码的静态分析工具,它可以帮助查找 python 代码的 bug, 会对代码的复杂度和格式提出警告
  • Pylint 是另外一个工具可以进行 codingstandard 检查。
  1. 如何在一个 function 里面设置一个全局的变量?
  • 解决方法是在 function 的开始插入一个 global 声明:
def f():    global a 
  1. 单引号,双引号,三引号的区别
  • 单引号和双引号是等效的,如果要换行,需要符号(),三引号则可以直接换行,并且可以包含注释,
  • 如果要表示 Let’s go 这个字符串,
    • 单引号:s = ‘Let\’s go’
    • 双引号:s = “Let’s go”
  • s = ‘I realy like “python”!’
s1 = 'Let\'s go's2 = "Let's go"s3 = 'I realy like "python"!'print(s1,'|',s2,'|',s3)
Let's go | Let's go | I realy like "python"!
  1. __init__和__new__的区别?
  • __init__在对象创建后,对对象进行初始化,只负责初始化。
  • __new__是在对象创建之前创建一个对象,并将该对象返回给__init__,只负责创建。

注:自定义 new() 方法一般并不常用,而且容易与 init() 相混淆。实际上这两个方法也确实相似,比如他们都是在创建类的实例时会被默认调用的方法,而且创建实例时传入的参数也都会传到这两个方法里。但他们也有很重要的区别,比如对 new() 的调用比 init() 要早,new() 有返回值,init() 没有。

真正完成构造实例工作的是 new() 方法,调用它需要一个默认参数 cls,就是将要返回的这个实例所属的类(MyClass)。一般情况下因为 new() 极少被覆盖,最终调用的都是 object.new()。这个时候我们的实例已经被创建了,就可以当做 self 参数传给 init() 了,init() 做的工作其实仅是初始化一些属性值之类的,与严格意义下的“构造”实例无关。

class Myclass(object):# 创建一个音乐播放器    def __init__(self):   # 初始化方法;对这个实例化对象再次加工 print("初始化")    def __new__(cls): print("创建对象,分配空间")    # 创建对象时,new方法会被自动调     instance = super().__new__(cls)   # 为对象分配空间# 创建对象my = Myclass()print(my)
创建对象,分配空间None
class Myclass(object):# 创建一个音乐播放器    def __init__(self):   # 初始化方法;对这个实例化对象再次加工 print("初始化")    def __new__(cls): print("创建对象,分配空间")    # 创建对象时,new方法会被自动调     instance = super().__new__(cls)   # 为对象分配空间 return instance   # 返回对象的引用,必须的有这个返回,不然self找不到对象# 创建对象my = Myclass()print(my)
创建对象,分配空间初始化

注:

  • self:self代表自身的意思,就是代表这个类对象自身的意思不代表类本身,创建对象后self就代表这个对象自身。
  • cls:cls代表这个类,这个类的所有属性、方法都在里面。
class SeftAndCls(object):# class(父类)    a = 'a'    @staticmethod  # 静态方法(装饰器)    def f1(): return SeftAndCls.a  # 正常     def f2(self): return 'f2'    @classmethod  # 类方法(装饰器)    def f3(cls, name): print('f3函数输出:') print('类.类属性调用一个类属性:',SeftAndCls.a)  # 使用类.类属性调用一个类属性 print('类.类方法调用一个类方法:',cls().f2()) # 使用类.类方法调用一个类方法  newobj = SeftAndCls()print('调用类的静态方法:', SeftAndCls.f1())print('正常调用:', newobj.f2())print('直接调用类属性', SeftAndCls.a)SeftAndCls.f3('World')
调用类的静态方法: a正常调用: f2直接调用类属性 af3函数输出:类.类属性调用一个类属性: a类.类方法调用一个类方法: f2

参考链接

  • Python-百度百科
  • Python官网
  • Python3 菜鸟教程
  • https://github.com/jackfrued/Python-Interview-Bible
  • https://github.com/taizilongxu/interview_python