Python 面向对象进阶(一)

1. 生成器

  • 通过列表生成式,可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个
    包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数
    的元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的
    过程中不断推算出后续的元素呢?这样,就不必创建完整的list,从而节省大量的空间。
  • 在Python中,这种一边循环一边计算的机制,称为生成器(generator)
# 创建生成器的方法一:只要把一个列表生成式的 [] 改成 ()
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 0x1077d9db0>
next(G) # 每执行一次 next(),输出一个元素

# 创建生成器的第二种方式: 使用函数
# 斐波拉契数列(Fibonacci)
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)

# 生成器(ipython 中操作)
def fib():
    print("=== start ===")
    a, b = 0, 1
    for i in range(5):
        print("=== 1 ===")
        yield b
        print("=== 2 ===")
        a, b = b, a+b
        print("=== 3 ===")
    print("=== stop ===")

a = fib()
a   # 输出: <generator object fib at 0x23355>
next(a)   # 等价于 a.__next__()
# 输出:
# === start ===
# === 1 ===
#   1

# 此时,fib()函数就是生成器,可以使用循环来迭代
for num in a:
    print(num)

1.1 send

# 示例:
# ipython3 中操作
def gen():
    i = 0
    while i<5:
        temp = yield i
        print(temp)
        i+=1

a = gen()

a.__next__()    # 输出: 0
a.__next__()    # 输出: None  1
a.send("haha")  # 输出: haha  2

# 说明: 程序执行到yield时,gen函数暂时停止,同时返回i的值;
# temp 接收send过来的值(haha);
# a.__next__() 等价 a.send(None)
# 若是第一次直接调用 a.send("haha"), 程序会报错

2. 迭代器

  • 迭代是访问集合元素的一种方式。
  • 迭代器是一个可以记住遍历的位置的对象;
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束;
  • 迭代器只能往前不会后退;

2.1 可迭代对象

  • 可以直接作用于 for 循环的数据类型有以下几种:

    • 集合数据类型:list, tuple, dict, set, str等;
    • generator, 包括生成器和带 yieldgeneration function;
    • 这些可以直接作用于for循环的对象统称为可迭代对象(Iterable)
  • 可以使用 isinstance() 判断一个对象是否是 Iterable对象;
# 示例:
from collections import Iterable
isinstance([], Iterable)    # True

2.2 迭代器

  • 可以被 next() 函数调用并不断返回下一个值的对象称为迭代器(Iterator);
  • 可以使用 isinstance() 判断一个对象是否是 Iterator 对象;
