Python语言特性

1、迭代器与生成器
迭代器是遵循迭代协议的对象,用户可以使用iter()以从任何序列得到迭代器(如list,tuple,dictionary,set等)
生成器(Generator),只是在需要返回数据的时候使用yield语句。每次next()语句被调用时,生成器会返回它脱离的位置(它会记忆语句最后一次执行的位置和所有的数据值。)
生成器能做到迭代器能做的所有事,而且因为自动创建iter()和next()方法,生成器显得特别简洁,而且也很高效,同时,使用生成器表达式取代列表解析可以节省内存。除了创建和保存程序状态的自动方法,当生成器终结时,还会抛出StopIteration异常。
变式提问:列表生成式中[]改成()之后数据结构是否会发生改变?
答案是会改变,因为从列表(迭代器)变成了生成器:

l=[x*x for x in range(10)]
print(l)
g=(x*x for x in range(10))
print(g)
>>>
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x7fc63794e410>

创建了一个generator后,基本上永远不会调用next()方法,而是通过for循环来迭代它。
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

>>> def odd():
...     print 'step 1'
...     yield 1
...     print 'step 2'
...     yield 3
...     print 'step 3'
...     yield 5
...
>>> o = odd()
>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5
>>> o.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

小结
generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。

要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。
2、关于装饰器
装饰器本质上是一个callable object,它可以让其他函数在不需要做任何代码的变动的前提下增加额外的功能,其返回值也是一个函数的对象,经常用于有切面需求的场景,比如插入日志,性能测试,事务处理,缓存等等。概括来讲,装饰器的作用就是为了已经存在的对象添加额外的功能。

import datetime

def timecheck(func):
    def wrapper(*args,**kwargs):
        if datetime.datetime.now().year==2020:
            func(*args,**kwargs)
        else:
            print('wahaha')
    return wrapper

@timecheck
def test(name):
    print('hello{},2020 happy'.format(name))

if __name__ == '__main__':
    test('guy')
>>>
wahaha   

decorator是一个返回函数的高阶函数,所以这里的timecheck接收一个函数作为参数,并返回一个函数。

借助Python的@语法,把decorator置于test函数的定义处,此时调用test()函数,不仅会运行now()函数本身,还会在运行now()函数前先运行timecheck函数,相当于执行了语句test = timecheck(now)
经过decorator装饰之后的函数,它们的__name__会发生改变,这里例子的就是从‘test’变成了’wrapper‘

test.__name__
'wrapper'

如果没有装饰器(此处为@timeback),执行test(‘guy’)的返回结果应该是hello guy,2020 happy,但是在函数timecheck中,需要对当前的年份进行了判断,相当于给test函数增加了额外的功能。结果很明显,今年是2019而不是2020,所以得到结果是wahaha。
3、猴子补丁
猴子补丁仅指在运行时动态改变类或模块,即函数在Python中可以像使用变量一样对它进行赋值等操作,为的是将第三方代码打补丁在不按预期运行的bug或feature上,适用于Python这种动态语言。

主要用处:
(1)在运行时替换方法、属性等
(2)在不修改第三方代码的情况下增加原来不支持的功能
(3)在运行时为内存中的对象增加patch而不是在磁盘的源代码中增加

class MyClass(object):
    def func1(self):
        print('1')
class ClName(object):
    def func2(self):
        print('2')
data=MyClass()
data.func1()
>>>
1

在上面加上两行代码:

MyClass.func1=ClName.func2
data.func1()
>>>
1
2

再次执行会发现,输出结果还有一个2,在这个过程中通过对MyClass.func1重新赋值,动态改变了输出的结果。
4、==和is的区别
==用来判断内容是否一致,is用来判断两者的地址是否一致,属于内存地址的判断
5、浅拷贝和深拷贝
Python中对象的赋值实际上是简单的对象引用,也就是说当你创建一个对象,然后把它赋值给另外一个变量的时候,Python并没有拷贝这个对象,而是调用了这个对象。真正的拷贝分为浅拷贝和深拷贝。
浅拷贝一般使用copy.copy(),可以进行对象的浅拷贝,但是不会拷贝对象内部的子对象。

import copy
a=[1,2,[3,4]]
b=copy.copy(a)
a[2][0]=0
a[0]=999
print(a)
print(b)
>>>
[999, 2, [0, 4]]
[1, 2, [0, 4]]

由于只拷贝了第一层元素,所以a[0]修改的时候,并不影响b;但是a[2][0]发生修改的时候,b也随之发生改变,因为没有拷贝子对象(也就是内层元素),此时两者是指向同一块内存地址。
深拷贝需要copy.deepcopy()进行,它会完全拷贝对象,也就是会包括内层元素:

import copy
a=[1,2,[3,4]]
b=copy.deepcopy(a)
a[2][0]=0
a[0]=999
print(a)
print(b)
>>>
[999, 2, [0, 4]]
[1, 2, [3, 4]]

深拷贝之后,a与b完全独立,指向不同的地址,所以a的改变并不会影响到b。
6、可变类型与不可变类型
可变类型传递的是内存中的地址,也就是说当进行修改操作时,会直接修改内存中的值,并没有开辟新的内存,可变类型的代表有list,dict。
不可变类型被改变时,并没有改变原内存地址中的值。而是开辟了一块新的内存,将原地址中的值复制过去,对这块新开辟的内存中的值进行操作,其代表有string,number,tuple。
因此可变类型与不可变类型的区别在于,修改前后是否指向同一个对象,也就是修改前后对象的内存地址是否发生改变。
7、Python的自省特性
自省就是面向对象的语言所写的程序在运行时,能够知道对象的类型。简单来说就是运行时能够获得对象的类型,比如type()、dir()、getattr()、hasattr()、isinstance()等方法。

a=[1,2,3]
b={'a':1,"b":2,"c":3}
c=True
print(type(a))
print(type(b))
print(type(c))
print(isinstance(a,list))
print(dir(b))
>>>
<class 'list'>
<class 'dict'>
<class 'bool'>
True
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

type函数返回的是变量的数据类型,isinstance判断变量(参数1)是否属于某数据类型(参数2),dir函数则会返回参数的属性、方法列表。
8、Python的下划线
前置单下划线_foo,这里的下划线是用来指定私有变量的一种方式,常用于模块中,在一个模块中以单下划线开头的变量和函数被默认当做内部函数,如果使用from a_module import * 导入时,这部分变量和函数不会被导入。
前置双下划线__foo,主要是为了区别和其他类相同的命名,避免该成员的名称与子类中的名称冲突。
前后双下划线__foo__,定义是Python中的魔法对象,如类成员的全局变量__init__、del、全局的__file__、__name__等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值