摘要:本文主要向大家介绍了Python语言学习之月薪过万不是梦!2018年最全/最新Python面试题(整理汇总),通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。
本文主要向大家介绍了Python语言学习之月薪过万不是梦!2018年最全/最新Python面试题(整理汇总),通过具体的内容向大家展示,希望对大家学习Python语言有所帮助。
1.args和kwargs是什么意思?*
答:args表示可变参数(variadic arguments),它允许你传入0个或任意个无名参数,这些参数在函数调用时自动组装为一个tuple; kwargs表示关键字参数(keyword arguments),它允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。同时使用args和kwargs的时候,必须保证args在*kwargs之前。
释:*args 是用来发送一个(非键值对)可变数量的参数列表给一个函数
这里有个例子帮你理解这个概念:
<bi style="box-sizing: border-box; display: block;">def test_var_args(f_arg, *argv):</bi><bi style="box-sizing: border-box; display: block;"> print("first normal arg:", f_arg)</bi><bi style="box-sizing: border-box; display: block;"> for arg in argv:</bi><bi style="box-sizing: border-box; display: block;"> print("another arg through *argv:", arg)</bi><bi style="box-sizing: border-box; display: block;">test_var_args('yasoob', 'python', 'eggs', 'test')</bi>
这会产生如下输出:
<bi style="box-sizing: border-box; display: block;">first normal arg: yasoob</bi><bi style="box-sizing: border-box; display: block;">another arg through *argv: python</bi><bi style="box-sizing: border-box; display: block;">another arg through *argv: eggs</bi><bi style="box-sizing: border-box; display: block;">another arg through *argv: test</bi>
****kwargs 是允许你将不定长度的键值对, 作为参数传递给一个函数。 如果你想要在一个函数里处理带名字的参数, 你应该使用kwargs。
这里有个让你上手的例子:
<bi style="box-sizing: border-box; display: block;">def greet_me(**kwargs):</bi> <bi style="box-sizing: border-box; display: block;">for key, value in kwargs.items():</bi><bi style="box-sizing: border-box; display: block;"> print("{0} == {1}".format(key, value))</bi><bi style="box-sizing: border-box; display: block;">>>> greet_me(name="yasoob")</bi><bi style="box-sizing: border-box; display: block;">name == yasoob</bi>
现在你可以看出我们怎样在一个函数里, 处理了一个键值对参数了。
什么时候使用它们?
这还真的要看你的需求而定。
最常见的用例是在写函数装饰器的时候。
此外它也可以用来做猴子补丁(monkey patching)。猴子补丁的意思是在程序运行时(runtime)修改某些代码。 打个比方,你有一个类,里面有个叫get_info的函数会调用一个API并返回相应的数据。如果我们想测试它,可以把API调用替换成一些测试数据。例如:
<bi style="box-sizing: border-box; display: block;">import someclass</bi><bi style="box-sizing: border-box; display: block;">def get_info(self, *args):</bi><bi style="box-sizing: border-box; display: block;"> return "Test data"</bi><bi style="box-sizing: border-box; display: block;">someclass.get_info = get_info</bi>
2.python里面如何拷贝一个对象?
答:
(1) 赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个;
(2)浅拷贝(copy.copy()),创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另一个也会被改变);
(3)深拷贝(copy.deepcopy()),创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另一个不会改变)
(注意:并不是所有的对象都可以拷贝)
释:Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果。
对象赋值
直接看一段代码:
<bi style="box-sizing: border-box; display: block;">will = ["Will", 28, ["Python", "C#", "JavaScript"]]</bi><bi style="box-sizing: border-box; display: block;">wilber = will</bi><bi style="box-sizing: border-box; display: block;">print id(will)</bi><bi style="box-sizing: border-box; display: block;">print will</bi><bi style="box-sizing: border-box; display: block;">print [id(ele) for ele in will]</bi><bi style="box-sizing: border-box; display: block;">print id(wilber)</bi><bi style="box-sizing: border-box; display: block;">print wilber</bi><bi style="box-sizing: border-box; display: block;">print [id(ele) for ele in wilber]</bi><bi style="box-sizing: border-box; display: block;">will[0] = "Wilber"</bi><bi style="box-sizing: border-box; display: block;">will[2].append("CSS")</bi><bi style="box-sizing: border-box; display: block;">print id(will)</bi><bi style="box-sizing: border-box; display: block;">print will</bi><bi style="box-sizing: border-box; display: block;">print [id(ele) for ele in will]</bi><bi style="box-sizing: border-box; display: block;">print id(wilber)</bi><bi style="box-sizing: border-box; display: block;">print wilber</bi><bi style="box-sizing: border-box; display: block;">print [id(ele) for ele in wilber]</bi>
代码的输出为:
<tt-image
contenteditable="false" data-render-status="finished"
data-syl-blot="image" style="box-sizing: border-box; cursor: text;
color: rgb(93, 93, 93); font-family: Helvetica, Arial, sans-serif;
font-size: 16px; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; font-weight: 400; letter-spacing: normal;
orphans: 2; text-align: left; text-indent: 0px; text-transform: none;
white-space: pre-wrap; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255);
text-decoration-style: initial; text-decoration-color: initial; display:
block;">
image
<input placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 420.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 841px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);"></tt-image>
下面来分析一下这段代码:
首先,创建了一个名为will的变量,这个变量指向一个list对象,从第一张图中可以看到所有对象的地址(每次运行,结果可能不同)
然后,通过will变量对wilber变量进行赋值,那么wilber变量将指向will变量对应的对象(内存地址),也就是说"wilber is will","wilber[i] is will[i]"
可以理解为,Python中,对象的赋值都是进行对象引用(内存地址)传递
第三张图中,由于will和wilber指向同一个对象,所以对will的任何修改都会体现在wilber上
这里需要注意的一点是,str是不可变类型,所以当修改的时候会替换旧的对象,产生一个新的地址39758496
<tt-image
contenteditable="false" data-render-status="finished"
data-syl-blot="image" style="box-sizing: border-box; cursor: text;
color: rgb(93, 93, 93); font-family: Helvetica, Arial, sans-serif;
font-size: 16px; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; font-weight: 400; letter-spacing: normal;
orphans: 2; text-align: left; text-indent: 0px; text-transform: none;
white-space: pre-wrap; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255);
text-decoration-style: initial; text-decoration-color: initial; display:
block;">
image
<input placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 420.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 841px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);"></tt-image>
浅拷贝
下面就来看看浅拷贝的结果:
<bi style="box-sizing: border-box; display: block;">import copy</bi><bi style="box-sizing: border-box; display: block;">will = ["Will", 28, ["Python", "C#", "JavaScript"]]</bi><bi style="box-sizing: border-box; display: block;">wilber = copy.copy(will)</bi><bi style="box-sizing: border-box; display: block;">print id(will)</bi><bi style="box-sizing: border-box; display: block;">print will</bi><bi style="box-sizing: border-box; display: block;">print [id(ele) for ele in will]</bi><bi style="box-sizing: border-box; display: block;">print id(wilber)</bi><bi style="box-sizing: border-box; display: block;">print wilber</bi><bi style="box-sizing: border-box; display: block;">print [id(ele) for ele in wilber]</bi><bi style="box-sizing: border-box; display: block;">will[0] = "Wilber"</bi><bi style="box-sizing: border-box; display: block;">will[2].append("CSS")</bi><bi style="box-sizing: border-box; display: block;">print id(will)</bi><bi style="box-sizing: border-box; display: block;">print will</bi><bi style="box-sizing: border-box; display: block;">print [id(ele) for ele in will]</bi><bi style="box-sizing: border-box; display: block;">print id(wilber)</bi><bi style="box-sizing: border-box; display: block;">print wilber</bi><bi style="box-sizing: border-box; display: block;">print [id(ele) for ele in wilber]</bi>
代码结果为:
<tt-image
contenteditable="false" data-render-status="finished"
data-syl-blot="image" style="box-sizing: border-box; cursor: text;
color: rgb(93, 93, 93); font-family: Helvetica, Arial, sans-serif;
font-size: 16px; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; font-weight: 400; letter-spacing: normal;
orphans: 2; text-align: left; text-indent: 0px; text-transform: none;
white-space: pre-wrap; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255);
text-decoration-style: initial; text-decoration-color: initial; display:
block;">
image
<input placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 420.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 841px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);"></tt-image>
分析一下这段代码:
首先,依然使用一个will变量,指向一个list类型的对象
然后,通过copy模块里面的浅拷贝函数copy(),对will指向的对象进行浅拷贝,然后浅拷贝生成的新对象赋值给wilber变量
浅拷贝会创建一个新的对象,这个例子中"wilber is not will"
但是,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址),也就是说"wilber[i] is will[i]"
当对will进行修改的时候
由于list的第一个元素是不可变类型,所以will对应的list的第一个元素会使用一个新的对象39758496
但是list的第三个元素是一个可不类型,修改操作不会产生新的对象,所以will的修改结果会相应的反应到wilber上
<tt-image
contenteditable="false" data-render-status="finished"
data-syl-blot="image" style="box-sizing: border-box; cursor: text;
color: rgb(93, 93, 93); font-family: Helvetica, Arial, sans-serif;
font-size: 16px; font-style: normal; font-variant-ligatures: normal;
font-variant-caps: normal; font-weight: 400; letter-spacing: normal;
orphans: 2; text-align: left; text-indent: 0px; text-transform: none;
white-space: pre-wrap; widows: 2; word-spacing: 0px;
-webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255);
text-decoration-style: initial; text-decoration-color: initial; display:
block;">
image
<input placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 420.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 841px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);"></tt-image>
总结一下,当我们使用下面的操作的时候,会产生浅拷贝的效果:
使用切片[:]操作
使用工厂函数(如list/dir/set)
使用copy模块中的copy()函数
3.简要描述python的垃圾回收机制
答:python中的垃圾回收是以引用计数为主,标记-清除和分代收集为辅。
引用计数:python在内存中存储每个对象的引用计数,如果计数变成0,该对象就会消失,分配给该对象的内存就会释放出来。
标记-清除:一些容器对象,比如说list、dict、tuple、instance等可能会出现引用循环,对于这些循环,垃圾回收器会定时回收这些循环(对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边)。
分代收集:python把内存根据对象存活时间划分为三代,对象创建之后,垃圾回收器会分配它们所属的代。每个对象都会被分配一个代,而被分配更年轻的代是被优先处理的,因此越晚创建的对象越容易被回收。
释:
python里也同java一样采用了垃圾收集机制,不过不一样的是:
python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略
引用计数机制:
python里每一个东西都是对象,它们的核心就是一个结构体:PyObject
<bi style="box-sizing: border-box; display: block;">typedef struct_object {</bi> <bi style="box-sizing: border-box; display: block;">int ob_refcnt;</bi> <bi style="box-sizing: border-box; display: block;">struct_typeobject *ob_type;</bi><bi style="box-sizing: border-box; display: block;">} PyObject;</bi>
PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少
<bi style="box-sizing: border-box; display: block;">#define Py_INCREF(op) ((op)->ob_refcnt++) //增加计数</bi><bi style="box-sizing: border-box; display: block;">#define Py_DECREF(op) \ //减少计数</bi> <bi style="box-sizing: border-box; display: block;">if (--(op)->ob_refcnt != 0) </bi> <bi style="box-sizing: border-box; display: block;">; </bi> <bi style="box-sizing: border-box; display: block;">else </bi> <bi style="box-sizing: border-box; display: block;">__Py_Dealloc((PyObject *)(op))</bi>
当引用计数为0时,该对象生命就结束了。
引用计数机制的优点:
简单
实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。
引用计数机制的缺点:
维护引用计数消耗资源
循环引用
<bi style="box-sizing: border-box; display: block;">list1 = []</bi><bi style="box-sizing: border-box; display: block;">list2 = []</bi><bi style="box-sizing: border-box; display: block;">list1.append(list2)</bi><bi style="box-sizing: border-box; display: block;">list2.append(list1)</bi>
list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。
对于如今的强大硬件,缺点1尚可接受,但是循环引用导致内存泄露,注定python还将引入新的回收机制。(标记清除和分代收集)
4.什么是lambda函数?它有什么好处?
答:lambda表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。
Python允许你定义一种单行的小函数。定义lambda函数的形式如下(lambda参数:表达式)lambda函数默认返回表达式的值。你也可以将其赋值给一个变量。lambda函数可以接受任意个参数,包括可选参数,但是表达式只有一个。
释:
简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。这一用法跟所谓 λ 演算(题目说明里的维基链接)的关系,有点像原子弹和质能方程的关系,差别其实还是挺大的。
不谈形式化的 λ 演算,只说有实际用途的匿名函数。先举一个普通的 Python 例子:将一个 list 里的每个元素都平方:
<bi style="box-sizing: border-box; display: block;">map( lambda x: x*x, [y for y in range(10)] )</bi>
这个写法要好过
<bi style="box-sizing: border-box; display: block;">def sq(x):</bi> <bi style="box-sizing: border-box; display: block;">return x * x</bi><bi style="box-sizing: border-box; display: block;">map(sq, [y for y in range(10)])</bi>
因为后者多定义了一个(污染环境的)函数,尤其如果这个函数只会使用一次的话。而且第一种写法实际上更易读,因为那个映射到列表上的函数具体是要做什么,非常一目了然。如果你仔细观察自己的代码,会发现这种场景其实很常见:你在某处就真的只需要一个能做一件事情的函数而已,连它叫什么名字都无关紧要。Lambda 表达式就可以用来做这件事。
进一步讲,匿名函数本质上就是一个函数,它所抽象出来的东西是一组运算。这是什么意思呢?类比
<bi style="box-sizing: border-box; display: block;">a = [1, 2, 3]</bi>
和
<bi style="box-sizing: border-box; display: block;">f = lambda x : x + 1</bi>
你会发现,等号右边的东西完全可以脱离等号左边的东西而存在,等号左边的名字只是右边之实体的标识符。如果你能习惯 [1, 2, 3] 单独存在,那么 lambda x : x + 1 也能单独存在其实也就不难理解了,它的意义就是给「某个数加一」这一运算本身。
现在回头来看 map() 函数,它可以将一个函数映射到一个可枚举类型上面。沿用上面给出的 a 和 f,可以写:
<bi style="box-sizing: border-box; display: block;">map(f, a)</bi>
也就是将函数 f 依次套用在 a 的每一个元素上面,获得结果 [2, 3, 4]。现在用 lambda 表达式来替换 f,就变成:
<bi style="box-sizing: border-box; display: block;">map( lambda x : x + 1, [1, 2, 3] )</bi>
会不会觉得现在很一目了然了?尤其是类比
<bi style="box-sizing: border-box; display: block;">a = [1, 2, 3]</bi><bi style="box-sizing: border-box; display: block;">r = []</bi><bi style="box-sizing: border-box; display: block;">for each in a:</bi> <bi style="box-sizing: border-box; display: block;">r.append(each+1)</bi>
这样的写法时,你会发现自己如果能将「遍历列表,给遇到的每个元素都做某种运算」的过程从一个循环里抽象出来成为一个函数 map,然后用 lambda 表达式将这种运算作为参数传给 map 的话,考虑事情的思维层级会高出一些来,需要顾及的细节也少了一点。Python 之中,类似能用到 lambda 表达式的「高级」函数还有 reduce、filter 等等,很多语言也都有这样的工具(不过这些特性最好不要在 Python 中用太多,原因详见 //www.zhihu.com/question/19794855/answer/12987428 的评论部分)。这种能够接受一个函数作为参数的函数叫做「高阶函数」(higher-order function),是来自函数式编程(functional programming)的思想。
和其他很多语言相比,Python 的 lambda 限制多多,最严重的当属它只能由一条表达式组成。这个限制主要是为了防止滥用,因为当人们发觉 lambda 很方便,就比较容易滥用,可是用多了会让程序看起来不那么清晰,毕竟每个人对于抽象层级的忍耐 / 理解程度都有所不同。
5.python如何实现单例模式?
答:单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个单例而且该单例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
new()在init()之前被调用,用于生成实例对象。利用这个方法和累的属性的特点可以实现设计模式的单例模式。单例模式是指创建唯一对象,单例模式设计的类只能实例。
1.使用new方法
<bi style="box-sizing: border-box; display: block;">class Singleton(object):</bi> <bi style="box-sizing: border-box; display: block;">def new(cls, *args, **kw):</bi> <bi style="box-sizing: border-box; display: block;">if not hasattr(cls, '_instance'):</bi> <bi style="box-sizing: border-box; display: block;">orig = super(Singleton, cls)</bi> <bi style="box-sizing: border-box; display: block;">cls._instance = orig.new(cls, *args, **kw)</bi> <bi style="box-sizing: border-box; display: block;">return cls._instance</bi><bi style="box-sizing: border-box; display: block;">class MyClass(Singleton):</bi> <bi style="box-sizing: border-box; display: block;">a = 1</bi>
2.共享属性
<bi style="box-sizing: border-box; display: block;">class Borg(object):</bi> <bi style="box-sizing: border-box; display: block;">_state = {}</bi> <bi style="box-sizing: border-box; display: block;">def new(cls, *args, **kw):</bi> <bi style="box-sizing: border-box; display: block;">ob = super(Borg, cls)。new(cls, *args, **kw)</bi> <bi style="box-sizing: border-box; display: block;">ob.dict = cls._state</bi> <bi style="box-sizing: border-box; display: block;">return ob</bi><bi style="box-sizing: border-box; display: block;">class MyClass2(Borg):</bi> <bi style="box-sizing: border-box; display: block;">a = 1</bi>
3.装饰器版本
<bi style="box-sizing: border-box; display: block;">def singleton(cls, *args, *kw):</bi> <bi style="box-sizing: border-box; display: block;">instances = {}</bi> <bi style="box-sizing: border-box; display: block;">def getinstance():</bi> <bi style="box-sizing: border-box; display: block;">if cls not in instances:</bi> <bi style="box-sizing: border-box; display: block;">instances[cls] = cls(args, **kw)</bi> <bi style="box-sizing: border-box; display: block;">return instances[cls]</bi> <bi style="box-sizing: border-box; display: block;">return getinstance</bi><bi style="box-sizing: border-box; display: block;">@singleton</bi><bi style="box-sizing: border-box; display: block;">class MyClass:</bi><bi style="box-sizing: border-box; display: block;">…</bi>
4.import方法
<bi style="box-sizing: border-box; display: block;">class My_Singleton(object):</bi> <bi style="box-sizing: border-box; display: block;">def foo(self):</bi> <bi style="box-sizing: border-box; display: block;">pass</bi><bi style="box-sizing: border-box; display: block;">my_singleton = My_Singleton()</bi><bi style="box-sizing: border-box; display: block;"># to use</bi><bi style="box-sizing: border-box; display: block;">from mysingleton import my_singleton</bi><bi style="box-sizing: border-box; display: block;">my_singleton.foo()</bi>
方法拓展:
<bi style="box-sizing: border-box; display: block;">#方法1,实现new方法 </bi><bi style="box-sizing: border-box; display: block;">#并在将一个类的实例绑定到类变量_instance上, </bi><bi style="box-sizing: border-box; display: block;">#如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回 </bi><bi style="box-sizing: border-box; display: block;">#如果cls._instance不为None,直接返回cls._instance </bi><bi style="box-sizing: border-box; display: block;">class Singleton(object): </bi><bi style="box-sizing: border-box; display: block;"> def new(cls, args, kw): </bi><bi style="box-sizing: border-box; display: block;"> if not hasattr(cls, '_instance'): </bi><bi style="box-sizing: border-box; display: block;"> orig = super(Singleton, cls) </bi><bi style="box-sizing: border-box; display: block;"> cls._instance = orig.new(cls, args, kw) </bi><bi style="box-sizing: border-box; display: block;"> return cls._instance </bi><bi style="box-sizing: border-box; display: block;">class MyClass(Singleton): </bi><bi style="box-sizing: border-box; display: block;"> a = 1 </bi><bi style="box-sizing: border-box; display: block;">one = MyClass() </bi><bi style="box-sizing: border-box; display: block;">two = MyClass() </bi><bi style="box-sizing: border-box; display: block;">two.a = 3 </bi><bi style="box-sizing: border-box; display: block;">print** one.a </bi><bi style="box-sizing: border-box; display: block;">#3 </bi><bi style="box-sizing: border-box; display: block;">#one和two完全相同,可以用id(), ==, is检测 </bi><bi style="box-sizing: border-box; display: block;">print id(one) </bi><bi style="box-sizing: border-box; display: block;">#29097904 </bi><bi style="box-sizing: border-box; display: block;">print id(two) </bi><bi style="box-sizing: border-box; display: block;">#29097904 </bi><bi style="box-sizing: border-box; display: block;">print one == two </bi><bi style="box-sizing: border-box; display: block;">#True </bi><bi style="box-sizing: border-box; display: block;">print one is two </bi><bi style="box-sizing: border-box; display: block;">#True </bi><bi style="box-sizing: border-box; display: block;">#方法2,共享属性;所谓单例就是所有引用(实例、对象)拥有相同的状态(属性)和行为(方法) </bi><bi style="box-sizing: border-box; display: block;">#同一个类的所有实例天然拥有相同的行为(方法), </bi><bi style="box-sizing: border-box; display: block;">#只需要保证同一个类的所有实例具有相同的状态(属性)即可 </bi><bi style="box-sizing: border-box; display: block;">#所有实例共享属性的最简单最直接的方法就是dict属性指向(引用)同一个字典(dict) </bi><bi style="box-sizing: border-box; display: block;">#可参看://code.activestate.com/recipes/66531/ </bi><bi style="box-sizing: border-box; display: block;">class Borg(object): </bi><bi style="box-sizing: border-box; display: block;"> _state = {} </bi><bi style="box-sizing: border-box; display: block;"> def new(cls, args, kw): </bi><bi style="box-sizing: border-box; display: block;"> ob = super(Borg, cls).new(cls, args, kw) </bi><bi style="box-sizing: border-box; display: block;"> ob.dict = cls._state </bi><bi style="box-sizing: border-box; display: block;"> return ob </bi><bi style="box-sizing: border-box; display: block;">class MyClass2(Borg): </bi><bi style="box-sizing: border-box; display: block;"> a = 1 </bi><bi style="box-sizing: border-box; display: block;">one = MyClass2() </bi><bi style="box-sizing: border-box; display: block;">two = MyClass2() </bi><bi style="box-sizing: border-box; display: block;">#one和two是两个不同的对象,id, ==, is对比结果可看出 </bi><bi style="box-sizing: border-box; display: block;">two.a = 3 </bi><bi style="box-sizing: border-box; display: block;">print** one.a </bi><bi style="box-sizing: border-box; display: block;">#3 </bi><bi style="box-sizing: border-box; display: block;">print id(one) </bi><bi style="box-sizing: border-box; display: block;">#28873680 </bi><bi style="box-sizing: border-box; display: block;">print id(two) </bi><bi style="box-sizing: border-box; display: block;">#28873712 </bi><bi style="box-sizing: border-box; display: block;">print one == two </bi><bi style="box-sizing: border-box; display: block;">#False </bi><bi style="box-sizing: border-box; display: block;">print one is two </bi><bi style="box-sizing: border-box; display: block;">#False </bi><bi style="box-sizing: border-box; display: block;">#但是one和two具有相同的(同一个dict属性),见: </bi><bi style="box-sizing: border-box; display: block;">print id(one.dict) </bi><bi style="box-sizing: border-box; display: block;">#30104000 </bi><bi style="box-sizing: border-box; display: block;">print id(two.dict) </bi><bi style="box-sizing: border-box; display: block;">#30104000 </bi><bi style="box-sizing: border-box; display: block;">#方法3:本质上是方法1的升级(或者说高级)版 ** </bi><bi style="box-sizing: border-box; display: block;">#使用metaclass(元类)的高级python用法 </bi><bi style="box-sizing: border-box; display: block;">class** Singleton2(type): </bi><bi style="box-sizing: border-box; display: block;"> def init(cls, name, bases, dict): </bi><bi style="box-sizing: border-box; display: block;"> super(Singleton2, cls).init(name, bases, dict) </bi><bi style="box-sizing: border-box; display: block;"> cls._instance = None </bi><bi style="box-sizing: border-box; display: block;"> def call(cls, args, kw): </bi><bi style="box-sizing: border-box; display: block;"> if cls._instance is None: </bi><bi style="box-sizing: border-box; display: block;"> cls._instance = super(Singleton2, cls).call(args, kw) </bi><bi style="box-sizing: border-box; display: block;"> return cls._instance </bi><bi style="box-sizing: border-box; display: block;">class MyClass3(object): </bi><bi style="box-sizing: border-box; display: block;"> metaclass = Singleton2 </bi><bi style="box-sizing: border-box; display: block;">one = MyClass3() </bi><bi style="box-sizing: border-box; display: block;">two = MyClass3() </bi><bi style="box-sizing: border-box; display: block;">two.a = 3 </bi><bi style="box-sizing: border-box; display: block;">print one.a </bi><bi style="box-sizing: border-box; display: block;">#3 </bi><bi style="box-sizing: border-box; display: block;">print id(one) </bi><bi style="box-sizing: border-box; display: block;">#31495472 </bi><bi style="box-sizing: border-box; display: block;">print id(two) </bi><bi style="box-sizing: border-box; display: block;">#31495472 </bi><bi style="box-sizing: border-box; display: block;">print one == two </bi><bi style="box-sizing: border-box; display: block;">#True </bi><bi style="box-sizing: border-box; display: block;">print one is two </bi><bi style="box-sizing: border-box; display: block;">#True </bi><bi style="box-sizing: border-box; display: block;">#方法4:也是方法1的升级(高级)版本, </bi><bi style="box-sizing: border-box; display: block;">#使用装饰器(decorator), </bi><bi style="box-sizing: border-box; display: block;">#这是一种更pythonic,更elegant的方法, </bi><bi style="box-sizing: border-box; display: block;">#单例类本身根本不知道自己是单例的,因为他本身(自己的代码)并不是单例的 </bi><bi style="box-sizing: border-box; display: block;">def singleton(cls, args, kw): </bi><bi style="box-sizing: border-box; display: block;"> instances = {} </bi><bi
本文由职坐标整理并发布,希望对同学们学习Python有所帮助,更多内容请关注职坐标编程语言Python频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号