# 示例:
from collections import Iterator
isinstance((x for x in range(10), Iterator)  # True
isinstance([], Iterator)  # False

2.3 iter()函数

  • 生成器都是 Iterator 对象;
  • list, dict, str虽然是 Iterable,却不是 Iterator;
  • 可以使用 iter() 函数把 list,dict, str等 Iterable 变成 Iterator;
# 示例:
from collections import Iterator
isinstance(iter([]), Iterator)  # True

3. 闭包

# 示例一:
def test():
    print("=== in test func ===")

# 调用函数
test()

# 引用函数, 直接书写函数名,表示引用函数;
# 在 ipython 中运行 test,会输出: <function __main__.test>
ret = test

print(id(ret))
print(id(test))

ret()

# 运行结果:
=== in test func ===
4409211080
4409211080
=== in test func ===

# 示例二: 闭包定义
# 定义一个函数
def test1(number):

    # 在函数内部再定义一个函数,并且这个函数用到了外边函数(test1)的变量(number),
    # 那么将这个函数以及用到的一些变量称之为闭包
    def test_in(number_in):
        print("in test_in 函数, number_in is %d" % number_in)
        return number + number_in
    # 其实,这里返回的就是闭包的结果
    return test_in

# 给 test1 函数赋值,这个20就是给参数 number
# 此时, ret 指向 test_in, 也就是说, ret = test_in, number = 20
ret = test1(20)

# 注意,这里的100,其实是给参数 number_in
print(ret(100))     # 输出 120

#注意这里的200,其实是给参数 number_in
print(ret(200))     # 输出 220

4. 装饰器

# 示例一:
def foo():
    print('foo')

foo     # 表示是函数
foo()   # 表示执行foo函数

# 示例二:
def foo():
    print('foo')

foo = lambda x:x + 1

foo()   # 执行下面的lambda表达式,而不再是原来的foo函数,因为foo这个名字被重新指向了另外一个匿名函数

# 示例三:装饰器之前代码
# 需求: 一个基础平台部门,负责提供底层的功能,如数据库操作,redis调用,监控API等功能
# 其他业务部门使用基础功能时,只需调用基础平台提供的功能即可;
========== 基础平台提供的功能 ===========

def f1():
    print("f1")

def f2():
    print("f2")

def f3():
    print("f3")

def f4():
    print("f4")

=========== 业务部门A 调用基础功能 ==========
f1()
f2()
f3()
f4()

========== 业务部门B 调用基础功能 ==========
f1()
f2()
f3()
f4()

# 示例四:装饰器
# 需求: 执行基础功能之前,需要先进行验证
# 写代码的开放封闭原则:
#       封闭: 已实现的功能代码块
#       开放: 对扩展开放

def w1(func):
    def inner():
        # 验证1
        # 验证2
        # 验证3
        func()
    return inner

# @w1 等价于 f1 = w1(f1), 此时, f1 指向 (inner 指向的函数体)
# 调用方,继续为 f1(),不需要做修改
@w1
def f1():
    print('f1')

@w1
def f2():
    print('f2')

@w1
def f3():
    print('f3')

@w1
def f4():
    print('f4')

# 示例五: 装饰器扩展
def makeBold(fn):
    print("=== bold ===")
    def wrapped():
        print("=== 1 ===")
        return "<b>" + fn() + "</b>"
    return wrapped

def makeItalic(fn):
    print("=== italic ===")
    def wrapped():
        print("=== 2 ===")
        return "<i>" + fn() + "</i>"
    return wrapped

@makeBold
@makeItalic
def test1():
    print("=== 3 ===")
    return "Hello world!"

print(test1())
# 输出:
# (前面两句,不调用test1()函数也会输出)
# === italic ===
# === bold ===
# === 1 ===
# === 2 ===
# === 3 ===
# <b><i>Hello world!</i></b>

# 示例六: 装饰器什么时间执行
def w1(func):
    print("=== 正在装饰 ===")
    def inner():
        print("=== 正在验证权限 ===")
        func()
    return inner

# 只要Python 解释器执行到 @w1 这行代码,那么就会自动的进行装饰,
# 而不是等到调用f1()的时候才装饰
# 控制台会输出: === 正在装饰 ===
@w1
def f1():
    print("=== f1 ===")

# 示例七: 被装饰的函数带有参数
def w1(func):
    def inner(x, y):  # 如果x,y没有定义,那么会导致f1(22, 33)调用失败
        # 验证1
        func(x, y)    # 如果没有把x, y当做实参进行传递,那么,会导致调用f1(a, b)失败
    return inner

@w1
def f1(a, b):
    print('a = %d, b = %d' % (a, b))

f1(22, 33)

# 示例八: 被装饰的函数带有不定长参数
def w1(func):
    def inner(*args, **kwargs):
        # 验证1
        func(*args, **kwargs)
    return inner

@w1
def f2(a, b, c):
    print('a = %d, b = %d, c = %d' % (a, b, c))

@w1
def f3(a, b, c, d):
    print('a = %d, b = %d, c = %d, d = %d' % (a, b, c, d))

f2(11, 22, 33)
f3(11, 22, 33, 44)

# 示例九: 对带有返回值的函数装饰
def w1(func):
    def inner():
        print("=== 执行前 ===")
        result = func()
        print("=== 执行后 ===")
        return result

    return inner

@w1
def f1():
    print("=== 功能代码 ===")
    return "zhangsan"

name = f1()
print("查询到的姓名: %s" % name)

# 示例十: 通用装饰器((不)带参数,(不)带返回值)
def w1(func):
    def inner(*args, **kwargs):
        print("=== 执行前 ===")
        result = func(*args, **kwargs)
        print("=== 执行后 ===")
        return result

    return inner

@w1
def f1():
    print("=== 功能代码 ===")
    return "haha"

@w1
def f1(a):
    print("=== 功能代码 ===")
    print("输入的字符为: %s" % a)

# 示例十一: 装饰器带参数,在原有装饰器的基础上,设置外部变量
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("noodles")
def foo():
    print("I am Noodles")

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

foo()
sleep(2)
too()

# 输出:
foo called at Sat Mar 10 17:56:06 2018 noodles
I am Noodles
too called at Sat Mar 10 17:56:08 2018 google
I am google

# 备注:
# 1. 先执行timefun_arg("noodles")函数, 这个函数返回的结果是 timefun 函数的引用
# 2. @timefun
# 3. 使用 @timefun 对 foo 进行装饰

4.1 类装饰器

  • 装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。
  • 在Python中一般callable对象都是函数,但也有例外,只要某个对象重写了 __call__()方法,那么这个
    对象就是callable的;
# 示例一: callable
class Test():
    def __call__(self):
        print("call me!")

t = Test()
t()
# 输出: call me!
# 对象(),会调用 __call__ 方法

# 示例: 类装饰器
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__ 方法中;
#
# 2, test函数相当于指向了用Test创建出来的实例对象;
#
# 3, 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的 __call__ 方法;
#
# 4. 为了能够在__call__ 方法中调用原来test指向的函数体,所以在__init__方法中就需要一个实例属性来保存
# 所以才有了 self.__func = func 这句代码,从而在调用 __call__ 方法中能够调用到test之前的函数体

@Test
def test():
    print("=== test ===")
test()

5. 元类

  • 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段;
  • 在Python中的类远不止如此,类还是一种对象;
  • 使用type动态的创建类,
    • 格式:type(类名, 有父类名称组成的元组(针对继承的情况,可以为空), 包括属性的字典(名称和值))
  • type就是Python在背后用来创建所有类的元类;
# 示例:
# 传统方式定义类
class Test:
    pass

t1 = Test()

# type 定义类
Test2 = type("Test2", (), {})
t2 = Test2()

type(t1)     # 输出: __main__.Test
type(t2)     # 输出: __main__.Test2

# 带有属性的类
class Person:
    age = 15

Person2 = type("Person2", (), {"age":15})

# 带有方法的类
# 定义方法
def printAge(self):
    print("=== 年龄是: %d ===" % self.num)

Person3 = type("Person3", (), {"printAge": printAge})

p = Person3()
p.age = 22
p.printAge()

# 存在继承关系的类
class Animal:
    def eat(self):
        print("=== eat ===")

Cat = type("Cat", (Animal,), {})
tom = Cat()
tom.eat()

5.1 __metaclass__ 属性

# 示例:
class Foo(Bar):
    pass

# Python 创建类的过程中,做了如下操作
# 1, Foo 中有 __metaclass__ 这个属性吗?如果有,Python 会通过 __metaclass__ 创建一个名字为Foo的类对象;
# 2, 如果Python没有找到__metaclass__, 它会继续在Bar(父类)中寻找 __metaclass__ 属性,并尝试做和前面同样的操作;
# 3, 如果Python在任何父类中到找不到__metaclass__, 它就会在模块层次中去寻找 __metaclass__, 并尝试做同样的操作;
# 4. 如果还是找不到 __metaclass__, Python 就会用内置的type来创建这个类对象;

参考资料:

原文地址:https://www.cnblogs.com/linkworld/p/8542887.html

时间: 2024-10-17 09:49:52

Python 面向对象进阶(一)的相关文章

Python面向对象进阶和socket网络编程-day08

写在前面 上课第八天,打卡: 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __init__(self,name): self.name=name p = Chinese('standby') # 实例化一个对象 print(p) # 打印这个对象 --- <__main__.Chinese object at 0x0000000000B3A978> - 示例2: >&g

python面向对象进阶版

面向对象基础知识: 1.面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用: 2.类是一个模板,模板中包装了多个'函数'供使用(可以将多函数中公用的变量封装到对象中): 3.对象,根据模板创建的实例(即:对象),实例用于被包装在类中的函数: 4.面向对象三大特性:封装.继承和多态. 面向对象进阶篇详细介绍python类的成员.成员修饰符和类的特殊成员. 类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存

python面向对象进阶

isinstance(obj,cls)检查是否obj是否是类 cls 的对象. isinstance(obj,cls)检查是否obj是否是类 cls 的对象. 反射 python面向对象中的反射:通过字符串的形式操作对象相关的属性.python中的一切事物都是对象(都可以使用反射) 四个可以实现自省的函数(参数是对象,字符串格式的属性名) hasattr getattr setattr delattr __del__,就是析构方法,当对象在内存中被释放时,自动触发执行. 注:此方法一般无须定义,

python 面向对象 进阶篇

在上篇<python面向对象>中,简单介绍了python中面向对象的基本知识 在这篇博客中,详细介绍python类的成员,成员修饰符,类的特殊成员. 类的成员 类的成员分为三种:字段,方法和属性 所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段.而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份. 字段 字段包括普通字段和静态字段.静态字段,保存在类中.普通字段,保存在对象中. class FOO: country = “中国

python面向对象进阶(八)

上一篇<Python 面向对象初级(七)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中) 对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数 面向对象三大特性:封装.继承和多态 本篇将详细介绍Python 类的成员.成员修饰符.类的特殊成员. 类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象

