1.迭代器和生成器
1.1可迭代对象的判断
使用for循环遍历取值的对象叫做可迭代对象
# 元组,列表,字典,字符串,集合,range都是可迭代对象
from collections import Iterable
# 判断对象是否是指定类型
result = isinstance((3, 5), Iterable)
print("元组是否是可迭代对象:", result)
result = isinstance([3, 5], Iterable)
print("列表是否是可迭代对象:", result)
result = isinstance({"name": "张三"}, Iterable)
print("字典是否是可迭代对象:", result)
result = isinstance("hello", Iterable)
print("字符串是否是可迭代对象:", result)
result = isinstance({3, 5}, Iterable)
print("集合是否是可迭代对象:", result)
result = isinstance(range(5), Iterable)
print("range是否是可迭代对象:", result)
result = isinstance(5, Iterable)
print("整数是否是可迭代对象:", result)
1.2 自定义可迭代对象
自定义可迭代对象: 在类里面定义__iter__方法创建的对象就是可迭代对象。
from collections import Iterable
# 自定义可迭代对象: 在类里面定义__iter__方法创建的对象就是可迭代对象
class MyList(object):
def __init__(self):
self.my_list = list()
# 添加指定元素
def append_item(self, item):
self.my_list.append(item)
def __iter__(self):
# 可迭代对象的本质:遍历可迭代对象的时候其实获取的是可迭代对象的迭代器, 然后通过迭代器获取对象中的数据
pass
my_list = MyList()
my_list.append_item(1)
my_list.append_item(2)
result = isinstance(my_list, Iterable)
print(result)
1.3 自定义迭代器对象
自定义迭代器对象: 在类里面定义__iter__和__next__方法创建的对象就是迭代器对象
iter函数: 获取可迭代对象的迭代器,会调用可迭代对象身上的__iter__方法
next函数: 获取迭代器中下一个值,会调用迭代器对象身上的__next__方法
from collections import Iterable
# 自定义可迭代对象: 在类里面定义__iter__方法创建的对象就是可迭代对象
class MyList(object):
def __init__(self):
self.my_list = list()
# 添加指定元素
def append_item(self, item):
self.my_list.append(item)
def __iter__(self):
# 可迭代对象的本质:遍历可迭代对象的时候其实获取的是可迭代对象的迭代器, 然后通过迭代器获取对象中的数据
my_iterator = MyIterator(self.my_list)
return my_iterator
# 自定义迭代器对象: 在类里面定义__iter__和__next__方法创建的对象就是迭代器对象
class MyIterator(object):
def __init__(self, my_list):
self.my_list = my_list
# 记录当前获取数据的下标
self.current_index = 0
# 判断当前对象是否是迭代器
result = isinstance(self, Iterator)
print("MyIterator创建的对象是否是迭代器:", result)
def __iter__(self):
return self
# 获取迭代器中下一个值
def __next__(self):
if self.current_index < len(self.my_list):
self.current_index += 1
return self.my_list[self.current_index - 1]
else:
# 数据取完了,需要抛出一个停止迭代的异常
raise StopIteration
my_list = MyList()
my_list.append_item(1)
my_list.append_item(2)
result = isinstance(my_list, Iterable)
print(result)
for value in my_list:
print(value)
1.4 生成器的概念
生成器是一类特殊的迭代器,它不需要再像上面的类一样写__iter__()和__next__()方法了, 使用更加方便。
创建生成器方法一,只要把一个列表生成式的 [ ] 改成 ( )
my_list = [i * 2 for i in range(5)]
print(my_list)
# 创建生成器
my_generator = (i * 2 for i in range(5))
print(my_generator)
# next获取生成器下一个值
# value = next(my_generator)
#
# print(value)
for value in my_generator:
print(value)
创建生成器方法二,在def函数里面看到有yield关键字那么就是生成器
def fibonacci(num):
a = 0
b = 1
# 记录生成fibonacci数字的下标
current_index = 0
print("--11---")
while current_index < num:
result = a
a, b = b, a + b
current_index += 1
print("--22---")
# 代码执行到yield会暂停,然后把结果返回出去,下次启动生成器会在暂停的位置继续往下执行
yield result
print("--33---")
return "嘻嘻"
fib = fibonacci(5)
value = next(fib)
print(value)
# return 和 yield的区别
# yield: 每次启动生成器都会返回一个值,多次启动可以返回多个值,也就是yield可以返回多个值
# return: 只能返回一次值,代码执行到return语句就停止迭代
2闭包和装饰器
2.1 闭包
外层函数返回内层函数的引用
# 定义一个函数
def test(number):
def test_in(number_in):
print("in test_in 函数, number_in is %d" % number_in)
return number+number_in
# 其实这里返回的就是闭包的结果
return test_in
# 给test函数赋值,这个20就是给参数number
ret = test(20)
# 注意这里的100其实给参数number_in
print(ret(100))
#注 意这里的200其实给参数number_in
print(ret(200))
2.2 装饰器
是给函数添加额外的功能
# ##################无参,无返回##################################
# 装饰器作用在不改变原函数代码的情况下添加<<额外的功能>>
# 装饰前的test(就是原先定义的那个test函数),是由func指向
# 装饰后的test,其实调用的是call_fun
# 1.闭包
# 2.装饰器
# 1.闭包
def deco(func):
def warpper():
print("添加额外的功能")
func()
return warpper
@deco
def test():
print("test")
test()
########################2.无参,有返回###################################
# 1.闭包
def deco(func):
def warpper():
print("添加功能")
return func() # 返回原先函数的值
return warpper
# 2.装饰器
@deco # @deco ===> test = deco(test)
def test():
print("test")
return 1000
print(test()) # warpper
######################3.有参,无返回#####################
# 1.闭包
def deco(func):
def warpper(args):
print("添加功能")
func(args) # 调用test
return warpper
# 2.装饰器
@deco
def test(args):
print(args)
test(123) # call_fun
######################4.有参,有返回############################
# 1.闭包
def deco(func):
def warpper(args):
print("添加功能")
return func(args)
return warpper
# 2.装饰器
@deco
def test(args):
return args
print(test(1000)) # call_fun
####################5.不定长参数,返回###################################
# 1.闭包
def deco(func):
def warpper(*args, **kwargs):
print("call_funn", args)
print("call_fun", kwargs)
return func(*args, **kwargs) # 拆包
return warpper
# 2.装饰器
@deco
def test(*args, **kwargs):
print(args)
print(kwargs)
return 100
print(test(1, a=2)) # 调用warpper
def deco1(func1):
def warpper1(*args, **kwargs):
print("添加功能--1")
return func1(*args, **kwargs)
return warpper1
def deco2(func2):
def warpper2(*args, **kwargs):
print("添加功能--2")
return func2(*args, **kwargs)
return warpper2
@deco2 test = deco2(warpper1)
@deco1 warpper1 = deco1(test)
def test():
print("功能test")
test()
添加功能--2
添加功能--1
功能test
类装饰器
# 使用类装饰器
class SetFun(object):
def __init__(self, func):
self.func = func # 把传入的函数引用保存
def __call__(self, *args, **kwargs):
# 添加的功能
print("添加的功能", self.value)
# 把以前的功能执行一下
self.func()
@classmethod
def set_value(cls, value):
print(value)
# return SetFun
# 类属性
cls.value = value
return cls
# @SetFun.set_value("添加功能!")
# 第一步SetFun.set_value("添加功能!"),返回类引用
# 第二步@类引用===> @SetFun ===> test = SetFun(test)
@SetFun.set_value("添加功能!")
def test():
print("test")
3.拷贝
3.1 浅拷贝
浅拷贝是对一个对象的顶层数据的拷贝
import copy
<<< a = [11,22,33]
<<< b = copy.copy(a)
<<< id(a)
<<< 59275144
<<< id(b)
<<< 59525600
<<< a.append(44)
<<< a
<<< [11, 22, 33, 44]
<<< b
<<< [11, 22, 33]
<<< a = [11,22]
<<< b = [22,33]
<<< id(a)
<<< 58890680
<<< id(b)
<<< 53652634
<<< c = [a,b]
<<< d = copy.copy(c)
<<< id(c)
<<< 52390123
<<< id(d)
<<< 53590678
<<< a.append(44)
<<< c
<<< [[11,22,44],[22,33]]
<<< d
<<< [[11,22,44],[22,33]]
<<< id(d[0])
<<< 58890680
<<< id(d[1])
<<< 53652634
3.2 深拷贝
深拷贝是对于一个对象所有层次的拷贝(递归)
import copy
<<< a = [11,22,33]
<<< b = copy.deepcopy(a)
<<< id(a)
<<< 59275144
<<< id(b)
<<< 59525600
<<< a.append(44)
<<< a
<<< [11, 22, 33, 44]
<<< b
<<< [11, 22, 33]
<<< a = [11,22]
<<< b = [22,33]
<<< id(a)
<<< 58890680
<<< id(b)
<<< 53652634
<<< c = [a,b]
<<< d = copy.deepcopy(c)
<<< id(c)
<<< 52390123
<<< id(d)
<<< 53590678
<<< a.append(44)
<<< c
<<< [[11,22,44],[22,33]]
<<< d
<<< [[11,22],[22,33]]
<<< id(d[0])
<<< 58634589
<<< id(d[1])
<<< 56523852
注意 :
- copy.copy对于可变类型,会进行浅拷贝
- copy.copy和copy.deepcopy对于不可变类型没有意义,全部等价于对象之间的赋值操作。
- copy.copy和copy.deepcopy对于一维的数据一样的。
4.property属性
一种用起来像是使用的实例属性一样的特殊属性,可以对应于某个方法。
# ############### 定义 ###############
class Foo:
def func(self):
pass
# 定义property属性
@property
def prop(self):
pass
# ############### 调用 ###############
foo_obj = Foo()
foo_obj.func() # 调用实例方法
foo_obj.prop # 调用property属性
#coding=utf-8
# ############### 定义 ###############
class Goods:
"""python3中默认继承object类
以python2、3执行此程序的结果不同,因为只有在python3中才有@xxx.setter @xxx.deleter
"""
@property
def price(self):
print('@property')
@price.setter
def price(self, value):
print('@price.setter')
@price.deleter
def price(self):
print('@price.deleter')
# ############### 调用 ###############
obj = Goods()
obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数
del obj.price # 自动执行 @price.deleter 修饰的 price 方法
property对象的类属性
class Foo:
def func(self):
return "test"
BAR = property(func)
obj = Foo()
reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值
print(reuslt)
property方法中有个四个参数
第一个参数是方法名,调用 对象.属性 时自动触发执行方法
第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息
#coding=utf-8
class Foo(object):
def get_price(self):
print("getter...")
return '100'
def set_price(self, value):
"""必须两个参数"""
print("setter...")
return 'set value' + value
def del_price(self):
print("deleter...")
return '100'
BAR = property(get_price, set_price, del_price, "description...")
obj = Foo()
obj.BAR # 自动调用第一个参数中定义的方法:get_price
obj.BAR = "200" # 自动调用第二个参数中定义的方法:set_price方法,并将“200”当作参数传入
desc = Foo.BAR.__doc__ # 自动获取第四个参数中设置的值:description...
print(desc)
del obj.BAR # 自动调用第三个参数中定义的方法:del_bar方法
5.魔法属性
5.1 doc
表示类的描述信息
在这里插入代码片
class Foo:
""" 描述类信息,这是用于看片的神奇 """
def func(self):
pass
print(Foo.__doc__)
#输出:类的描述信息
5.2 module 和 class
- module 表示当前操作的对象在那个模块
- class 表示当前操作的对象的类是什么
# -*- coding:utf-8 -*-
--- test.py ---
class Person(object):
def __init__(self):
self.name = 'laowang'
--- main.py ---
from test import Person
obj = Person()
print(obj.__module__) # 输出 test 即:输出模块
print(obj.__class__) # 输出 test.Person 即:输出类
5.3 init
初始化方法,通过类创建对象时,自动触发执行
class Person:
def __init__(self, name):
self.name = name
self.age = 18
obj = Person('zhangsan') # 自动执行类中的 __init__ 方法
5.4 del
当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,del的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
def __del__(self):
pass
5.5 call
- 对象后面加括号,触发执行。
注:init方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
5.6 dict
- 类或对象中的所有属性
类的实例属性属于对象;类中的类属性和方法等属于类,即:
class Province(object):
country = 'China'
def __init__(self, name, count):
self.name = name
self.count = count
def func(self, *args, **kwargs):
print('func')
# 获取类的属性,即:类属性、方法、
print(Province.__dict__)
# 输出:{'__dict__': <attribute '__dict__' of 'Province' objects>, '__module__': '__main__', 'country': 'China', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Province' objects>, 'func': <function Province.func at 0x101897950>, '__init__': <function Province.__init__ at 0x1018978c8>}
obj1 = Province('山东', 10000)
print(obj1.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 10000, 'name': '山东'}
obj2 = Province('山西', 20000)
print(obj2.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 20000, 'name': '山西'}
5.7 str
- 如果一个类中定义了str方法,那么在打印 对象 时,默认输出该方法的返回值。
class Foo:
def __str__(self):
return 'test'
obj = Foo()
print(obj)
# 输出:test
21.8 getitem、setitem、delitem
- 用于索引操作,如字典。以上分别表示获取、设置、删除数据
# -*- coding:utf-8 -*-
class Foo(object):
def __getitem__(self, key):
print('__getitem__', key)
def __setitem__(self, key, value):
print('__setitem__', key, value)
def __delitem__(self, key):
print('__delitem__', key)
obj = Foo()
result = obj['k1'] # 自动触发执行 __getitem__
obj['k2'] = 'test' # 自动触发执行 __setitem__
del obj['k1'] # 自动触发执行 __delitem__