1 ==,is的使用
- is 是比较两个引用是否指向了同一个对象(地址引用比较)。
- == 是比较两个对象是否相等。(比较的数值)
2 深拷贝、浅拷贝、copy.copy
2.1 浅拷贝
浅拷贝:
- 拷贝的是地址引用。可以找到共同的内容
- 一方修改了,另一方受影响
a = [1,2,3,4]
b = a
print(id(a)) #2540558597256
print(id(b)) #2540558597256
a.append(5)
print(a) #[1, 2, 3, 4, 5]
print(b) #[1, 2, 3, 4, 5]
2.2 深拷贝
深拷贝:
- 深拷贝的是内容一样。地址不一样。
- 一方修改了,另一方不受影响
-
b = copy.deepcopy(a)
b得到的内容与a的内容完全一样,地址不一样。
就算a中有对象引用,b中对应的引用的对象依然是内容一样,地址不一样。
递归拷贝
注意:
如果是一个不可变对象(内部存储还是不可变对象),深拷贝的结果 = 浅拷贝,地址一样
2.3 copy.copy
copy.copy
- copy.copy这个函数结果会因为是可变或者不可变导致结果不同
- 只能拷贝一层。根据类型有关。如果是列表(可变类型),深拷贝。如果是元组(不可变)浅拷贝
- 如果里面还有嵌套的对象,浅拷贝
- b = copy.copy(a)
import copy
a = [1,2,3,4]
#相当于深拷贝
b = copy.copy(a)
print(id(a))
print(id(b))
a.append(5)
print(a)
print(b)
print('*'*50)
a = (1,2,3,4)
#相当于浅拷贝
b = copy.copy(a)
print(id(a))
print(id(b))
----------------------------
a = [11,22,33]
b = [44,55,66]
c = [a,b]
d = copy.copy(c)
print(id(c))
print(id(d))
print(c)
print(d)
print('*'*50)
a.append(120)
#c[0].append(120)
print(c)
print(d)
print('*'*50)
a = [11,22,33]
b = [44,55,66]
c = (a,b)
d = copy.copy(c)
print(id(c))
print(id(d))
print(c)
print(d)
print('*'*50)
a.append(120)
#c[0].append(120)
print(c)
print(d)
3 属性property
3.1私有属性添加getter和setter方法
私有的内容,对外不能直接访问。
如果想对外访问,需要提供可以访问的方法,比如这里的getMoney,setMoney
调用的时候比较麻烦。
能不能像操作属性一样呢?
属性名 = property(get,set)
class Money(object):
def __init__(self):
self.__money = 0
def getMoney(self):
return self.__money
def setMoney(self, value):
if isinstance(value, int):
self.__money = value
else:
print("error:不是整型数字")
m = Money()
print(m.getMoney())
m.setMoney(10)
print(m.getMoney())
3.2 使用property升级getter和setter方法
class Money(object):
def __init__(self):
self.__money = 0
def getMoney(self):
return self.__money
def setMoney(self, value):
if isinstance(value, int):
self.__money = value
else:
print("error:不是整型数字")
money = property(getMoney,setMoney)
m.money = 120 #相当于上面的m.setMoney(120)
print(m.money) #相当于上面的m.getMoney
#或者是
print(Money.money)
3.3 使用property取代getter和setter方法
class Money(object):
def __init__(self):
self.__money = 0
@property
def money(self):
return self.__money
@money.setter
def money(self, value):
if isinstance(value, int):
self.__money = value
else:
print("error:不是整型数字")
m = Money()
print(m.money)
m.money = 120
print(m.money)
4 生成器
4.1 什么是生成器
如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
4.2 创建生成器方法1
要创建一个生成器,有很多种方法。第一种方法很简单,只要把一个列表生成式的 [ ] 改成 ( )
#列表生成式
ls = [x for x in range(100)]
print(ls)
#生成器
ge = (x**2 for x in range(1000))
print(ge)
print(type(ge))
i = 0
while i<19:
next(ge)
i+=1
print(next(ge))
总结
生成器保存的是算法,每次调用 next(G) ,就计算出 G 的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration 的异常。当然,这种不断调用 next() 实在是太变态了,正确的方法是使用 for 循环,因为生成器也是可迭代对象。所以,我们创建了一个生成器后,基本上永远不会调用 next() ,而是通过 for 循环来迭代它,并且不需要关心 StopIteration 异常。
4.3 创建生成器方法2 yield 值
yield 值
- 调用函数,得到一个生成器对象。这个函数没有执行
- next调用1得到的对象,如果遇到了yield,代码会阻塞,next的返回值就yield后的值
def fib(times):
print('0....')
n = 0
a,b = 0,1
while n<times:
print('1....')
yield b
print('2....')
a,b = b,a+b
n+=1
print('3....')
ge = fib(5)
print(ge)
print('*'*50)
m = 0
while m<5:
print(next(ge))
m+=1
4.4 send的使用
第一种和第二种,一旦生成器确定,算法不能改变。
这里的例子,定义了变量(temp),可以使用send发送参数,发给这里变量。
根据这个变量的值的不同,可以改变算法的逻辑。
所以,这种写法的作用:在运行过程中,可以改变算法
def gen():
i = 0
while i<1000:
temp = yield i
if temp==True:
#逻辑代码
print('执行A计划')
i+1
else:
#逻辑代码
print('执行B计划')
i+=2
myGenerator = gen()
ret = next(myGenerator)
print(ret)
#1、为当前停止的代码的左侧变量赋值
#2、生成器往下走一个行,返回yield值
ret = myGenerator.send(True)
print(ret)
ret = myGenerator.send(False)
print(ret)
4.5 模拟多任务实现方式之一:模拟协程
import time
def test1():
while True:
print("--王者荣耀--")
#time.sleep(2)
yield None
def test2():
while True:
print("--music--")
yield None
def main():
t1 = test1()
t2 = test2()
while True:
t1.__next__()
t2.__next__()
main()
4.6 总结
总结
- 生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。
- 生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。
生成器的特点:
- 节约内存
- 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
5 迭代器
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
5.1 可迭代对象
以直接作用于 for 循环的数据类型有以下几种:
- 一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;
- 一类是 generator ,包括生成器和带 yield 的generator function。
这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable 。
5.2 迭代器
isinstance(对象,Iterable)
如果结果为True
只是表示,这些对象以使用for循环迭代遍历,可以使用next
import collections
ge = (x for x in range(10))
print(isinstance(ge,collections.Iterable)) #True
print(isinstance(ge,collections.Iterator)) #True
print(next(ge)) #0
print('************************华丽的分割线************************')
ls = [x for x in range(10)]
print(isinstance(ls,collections.Iterable)) #True
print(isinstance(ls,collections.Iterator)) #False
for i in ls:
print(i) #0-9的数
5.3 iter()函数
- 生成器都是 Iterator 对象,但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator 。
- 把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数:
ls = [33,4,5,6,7,8]
it=iter(ls)
for i in range(len(ls)):
print(next(it)) #33-8的数
总结
- 凡是可作用于 for 循环的对象都是 Iterable 类型;
- 凡是可作用于 next() 函数的对象都是 Iterator 类型
- 集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,不过可以通过 iter() 函数获得一个 Iterator 对象。
- 目的是在使用集合的时候,减少占用的内容。
6 闭包
6.1 函数引用
def test1():
print("--- in test1 func----")
#调用函数
test1()
#此是ret引用函数
ret = test1
print(id(ret)) #18779264
print(id(test1)) #18779264,地址都一样,说明指向同一个内存地址
#通过引用调用函数
ret() #--- in test1 func----
6.2 闭包
- 在函数内部再定义一个函数,并且这个内部函数用到了外部函数的局部变量
- 那么将这个内部函数以及用到的一些局部变量称之为闭包
def outer(num):
print('outer...')
def inner():
print('num=%s'%num)
return inner
ret = outer(100) #outer...
ret() #num=100
ret() #num=100
def line_conf(a, b):
def line(x):
return a*x + b
return line
line1 = line_conf(2,3)
print(line1(10)) #23
line2 = line_conf(3,4)
print(line2(10)) #34
闭包的优缺点
- 闭包似优化了变量,原来需要类对象完成的工作,闭包也可以完成
- 由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存
7 装饰器
- 装饰器,装饰器是闭包现象的一种体现,功能就是在运行原来功能基础上,加上一些其它功能,比如权限的验证,比如日志的记录等等。不修改原来的代码,进行功能的扩展。
7.1 简单的装饰器
def outer(func):
print('outer...')
def inner():
print('inner...')
func()
return inner
def save():
print('save...')
ret = outer(save) #outer
ret() #inner... save...
def login(func):
def inner():
name = input('输入用户名:')
pwd = input('输入密码:')
if name=='laowang' and pwd=='123':
func()
else:
print('赶紧去登录。。。。。。')
return inner
@login
def save():
print('save...')
save()
7.2 多个装饰器
- 多个装饰器,按照从内往外(从下往上)先后顺序执行
- 为了方便记忆:可以理解为先写后运行,先写后结束
def makeBold(fn):
print('makeBold...')
def wrapped():
return "--1--" + fn() + "--1--"
return wrapped
def makeItalic(fn):
print('makeItalic...')
def wrapped():
return "--2--" + fn() + "--2--"
return wrapped
@makeBold
@makeItalic
def test():
return "hello world-test"
print(test())
#结果
#makeItalic...
#makeBold...
#--1----2--hello world-test--2----1--
7.3 装饰器功能
- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 异常的处理
- 缓存
7.4 装饰器示例
- 无参数的函数
from time import ctime, sleep
def timefun(func):
def wrappedfunc():
print("%s called at %s"%(func.__name__, ctime()))
func()
return wrappedfunc
@timefun
def foo():
print("I am foo")
foo() #foo called at Thu Jul 20 16:03:59 2017
#I am foo
sleep(2)
foo()
foo = timefun(foo)
#foo先作为参数赋值给func后,foo接收指向timefun返回的wrappedfunc
foo()
#调用foo(),即等价调用wrappedfunc()
#内部函数wrappedfunc被引用,所以外部函数的func变量(自由变量)并没有释放
#func里保存的是原foo函数对象
- 被装饰的函数有参数
def timefun(func):
def wrappedfunc(a, b):
print("%s called at %s"%(func.__name__, ctime()))
print(a, b)
func(a, b)
return wrappedfunc
@timefun
def foo(a, b):
print(a+b)
foo(3,5)
#foo called at Thu Jul 20 16:07:48 2017
#3 5
#8
- 被装饰的函数有不定长参数
from time import ctime, sleep
def timefun(func):
def wrappedfunc(*args, **kwargs):
print(args)
print(kwargs)
print("%s called at %s"%(func.__name__, ctime()))
func(*args,**kwargs)
return wrappedfunc
@timefun
def foo(a, b, c,num):
print(a+b+c)
print(num)
foo(3,5,7,num=123)
#(3, 5, 7)
#{'num': 123}
#foo called at Thu Jul 20 16:11:06 2017
#15
#123
- 装饰器中的return
from time import ctime, sleep
def timefun_arg(pre="hello"):
def timefun(func):
def wrappedfunc():
print("%s called at %s %s"%(func.__name__, ctime(), pre))
return func()
return wrappedfunc
return timefun
@timefun_arg("wangcai")
def foo():
print("I am foo")
@timefun_arg("python")
def too():
print("I am too")
foo()
#foo called at Thu Jul 20 16:23:48 2017 wangcai
#I am foo
print('************************华丽的分割线************************')
too()
#too called at Thu Jul 20 16:23:48 2017 python
#I am too
总结:
一般情况下为了让装饰器更通用,可以有return
- 装饰器带参数,在原有装饰器的基础上,设置外部变量
def haha(x):
def outer(func):
def inner():
if x%2==0:
return func()+'八'
else:
return '八'+func()
return inner
return outer
@haha(1)
def laowang():
return '老王'
print(laowang()) #八老王
- 类装饰器(扩展,非重点)
装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重写了call()方法,那么这个对象就是callable的。
class Test(object):
def __init__(self, func):
print("---初始化---")
print("func name is %s"%func.__name__)
self.__func = func
def __call__(self):
print("---装饰器中的功能---")
self.__func()
#说明:
#1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象
# 并且会把test这个函数名当做参数传递到__init__方法中
# 即在__init__方法中的func变量指向了test函数体
#
#2. test函数相当于指向了用Test创建出来的实例对象
#
#3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的__call__方法
#
#4. 为了能够在__call__方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存这个函数体的引用
# 所以才有了self.__func = func这句代码,从而在调用__call__方法中能够调用到test之前的函数体
@Test
def test():
print("----test---")
test()
showpy()#如果把这句话注释,重新运行程序,依然会看到"--初始化--"
运行结果如下:
---初始化---
func name is test
---装饰器中的功能---
----test---
8 python是动态语言
8.1 动态语言的定义
动态编程语言是高级程序设计语言的一个类别,在计算机科学领域已被广泛应用。它是一类 在运行时可以改变其结构的语言 :例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。动态语言目前非常具有活力。例如JavaScript便是一个动态语言,除此之外如 PHP 、 Ruby 、 Python 等也都属于动态语言,而 C 、 C++ 等语言则不属于动态语言。----来自维基百科
8.2 运行的过程中给类、对象绑定(添加)属性、方法
class mv_hero:
def __init__(self,name,HP,MP):
self.name = name
self.HP = HP
self.MP = MP
#调用,实例化
gtx = mv_hero('cjr',10,10)
print(gtx.name) #cjr
#添加一个实例属性
gtx.XP = 100
print(gtx.XP) #100
#添加一个类属性
mv_hero.xx = 99
#gtx.xx = 111
print(gtx.xx) #99
#定义一个类方法
@classmethod
def atteck(cls):
cls.num = 100
#定义一个静态方法
@staticmethod
def test_hero():
print('--test_hero--')
#给mv_hero类绑定类方法
mv_hero.atteck = atteck
#调用刚才绑定的类方法
mv_hero.atteck()
print(mv_hero.num) #100
#给mv_hero类绑定静态方法
mv_hero.test_hero = test_hero
#调用刚才绑定的静态方法
mv_hero.test_hero() #--test_hero--
import types
#定义一个实例方法
def fly(self, speed):
print("%s在移动, 速度是 %s"%(self.name, speed))
#给mv_hero中的对象绑定实例方法
gtx.fly = types.MethodType(fly, gtx)
#调用刚才的实例方法
gtx.fly(180) #cjr在移动, 速度是 180
9 元类
现在回到我们的大主题上来,究竟是为什么你会去使用这样一种容易出错且晦涩的特性?好吧,一般来说,你根本就用不上它!
'''
使用type创建类
type的第3个参数
1、字符串 类名
2、元组 父类
3、字典 类属性
'''
'''
class Test:
pass
'''
Test = type('Test',(),{})
print(Test)
Test = type('Test',(),{'name':'老王','age':10})
print(Test.name)
class Fu:
def fu(self):
print('fu...')
Zi = type('Zi',(Fu,),{})
print(Zi.__mro__)
print('***************************************华丽的分割线***************************************')
def haha(self):
print('haha...')
def __init__(self,num):
print('self...')
self.num = num
@classmethod
def hehe(cls):
print('hehe...')
Test = type('Test',(),{'name':'老王','age':10,'haha':haha,'hehe':hehe,'__init__':__init__})
t = Test(110)
t.haha()
Test.hehe()
10 垃圾回收
10.1 小整数对象池
- 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。
- Python 对小整数的定义是 [-5, 257) 这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,所有位于这个范围内的整数使用的都是同一个对象.
- 同理,单个字母也是这样的。
- 但是当定义2个相同的字符串时,引用计数为0,触发垃圾回收
10.2 大整数对象池
- 每一个大整数,均创建一个新的对象
10.3 intern机制
python创建9个”HelloWorld”对象,让他只占用一个”HelloWorld”所占的内存空间,python中有这样一个机制——intern机制,靠引用计数去维护何时释放。
字符串(含有空格),不可修改,没开启intern机制,不共用对象,引用计数为0,销毁。
总结
- 小整数[-5,257)共用对象,常驻内存
- 单个字符共用对象,常驻内存
- 单个单词,不可修改,默认开启intern机制,共用对象,引用计数为0,则销毁
10.4Garbage collection(GC垃圾回收)
python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略
11 内建属性
12 内建函数
- map():map函数会根据提供的函数对指定序列做映射
map(function, sequence[, sequence, ...]) -> list
·function:是一个函数
·sequence:是一个或多个序列,取决于function需要几个参数
·返回值是一个列表
参数序列中的每一个元素分别调用function函数
返回包含每次function函数返回值的list。
注意:先转成list才能print
>>>def square(x) : # 计算平方数
... return x ** 2
>>> map(square, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5
[1, 4, 9, 16, 25]
>>> map(lambda x: x ** 2, [1, 2, 3, 4, 5]) # 使用 lambda 匿名函数
[1, 4, 9, 16, 25]
# 提供了两个列表,对相同位置的列表数据进行相加
>>> map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
[3, 7, 11, 15, 19]
- range():
range(start, stop[, step]) -> list of integers
·start:计数从start开始。默认是从0开始。例如range(5)等价于range(0,5);
·stop:到stop结束,但不包括stop.例如:range(0,5) 是[0, 1, 2, 3, 4]没有5
·step:每次跳跃的间距,默认为1。例如:range(0,5) 等价于range(0, 5, 1)
python2中range返回列表,python3中range返回一个迭代值。如果想得到列表,可通过list函数
- filter():filter函数会对指定序列执行过滤操作
filter(function or None, sequence) -> list, tuple, or string
·function:接受一个参数,返回布尔值True或False
·sequence:序列可以是str,tuple,list
·返回值是一个列表
过滤出列表中的所有奇数:
def is_odd(n):
return n % 2 == 1
newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(newlist)
输出结果 :
[1, 3, 5, 7, 9]
- sorted()
sort 与 sorted 区别:
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。
sorted(iterable, key=None, reverse=False) --> new sorted list
reverse默认值为False,升序排序
>>>a = [5,7,6,3,4,1,2]
>>> b = sorted(a) # 保留原列表
>>> a
[5, 7, 6, 3, 4, 1, 2]
>>> b
[1, 2, 3, 4, 5, 6, 7]
>>> L=[('b',2),('a',1),('c',3),('d',4)]
>>> sorted(L, cmp=lambda x,y:cmp(x[1],y[1])) # 利用cmp函数
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> sorted(L, key=lambda x:x[1]) # 利用key
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
>>> sorted(students, key=lambda s: s[2]) # 按年龄排序
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
>>> sorted(students, key=lambda s: s[2], reverse=True) # 按降序
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
- reduce():reduce函数会对参数序列中元素进行累积
reduce(function, sequence[, initial]) -> value
·function:该函数有两个参数
·sequence:序列可以是str,tuple,list
·initial:固定初始值
reduce依次从sequence中取一个元素,
和上一次调用function的结果做参数再次调用function。
第一次调用function时,如果提供initial参数,
会以sequence中的第一个元素和initial作为参数调用function,
否则会以序列sequence中的前两个元素做参数调用function。
注意function函数不能为None。
在Python3里,reduce函数已经被从全局名字空间里移除了,它现在被放置在fucntools模块里用的话要先引入:from functools import reduce
>>>def add(x, y) : # 两数相加
... return x + y
...
>>> reduce(add, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5
15
>>> reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数
15
def f(x,y):
print('x=%s,y=%s'%(x,y))
return x+y
#ret = functools.reduce(lambda x, y: x+y, ['a','b','c','d'],'o')
ret = functools.reduce(f, ['a','b','c','d'],'o')
运行结果:
x=o,y=a
x=oa,y=b
x=oab,y=c
x=oabc,y=d
13 functools
functools 是python2.5被引人的,一些工具函数放在此包里。
知道有这么个东西
14 模块进阶
14.1 常用标准库
标准库 | 说明 |
---|---|
builtins | 内建函数默认加载 |
sys | 操作系统借口 |
functooks | 常用的工具 |
json | 编码和解码JSON对象 |
logging | 记录日志、调试 |
multiprocessing | 多进程 |
threading | 多线程 |
copy | 拷贝 |
time | 时间 |
datetime | 日期和时间 |
calendar | 日历 |
hashlib | 加密算法 |
random | 生成随机数 |
re | 字符串正则匹配 |
socket | 标准的BSD Sockets API |
shutil | 文件和目录管理 |
glob | 基于文件通配符搜索 |
更多标准库
http://python.usyiyi.cn/translate/python_352/library/index.html
15 编码风格
在pycharm里,Ctrl+Alt+L自动排版,排版的时候注意看一看就记住了
16 代码调试
pycharm
步骤:
- 设置断点
- shift+f9 开始调试
- 光标就在断点处停了。这一行没有运行的
- 下一行:f8
- 进入方法:f7
- 跳到下一个断点:alt+f9
- 进入方法,跳出这一步,shift+f8
网友评论