python的高级属性探究笔记-包括但不限于 动态性,生成器,迭代器,闭包,装饰器

python 是门动态语言

class Person(object):
    num = 0
    def __init__(self, name=None, age = None):
        self.name = name
        self.age = age
        
p = Person('xm', '24')
p.name
'xm'
p.sex = 'male'
p.sex
'male'
Person.sex = None
p2 = Person('xl', 24)
print(p2.sex)
None
# 运行过程中给类绑定方法
def eat(self):
    print('eat food')
    
import types
Person.eat = types.MethodType(eat, Person)
p.eat()
eat food
# 定义一个类方法
@classmethod
def t1(cls):
    cls.num = 100
# 添加
Person.t1 = t1
# 调用
Person.t1()
print(Person.num)
100
# 定义一个静态方法
@staticmethod
def t2():
    print('--------static method--------')
# 绑定
Person.t2 = t2
# 调用
Person.t2()
--------static method--------

运行的过程中删除属性方法

del Person.t2
Person.t2()
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-123-f8efff5b70b3> in <module>()
----> 1 Person.t2()


AttributeError: type object 'Person' has no attribute 't2'

玩动态语言的时候小心动态的坑
如何避免,使用’slots

# 如果我们想要限制实例的属性怎么办?比如,只允许对Person实例添加name和age属性。
class Person(object):
    __slots__ = ('name', 'age')
    
p = Person()
p.name = 'hh'
p.age = 20
p.score = 100

#使用__slots__要注意,
#__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-126-91c47bf50c73> in <module>()
----> 1 p.score = 100


AttributeError: 'Person' object has no attribute 'score'

‘’

1.生成器


# 1
l = [x * 2 for x in range(5)]
l
[0, 2, 4, 6, 8]
g = (x * 2 for x in range(5))
g
<generator object <genexpr> at 0x10298f8b8>
for i in g:
    print(i)
0
2
4
6
8
# 上面的生成器被使用过,无法再用?
g = (x * 2 for x in range(5))
next(g)
0
next(g)
2
next(g)
4
next(g)
6
next(g)
8
next(g)
---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-138-e734f8aca5ac> in <module>()
----> 1 next(g)


StopIteration: 

生成器保存的是算法
每次调用 next(G) ,就计算出 G 的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出 StopIteration 的异常。当然,这种不断调用 next() 实在是太变态了,正确的方法是使用 for 循环,因为生成器也是可迭代对象。所以,我们创建了一个生成器后,基本上永远不会调用 next() ,而是通过 for 循环来迭代它,并且不需要关心 StopIteration 异常。

# 方法2
# 用函数
# 此处的例子使用斐波那契数列
def fib(times):
    n = 0
    a,b = 0,1
    while n < times:
        print(b)
        a,b = b,a+b
        n += 1
    return 'done'

fib(5)
1
1
2
3
5





'done'
def fib(times):
    n = 0
    a,b = 0,1
    while n < times:
        yield b
        a,b = b,a+b
        n += 1
    return 'done'

F = fib(5)
for i in fib(5):
    print(i)
1
1
2
3
5

yield 性质探究

程序执行到yield时就会停止
知道再次调用这个函数的时候,会重新在yield下一步开始

def test():
    i = 0
    while i < 5:
        temp = yield i
        print(temp)
        i += 1
t = test()
# t为一个生成器
t.__next__()
0
t.__next__()
None





1
t.__next__()
None





2
t.send('hh') # send把'hh'传给了test中得temp
hh





3
next(t)
None





4
# 生成器的应用
def test1():
    while True:
        print('--1--')
        yield None
        
def test2():
    while True:
        print('--2--')
        yield None

#t1 = test1()
#t1 = test2()
# while True:
#    t1.__next__()
#    t2.__next__()

# 多任务: 看上去同时执行的程序就是多任务,切换足够快
# 这种事三种多任务方式的一种: 协程

2.迭代器

1> 可迭代对象
以直接作用于 for 循环的数据类型有以下几种:

一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;

一类是 generator ,包括生成器和带 yield 的generator function。

这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable 。

2> 判断是否可以迭代

from collections import Iterable

isinstance([], Iterable)
True
isinstance((), Iterable)
True
isinstance((x for x in range(10)), Iterable)

