1 Python的函数参数传递

两个例子

  1. a = 1
  2. def fun(a):
  3. a = 2
  4. fun(a)
  5. print a #
  1. a = []
  2. def fun(a):
  3. a.append(1)
  4. fun(a)
  5. print a # [1]

所有的变量都可以理解是内存中一个对象的“引用”,或者,也可以看似c中void*的感觉。

通过id来看引用a的内存地址可以比较理解:

  1. a = 1
  2. def fun(a):
  3. print "func_in",id(a) # func_in 41322472
  4. a = 2
  5. print "re-point",id(a), id(2) # re-point 41322448 41322448
  6. print "func_out",id(a), id(1) # func_out 41322472 41322472
  7. fun(a)
  8. print a #

注:具体的值在不同电脑上运行时可能不同。

可以看到,在执行完a = 2之后,a引用中保存的值,即内存地址发生变化,由原来1对象的所在的地址变成了2这个实体对象的内存地址。

而第2个例子a引用保存的内存值就不会发生变化:

  1. a = []
  2. def fun(a):
  3. print "func_in",id(a) # func_in 53629256
  4. a.append(1)
  5. print "func_out",id(a) # func_out 53629256
  6. fun(a)
  7. print a # [1]

这里记住的是类型是属于对象的,而不是变量。而对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而 list, dict, set 等则是可以修改的对象。(这就是这个问题的重点)

当一个引用传递给函数的时候,函数自动复制一份引用,这个函数里的引用和外边的引用没有半毛关系了.所以第一个例子里函数把引用指向了一个不可变对象,当函数返回的时候,外面的引用没半毛感觉.而第二个例子就不一样了,函数内的引用指向的是可变对象,对它的操作就和定位了指针地址一样,在内存里进行修改.

2 Python中的元类(metaclass)

a.作用:

metaclass 就是创建类的那家伙。(事实上,type就是一个metaclass)

那么,metaclass就是用来创造“类对象”的类.它是“类对象”的“类”。  如下图所示:

b.如何创建:


  1. MyClass = MetaClass() #生成类对象
  2. MyObject = MyClass() #生成实例对象

也可以用我们上面学到的type来表示:

  1. MyClass = type('MyClass', (), {})

说白了,函数type就是一个特殊的metaclass.
       python在背后使用type创造了所有的类。type是所有类的metaclass.

metaclass就是创造类对象的工具.如果你喜欢,你也可以称之为"类的工厂".

type是python內置的metaclass。不过,你也可以编写自己的metaclass.

 __metaclass__ 属性 以及 创建过程

我们可以在一个类中加入 __metaclass__ 属性.

  1. class Foo(object):
  2. __metaclass__ = something...
  3. ...... # 省略

当你这么做了,python就会使用metaclass来创造类:Foo

注意啦,这里有些技巧的。

当你写下class Foo(object)的时候,类对象Foo还没有在内存中生成。

python会在类定义中寻找__metaclass__ 。如果找到了,python就会使用这个__metaclass__ 来创造类对象: Foo。如果没找到,python就使用type来创造Foo。

请把下面的几段话重复几遍:

当你写如下代码的时候:

  1. class Foo(Bar):
  2. pass

python做了以下事情:

Foo中有__metaclass__这个属性吗?
如果有,python会在内存中通过__metaclass__创建一个名字为Foo的类对象。
如果python没有在Foo中找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__,并尝试做和前面同样的操作。
如果python由下往上遍历父类也都没有找不到__metaclass__,它就会在模块(module)中去寻找__metaclass__,并尝试做同样的操作。
如果还是没有找不到__metaclass__, python才会用内置的type(这也是一个metaclass)来创建这个类对象。

现在问题来了,我们要怎么用代码来实现__metaclass__呢? 写一些可以用来产生类(class)的东西就行。

那什么可以产生类?无疑就是type,或者type的任何子类,或者任何使用到type的东西都行.

自定义metaclass

使用metaclass的主要目的,是为了能够在创建类的时候,自动地修改类。

