python相关知识

1.python-GIL
GIL 是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),
使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。
所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。多进程中因为每个进程都能被系统分配资源,相当于每个进程有了一个python解释器,
所以多进程可以实现多个进程的同时运行,缺点是进程系统资源开销大
2.可变参数
1)作为行参
    (1)*args表示可接受任意个(包含0个)位置参数,当函数调用时,所有未使用(未匹配)的位置参数会在函数内自动组装进一个tuple对象中,此tuple对象会赋值给变量名args
    (2)**kwargs表示可接受任意个(包含0个)关键字参数,当函数调用时,所有未使用(未匹配)的关键字参数会在函数内组装进一个dict对象中,此dict对象会赋值给变量名kwargs
    注意:函数定义时,二者同时存在,一定需要将*args放在**kwargs之前
def print_str(first, *second):
    print(first) # hello
    print(second) # ()
print_str("hello")

print_str("hello","美女","小猫","青蛙")
# hello
# ('美女', '小猫', '青蛙')

def printStr(**anything):
    print(anything) # {'second': 100, 'first': 5}
printStr(first=5, second=100)
2)作为实参
    (1)*args表示解包元组对象中的每个元素作为函数调用时传入的位置参数
    (2)**kwargs表示解包字典对象中的每个元素作为函数调用时传入的关键字参数
def print_str(first, *second):
    print(first)     # 1
    print(second)    # ('2', '3', '4', '5')
numbers_strings = ("1", "2", "3", "4", "5")
print_str(*numbers_strings)  # 等同于print_str("1", "2", "3", "4", "5")

def printStr(first, **dict):
    print(first)         #100
    print(dict)          # {'age': '99', 'name': 'tyson'}
printDic = {"name": "tyson", "age": "99"}
printStr(100, **printDic)  # 等同于 printStr(100, name="tyson", age="99")
3.python2和python3的range(100)的区别
python2返回列表,python3返回迭代器,节约内存
4.私有属性和私有方法
定义:通过在属性和方法前加两个下划线定义私有
访问:
    1)通过 实例._类名+私有属性(私有方法) 可以访问,但是会被警告
class Add(object):
    def __init__(self):
        self.__privatename = 123
    def __func(self):
        print '111'

add = Add()
print add._Add__privatename  #这是一种不好的访问方式
print add._Add__func()
    2)通过公有方法访问
class Person(object):
    def __init__(self, name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_name(self, new_name):
        if len(new_name) >= 5:
            self.__name = new_name
        else:
            print("error:名字长度需要大于或者等于5")
            
    def __print_name(self):
        print self.__name
        
    def print_name(self):
        self.__print_name()

xiaoming = Person("skyter")
print xiaoming.get_name()
# print xiaoming.__name #会报错
xiaoming.print_name()
# xiaoming.__print_name() #会报错
5.静态方法和类方法(self和cls)
1)静态方法:通过@staticmethod装饰器修饰的方法,静态方法无需实例化类即可调用
2)类方法:通过@classmethod装饰器修饰的方法,类方法无需实例化类即可调用
3)*self*表示一个具体的实例本身。如果用了@staticmethod修饰,可以无视这个self,将这个方法当成一个普通的函数使用。
4)*cls*表示这个类本身
ps:@staticmethod修饰的方法,不能在类内调用类的其他的方法,而classmethod可以调用其他的方法,因为有cls这个参数。
    @staticmethod与@classmethod的方法与self这个方法的区别,就是self必须使用实例化对象(a=A(),a.fun())
    而另外两个方法只用,A.fun()即可
class C(object):
    def f0(self, name):
        print('common', name)

    @staticmethod
    def f1(name):
        print('static', name)

    @classmethod
    def f2(cls, name):
        print('class', name)
        cls().f0(name)

C.f1('hou')
C.f2('hou')
6.魔法方法和特殊成员属性
1)__init__:构造函数,创建对象的时候自动调用
   __new__:只有继承于object的新式类才能有__new__方法,__new__必须要有返回值,返回实例化出来的实例
   执行顺序:先__new__,后__init__
2)__del__:析构函数,对象被系统回收的时候自动调用
3)__call__:使实例可以像函数一样被调用
class Add(object):
    def __call__(self, *args, **kwargs):
        return args[0] + args[1]