True
isinstance(100, Iterable)
False

3> 迭代器

# 可以被next()调用并不断返回下一个值的对象称为 迭代器 : Iterator
# 可以使用 isinstance() 判断一个对象是否是 Iterator 对象:

from collections import Iterator

isinstance([], Iterator)# 可迭代对象并不是一个迭代器
/Users/goodbyekiller/anaconda3/lib/python3.7/site-packages/ipykernel_launcher.py:4: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working
  after removing the cwd from sys.path.





False
isinstance((x for x in range(10)), Iterator)
True

4> iter() 函数
生成器都是 Iterator 对象

但 list 、 dict 、 str 虽然是 Iterable ,却不是 Iterator 。

把 list 、 dict 、 str 等 Iterable 变成 Iterator 可以使用 iter() 函数

isinstance(iter([]), Iterator)
True

3.闭包

def test1():
    print("--- in test1 func----")

ret = test1 # 变量ret存储指向函数test1的指针
print(id(test1))
print(id(ret))
4338532424
4338532424
# 什么是闭包
def test(n):
    # 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量
    # 那么将这个函数以及用到的一些变量称之为闭包
    def test_in(n_in):
        print(f'在 test_in 函数中, n_in 是{n_in}')
        return n + n_in
    # 返回闭包的结果
    return test_in

ret = test(20)

print(ret(100))
print(' ')
print(test(20)(100))
print(' ')
print(test(20,100))
在 test_in 函数中, n_in 是100
120
 
在 test_in 函数中, n_in 是100
120
 



---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-170-84387b2ca350> in <module>()
     15 print(test(20)(100))
     16 print(' ')
---> 17 print(test(20,100))


TypeError: test() takes 1 positional argument but 2 were given

内部函数对外部函数作用域里变量的引用(非全局变量),则称内部函数为闭包。

nonlocal访问外部函数的局部变量(python3)

def counter(start=0):
    def incr():
        nonlocal start
        start += 1
        return start
    return incr

c1 = counter(5)
print(c1())
print(c1())
6
7
# 一个闭包应用的实际例子

def line_conf(a, b):
    def line(x):
        return a*x + b
    return line

line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5))
print(line2(5))



#这个例子中,函数line与变量a,b构成闭包。
#在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个变量的取值,
#这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。
#我们只需要变换参数a,b,就可以获得不同的直线表达函数。
#由此,我们可以看到,闭包也具有提高代码可复用性的作用。

#如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。
#这样,我们就需要更多的参数传递,也减少了代码的可移植性。



#由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

3.装饰器

#引入
def t1():
    print('-1-')
    
def t1():
    print('-2-')
    
t1() # python 编译器从上到下顺序执行, t1在后面已经被修改, 调用的时候调用修改后的
    
-2-
# 在例如
def foo():
    print('foo')

foo = lambda x: x + 2

foo(2) # foo不再保存之前的操作,转向新的匿名函数保存的操作
4
def w1(func):
    def inner():
        # 验证1
        # 验证2
        func()
    return inner

@w1
def f1():
    print('f1')
#
# 过程
# 执行w1函数 ,并将 @w1 下面的函数作为w1函数的参数,
# 即:@w1 等价于 w1(f1) 所以,内部就会去执行:

def inner(): 
    #验证 1
    #验证 2
    #验证 3
    f1()     # func是参数,此时 func 等于 f1 
return inner
# 返回的 inner,inner代表的是函数w1的内部函数,用于处理f1
# 其实就是将原来的 f1 函数塞进另外一个函数中

@函数名 是python的一种语法糖。

# 例子

def make_bold(fn):
    def wrapped():
        return '<b>' + fn() + '</b>'
    return wrapped

def makeItalic(fn):
    def wrapped():
        return "<i>" + fn() + "</i>"
    return wrapped

@make_bold
def t1():
    return 'hello world!'
# 过程 将t1函数作为参数传给函数make_blod
# 内部函数调用 函数t1  ,及t1()
# 在函数make_blod中返回函数 wrapped , 而不是调用
# 装饰器返回的是一个函数,而不是返回一个函数的调用

print(t1())
# 而我们调用这个函数的时候, 及 t1() 
# 会执行刚才 装饰t1的过程, 结果是返回内部的函数
# 并且调用这个返回的函数, 得到的结果即 最后结果