例:一个很傻的需求,我们决定要将该模块中的所有类的属性,改为大写。

  1. # type也是一个类,我们可以继承它.
  2. class UpperAttrMetaclass(type):
  3. # __new__ 是在__init__之前被调用的特殊方法
  4. # __new__是用来创建对象并返回这个对象
  5. # 而__init__只是将传入的参数初始化给对象
  6. # 实际中,你很少会用到__new__,除非你希望能够控制对象的创建
  7. # 在这里,类是我们要创建的对象,我们希望能够自定义它,所以我们改写了__new__
  8. # 如果你希望的话,你也可以在__init__中做些事情
  9. # 还有一些高级的用法会涉及到改写__call__,但这里我们就先不这样.
  10.  
  11. def __new__(upperattr_metaclass, future_class_name,
  12. future_class_parents, future_class_attr):
  13.  
  14. uppercase_attr = {}
  15. for name, val in future_class_attr.items():
  16. if not name.startswith('__'):
  17. uppercase_attr[name.upper()] = val
  18. else:
  19. uppercase_attr[name] = val
  20. return type(future_class_name, future_class_parents, uppercase_attr)

这里的方式其实不是OOP(面向对象编程).因为我们直接调用了type,而不是改写父类的__type__方法.

  1. class UpperAttrMetaclass(type):
  2.  
  3. def __new__(upperattr_metaclass, future_class_name,
  4. future_class_parents, future_class_attr):
  5.  
  6. uppercase_attr = {}
  7. for name, val in future_class_attr.items():
  8. if not name.startswith('__'):
  9. uppercase_attr[name.upper()] = val
  10. else:
  11. uppercase_attr[name] = val
  12. return type.__new__(upperattr_metaclass, future_class_name,
  13. future_class_parents, uppercase_attr)

这样子看,我们只是复用了 type.__new__方法,这就是我们熟悉的基本的OOP编程,没什么魔法可言.

又或者:

  1. class UpperAttrMetaclass(type):
  2.  
  3. def __new__(cls, clsname, bases, attrs):
  4. uppercase_attr = {}
  5. for name, val in attrs.items():
  6. if not name.startswith('__'):
  7. uppercase_attr[name.upper()] = val
  8. else:
  9. uppercase_attr[name] = val
  10. return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, attrs)

使用了 metaclass 的代码是比较复杂,但我们使用它的原因并不是为了复杂, 而是因为我们通常会使用 metaclass 去做一些晦涩的事情,比如, 依赖于自省,控制继承等等。

确实,用 metaclass 来搞些“黑魔法”是特别有用的,因而会复杂化代码。

但就metaclass本身而言,它们其实是很简单的:中断类的默认创建、修改类、最后返回修改后的类.

c.运用场景:

实际用到metaclass的人,很清楚他们到底需要做什么,根本不用解释为什么要用.

metaclass 的一个主要用途就是构建API。

3 @staticmethod和@classmethod

Python其实有3个方法,即静态方法(staticmethod),类方法(classmethod)和实例方法,如下:

  1. def foo(x):
  2. print "executing foo(%s)"%(x)
  3.  
  4. class A(object):
  5. def foo(self,x):
  6. print "executing foo(%s,%s)"%(self,x)
  7.  
  8. @classmethod
  9. def class_foo(cls,x):
  10. print "executing class_foo(%s,%s)"%(cls,x)
  11.  
  12. @staticmethod
  13. def static_foo(x):
  14. print "executing static_foo(%s)"%x
  15.  
  16. a=A()

这里先理解下函数参数里面的self和cls.这个self和cls是对类或者实例的绑定,对于一般的函数来说我们可以这么调用foo(x),这个函数就是最常用的,它的工作跟任何东西(类,实例)无关.对于实例方法,我们知道在类里每次定义方法的时候都需要绑定这个实例,就是foo(self, x),为什么要这么做呢?因为实例方法的调用离不开实例,我们需要把实例自己传给函数,调用的时候是这样的a.foo(x)(其实是foo(a, x)).类方法一样,只不过它传递的是类而不是实例,A.class_foo(x).注意这里的self和cls可以替换别的参数,但是python的约定是这俩,还是不要改的好.

