python必知必会的语言基础篇

本文详细介绍了Python编程的基础知识,包括数据类型、参数传递、内存管理、线程安全、迭代器与生成器以及闭包的概念。讲解了Python如何处理可变与不可变数据类型,特别是对引用计数和垃圾回收机制的深入理解。此外,还探讨了Python的线程安全问题,由于全局解释器锁(GIL)的存在,Python在同一时刻仅能执行一个线程。最后,提到了迭代器和生成器的使用,强调了生成器在节省内存方面的优势。通过实例解析了闭包的定义及其在函数嵌套中的应用。

python是动态(运行期确定类型)强类型(不会发生隐式转换)语言

1. python基本数据类型

6个标准数据类型:

  • Number(int float bool etc)
  • String
  • List
  • Tuple
  • Set
  • Dictionary

其中:

不可变数据:Number、String、Tuple
可变数据:List、Dictionary、Set

2. python如何传参

python传递的都是引用, 如果是可变数据,则直接修改;如果是不可变数据,则产生新对象,让形参指向新对象。

举例:

def first(l):
    l.append(0)
    print(id(l))
    print(l)

ll = []
print(id(ll))
first(ll) # [0]
first(ll) # [0, 0]

def second(s):
    print(id(s))
    s += 'a'
    print(id(s))
    print(s)

s = "test"
print(id(s))
second(s)
print(s)

另外两个关于形参的例子:

def clear_list(l):
    l = [] # 创建了新对象,与ll无关

ll = [1, 2, 3]
clear_list(ll)
print(ll) # [1, 2, 3]

def default(l=[]):
    l.append(1)
    print(l)
    print(id(l))

default() # [1]
default() # [1, 1]

第一个例子中,L是新创建的对象,与传入的LL无关;
第二个例子中,L默认参数只会在第一次调用的时候生成。

python中的 *args**kargs

用于处理可变参数,本质上*args被打包成tuple**kwargs被打包成为dict

举例子:

def print_multi_args(*args):
    print(type(args), args)
    for idx, val in enumerate(args):
        print(idx, val)

print_multi_args(1,2,3,'sad')

def print_kwargs(**kwargs):
    print(type(kwargs), kwargs)
    for k, v in kwargs.items():
        print('{}:{}'.format(k, v))

print_kwargs(a=1, b=2, c='qq')

3. python的线程安全

在这里插入图片描述
首先,解释器读取Python代码并检查是否有语法或格式错误。

如果发现错误,则暂停执行。如果没有发现错误,则解释器会将Python代码转换为等效形式或字节代码。

然后将字节码发送到Python虚拟机(PVM),这里Python代码将被执行,如果发现任何错误,则暂停执行,否则结果将显示在输出窗口中。

编译后的字节码在解释器中执行过程中,Cpython解释器中的GIL(Global interpreter Lock, 全局解释器GIL)会导致同一时刻只有一个线程执行字节码。

所以,在一个解释器进程中通过多线程的方式无法利用多核处理器来实现真正的并行。python伪装多线程,同一时刻只有一个线程真正运行。

我们通常说的线程互斥锁,是在另一个层面上保证线程安全。GIL保证了解释器级别的互斥。线程互斥锁是代码级别的互斥,保证程序级别共享数据的一致性。

4. Python内存管理

  1. 内存池
    创建大量消耗小内存的对象时,C中频繁调用new/malloc会导致大量的内存碎片,进而导致效率降低。
    内存池就是预先在内存申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,先从内存池分配内存,不够了再申请新的。
    pymalloc对于小的对象(< 236k)内存池申请,大的对象直接new/malloc申请。

  2. 垃圾回收机制
    GC做两件事情:1. 找到内存中无用的垃圾对象资源,2. 清除找到的这些垃圾对象,释放内存给其他对象使用。
    方法:

    • 引用计数:reference counting
    • 标记-清除(mark and sweep)解决容器对象可能产生的循环引用问题
    • 分代回收(generation collection)以空间换时间提高垃圾回收效率

引用计数:

对象在源码中的结构体如下:

typedef struct_object {
	int ob_refcnt;
	struct_typeobject *ob_type;
} PyObject;

PyObject是每个对象必有的内容,其中ob_refcnt就是作为引用计数。每当出现对象新的引用,ob_refcnt会增加;当引用对象被删除,ob_refcnt相应减少。引用计数为0时候,对象立即被回收,占用的内存空间被释放。

循环引用:

A B 相互引用而且没有外部引用AB中任意一个。

举例:

a = {}
b = {}

a['b'] = b
b['a'] = a

del a
del b

对于上例,如果使用引用计数法就会导致内存泄漏。python用两种方法来应对:

标记清除:

对象之间通过引用连在一起,构成以有向图。对象构成这个有向图的节点。引用关系构成这个有向图的边。从根对象(全局变量,调用栈,寄存器)出发,所有可达的对象标记为活动对象,不可达的就是要被清除的非活动对象。

分代技术:

python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,python将内存分为三代,分别对应三个链表,年轻代链表达到上限就会触发垃圾回收,将可回收的回收掉,不可回收的移动到中年代。以此类推。
分代机制是建立在标记清除技术基础上。

5. 迭代器与生成器

迭代器

容器(container)

多个元素组织在一起的数据结构,其元素可以逐个迭代获取,可以用 in, not in 关键字判断元素是否包含在容器中。常见的容器:list,set,deque

可迭代对象(iterables)

大部分container都是iterable,返回一个迭代器的都可以称为可迭代对象。

迭代器(iterator)

我们通常用 for in 语句对可迭代对象进行枚举,其底层机制是:可迭代对象通过iter()函数返回一个迭代器,迭代器提供一个next方法,调用这个方法得到容器下一个对象或者stopiteration错误。
迭代器是一个懒加载的工厂,需要他的时候才生成值返回,不调用的时候就是休眠状态等待下一次调用。

举例:

x = [1,2,3] # container
y = iter(x) # 调用迭代函数,返回一个迭代器
print(type(x), '  ', type(y))
# output: <class 'list'>    <class 'list_iterator'>
print(next(y))

生成器generator

生成器是升级版本的迭代器。相比迭代器的优势是,不会像迭代器那样占用大量内存。举个例子:
[i for i in range(1000000)] 这个列表中每个元素都会保存在内存中,实际上我们也许并不需要保存那么多东西,只是需要在使用next()函数的时候,再生成下一个对象。面向这个问题,生成器应运而生。比如这个例子,生成器的写法(i for i in range(1000000))

生成器的其他形式:

def example(start, stop, increment):
    x = start
    while x < stop:
        yield x
        x += increment

for n in example(0, 2, 0.5):
    print(n)

用图表示:

在这里插入图片描述

6. 闭包

函数套函数,内部函数用到外部函数的变量,内部函数为闭包(closure)

举例:

def addx(x):
    def adder(y):
        return x + y
    return adder

# c 是 return回来的adder函数
c = addx(8)
print(type(c))
print(c.__name__)
print(c(10))


# output:
<class 'function'>
adder
18

7. 深拷贝和浅拷贝

直接看例子:

import copy

a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)

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

print(a)
print(b)
print(c)
print(d)

# output:
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
[1, 2, 3, 4, ['a', 'b', 'c']]
[1, 2, 3, 4, ['a', 'b']]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值