add = Add()
print add(1, 2)
print callable(add) #返回True,可以通过callable()检验该类是否有定义__call__魔法方法
4)__str__:重载类的str方法,返回自定义的打印形式
class Add(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return "I am %s" % self.name

add = Add('hou')
print add
5)__len__:为类增加len方法
class Add(object):
    def __init__(self, name):
        self.name = name

    def __len__(self):
        return 10

add = Add('hou')
print len(add)  #返回10
6)__iter__:为类增加迭代功能
class Add(object):
    def __init__(self, data):
        self.data = data

    def __iter__(self):
        return iter(self.data)

add = Add([1, 2, 3, 4, 5])
for i in add:
    print i
7)__add__:为类增加计算功能(__sub__: -,__mul__: *,__div__: /,__mod__: %,__pow__: **)
class Cat(object):
    def __init__(self, age):
        self.age = age

    def __add__(self, other):
        return self.age + other.age

cat1 = Cat(12)
cat2 = Cat(14)
print cat1 + cat2  #输出26
8)__getitem__,__setitem__,__delitem__:为类提供增加类似字典访问的方式
class Add(object):
    def __init__(self, name):
        self.name = name

    def __getitem__(self, item):
        if hasattr(self, item):
            return getattr(self, item)
        else:
            return None

    def __setitem__(self, key, value):
        setattr(self, key, value)

    def __delitem__(self, key):
        if key == 'yao':
            del self.yao

add = Add('hou')
add['yao'] = 'lijun'
print add['yao']
del add['yao']
print add['yao']
9)__getattr__:当类的属性不存在时,走此函数
   __getattribute__:无论属性是否存在,都走此函数,需要特殊操作时需要重载此方法,
                     如果__getattribute__抛出了AttributeError异常,那么会继续访问__getattr__函数的。
   __setattr__:不管对象的某个属性是否存在,它都允许你为该属性进行赋值,因此你可以为属性的值进行自定义操作,
   __delattr__:当删除类属性的时候走此函数)
class Cat(object):
    def __init__(self, name):
        self.name = name

    def __getattr__(self, func):
        def _func():
            if func == 'get_name':
                return self.name
            else:
                return None
        setattr(self, func, _func)
        return _func

    def __setattr__(self, name, value):
        return super(Cat, self).__setattr__(name, value)

    def __delattr__(self, name):
        return super(Cat, self).__delattr__(name)

    def __getattribute__(self, name):
        return super(Cat, self).__getattribute__(name)

cat = Cat('hou')
print cat.get_name()
cat.yao = 'lijun'
print cat.yao
del cat.yao
10)__get__, __set__
    拥有__get__方法的类是只能其实例属于类属性的时候生效
    如果定义了__set__,需要通过类的属性方式赋值,而不是类的实例方式赋值
class TestDes(object):
    def __get__(self, instance, owner):
        print(instance, owner)
        return 'TestDes:__get__'

    def __set__(self, instance, value):
        print('TestDes:__set__', instance, value)

class TestMain(object):
    des = TestDes()

if __name__ == '__main__':
    t = TestMain()
    print(t.des)
    print(TestMain.des)

    print '*'*10
    
    # 类的实例赋值,失败
    t.des = 1
    print(t.des)
    print(TestMain.des)

    print '*' * 10

    # 类的属性赋值,成功
    TestMain.des = 1
    print(t.des)
    print(TestMain.des)
11)__doc__:返回类的描述,需要在init函数前用三引号定义
12)__model__:返回类的模块名字
13)__class__:返回当前对象所属的类
14)__dict__:以dict的形式返回当前对象的成员属性,私有变量会以  形式存在
7.python经典类和新式类的多继承调用顺序
1)经典类:深度优先调用
class A:
    def __init__(self):
        print('A')

class B(A):
    pass
    # def __init__(self):
    #     print('B')

class C(A):
    # pass
    def __init__(self):
        print('C')

class D(B, C):
    pass
    # def __init__(self):
    #     print('D')

r1 = D() #输出A,不会去C里找,会深度优先递归到A
2)新式类:广度优先调用(定义类的时候传入object)
class A(object):
    def __init__(self):
        print('A')