对于静态方法其实和普通的方法一样,不需要对谁进行绑定,唯一的区别是调用的时候需要使用a.static_foo(x)或者A.static_foo(x)来调用.

4 类变量和实例变量

类变量:

是可在类的所有实例之间共享的值(也就是说,它们不是单独分配给每个实例的)。例如下例中,num_of_instance 就是类变量,用于跟踪存在着多少个Test 的实例。

实例变量:

实例化之后,每个实例单独拥有的变量。

  1. class Test(object):
  2. num_of_instance = 0
  3. def __init__(self, name):
  4. self.name = name
  5. Test.num_of_instance += 1
  6.  
  7. if __name__ == '__main__':
  8. print Test.num_of_instance #
  9. t1 = Test('jack')
  10. print Test.num_of_instance #
  11. t2 = Test('lucy')
  12. print t1.name , t1.num_of_instance # jack 2
  13. print t2.name , t2.num_of_instance # lucy 2

补充的例子

  1. class Person:
  2. name="aaa"
  3.  
  4. p1=Person()
  5. p2=Person()
  6. p1.name="bbb"
  7. print p1.name # bbb
  8. print p2.name # aaa
  9. print Person.name # aaa

这里p1.name="bbb"是实例调用了类变量,这其实和上面第一个问题一样,就是函数传参的问题,p1.name一开始是指向的类变量name="aaa",但是在实例的作用域里把类变量的引用改变了,就变成了一个实例变量,self.name不再引用Person的类变量name了.

可以看看下面的例子:

  1. class Person:
  2. name=[]
  3.  
  4. p1=Person()
  5. p2=Person()
  6. p1.name.append(1)
  7. print p1.name # [1]
  8. print p2.name # [1]
  9. print Person.name # [1]

5 Python自省

自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型.简单一句就是运行时能够获得对象的类型.比如type(),dir(),getattr(),hasattr(),isinstance().

hasattr(object, name)
判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。
需要注意的是name要用括号括起来

  1. 1 >>> class test():
  2. 2 ... name="xiaohua"
  3. 3 ... def run(self):
  4. 4 ... return "HelloWord"
  5. 5 ...
  6. 6 >>> t=test()
  7. 7 >>> hasattr(t, "name") #判断对象有name属性
  8. 8 True
  9. 9 >>> hasattr(t, "run") #判断对象有run方法
  10. 10 True
  11. 11 >>>

getattr(object, name[,default])
获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。
需要注意的是,如果是返回的对象的方法,返回的是方法的内存地址,如果需要运行这个方法,
可以在后面添加一对括号。

  1. 1 >>> class test():
  2. 2 ... name="xiaohua"
  3. 3 ... def run(self):
  4. 4 ... return "HelloWord"
  5. 5 ...
  6. 6 >>> t=test()
  7. 7 >>> getattr(t, "name") #获取name属性,存在就打印出来。
  8. 8 'xiaohua'
  9. 9 >>> getattr(t, "run") #获取run方法,存在就打印出方法的内存地址。
  10. 10 <bound method test.run of <__main__.test instance at 0x0269C878>>
  11. 11 >>> getattr(t, "run")() #获取run方法,后面加括号可以将这个方法运行。
  12. 12 'HelloWord'
  13. 13 >>> getattr(t, "age") #获取一个不存在的属性。
  14. 14 Traceback (most recent call last):
  15. 15 File "<stdin>", line 1, in <module>
  16. 16 AttributeError: test instance has no attribute 'age'
  17. 17 >>> getattr(t, "age","18") #若属性不存在,返回一个默认值。
  18. 18 '18'
  19. 19 >>>

setattr(object, name, values)
给对象的属性赋值,若属性不存在,先创建再赋值。

  1. 1 >>> class test():
  2. 2 ... name="xiaohua"
  3. 3 ... def run(self):
  4. 4 ... return "HelloWord"
  5. 5 ...
  6. 6 >>> t=test()
  7. 7 >>> hasattr(t, "age") #判断属性是否存在
  8. 8 False
  9. 9 >>> setattr(t, "age", "18") #为属相赋值,并没有返回值
  10. 10 >>> hasattr(t, "age") #属性存在了
  11. 11 True
  12. 12 >>>

