你真的了解Python吗?Python一些常见问题总结(一)
你真的了解Python吗?Python一些常见问题总结(一)
- 前言
- Python40问
- 参考链接
前言
本文整理和解答了关于python的一些常见问题,由于水平有限,难免出现错漏,敬请批评改正。
Python40问
- 什么是 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 让困难的事情变得容易,因此程序员可以专注于算法和数据结构的设计,而不用处理底层的细节。
- 什么是 PEP8?
- PEP8 是一个Python 代码风格指南、编程规范,内容是一些关于如何让你的程序更具可读性的建议,本文档所提供的编码规范,适用于主要的Python发行版中组成标准库的Python代码。
- PEP8 官网
- 什么是 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, [...]]
- Python 是如何被解释的?
- Python 是一种解释性语言,它的源代码可以直接运行。Python 解释器会将源代码转换成中间语言,之后再翻译成机器码再执行。
- Python 是怎样管理内存的?
- Python 的内存管理是由私有 heap 空间管理的。所有的 Python 对象和数据结构都在一个私有 heap 中。程序员没有访问该 heap 的权限,只有解释器才能对它进行操作。
- Python 的 heap 空间分配内存是由 Python 的内存管理模块进行的,其核心 API 会提供一些访问该模块的方法供程序员使用。
- Python 有自带的垃圾回收系统,它回收并释放没有被使用的内存,让它们能够被其他程序使用。
- 有哪些工具可以帮助 debug 或做静态分析?
- PyChecker 是一个静态分析工具,它不仅能报告源代码中的错误,并且会报告错误类型和复杂度。
- Pylint 是检验模块是否达到代码标准的另一个工具。
- 什么是 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
- 数组和元组之间的区别是什么?
- 数组和元组之间的区别:数组内容是可以被修改的,而元组内容是只读的。另外,元组可以被哈希,比如作为字典的关键字。
hash((0,1,2)) # 元组可以被哈希,得到对应的哈希值
1267305975155491464
- 参数按值传递和引用传递是怎样实现的?
-
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]]
- 字典推导式和列表推导式是什么?
-
它们是可以轻松创建字典和列表的语法结构。
-
列表推导式 - 计算 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}
- Python 都有哪些自带的数据结构?
- Python 自带的数据结构分为可变的和不可变的。
- 可变的有:数组、集合、字典;
- 不可变的有:字符串、元组、数
- 什么是 Python 的命名空间?
- 在 Python 中,所有的名字都存在于一个空间中,它们在该空间中存在和被操作——这就是命名空间。
- 它就好像一个盒子,每一个变量名字都对应装着一个对象。当查询变量的时候,会从该盒子里面寻找相应的对象
- 命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。
- 命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。
# var1 是全局名称var1 = 5def some_func(): # var2 是局部名称 var2 = 6 def some_inner_func(): # var3 是内嵌的局部名称 var3 = 7
- 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
- 为什么 lambda 没有语句?
- 匿名函数 lambda 没有语句的原因,是它被用于在代码被执行的时候构建新的函数对象并且
返回。
- 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
- Python 中什么是遍历器?
- 遍历器用于遍历一组元素,比如列表这样的容器。
- 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)
- 在 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)
- 在 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
- Python 中的 docstring 是什么?
- Python 中文档字符串被称为 docstring,它在 Python 中的作用是为函数、模块和类注释生成文档
- 如何在 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
- Python 中的负索引是什么?
- Python 中的序列索引可以是正也可以是负。如果是正索引,0 是序列中的第一个索引,1是第二个索引。如果是负索引,(-1)是最后一个索引而(-2)是倒数第二个索引。
- 如何将一个数字转换成一个字符串?
- 你可以使用自带函数 str()将一个数字转换为字符串。如果你想要八进制或者十六进制数,可以用 oct()或 hex()
num = 1print(str(num))print(oct(num))print(hex(num))
10o10x1
- Xrange 和 range 的区别是什么?
- Xrange 用于返回一个 xrange 对象,而 range 用于返回一个数组。不管那个范围多大,Xrange 都使用同样的内存。
- xrange() 函数用法与 range 完全相同,所不同的是生成的不是一个数组,而是一个生成器。
- 注意:python3 取消了 xrange() 函数,并且和 range() 函数合并为 range()。
- Python 中的模块和包是什么?
- 在 Python 中,模块是搭建程序的一种方式。每一个 Python 代码文件都是一个模块,并可以引用其他的模块,比如对象和属性。一个包含许多 Python 代码的文件夹是一个包。一个包可以包含模块和子文件夹
- Python 是如何进行内存管理的?
- 从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制。
-
对象的引用计数机制
- Python 内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
- 引用计数增加的情况:
- 一个对象分配一个新名称
- 将其放入一个容器中(如列表、元组或字典)
- 引用计数减少的情况:
- 使用 del 语句对对象别名显示的销毁
- 引用超出作用域或被重新赋值
- 引用计数增加的情况:
- sys.getrefcount( )函数可以获得对象的当前引用计数
- 多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。
- Python 内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
-
垃圾回收
- 当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
- 当两个对象 a 和 b 相互引用时,del 语句可以减少 a 和 b 的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。
- 为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。
-
内存池机制
- Python 提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
- Pymalloc 机制。为了加速 Python 的执行效率,Python 引入了一个内存池机制,用于管理对小块内存的申请和释放。
- Python 中所有小于 256 个字节的对象都使用 pymalloc 实现的分配器,而大的对象则使用系统的 malloc。
- 对于 Python 对象,如整数,浮点数和 List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
- Python 提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
-
- 什么是 lambda 函数?它有什么好处?
- lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数
- lambda 函数:首要用途是指点短小的回调函数
- lambda [arguments]:expression
a=lambda x,y:x+ya(3,11)# lambda(3,11):3+11,此表达式只是为了方便说明,语法是错误的
14
- 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)
- Python 代码实现删除一个 list 里面的重复元
-
- 使用 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}
-
- 使用字典函数,利用字典的关键字不重复的性质
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]
- 用 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]
- except 的用法和作用?
- try…except…except…[else…][finally…]
- 执行 try 下的语句,如果引发异常,则执行过程会跳到 except 语句。对每个 except 分支顺序尝试执行,如果引发的异常与 except 中的异常组匹配,执行相应的语句。
- 如果所有的 except 都不匹配,则异常会传递到下一个调用本代码的最高层 try 代码中。
- try 下的语句正常执行,则执行 else 块代码。如果发生异常,就不会执行。
- 如果存在 finally 语句,最后总是会执行。
- range()函数的用法?
- 列出一组数据,经常用在 for in range()循环中
for i in range(10): print(i,end=" ")
0 1 2 3 4 5 6 7 8 9
- 如何用 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)
- 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)
- 用 Python 匹配 HTML tag 的时候,和有什么区别?
- 贪婪匹配( )和非贪婪匹配( )
import res = 'Title 'print(re.match('', s).group())
Title
import res = 'Title 'print(re.match('', s).group())
- 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
- 有没有一个工具可以帮助查找 python 的 bug 和进行静态的代码分析?
- PyChecker 是一个 python 代码的静态分析工具,它可以帮助查找 python 代码的 bug, 会对代码的复杂度和格式提出警告
- Pylint 是另外一个工具可以进行 codingstandard 检查。
- 如何在一个 function 里面设置一个全局的变量?
- 解决方法是在 function 的开始插入一个 global 声明:
def f(): global a
- 单引号,双引号,三引号的区别
- 单引号和双引号是等效的,如果要换行,需要符号(),三引号则可以直接换行,并且可以包含注释,
- 如果要表示 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"!
- __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