@make_bold
@makeItalic
def test3():
    return "hello world-3"  # 由内向外运行


print(test3())

<b>hello world!</b>
<b><i>hello world-3</i></b>
装饰器作用示例

1,无参数的函数

from time import ctime, sleep

def timefun(func):
    def wrappedfunc():
        print(f'{func.__name__} called at {ctime()}')
        func()
    return wrappedfunc

@timefun
def foo():
    print('I am foo')
    
foo()

sleep(3)

foo()

foo called at Wed Jun 19 14:55:35 2019
I am foo
foo called at Wed Jun 19 14:55:38 2019
I am foo

foo = timefun(foo)
#foo先作为参数赋值给func后,foo接收指向timefun返回的wrappedfunc
foo()
#调用foo(),即等价调用wrappedfunc()
#内部函数wrappedfunc被引用,所以外部函数的foo变量(自由变量)并没有释放
#func里保存的是原foo函数对象

2.被装饰的函数有参数

# 要将被装饰的函数参数同等的传递给装饰器的内部函数;

def a(fn):
def b(n):
return fn(n)
return b

@a
def y(n):
return n

y(32)

原因很简单,就是调用y的时候就是在调用内部翻书b.既然y有参数,y在b内部被处理
故肯定要给b传同样的参数

  1. 被装饰的函数有不定长的参数
from time import ctime, sleep

def timefun(fn):
    def w(*args, **kwargs):
        print(f'{fn.__name__} called at {ctime()}')
        fn(*args, **kwargs)
    return w

@timefun
def foo(a,b,c):
    print(a+b+c)
    
foo(1,1,2)

sleep(3)

foo(3,5,8)
foo called at Wed Jun 19 15:07:00 2019
4
foo called at Wed Jun 19 15:07:03 2019
16
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")

@timefun
def getInfo():
    return '----hahah---'

foo()
sleep(2)
foo()


print(getInfo())

# 看不懂为什么会打印出none的往后看
foo called at Wed Jun 19 15:08:17 2019
I am foo
foo called at Wed Jun 19 15:08:19 2019
I am foo
getInfo called at Wed Jun 19 15:08:19 2019
None
def haha():
    return 'hahahaah'
print(haha())
hahahaah
def ha(fn):
    print('fasfsafsadf')
    fn()
    
print(ha(haha))
fasfsafsadf
None
def h():
    'h'
    
print(h())
# 为什么会出现none可以理解
None
# 如果修稿为return func()
from time import ctime, sleep

def timefun(func):
    def wrappedfunc():
        print("%s called at %s"%(func.__name__, ctime()))
        return func()
    return wrappedfunc

@timefun
def foo():
    print("I am foo")

@timefun
def getInfo():
    return '----hahah---'

foo()
sleep(2)
foo()


print(getInfo())
foo called at Wed Jun 19 15:16:00 2019
I am foo
foo called at Wed Jun 19 15:16:02 2019
I am foo
getInfo called at Wed Jun 19 15:16:02 2019
----hahah---

总结:一般情况下为了让装饰器更通用,可以有return

5.装饰器带参数,在原有装饰器的基础上,设置外部变量

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))
            func() # 与return func() 作用相同,因为foo的函数里是print
        return wrappedfunc #
    return timefun  #

@timefun_arg()
def foo():
    print("I am foo")

@timefun_arg("python")
def too():
    print("I am too")

foo()
sleep(2)
foo()

too()
sleep(2)
too()
foo called at Wed Jun 19 15:23:30 2019 hello
I am foo
foo called at Wed Jun 19 15:23:32 2019 hello
I am foo
too called at Wed Jun 19 15:23:32 2019 python
I am too
too called at Wed Jun 19 15:23:34 2019 python
I am too
# 可以理解为
foo()==timefun_arg()(foo)()
foo called at Wed Jun 19 15:21:49 2019 hello
I am foo
wrappedfunc called at Wed Jun 19 15:21:49 2019 hello
foo called at Wed Jun 19 15:21:49 2019 hello
I am foo





True

6.类装饰器,比较少用

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()
---初始化---
func name is test
---装饰器中的功能---
----test---




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值