Python 面向对象进阶

1 isinstance 和issubclass instance:判断该对象是否是类的对象 isinstance(obj,Foo) x = [] print(isinstance(x,list)) 结果:True issubclass:判断是否是继承 class Foo: pass class Bar(Foo): pass print(issubclass(Bar,Foo)) 结果:True 通过下面的方式也可以查看print(Bar.base) 2 反射 反射是Smi首次提出的,主要指程序可

Python面向对象进阶及类成员

再次了解多继承 先来一段代码 #!/usr/bin/env python # _*_ coding:utf-8 _*_ class A:    def bar(self):        print("BAR")        self.f1() class B(A):    def f1(self):        print("B") class C:    def f1(self):        print("C") class D(C,

Python面向对象进阶之高级编程

__slots__:定义类时,使用__slots__变量可以限制能添加的实例的属性 形如:__slots__ = ['name','age'] 这样实例化的对象只能绑定到name和age属性,其他属性则无法被绑定 class People:     __slots__ = ['name','age']     def __init__(self,name,age):         self.name = name         self.age = age p = People('laowa

Python之路-python(面向对象进阶)

一.面向对象高级语法部分 1.静态方法.类方法.属性方法 2.类的特殊方法 3.反射 二.异常处理 三.Socket开发基础 一.面向对象高级语法部分 静态方法(@staticmethod) 定义:只是名义上归类管理,实际上在在静态方法里面访问不了类或实例中的属性 1 class Dog(object): 2 def __init__(self,name): 3 self.name = name 4 5 @staticmethod 6 def eat(x,s): 7 print("%s is e