class B(A):
    pass
    # def __init__(self):
    #     print('B')

class C(A):
    # pass
    def __init__(self):
        print('C')

class D(B, C):
    pass
    # def __init__(self):
    #     print('D')

r1 = D() #输出C,会先去C里找,会广度优先递归到C
3)super
class A(object):
    def __init__(self):
        self.name = 'A'

class B(A):
    def __init__(self):
        self.name = 'B'

class C(A):
    def __init__(self):
        self.name = 'C'

class D(B, C):
    def __init__(self):
        self.name = 'D'
        super(D, self).__init__() #调用D的父类的init函数,覆盖了D的self.name

obj = D()
print obj.name #输出B
8.with
with语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
使用with方法必须先为类定义__enter__()和__exit__()
class mysql(object):
    def __init__(self, host, database):
        self.host = host
        self.database = database

    def __enter__(self):
        print 'connect: %s database: %s' % (self.host, self.database)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print 'close connect: %s' % self.host
        return True

    def print_data(self, data):
        print data

with mysql('127.0.0.1', 'flow_db') as m:
    m.print_data('hou')

# connect: 127.0.0.1 database: flow_db
# hou
# close connect: 127.0.0.1
9.列表推导,字典推导
1)列表[1,2,3,4,5],请使用map()函数输出[1,4,9,16,25],并使用列表推导式提取出大于10的数,最终输出[16,25]
[i for i in map(lambda x: x**2, [1, 2, 3, 4, 5]) if i > 10]
2)找到嵌套列表中名字含有两个‘e’的所有名字(有难度)
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
[j for i in names for j in i if j.count('e') >= 2]
3)[[1,2],[3,4],[5,6]]一行代码展开该列表,得出[1,2,3,4,5,6]
[j for i in [[1, 2], [3, 4], [5, 6]] for j in i]
4)字典推导式
{str(i): i for i in range(1, 5)}
10.内置函数
foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
print filter(lambda x: x % 3 == 0, foo) # [18, 9, 24, 12, 27]  fiter返回表达式为真的元素
print map(lambda x: x * 2 + 10, foo) # [14, 46, 28, 54, 44, 58, 26, 34, 64] map将foo中的元素逐一当作参数传给lambda函数
print reduce(lambda x, y: x + y, foo) # 139  reduce将foo中的元素逐一传给lambda函数后,将返回值进行叠加

a = [1, 2]
b = [3, 4]
e = [5, 6]
print [i for i in zip(a, b, e)]  # [(1, 3, 5), (2, 4, 6)]  zip会返回输入参数的列组合元组,当其中输入某列缺失时抛弃整列
11.排序
1)sort():原地排序,只能对list排序(a.sort())
2)sorted():非原地排序,能对list和set,dict排序(b=sorted(a))
# 使用lambda函数对list排序foo = [-5,8,0,4,9,-4,-20,-2,8,2,-4],
# 输出结果 [0,2,4,8,8,9,-2,-4,-4,-5,-20],正数从小到大,负数从大到小

foo = [-5, 8, 0, 4, 9, -4, -20, -2, 8, 2, -4]
print sorted(foo, key=lambda x: (x < 0, abs(x)))
# 列表字典根据键从小到大排序
dic = [
    {"name": "b", "age": 2},
    {"name": "c", "age": 3},
    {"name": "d", "age": 4},
    {"name": "a", "age": 3},
]

print sorted(dic, key=lambda x: x['age'], reverse=False)  
# [{'age': 2, 'name': 'b'}, {'age': 3, 'name': 'c'}, {'age': 3, 'name': 'a'}, {'age': 4, 'name': 'd'}]
print sorted(dic, key=lambda x: (x['age'], x['name']), reverse=False)  # age相同时,按name排序
# [{'age': 2, 'name': 'b'}, {'age': 3, 'name': 'a'}, {'age': 3, 'name': 'c'}, {'age': 4, 'name': 'd'}]
# 根据字符串长度排序
a = ['abc', 'ab', 'abcd', 'a']
print sorted(a, key=lambda x: len(x))
12.x=“abc”,y=“def”,z=[“d”,“e”,“f”],分别求出x.join(y)和x.join(z)返回的结果
x="abc"
y="def"
z=["d", "e", "f"]
print x.join(y)  #dabceabcf
print x.join(z)  #dabceabcf
13.举例说明异常模块中try except else finally的相关意义
try..except..else没有捕获到异常,执行else语句
try..except..finally不管是否捕获到异常,都执行finally语句
try:
    print 'aaa'
    # 1/0 #异常则走except,不走else