一种综合的用法是:判断一个对象的属性是否存在,若不存在就添加该属性。

  1. 1 >>> class test():
  2. 2 ... name="xiaohua"
  3. 3 ... def run(self):
  4. 4 ... return "HelloWord"
  5. 5 ...
  6. 6 >>> t=test()
  7. 7 >>> getattr(t, "age") #age属性不存在
  8. 8 Traceback (most recent call last):
  9. 9 File "<stdin>", line 1, in <module>
  10. 10 AttributeError: test instance has no attribute 'age'
  11. 11 >>> getattr(t, "age", setattr(t, "age", "18")) #age属性不存在时,设置该属性
  12. 12 '18'
  13. 13 >>> getattr(t, "age") #可检测设置成功
  14. 14 '18'
  15. 15 >>>

6 字典推导式

  1. d = {key: value for (key, value) in iterable}

7 Python中单下划线和双下划线

  1. >>> class MyClass():
  2. ... def __init__(self):
  3. ... self.__superprivate = "Hello"
  4. ... self._semiprivate = ", world!"
  5. ...
  6. >>> mc = MyClass()
  7. >>> print mc.__superprivate
  8. Traceback (most recent call last):
  9. File "<stdin>", line 1, in <module>
  10. AttributeError: myClass instance has no attribute '__superprivate'
  11. >>> print mc._semiprivate
  12. , world!
  13. >>> print mc.__dict__
  14. {'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}

__foo__:一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突,就是例如__init__(),__del__(),__call__()这些特殊方法

_foo:一种约定,用来指定变量私有.程序员用来指定私有变量的一种方式.不能用from module import * 导入,其他方面和公有一样访问;

__foo:这个有真正的意义:解析器用_classname__foo来代替这个名字,以区别和其他类相同的命名,它无法直接像公有成员一样随便访问,通过对象名._类名__xxx这样的方式可以访问.

8 字符串格式化:%和.format

  1. 实例:
    "{} {}".format("hello", "world") # 不设置指定位置,按默认顺序
    "{0} {1}".format("hello", "world") # 设置指定位置
    "{1} {0} {1}".format("hello", "world") # 设置指定位置
  1. print("{:.2f}".format(3.1415926));
    # 通过字典设置参数 site = {"name": "菜鸟教程", "url": "www.runoob.com"} print("网站名:{name}, 地址 {url}".format(**site))
    # 通过列表索引设置参数 my_list = ['菜鸟教程', 'www.runoob.com'] print("网站名:{0[0]}, 地址 {0[1]}".format(my_list)) # "0" 是必须的

9 迭代器和生成器

10 *args and **kwargs

*args**kwargs只是为了方便并没有强制使用它们.

当你不确定你的函数里将要传递多少参数时你可以用*args.例如,它可以传递任意数量的参数:

  1. >>> def print_everything(*args):
  2. for count, thing in enumerate(args):
  3. ... print '{0}. {1}'.format(count, thing)
  4. ...
  5. >>> print_everything('apple', 'banana', 'cabbage')
  6. 0. apple
  7. 1. banana
  8. 2. cabbage

相似的,**kwargs允许你使用没有事先定义的参数名:

  1. >>> def table_things(**kwargs):
  2. ... for name, value in kwargs.items():
  3. ... print '{0} = {1}'.format(name, value)
  4. ...
  5. >>> table_things(apple = 'fruit', cabbage = 'vegetable')
  6. cabbage = vegetable
  7. apple = fruit

你也可以混着用.命名参数首先获得参数值然后所有的其他参数都传递给*args**kwargs.命名参数在列表的最前端.例如:

  1. def table_things(titlestring, **kwargs)
  1. *args**kwargs可以同时在函数的定义中,但是*args必须在**kwargs前面.
    当调用函数时你也可以用***语法.例如:
  1. >>> def print_three_things(a, b, c):
  2. ... print 'a = {0}, b = {1}, c = {2}'.format(a,b,c)
  3. ...
  4. >>> mylist = ['aardvark', 'baboon', 'cat']
  5. >>> print_three_things(*mylist)
  1. a = aardvark, b = baboon, c = cat
  2.  
  3. 就像你看到的一样,它可以传递列表(或者元组)的每一项并把它们解包.注意必须与它们在函数里的参数相吻合.当然,你也可以在函数定义或者函数调用时用*.

11 面向切面编程AOP和装饰器

a.装饰器的作用

       装饰器的作用就是为已经存在的对象添加额外的功能。

b.装饰器原理与闭包

c.装饰器分类

1.类装饰器

2.函数装饰器

d.装饰器传参

12 鸭子类型

13 Python中重载

函数重载主要是为了解决两个问题。

  1. 可变参数类型。 python 函数可以接受任意类型的参数
  2. 可变参数个数。 python 对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。
  3. 因此python不需要函数重载

14 新式类和旧式类

一个旧式类的深度优先的例子

按照经典类的查找顺序从左到右深度优先的规则,在访问d.foo1()的时候,D这个类是没有的..那么往上查找,先找到B,里面没有,深度优先,访问A,找到了foo1(),所以这时候调用的是A的foo1(),从而导致C重写的foo1()被绕过

15 __new____init__的区别

这个__new__确实很少见到,先做了解吧.

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

16 单例模式

a.单例的作用:

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

b.实现

1.使用__new__()

  1. class Singleton(object):
  2. def __new__(cls, *args, **kw):
  3. if not hasattr(cls, '_instance'):
  4. orig = super(Singleton, cls)
  5. cls._instance = orig.__new__(cls, *args, **kw)
  6. return cls._instance
  7.  
  8. class MyClass(Singleton):
  9. a = 1

2.共享属性

创建实例时把所有实例的__dict__指向同一个字典,这样它们具有相同的属性和方法.

  1. class Borg(object):
  2. _state = {}
  3. def __new__(cls, *args, **kw):
  4. ob = super(Borg, cls).__new__(cls, *args, **kw)
  5. ob.__dict__ = cls._state
  6. return ob
  7.  
  8. class MyClass2(Borg):
  9. a = 1

3.装饰器

  1. def singleton(cls):
  2. instances = {}
  3. def getinstance(*args, **kw):
  4. if cls not in instances:
  5. instances[cls] = cls(*args, **kw)
  6. return instances[cls]
  7. return getinstance
  8.  
  9. @singleton
  10. class MyClass:
  11. ...

4 import方法

作为python的模块是天然的单例模式

  1. # mysingleton.py
  2. class My_Singleton(object):
  3. def foo(self):
  4. pass
  5.  
  6. my_singleton = My_Singleton()
  7.  
  8. # to use
  9. from mysingleton import my_singleton
  10.  
  11. my_singleton.foo()

17 Python中的作用域

Python 中,一个变量的作用域总是由在代码中被赋值的地方所决定的。

当 Python 遇到一个变量的话他会按照这样的顺序进行搜索:

本地作用域(Local)→当前作用域被嵌入的本地作用域(Enclosing locals)→全局/模块作用域(Global)→内置作用域(Built-in)

18 GIL线程全局锁

a.定义:线程全局锁(Global Interpreter Lock),即Python为了保证线程安全而采取的独立线程运行的限制,说白了就是一个核只能在同一时间运行一个线程.

b.缺陷:对于io密集型任务,python的多线程起到作用,但对于cpu密集型任务,python的多线程几乎占不到任何优势,还有可能因为争夺资源而变慢。

c.实现:

  1. import threading
  2.  
  3. #创建锁对象
  4. lock = threading.Lock()
  5.  
  6. #获取锁
  7. lock.acquire()
  8. # 要锁定的语句
  9. #释放锁
  10. lock.release()

d 替代方案:多进程和协程(协程也只是单CPU,但是能减小切换代价提升性能).

19 协程

a.定义:

是python中另外一种实现多任务的方式,比线程更小占用执行单元

在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定

b.实现:

  1. import time
  2.  
  3. def work1():
  4. while True:
  5. print("-----work1-----")
  6. yield
  7. time.sleep(0.5)
  8.  
  9. def work2():
  10. while True:
  11. print("-----work2-----")
  12. yield
  13. time.sleep(0.5)
  14.  
  15. def main():
  16. w1 = work1()
  17. w2 = work2()
  18. while True:
  19. next(w1)
  20. next(w2)
  21.  
  22. if __name__ == '__main__':
  23. main()

20 闭包

a.定义:

当一个内嵌函数引用其外部作作用域的变量,我们就会得到一个闭包.

b.特点 :

  1. 必须有一个内嵌函数
  2. 内嵌函数必须引用外部函数中的变量
  3. 外部函数的返回值必须是内嵌函数

21 lambda函数

a.输入与输出:

lambda [arg1[, arg2, ... argN]]: expression

参数是可选的,如果使用的参数话,参数通常也是表达式的一部分

b.使用

lambda x, y: xy;函数输入是x和y,输出是它们的积xy
             lambda:None;函数没有输入参数,输出是None
             lambda *args: sum(args); 输入是任意个数的参数,输出是它们的和(隐性要求是输入参数必须能够进行加法运算)
             lambda **kwargs: 1;输入是任意键值对参数,输出是1

lambda函数主要用来写一些小体量的一次性函数,避免污染环境,同时也能简化代码。

lambda起到了一种函数速写的作用,允许在使用的代码内嵌入一个函数的定义。他们完全是可选的(你总是能够使用def来替代它们),但是你仅需要嵌入小段可执行代码的情况下它们会带来一个更简洁的代码结构。

map( lambda x: x*x, [y for y in range(10)] )

lambda使用可以加参数也可以不加参数

lambda通常用来编写跳转表(jump table),也就是行为的列表或字典,能够按照需要执行相应的动作

22 Python函数式编程

a.filter 函数的功能相当于过滤器。调用一个布尔函数bool_func来迭代遍历每个seq中的元素;返回一个使bool_seq返回值为true的元素的序列。

  1. >>>a = [1,2,3,4,5,6,7]
  2. >>>b = filter(lambda x: x > 5, a)
  3. >>>print b
  4. >>>[6,7]

b.map函数是对一个序列的每个项依次执行函数,下面是对一个序列每个项都乘以2

  1. >>> a = map(lambda x:x*2,[1,2,3])
  2. >>> list(a)
  3. [2, 4, 6]

c.reduce函数是对一个序列的每个项迭代调用函数,下面是求3的阶乘

  1. >>> reduce(lambda x,y:x*y,range(1,4))
  2. 6

23 Python里的拷贝

  1. import copy
  2. a = [1, 2, 3, 4, ['a', 'b']] #原始对象
  3.  
  4. b = a #赋值,传对象的引用
  5. c = copy.copy(a) #对象拷贝,浅拷贝
  6. d = copy.deepcopy(a) #对象拷贝,深拷贝
  7.  
  8. a.append(5) #修改对象a
  9. a[4].append('c') #修改对象a中的['a', 'b']数组对象
  10.  
  11. print 'a = ', a
  12. print 'b = ', b
  13. print 'c = ', c
  14. print 'd = ', d
  15.  
  16. 输出结果:
  17. a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
  18. b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
  19. c = [1, 2, 3, 4, ['a', 'b', 'c']]
  20. d = [1, 2, 3, 4, ['a', 'b']]

24 Python垃圾回收机制

https://www.cnblogs.com/wupeiqi/p/11507404.html

a 引用计数以及循环引用

就是当这个对象的引用计数值为 0 时,说明这个对象永不再用,自然它就变成了垃圾,需要被回收

引用计算增减

对象的引用计数增加的情况:

  • 对象被创建:x = 3.14
  • 另外的别名被创建:y = x
  • 对象被作为参数传递给函数(新的本地引用):foobar(x)
  • 对象成为容器对象的一个元素:myList = [123, x, 'xyz']

对象的引用计数减少的情况:

  • 一个本地引用离开了其作用范围。如fooc()函数结束时,func函数中的局部变量(全局变量不会)
  • 对象的别名被显式销毁:del y
  • 对象的一个别名被赋值给其他对象:x = 123
  • 对象被从一个窗口对象中移除:myList.remove(x)
  • 窗口对象本身被销毁:del myList

Del语句会删除对象的一个引用,它的语法如下:del obj[, obj2[, ...objN]]

例如,在上例中执行del y会产生两个结果:

  • 从现在的名称空间中删除y
  • x的引用计数减1

循环应用

  1. list1 = []
  2. list2 = []
  3. list1.append(list2)
  4. list2.append(list1)

list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。

b 标记-清除机制

1.标记-清除机制,顾名思义,首先标记对象(垃圾检测),然后清除垃圾(垃圾回收)

2首先初始所有对象标记为白色,并确定根节点对象(这些对象是不会被删除),标记它们为黑色(表示对象有效)。

3将有效对象引用的对象标记为灰色(表示对象可达,但它们所引用的对象还没检查),检查完灰色对象引用的对象后,将灰色标记为黑色。

4重复直到不存在灰色节点为止。最后白色结点都是需要清除的对象。

c 分代技术

对象存在时间越长,越可能不是垃圾,应该越少去收集。

为了更合理的进行【标记-删除】,就需要对对象进行分代处理,思路很简单:

  1. 1、新创建的对象做为0
  2. 2、每执行一个【标记-删除】,存活的对象代数就+1
  3. 3、代数越高的对象(存活越持久的对象),进行【标记-删除】的时间间隔就越长。这个间隔,江湖人称阀值。
    40代触发将清理所有三代,1代触发会清理1,2代,2代触发后只会清理自己。

25 Python的List

26 Python的is

is是对比地址,==是对比值

27 read,readline和readlines

  • read 读取整个文件
  • readline 读取下一行,使用生成器方法
  • readlines 读取整个文件到一个迭代器以供我们遍历

28 Python2和3的区别

29 super init

30 range and xrange

range产生的是一个列表,而xrange产生的是一个类似迭代器的。

所以对于较大的集合时候,xrange比range性能好。

因为range一次把所以数据都返回,而xrange每次调用返回其中的一个值

31 请列举你熟悉的设计模式?

32 Python解释器种类以及特点

  • CPython

    • c语言开发的 使用最广的解释器
  • IPython
    • 基于cpython之上的一个交互式计时器 交互方式增强 功能和cpython一样
  • PyPy
    • 目标是执行效率 采用JIT技术 对python代码进行动态编译,提高执行效率
  • JPython
    • 运行在Java上的解释器 直接把python代码编译成Java字节码执行
  • IronPython
    • 运行在微软 .NET 平台上的解释器,把python编译成. NET 的字节码

python 面试题一:Python语言特性的更多相关文章

  1. 千万不要错过这几道Python面试题,Python面试题No16

    第1题: python下多线程的限制以及多进程中传递参数的方式? python多线程有个全局解释器锁(global interpreter lock),简称GIL,这个GIL并不是python的特性, ...

  2. Python面试题之python是一种什么语言及优缺点

    1.说说python是一种什么语言? 参考答案:python是一门动态解释性的强类型定义语言 编译型vs解释型 编译型优点:编译器一般会有预编译的过程对代码进行优化.因为编译只做一次,运行时不需要编译 ...

  3. Python面试题之Python面试题汇总

    在这篇文章中: Python基础篇 1:为什么学习Python 2:通过什么途径学习Python 3:谈谈对Python和其他语言的区别 Python的优势: 4:简述解释型和编译型编程语言 5:Py ...

  4. python面试题之Python支持什么数据类型?

    所属网站分类: 面试经典 > python 作者:外星人入侵 链接:http://www.pythonheidong.com/blog/article/67/ 来源:python黑洞网,专注py ...

  5. Python面试题之Python中type和object的关系

    知乎上看到的提问: 两个是互为实例的关系,但不是互为子类的关系,只有type是object的子类,反之则不成立. 大牛说两者是蛋生鸡鸡生蛋的关系,但我还是不明白,有懂的麻烦解释一下, 希望不要给出外文 ...

  6. Python面试题之Python面向对象编程汇总

    面向对象的设计思想是从自然界中来的,因为在自然界中,类(Class)和实例(Instance)的概念是很自然的.Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念, ...

  7. python面试题之Python 的特点和优点是什么

    Python 可以作为编程的入门语言,因为他具备以下特质: 1. 解释性 2. 动态特性 3. 面向对象 4. 语法简洁 5. 开源 6. 丰富的社区资源 7 库丰富 文章转载自Python黑洞网

  8. python面试题三:Python 网络编程与并发

    1 简述 OSI 七层协议. OSI七层协议模型主要是: 应用层(Application):为用户的应用程序(例如电子邮件.文件传输和终端仿真)提供网络服务. 表示层(Presentation):使用 ...

  9. Python面试题之Python中的类和实例

    0x00 前言 类,在学习面向对象我们可以把类当成一种规范,这个思想就我个人的体会,感觉很重要,除了封装的功能外,类作为一种规范,我们自己可以定制的规范,从这个角度来看,在以后我们学习设计模式的时候, ...

  10. Python面试题之Python反射详解

    0x00 前言 反射,可以理解为利用字符串的形式去对象中操作成员属性和方法 反射的这点特性让我联想到了exec函数,也是把利用字符串的形式去让Python解释器去执行命令 Python Version ...

随机推荐

  1. @RequestMAPPPING映射请求占位符@PathVariable注解

    @PathVariable:通过@PathVariable 可以将URL 中占位符参数绑定到控制器处理方法的入参中 URL中的{xxx} 占位符可以通过 @PathVariable{"xxx ...

  2. Java—— 一点关于String的转换

    在Java学习中,恐怕我们遇到的最多的就是有关String与其他类型的转换了,我们来看一张图: 我们看到对于8种基本数据类型,除去byte和short类型没有外,其他的都有,值得注意的是可以把char ...

  3. 小师妹学JVM之:JVM的架构和执行过程

    目录 简介 JVM是一种标准 java程序的执行顺序 JVM的架构 类加载系统 运行时数据区域 执行引擎 总结 简介 JVM也叫Java Virtual Machine,它是java程序运行的基础,负 ...

  4. deepin双屏实现方式

    先xrandr --listproviders看下有几个provider,如果有多个,那么可能是不同显示口在不同显卡上,运行xrandr --setprovideroutputsource 0 1或x ...

  5. Redis的常用配置

    1. 配置守护线程方式运行,修改damonize,使用yes启用守护线程,这样就可以后台运行了 damonize no 修改为 damonize yes 2. 手动指定redis的pid,可以通过pi ...

  6. 谈谈spring-boot-starter-data-redis序列化

    在上一篇中springboot 2.X 集成redis中提到了在spring-boot-starter-data-redis中使用JdkSerializationRedisSerializerl来实现 ...

  7. MySQL LOAD DATA INFILE—批量从文件(csv、txt)导入数据

    最近做的项目,有个需求(从Elastic Search取数据,业务运算后),每次要向MySQL插入1300万数据左右.最初用MySQL的executemany()一次插入10000条数据,统计的时间如 ...

  8. 黎活明8天快速掌握android视频教程--20_采用ContentProvider对外共享数据

    1.内容提供者是让当前的app的数据可以让其他应用访问,其他应该可以通过内容提供者访问当前app的数据库 contentProvider的主要目的是提供一个开发的接口,让其他的应该能够访问当前应用的数 ...

  9. centos 6.5 dhcp桥接方式上网络设置

    首先虚拟机和主机之间采用桥接模式 然后在虚拟机中进行设置,首先进入到目录 /etc/sysconfig/network-scripts/ [root@localhost ~]# cd /etc/sys ...

  10. Python实用笔记 (16)函数式编程——偏函数

    假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去: def int2(x, base=2): re ...