except:
    print 'except'
else:
    print 'else'
finally:
    print 'finally'
14.生成器和迭代器
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,
使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
1)[] -> ()
lis = [x * x for x in range(10)]
print(lis)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

generator_ex = (x * x for x in range(10))
print generator_ex.next()  # 0
print generator_ex.next()  # 1
print next(generator_ex)   # 4
# for循环也可以迭代
2)yield
def fab(m):
    n, a, b = 0, 0, 1
    while n < m:
        yield b
        a, b = b, a + b
        n = n + 1

if __name__ == '__main__':
    for i in fab(10):
        print i
15.python中的异常
IOError:输入输出异常
AttributeError:试图访问一个对象没有的属性
ImportError:无法引入模块或包,基本是路径问题
IndentationError:语法错误,代码没有正确的对齐
IndexError:下标索引超出序列边界
KeyError:试图访问你字典里不存在的键
SyntaxError:Python代码逻辑语法出错,不能执行
NameError:使用一个还未赋予对象的变量
16.copy和deepcopy
cope:拷贝父对象,不会拷贝对象的内部的子对象。
deepcopy:完全拷贝了父对象及其子对象。完全复制一份,改变互不影响
from copy import copy, deepcopy


a = [1, 2, 3, 4, ['a', 'b']]

b = a               # 赋值,传对象的引用,引用传递,传址
c = copy(a)         # 对象拷贝,浅拷贝,不拷贝对象内的子对象,修改父对象的子对象会影响其值
d = deepcopy(a)     # 对象拷贝,深拷贝,拷贝对象内的子对象,修改父对象的子对象不会影响其值

a.append(5)
a[4].append('c')

print('a = ', a)  # [1, 2, 3, 4, ['a', 'b', 'c'], 5]
print('b = ', b)  # [1, 2, 3, 4, ['a', 'b', 'c'], 5]
print('c = ', c)  # [1, 2, 3, 4, ['a', 'b', 'c']]
print('d = ', d)  # [1, 2, 3, 4, ['a', 'b']]
17.元组内部的元素是否可变
a = (1, 2, [3, 4])
a[2].append(5)
print a  # (1, 2, [3, 4, 5])
18.python传参数是传值还是传址
是引用传递,传址
1)由于数值型、字符串、元组是不可变类型,所以运算不会影响到变量自身
2)由于列表字典为可变类型,函数体运算可能会更改传入的参数变量。
def selfadd(a):
    a += a

b = [1, 2]
selfadd(b)
print b  #[1,2,1,2]
19.python垃圾回收机制 详情点击 详情点击
python垃圾回收主要以引用计数为主,标记-清除和分代清除为辅的机制,其中标记-清除和分代回收主要是为了处理循环引用的难题。
1)引用计数器
    当有1个变量保存了对象的引用时,此对象的引用计数就会加1。当使用del删除变量指向的对象时,如果对象的引用计数不为1,比如3,
    那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除

image

image

image

image

2)标记清理
    (1)ref_cnt --> gc_cnt
    (2)遍历gc_cnt,gc_cnt -= 1
    (3)如果gc_cnt==0则放入unreachable队列,否则放入reachable队列
    (4)遍历reachable队列,深度递归,如果可达的对象在unreachable中,则拉回
    (5)清除unreachable队列中的对象
3)分代回收

image

(1)新生对象都放入0代中,会频繁进行gc(引用计数回收和分代回收)
(2)进行10次0代回都没有被销毁的放入1代
(3)进行10次1代回都没有被销毁的放入2代
(4)0代1代和2代回收都用引用计数回收和分代回收

4)缓存

image

>>> a = 233
>>> b = 233
>>> a is b
True
>>> a == b
True
>>> c = 1333
>>> d = 1333
>>> c is d
False
>>> c == d
True
(1)int:[-5, 257)
v1 = 38    # 去小数据池small_ints中获取38整数对象,将对象添加到refchain并让引用计数器+1。
print( id(v1))  #内存地址:4514343712
v2 = 38 # 去小数据池small_ints中获取38整数对象,将refchain中的对象的引用计数器+1。
print( id(v2) ) #内存地址:4514343712
# 注意:在解释器启动时候-5~256就已经被加入到small_ints链表中且引用计数器初始化为1,代码中使用的值时直接去small_ints中拿来用并将引用计数器+1即可。
# 另外,small_ints中的数据引用计数器永远不会为0(初始化时就设置为1了),所以也不会被销毁。
(2)float:维护的free_list链表最多可缓存100个float对象。
v1 = 3.14    # 开辟内存来存储float对象,并将对象添加到refchain链表。
print( id(v1) ) # 内存地址:4436033488
del v1    # 引用计数器-1,如果为0则在rechain链表中移除,不销毁对象,而是将对象添加到float的free_list.
v2 = 9.999    # 优先去free_list中获取对象,并重置为9.999,如果free_list为空才重新开辟内存。
print( id(v2) ) # 内存地址:4436033488
# 注意:引用计数器为0时,会先判断free_list中缓存个数是否满了,未满则将对象缓存,已满则直接将对象销毁。
(3)list和dict:维护的free_list数组最多可缓存80个对象。
v1 = [11,22,33]
print( id(v1) ) # 输出:4517628816
del v1
v2 = ["武","沛齐"]
print( id(v2) ) # 输出:4517628816
(4)tuple:维护一个free_list数组且数组容量20,数组中元素可以是链表且每个链表最多可以容纳2000个元组对象。元组的free_list数组在存储数据时,
            是按照元组可以容纳的个数为索引找到free_list数组中对应的链表,并添加到链表中。

image

(5)str:维护unicode_latin1[256]链表,内部将所有的ascii字符缓存起来,以后使用时就不再反复创建。
v1 = "A"
print( id(v1) ) # 输出:4517720496
del v1
v2 = "A"
print( id(v1) ) # 输出:4517720496
# 除此之外,Python内部还对字符串做了驻留机制,针对那么只含有字母、数字、下划线的字符串(见源码Objects/codeobject.c),
# 如果内存中已存在则不会重新在创建而是使用原来的地址里(不会像free_list那样一直在内存存活,只有内存中有才能被重复利用)。
v1 = "wupeiqi"
v2 = "wupeiqi"
print(id(v1) == id(v2)) # 输出:True
20.正则表达式
1).:表示任意的一个字符
2)*:匹配前边元素的0个,1个或者多个
3)+:匹配前边元素一个或多个
4)?:匹配前边元素的0个或者1个
5)[]:匹配中括号中的任意一个(中括号中的元素为or关系)
6)():匹配完之后只返回()中的字符串
7){}:{n}匹配前边元素n次,{n,}匹配前边元素大于等于n次,{n,m}匹配前边元素大雨等于n次,小于等于m次
8)^:放在[]里表示取反,否则表示以什么开头
9)$:以什么结尾
10)[a-z]和[A-Z]:应为字母集
11)\d:数字
12)\D:非数字
13)|:或者
import re

"""
content = '''001-苹果价格-60,
a002-橙子价格-700,
003-香蕉价格-80,
'''

p = re.compile(r'001.', re.M)
print p.findall(content)  # ['001-']

p = re.compile(r'-\d*', re.M)
print p.findall(content)  # ['-', '-60', '-', '-700', '-', '-80']

p = re.compile(r'-\d+', re.M)
print p.findall(content)  # ['-60', '-700', '-80']

p = re.compile(r'-\d?', re.M)
print p.findall(content)  # ['-', '-6', '-', '-7', '-', '-8']

p = re.compile(r'-[67]0', re.M)
print p.findall(content)  # ['-60', '-70']

p = re.compile(r'-([67]0)', re.M)
print p.findall(content)  # ['60', '70']

p = re.compile(r'-\d{1}', re.M)
print p.findall(content)  # ['-6', '-7', '-8']

p = re.compile(r'-\d{1,}', re.M)
print p.findall(content)  # ['-60', '-700', '-80']

p = re.compile(r'-\d{1,2}', re.M)
print p.findall(content)  # ['-60', '-70', '-80']

p = re.compile(r'^\d+', re.M)
print p.findall(content)  # ['001', '003']

p = re.compile(r'\d{2,3},$', re.M)
print p.findall(content)  # ['60,', '700,', '80,']

p = re.compile(r'^\D\d+', re.M)
print p.findall(content)  # ['a002']
1、re.A(re.ASCII)
    让\w,\W,\b,\B,\d,\D,\s和\S 执行ASCII-只匹配完整的Unicode匹配代替。这仅对Unicode模式有意义,而对于字节模式则忽略。

2、re.I(re.IGNORECASE)
    执行不区分大小写的匹配;类似的表达式也[A-Z]将匹配小写字母。

3、re.L(re.LOCALE)
  让\w,\W,\b,\B和区分大小写的匹配取决于当前的语言环境。该标志只能与字节模式一起使用。不建议使用此标志,因为语言环境机制非常不可靠,它一次只能处理一种“区域性”,并且仅适用于8位语言环境。默认情况下,Python3中已为Unicode(str)模式启用了Unicode匹配,并且能够处理不同的语言环境/语言。

4、re.M(re.MULTILINE)
  指定时,模式字符'^'在字符串的开头和每行的开头(紧随每个换行符之后)匹配;模式字符''在字符串的末尾和每行的末尾(紧接在每个换行符之前)匹配。默认情况下,'^' 仅在字符串的开头,字符串''的末尾和字符串末尾的换行符(如果有)之前立即匹配。

5、re.S(re.DOTALL)
    使'.'特殊字符与任何字符都匹配,包括换行符;没有此标志,'.'将匹配除换行符以外的任何内容。
    
6、re.split
>>> re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
['', '', 'cd']
7、re.sub
>>> re.sub('\d', 'S', 'abc12jh45li78', 2) #将匹配到的数字替换成S,替换2个
'abcSSjh45li78'

>>> re.sub('\d', 'S', 'abc12jh45li78') #将匹配到所有的数字替换成S
'abcSSjhSSliSS'
8、search与match方法:re.match()仅在字符串的开头匹配,re.search()检查匹配项在字符串中的任何位置检查匹配项。
>>> re.match("c", "abcdef") #Not match
>>> re.search("c", "abcdef") #match
<_sre.SRE_Match object; span=(2, 3), match='c'>
pattern = re.compile(r'([a-z]+) ([a-z]+) ([a-z]+)', re.I)   # re.I 表示忽略大小写
m = pattern.match('Hello World Wide Web')

print m.groups()
print m.group(1)
print m.span(1)
21.python程序运行流程
在说这个问题之前,我们先来说两个概念,PyCodeObject和pyc文件。
我们在硬盘上看到的pyc自然不必多说,而其实PyCodeObject则是Python编译器真正编译成的结果。我们先简单知道就可以了,继续向下看。
当python程序运行时,编译的结果则是保存在位于内存中的PyCodeObject中,当Python程序运行结束时,Python解释器则将PyCodeObject写回到pyc文件中。
当python程序第二次运行时,首先程序会在硬盘中寻找pyc文件,如果找到,就比对和py文件的修改时间,如果pyc文件的修改时间在py文件后边,则直接载入,否则就重复上面的过程。
所以我们应该这样来定位PyCodeObject和pyc文件,我们说pyc文件其实是PyCodeObject的一种持久化保存方式。
22.python数据结构底层实现
1)数组和元组:顺序表
    内存中一段连续的地址空间,a[i]操作是O(1)复杂度,因为地址空间连续,可以根据第一个元素的索引直接计算出索引为i的内存地址

image

2)字典:散列表(hash key)
    python采用开放地址法解决hash冲突
    解决hash冲突有四种方式:
    1)链式地址法:冲突的key下挂载list(key,value)
    2)再hash法:构造多个不同的哈希函数,发生冲突时,再用其他哈希函数进行计算,直到冲突不再产生
    3)建立公共溢出区:将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区
    4)开放地址法:

image

image

3)集合:散列表(hash值)

image

23.is和==
一个对象有三个属性:id,type,value
1)is:判断对象是否相等(判断id是否相等)
2)==:判断值是否相等(判断value是否相等)
24.字符串驻留机制
1)如果字符串只包含字母数字和下划线,则不会新创建对象
>>> a = 'abc_123'
>>> b = 'abc_123'
>>> id(a)
4505116608
>>> id(b)
4505116608
>>> a is b
True
>>> a == b
True

>>> c = 'abc_*'
>>> d = 'abc_*'
>>> id(c)
4505116080
>>> id(d)
4505162640
>>> c is d
False
>>> c == d
True
25.python的堆栈
内存中的堆栈和数据结构堆栈不是一个概念,可以说内存中的堆栈是真实存在的物理区,数
据结构中的堆栈是抽象的数据存储结构。
内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区
和堆区。
代码区:存储方法体的二进制代码。高级调度(作业调度)、中级调度(内存调度)、低级
调度(进程调度)控制代码区执行代码的切换。
静态数据区:存储全局变量、静态变量、常量,常量包括final修饰的常量和String常量。系
统自动分配和回收。
栈区:存储运行方法的形参、局部变量、返回值。由系统自动分配和回收。
堆区:new一个对象的引用或地址存储在栈区,指向该对象存储在堆区中的真实数据。

image

26.python2和python3差别
一、核心类差异
1. Python3 对 Unicode 字符的原生支持。
Python2 中使用 ASCII 码作为默认编码方式导致 string 有两种类型 str 和 unicode,Python3 只
支持 unicode 的 string。Python2 和 Python3 字节和字符对应关系为:
2. Python3 采用的是绝对路径的方式进行 import
Python2 中相对路径的 import 会导致标准库导入变得困难(想象一下,同一目录下有 file.py,如
何同时导入这个文件和标准库 file)。Python3 中这一点将被修改,如果还需要导入同一目录的文件必
须使用绝对路径,否则只能使用相关导入的方式来进行导入。
3. Python2 中存在老式类和新式类的区别,Python3 统一采用新式类。新式类声明要求继承 object,
必须用新式类应用多重继承。
4. Python3 使用更加严格的缩进。Python2 的缩进机制中,1 个 tab 和 8 个 space 是等价的,所
以在缩进中可以同时允许 tab 和 space 在代码中共存。这种等价机制会导致部分 IDE 使用存在问题。
Python3 中 1 个 tab 只能找另外一个 tab 替代,因此 tab 和 space 共存会导致报错:TabError:
inconsistent use of tabs and spaces in indentation.


二、废弃类差异
1. print 语句被 Python3 废弃,统一使用 print 函数
2. exec 语句被 python3 废弃,统一使用 exec 函数
3. execfile 语句被 Python3 废弃,推荐使用 exec(open("./filename").read())
4. 不相等操作符"<>"被 Python3 废弃,统一使用"!="
5. long 整数类型被 Python3 废弃,统一使用 int
6. xrange 函数被 Python3 废弃,统一使用 range,Python3 中 range 的机制也进行修改并提高
了大数据集生成效率
7. Python3 中这些方法再不再返回 list 对象:dictionary 关联的 keys()、values()、items(),zip(),
map(),filter(),但是可以通过 list 强行转换:
1. mydict={"a":1,"b":2,"c":3}
2. mydict.keys() #<built-in method keys of dict object at 0x000000000040B4C8>
3. list(mydict.keys()) #['a', 'c', 'b']
8. 迭代器 iterator 的 next()函数被 Python3 废弃,统一使用 next(iterator)
9. raw_input 函数被 Python3 废弃,统一使用 input 函数
10. 字典变量的 has_key 函数被 Python 废弃,统一使用 in 关键词
11. file 函数被 Python3 废弃,统一使用 open 来处理文件,可以通过 io.IOBase 检查文件类型
12. apply 函数被 Python3 废弃
13. 异常 StandardError 被 Python3 废弃,统一使用 Exception


三 、修改类差异
1. 浮点数除法操作符“/”和“//”的区别
“ / ”:
Python2:若为两个整形数进行运算,结果为整形,但若两个数中有一个为浮点数,则结果为
浮点数;
Python3:为真除法,运算结果不再根据参加运算的数的类型。
“//”:
Python2:返回小于除法运算结果的最大整数;从类型上讲,与"/"运算符返回类型逻辑一致。
Python3:和 Python2 运算结果一样。
2. 异常抛出和捕捉机制区别
Python2
1. raise IOError, "file error" #抛出异常
2. except NameError, err: #捕捉异常
Python3
1. raise IOError("file error") #抛出异常
2. except NameError as err: #捕捉异常
3. for 循环中变量值区别
Python2,for 循环会修改外部相同名称变量的值
1. i = 1
2. print ('comprehension: ', [i for i in range(5)])
3. print ('after: i =', i ) #i=4
Python3,for 循环不会修改外部相同名称变量的值
1. i = 1
2. print ('comprehension: ', [i for i in range(5)])
3. print ('after: i =', i ) #i=1
4. round 函数返回值区别
Python2,round 函数返回 float 类型值
1. isinstance(round(15.5),int) #True
Python3,round 函数返回 int 类型值
1. isinstance(round(15.5),float) #True
5. 比较操作符区别
Python2 中任意两个对象都可以比较
1. 11 < 'test' #True
Python3 中只有同一数据类型的对象可以比较
1. 11 < 'test' # TypeError: unorderable types: int() < str()
27.python数据类型转换
1)int():借助ascii码表
2)float:根据传入的值分类
28.python中的重载
重载定义:函数名相同,但是参数类型不同或者参数个数不同,根据传入不同的参数自动调用不同的函数
python中的重载:在语法上python不支持重载,但是python可以通过可变参数和函数内部类型判断实现重载功能
29.python中的反射
反射定义:在做程序开发中,我们常常会遇到这样的需求:需要执行对象里的某个方法,或需要调用对象中的某个变量,但是由于种种原因我们无法确定这个方法或变量是否存在,这是我们需要用一个特殊的方法或机制要访问和操作这个未知的方法或变量,这中机制就称之为反射。

python中的反射:
    1)hasattr:判断实例是否有某个属性或者方法
    2)getattr:获取实例的某个属性值或者方法
    3)setattr:为实例增加属性或者方法
    4)delattr:删除实力的属性,不能删除属性的方法
30.python的内存泄漏
虽然python有垃圾回收机制,但是也会存在内存泄漏问题
1)无穷大导致内存泄漏:i = 1024 ** 1024 ** 1024
2)循环引用导致内存泄漏:标记清理可以解决,weakref模块也可以
3)外面库导致内存泄漏
4)tracemalloc库可以定位内存泄漏位置
31.闭包
[详情点击](https://www.cnblogs.com/3me-linux/p/6761635.html)
定义:嵌套定义在非全局作用域里面的函数能够记住它在被定义的时候它所处的封闭命名空间
def outer():
    x = 1
    def inner():
        print x
    return inner

foo = outer()
foo()
# inner会记住被定义时的x的值
32.装饰器
基于闭包实现
from functools import wraps
"""它能保留原有函数的名称和docstring"""


"""
python装饰器
"""

# 不带参数装饰器
def debug(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print "[DEBUG]: enter {}()".format(func.__name__)
        print 'Prepare and say...', args
        return func(*args, **kwargs)
    return wrapper  # 返回


@debug
def say(something):
    print "hello {}!".format(something)


# 带参数装饰器
def logging(level):
    def wrapper(func):
        @wraps(func)
        def inner_wrapper(*args, **kwargs):
            print "[{level}]: enter function {func}()".format(level=level, func=func.__name__)
            return func(*args, **kwargs)
        return inner_wrapper
    return wrapper


@logging(level='INFO')
def say(something):
    print "say {}!".format(something)
33.封装继承多态
封装:本质是将事物相关的属性和方法封装在一个类里面,我们调用类创建实例的时候,不用关心类内部的代码细节
继承:子类需要复用父类里面的属性或者方法,当然子类也可以提供自己的属性和方法(python支持多继承,分经典类(深度优先)和新式类(广度优先))
多态:同一个方法不同对象调用同一个方法功能的表现形式不一样,只关心调用方法的实例
import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

obj1 = People()
obj2 = Dog()
obj1.talk()  # say hello'
obj2.talk()  # 'say wangwang'
34.python传值
a = [1,2,3]
for i in a:
    a.remove(i)
    
b = [1,2,3]
for i in b[:]:
    b.remove(i)  
35.super
用来调用父类的方法
super(父类,self).__init__()
先实例化父类,再调用方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值