精华内容
下载资源
问答
  • 2019-09-24 06:34:44

    下面的那一个不属于MVC模式中的对象?

     

    A. Model

     

    B. View

     

    C. Collection

     

    D. Controller

     

    解答:C

     

    MVC是三个单词的缩写,分别为: 模型(Model),视图(View)和控制Controller)。 MVC模式的目的就是实现Web系统的职能分工。 Model层实现系统中的业务逻辑,通常可以用JavaBean或EJB来实现。 View层用于与用户的交互,通常用JSP来实现。 Controller层是Model与View之间沟通的桥梁,

     

    它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作。

    转载于:https://www.cnblogs.com/borter/p/9553042.html

    更多相关内容
  • 1、什么是设计模式? 每一个模式描述了一个在我们周围不断重复发生的事情,以及该问题的解决方案的核心。 一般而言,一个模式有四个基本要素: 模式名称 — 一个助记名,它用一两次来描述模式的问题、解决方案和...

    1、什么是设计模式?

    每一个模式描述了一个在我们周围不断重复发生的事情,以及该问题的解决方案的核心。
    

    一般而言,一个模式有四个基本要素:

    • 模式名称 — 一个助记名,它用一两次来描述模式的问题、解决方案和效果。
    • 问题 — 描述了应该在何时使用模式。解释了设计问题和问题存在的前因后果。
    • 解决方案 — 描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。
    • 效果 — 描述了模式应用的效果及使用模式应权衡的问题。(包括它对系统的灵活性、扩充性或可移植性)

    2、描述设计模式

    同时记录设计产生的决定过程、选择过程和权衡过程

    模式名和分类

    模式名简洁的描述了模式的本质。

    意图

    是回答下列问题的简单描述:设计模式是做什么的?它的基本原理和意图是什么?它解决的是什么样的特定设计问题?

    别名

    模式的其他名称。

    动机

    用以说明一个设计问题以及如何用模式中的类、对象来解决该问题的特定情景。该情景会帮助你理解随后对模式更抽象的解释。

    适用性

    什么情况下可以使用该设计模式?该模式可用来改进哪些不良设计?你怎样识别这些情况?

    结果

    采用基于对象建模技术的表示法对模式中的类进行图形描述。

    参与者

    指设计模式中的类和/或对象以及它们各自的职责。

    协作

    模式的参与者怎样协作以实现它们的职责

    效果

    模式怎样支持它的目标?使用模式的效果和所需做的权衡取舍?系统结构的哪些方面可以独立改变?

    实现

    实现模式需要知道的一些提示、技术要点及应避免的缺陷,以及是否存在某些特定于实现语言的问题。

    相关模式

    与这个模式紧密相关的模式有哪些?其间重要的不同之处是什么?这个模式应与哪些其他模式一起使用?

    3、设计模式怎样解决设计问题?

    • 寻找合适的对象

      面向对象程序由对象组成,对象包括数据和数据进行操作的过程,过程通常称为方法或操作。
      对象在收到客户的请求(或消息)后执行相应的操作。
      
      客户请求是使对象操作执行的唯一方法,操作又是对象改变内部数据的唯一方法。
      由于这些限制,对象的内部状态是被封装的,它不能被直接访问,它的表示对于对象外部是不可见的。
      面向对象设计最困难的部分是将系统分解成对象集合。
      因为要考虑许多因素:封装、粒度、依赖关系、灵活性、性呢过、演化、复用等等。
      
      当给对象发送请求时,所引起的具体操作既与请求本身有关又与接收对象有关。
      支持相同请求的不同对象可能队请求激发的操作有不同的实现。
      发送给对象的请求和它的相应操作在运行时刻的链接就称之为**动态绑定**。
      
      
      动态绑定是指发送的请求直到运行时刻才受你的具体的实现的约束。
      因而,在之道任何有正确接口的对象都将接受此请求时,你可以写一个一般的程序,
      它期待着哪些具有该特定接口的对象。进一步讲,动态绑定允许你在运行时刻彼此替换有相同接口的对象。
      这种可替换性就称为**多态**。多态允许客户对象仅要求其他对象支持特定接口,除此之外对其架设几近于无。
      

    描述对象的实现

    抽象类的主要目的是为它的自雷定义公共接口。一个抽象类将把它的部分或全部操作的实现延迟到子类中,因此,一个抽象类不能被实例化。

    在抽象类中定义却没有实现的操作被称为抽象操作。

    非抽象类称为具体类。

    • 对接口编程,而不是对实现编程

    • 优先使用对象组合,而不是类继承

    委托的主要优点在于它便于运行时刻组合对象操作以及改变这些操作的组合方式。委托与那些通过对象组合以取得软件灵活性的技术一样,具有如下不足之处:动态的、高度参数化的软件比静态软件更难于理解。还有运行低效问题。只有当委托使设计比较简单而不是更复杂时,它才是好的选择。

    委托是对象组合的特例。它告诉你对象组合作为一个代码复用机制可以替代继承。

    聚合意味着一个对象拥有另一个对象或对另一个对象负责。一般我们称一个对象包含另一个对象或者是另一个对象的一部分。聚合意味着聚合对象和其所有者具有相同的生命周期

    相识意味着一个对象仅仅知道另一个对象。有时相识也被称为”关联“或”引用“关系。相识的对象可能请求彼此的操作,但是它们不为对方负责。相识是一种比聚合要弱的关系,它只标识了对象间较松散的耦合关系。


    4、设计应支持变化

    获得最大限度复用的关键在于对新需求和已知需求发生变化时的预见性,要求你的系统设计要能够相应的改进。

    为了设计适应这种变化,且据以偶健壮性的系统,你必须考虑系统在它的生命周期内会发生怎样的变化。一个不考虑系统变化的设计在将来就有可能需要重新设计。这些变化可能是类的重新定义和实现,修改客户和重新测试。重新设计会影响软件系统的许多方面,并且未曾料到的变化总是代价巨大的。

    设计模式可以确保系统能以特定方式变化,从而帮助你避免重新设计系统。每一个设计模式允许系统结构的某个方面的变化独立于其他方面,这样产生的系统对于某一种特殊变化将更健壮。

    下面阐述一些导致重新设计的一般原因:

    1. 通过显式的制定一个类来创建对象

      在创建对象时制定类名将使你受特定实现的约束而不是特定接口的约束。
      这会使未来的变化更复杂。要避免这种情况,应该间接的创建对象。
      
    2. 对特殊操作的依赖

      当你为请求指定一个特殊的操作时,完成该请求的方式就固定下来了。
      为避免把请求代码写死,你将可以在编译时刻或运行时刻很方便的改变相应请求的方法。
      
    3. 对硬件和软件平台的依赖

      外部的操作系统接口和应用编程接口(API)在不同的软硬件平台上是不同的。
      依赖于特定平台的软件将很难移植到其他平台上,甚至都很难跟上本地平台的更新。
      所以设计系统时限制其平台相关性就很重要了。
      
    4. 对对象表示或实现的依赖

      知道对象怎样表示、保存、定位或实现的应用端在对象变化时可能也需要变化。对应用端隐藏这些信息能阻止连锁变化。
      
    5. 算法依赖

      算法在开发和复用时常常被扩展、优化和替代。
      依赖于某个特定算法的对象在算法发生变化时不得不变化。
      因此有可能发生变化的算法应该被孤立起来。
      
    6. 紧耦合

      紧耦合的类很难独立的被复用,因为它们是相互依赖的。
      紧耦合产生单块的系统,要改变或删除一个类,你必须理解和改变其他许多类。
      这样的系统是一个很难学习、移植和维护的密集体。
      
    7. 通过生成子类来扩充功能

      通常很难通过定义子类来定义对象。每一个新类都有固定的实现开销(初始化、终止操作等)。
      定义子类还需要对父类有深入的了解。如:重新定义一个操作可能需要重定义其他操作。一个被重新定义的操作可能需要调用继承下来的操作。并且子类方法会导致类爆炸,因为即使对于一个简单的扩充,你也不得不引入许多新的子类。
      
      一般的对象组合技术和具体的委托技术,是继承之外组合对象行为的另一种灵活方法。
      新的功能可以通过以新的方式组合已有对象,而不是通过定义已存在类的子类的方式加到应用中去。另一方面,
      过多使用对象组合会使设计难于理解。许多设计模式产生的设计中,你可以定义一个子类,且将它的实例和已存在实例进行组合来引入定制的功能。
      
    8. 不能方便的对类进行修改

      有时你不得不改变一个难以修改的类。
      

    5、怎样选择设计模式

    1、考虑设计模式是怎样解决设计问题的

    2、浏览模式的意图部分

    3、研究模式怎样互相关联

    4、研究目的相似的模式

    5、检查重新设计的原因

    6、考虑你的设计中哪些是可变的

    目的设计模式可变的方面
    创建Abstract Factory
    Builder
    Factory Method
    Prototype
    Singleton
    产品对象家族
    如何创建一个组合对象
    被实例化的子类
    被实例化的类
    一个类的唯一实例
    结构Adapter
    Bridge
    Composite
    Decorator
    Facade
    Flyweight
    Proxy
    对象的接口
    对象的实现
    一个对象的结构和组成
    对象的职责,不生成子类
    一个子系统的接口
    对象的存储开销
    如何访问一个对象,该对象的位置
    行为Chain of Responsibility
    Command
    Interpreter
    Iterator
    Mediator
    Memento

    Observer

    State
    Strategy
    Template Method
    Visitor
    满足一个请求的对象
    何时、怎样满足一个请求
    一个语言的文法及解释
    如何遍历、访问一个聚合的各元素
    对象间怎样交互、和谁交互
    一个对象中哪些私有信息存放在该对象之外,以及在什么时候进行存储
    多个对象依赖于另外一个对象,而这些对象又如何保持一致
    对象的状态
    算法
    算法中的某些步骤
    某些可作用于一个(组)对象上的操作,但不修改这些对象的类

    6、怎样使用设计模式

    一旦你选择了一个设计模式,你怎么使用它呢?这里给出一个有效应用设计模式的循序渐进的方法。

    1. 大致浏览一遍模式

      特别注意其适用性部分和效果部分,确定它适合你的问题。
      
    2. 回头研究结构部分、参与者部分和协作部分

      确保你理解这个模式的类和对象以及它们是怎样关联的。
      
    3. 看代码示例部分,看看这个模式代码形式的具体例子

      研究代码将有助于你实现模式。
      
    4. 选择模式参与者的名字,使它们在应用上下文中有意义

      设计模式参与者的名字通常过于抽象而不会直接出现在应用中。
      然而,将参与者的名字和应用中出现的名字合并起来是很有用的,这会帮助你在实现中更显式的体现出模式来。
      
    5. 定义类

      声明它们的接口,建立它们的继承关系,定义代表数据和对象引用的实例变量。
      识别模式会影响到的你的应用中存在的类,做出相应的修改。
      
    6. 定义模式中专用于应用的操作名称

      使用与每一个操作相关联的责任和协作作为指导。
      
    7. 实现执行模式中责任和协作的操作

      实现部分提供线索指导你进行实现。
      
    展开全文
  • Oracle数据库模式对象管理

    千次阅读 2019-10-11 22:29:08
    实验四 Oracle数据库模式对象管理 一、预习报告 一、 实验目的 1) 掌握表的创建与管理。 2) 掌握索引的创建与管理。 3) 掌握视图的创建与管理。 4) 掌握序列的创建与管理。 5) 了解簇、同义词、数据库链接等...

    实验四 Oracle数据库模式对象管理

    一、预习报告

    一、 实验目的
    1) 掌握表的创建与管理。
    2) 掌握索引的创建与管理。
    3) 掌握视图的创建与管理。
    4) 掌握序列的创建与管理。
    5) 了解簇、同义词、数据库链接等其他模式对象的管理

    1) 什么是模式,模式有什么特点?
    模式是指一系列逻辑数据结构或对象的集合。特点:模式与用户相对应,一个模式只能被一个数据库用户所拥有,并且模式的名称与这个用户的名称相同。
    2) Oracle数据库中模式对象有哪些?表空间、用户、角色、目录、概要文件及上下文等数据库对象属于某个模式吗?
    模式对象有:表、索引、索引化表、分区表、物化视图、属兔、数据库连接、序列、同义词、PL/SQL包、存储函数与存储过程、Java类与其它Java资源。表用户、用户、角色、目录、概要文件属于非对象模式。
    3) 如何进行模式的选择与切换?
    用户以normal身份登录,则进入同名模式;用户以sysdba身份登陆进入sys模式;用户以sysoper身份登陆,进入public模式。
    4) 说明索引的作用,以及Oracle数据库中索引的类型。
    数据库中引入索引的目的是提高对表中数据的查询速度。
    类型:1.唯一性索引与非唯一性索引2.平衡树索引与位图索引3.单列索引与复合索引4.函数索引。

    二、实验报告

    一、 实验目的
    1) 掌握表的创建与管理。
    2) 掌握索引的创建与管理。
    3) 掌握视图的创建与管理。
    4) 掌握序列的创建与管理。
    5) 了解簇、同义词、数据库链接等其他模式对象的管理
    二、 实验环境
    Windows 7/Windows 10 + Oracle10g+PL/SQL Developer
    三、 实验内容及要求
    1)为图书销售系统创建数据表。
    2)在图书销售系统适当表的适当列上创建适当类型的索引。
    3)为图书销售系统创建视图。
    4)为图书销售系统创建序列。
    四、 实验步骤
    1) 打开SQL Plus,以system用户登录BOOKSALES数据库。
    Sqlplus system/oracle
    2) 按下列方式创建一个用户bs,并给该用户授权。
    SQL>CREATE USER bs INDENTIFIED BY bs DEFAULT TABLESPACE USERS;
    SQL>GRANT RESOURCE, CONNECT, CREATE VIEW TO bs;

    create user bs identified by bs default tablespace users;
    grant resource,connect,create view to bs;
    3) 使用bs用户登录数据库,并进行下面的相关操作。
    Conn bs/bs
    4) 根据图书销售系统关系模式设计,创建表A-1至表A-6。
    在这里插入图片描述
    在这里插入图片描述

    	create table customers(
    	  customer_id number(4) primary key,
    	  name char(20) not null,
    	  phone varchar2(50) not null,
    	  email varchar2(50),
    	  address varchar2(200),
    	  code varchar2(10));
    	create table publishers(
    	publisher_id number(2) primary key,
    	name varchar2(50),
    	contact char(10),
    	phone varchar2(50));
    	create table books(
    	ISBN varchar2(50) primary key,
    	title varchar2(50),
    	author varchar2(50),
    	pubdate date,
    	publisher_id number(2),
    	cost number(6,2),
    	retail number(6,2),
    	category varchar2(50),
    	foreign key(publisher_id)references publishers(publisher_id));
    		create table orders(
    	order_id number(4) primary key,
    	customer_id number(4) ,
    	orderdate date,
    	shipdate date,
    	shipaddress varchar2(200),
    	shipcode varchar2(10),
    	foreign key(customer_id) references customers(customer_id));
    	create table orderitem(
    	order_id number(4),
    	item_id number (4),
    	isbn varchar2(50) not null,
    	quantily number(4),
    	primary key(order_id,item_id),
    	foreign key(order_id) references orders(order_id));
    	create table promotion(
    	gift_id number(2),
    	name char(20) primary key,
    	minretail varchar2(50),
    	maxretail char(10));
    

    5) 在CUSTOMERS表的name列上创建一个B-树索引,要求索引值为大写字母。
    create index customer_name_index on customers(upper(name));
    6) 在BOOKS表的title列上创建一个非唯一性索引。
    create index books on books(title);
    7) 在ORDERS表的ISBN列上创建一个唯一性索引。
    create unique index orders_index on orders(isbn) ;
    8) 创建一个视图customers_book,描述客户与订单的详细信息,包括客户编号、客户名单、订购图书的ISBN、图书名称、图书数量、订货日期、发货日期等。
    create view customers_book as
    select c.customer_id,c.name,b.isbn,title,orderdate,shipdate
    from customers c,books b,orderitem o1,orders o2
    where c.customer_id=o2.customer_id and o2.order_id=o1.order_id and o1.ISBN=b.ISBN;
    9)创建一个视图customers_gift,描述客户获得礼品的信息,包括客户名称、图书总价、礼品名称。
    create view customers_gift(customers_name,book_allcost,gift_name)
    as
    select cname,p.name
    from(select c.name cname
    from customers c join orders o on c.customer_id=o.customer_id
    join ordertime oi on o.order_id=oi.order_id
    join books b on oi.ISBN=b.ISBN
    group by c.name) orderinfo
    join promotion p on allcost between minretail and maxretail;
    10)定义序列seq_customers,产生客户编号,序列起始值为1,步长为1,不缓存,不循环。
    create sequence seq_customers start with 1 increment by 1 nocache nocycle;
    11)定义序列seq_orders,产生订单编号,序列起始值为1000,步长为1,不缓存,不循环。
    create sequence seq_orders start with 1000 increment by 1 nocache nocycle;
    12)定义序列seq_promotion,产生礼品编号,序列起始值为1,步长为1,不缓存,不循环。
    create sequence seq_promotion start with 1 increment by 1 nocache nocycle;
    五、 思考题
    数据库中使用索引的优点和缺点,索引是如何工作的?

    优点:可以提高对表中数据的查询速度。缺点:索引越多,维护索引所需开销越大。当更新表时,需要同时更新于表有关的索引,降低了数据的维护速度。索引需要占用物理空间,特别是聚集索引,需要较大的空间。
    
    展开全文
  • python可迭代对象

    千次阅读 2021-01-14 18:38:29
    本身实现了迭代方法的对象称之为可迭代对象,可迭代对象特点:支持每次返回自己所包含的一个成员的对象对象实现了 __iter__ 方法:所有数据结构都是可迭代对象;for 循环要求对象必须是一个可迭代对象;用户自定义...

    本身实现了迭代方法的对象称之为可迭代对象,可迭代对象特点:

    支持每次返回自己所包含的一个成员的对象;

    对象实现了 __iter__ 方法:

    所有数据结构都是可迭代对象;

    for 循环要求对象必须是一个可迭代对象;

    用户自定义的一些包含了 __iter__() 或 __getitem__() 方法的类。

    它与一般的序列类型(list, tuple 等)有什么区别呢?它一次只返回一个数据项,占用更少的内存,但它需要记住当前的状态,以便返回下一数据项。

    迭代器

    迭代器(iterator)就是一种可迭代对象。所谓的 迭代器就是重复做一件事,它又称为游标(cursor),它是程序设计的软件设计模式,是一种可在容器物件(container,如列表等)上实现元素遍历的接口。迭代器是一种特殊的数据结构,在 python 中,它也是以对象的形式存在的。

    简单来说,在 python2 中存在 next 方法的可迭代对象是迭代器;而在 python3 中则变成了 __next__ 方法。因此迭代器同时具有 __iter__ 和 __next__ 这两种方法。

    通过 python 内置函数 iter 可以将一个可迭代对象转换成一个迭代器。为什么要将可迭代对象转换成迭代器呢?因为只有迭代器才能使用 python 内置函数 next。

    迭代器会保存一个指针,指向可迭代对象的当前元素。调用 next 函数的时候,会返回当前元素,并将指针指向下一个元素。当没有下一个元素的时候,它会抛出 StopIteration 异常。

    一个简单的迭代器用法:

    lst = [['m', 2, 4, 5], ['x', 3, 4, 5]]

    for x in lst:

    key = x[0]

    for v in x[1:]:

    print()

    for x in lst:

    it = iter(x)

    key = next(it)

    for v in it:

    print()

    复制代码

    使用第二种循环也就是迭代器会比第一种更有效率,因为切片将列表复制一份,占用的内存更多。

    for 循环对于可迭代对象首先会调用 iter 方法将之转换为迭代器,然后不断的调用 next 方法,直到抛出 StopIteration 异常。

    it = iter(itratable)

    while True:

    try:

    next(it)

    except StopIteration:

    return

    复制代码

    生成器

    生成器也是函数,函数中只要有 yield 关键字,那么它就是生成器函数,返回值为生成器。生成器存在 __iter__ 和 __next__ 这两种方法,因此它是一个迭代器。生成器应用非常广泛,官方的异步 IO 基本上都是基于 yield 做的。当我们在 async def 定义的函数中使用 yield,那么这个函数就被称为异步生成器。

    当我们调用生成器函数的时候,它会返回一个生成器对象,我们要使用一个变量去接受它,然后通过操作这个变量去操作生成器。生成器也是函数,函数都是从上到下执行,当执行到 yield 语句时,这个函数就停止了,并且会将此次的返回值返回。如果 yield 语句后没有任何值,那么它的返回值就是 None;如果有值,会将这个值返回给调用者。如果使用了生成器的 send 方法(下面会提到),那么返回值将是通过这个方法传递进去的值(前提是 yield 语句后没有任何值)。

    所有的这些特性让生成器看起来和协程非常相似:可以多次调用、有多个切入点、执行可以被暂停。唯一的区别是生成器函数无法控制 yield 之后应继续执行的位置,因为控制权在调用者的手中。

    对于一个没有调用结束的生成器,我们可以使用 close 方法将其关闭,可以将其写在 try 的 finally 语句中。

    当使用 yield from 时,它将提供的表达式视为子迭代器,该子迭代器生成的所有值直接传递给当前生成器函数的调用者。任何传递给 send() 的值和通过throw() 传入的异常都会传递给基础迭代器(如果它有适当的方法去接收)。如果不是这种情况,那么 send() 会引发 AttributeError 或 TypeError,而 throw() 会立即引发传入的异常。

    定义一个生成器:

    >>>def fn():

    ... for i in range(10):

    ... yield i

    ...

    >>>fn() # 可以看到它是一个生成器

    Out[3]:

    >>>f = fn() # 我们得先接收这个生成器

    >>>next(f) # 然后再对生成器进行操作

    Out[6]: 0

    >>>next(f)

    Out[7]: 1

    复制代码

    从函数的执行流程中可以知道,函数执行完毕之后现场应该被销毁,但是生成器却并不是这样。

    执行流程剖析,先定义一个函数:

    >>>def g1():

    ... print('a')

    ... yield 1

    ... print('b')

    ... yield 2

    ... print('c')

    ... return 3

    ...

    >>>g = g1() # 没有输出 a,证明执行生成器函数的时候不会执行函数体

    >>>g # 可以看出是一个生成器,证明 return 没有生效

    Out[10]:

    复制代码

    通过 next 函数执行一把生成器:

    >>>next(g) # 执行到第一个 yield 后,停止执行

    a

    Out[11]: 1

    复制代码

    再执行一次:

    >>>next(g) # 从第一个 yield 之后执行,到第二个 yield 停止

    b

    Out[12]: 2

    复制代码

    继续执行:

    >>>next(g) # 从第二个 yield 之后执行,当没有更多 yield 之后,抛出异常,异常的值正好是函数的返回值

    c # 下面的语句还是会执行的

    Traceback (most recent call last):

    File "/usr/local/python/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2862, in run_code

    exec(code_obj, self.user_global_ns, self.user_ns)

    File "", line 1, in

    next(g)

    StopIteration: 3

    复制代码

    生成器函数的特点:

    生成器函数执行的时候并不会执行函数体;

    当 next 生成器的时候,会从当前代码执行到之后的第一个 yield,会弹出值并暂停函数;

    当再次 next 生成器的时候,从上次暂停处开始向下执行;

    当没有多余 yield 的时候,会抛出 StopIteration 异常,异常的 Value 是函数的返回值。

    生成器是惰性求值的。比如我们可以定义一个计数器:

    def make_inc():

    def counter():

    x = 0

    while True:

    x += 1

    yield x

    c = counter()

    return lambda: next(c)

    >>>incr = make_inc()

    >>>incr()

    Out[9]: 1

    >>>incr()

    Out[10]: 2

    复制代码

    求斐波那契数列第 11 项:

    def fib():

    a = 0

    b = 1

    while True:

    a, b = b, a+b

    yield a

    >>>f = fib()

    >>>for _ in range(10):

    ... next(f)

    ...

    >>>print(next(f))

    89

    复制代码

    可以看到递归都可以通过生成器来解决,并且没有递归深度的限制,也没有递归慢的缺点,因为它不需要保存现场。

    以上都只是生成器的普通用法,协程才是生成器的高级用法。

    进程和线程的调度是通过操作系统完成的,但是协程的调度是由用户态,也就是用户进行的。一旦函数执行到 yield 之后,它会暂停,暂停也就意味着让出 cpu 了。那么接下来就由用户决定执行什么代码。

    当我们要对一个可迭代对象的前一项或几项做特殊处理时,如果直接对其进行循环的话,我们还需要判断是不是其第一个元素,或许我们还要在其外部定义一个计数器,这其实是一种和古老和 low 的方式。有了生成器之后,我们就可以在循环之前使用 next() 函数取出其中的第一个值,然后再对其进行 for 循环即可。如果无法对其直接使用 next 方法,那就调用它的 __iter__() 方法将其变成一个生成器后再继续。

    yield

    函数中一旦使用了 yield,这个函数就变成了生成器函数。但 yield 不能和 return 共存,并且 yield 只能定义在函数中。当我们调用这个函数的时候,函数内部的代码并不立即执行,这个函数只是返回一个生成器对象。当我们使用 for 对其进行迭代的时候,函数内的代码才会被执行。

    python3 新增了 yield from 语法,它相当于 for + yield。比如:

    yield from a()

    # 等同于下面

    for i in a():

    yield i

    复制代码

    yield 和 return 的区别:

    return 的时候这个函数的局部变量都被销毁了;

    所有 return 是得到所有结果之后的返回;

    yield 是产生了一个可以恢复的函数(生成器),恢复了局部变量;

    生成器只有在调用 .next() 时才运行函数生成一个结果。

    复制代码

    yield 会记住函数执行的位置,下次再次执行时会从上次的位置继续向下执行。而如果在函数中使用 return,函数就直接退出了,无法继续执行。定义一个生成器:

    >>>def fun1(n):

    ... for i in xrange(n):

    ... yield i

    ...

    复制代码

    先执行一下:

    >>>a = fun1(5)

    >>>a.next()

    0

    复制代码

    然后再对其进行循环会从之前的地方继续向下:

    >>>for i in a:print i

    ...

    1

    2

    3

    4

    复制代码

    yield 的用处在于如果函数每次循环都会产生一个字串,如果想要将这些字串都传递给函数外的其他变量使用 return 是不行的,因为当函数第一次循环时碰到 return 语句整个函数就退出了,是不可能继续循环的,也就是说只能传递一个字串出去。这显然不符合我们的要求,这时就可以通过 yield 搞定了。

    实现xrange:

    def xrange(n):

    start = 0

    while True:

    if start >= n:

    return

    yield start

    start += 1

    复制代码

    具体案例:

    import csv

    from pyzabbix import ZabbixAPI

    zapi = ZabbixAPI('http://127.0.0.1/api_jsonrpc.php')

    zapi.login('uxeadmin', 'Uxe(00456)AdmIN.^??')

    with open('_zabbix.csv', 'w', encoding='gbk') as f:

    spamwriter = csv.writer(f)

    for i in zapi.host.get(output=["host"]):

    item_info = zapi.item.get(hostids=i['hostid'], output=["name", 'status']).__iter__()

    for j in item_info:

    if not int(j['status']):

    spamwriter.writerow([i['host'], j['name']])

    break

    for j in item_info:

    if not int(j['status']):

    spamwriter.writerow(['', j['name']])

    复制代码

    生成器方法

    请注意,在生成器已经执行时调用下面的任何生成器方法会引发 ValueError 异常。

    __next__

    开始执行一个生成器或者从上一次 yield 语句后继续执行。当使用该方法继续(注意是继续而不是第一次执行)时,那么当前 yield 的返回值为 None,直到执行到下一次的 yield 语句时,yield 语句后的表达式的结果才会返回给调用者。当迭代器结束时会抛出 StopIteration 异常。

    该方法会被 for 以及内置函数 next 隐式的调用。

    send

    继续执行生成器(注意是继续而不是第一次执行),并发送一个值到生成器函数。send 方法的参数是下一个 yield 语句的返回值,前提是 yield 语句中要事先接收它传递的参数。如果使用该方法启动(也就是第一次执行)生成器,必须使用 None 作为其参数,因为此时还没有 yield 能够接收它的值(毕竟接收该值的语句还没有开始执行)。

    def fn():

    a = 0

    while True:

    a += 1

    r = yield # r 就是接收 send 参数的变量

    print('{} => {}'.format(a, r))

    >>> f = fn()

    >>> f.send('a') # 不传递 None 的后果

    Traceback (most recent call last):

    File "/opt/python3/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2910, in run_code

    exec(code_obj, self.user_global_ns, self.user_ns)

    File "", line 1, in

    f.send('a')

    TypeError: can't send non-None value to a just-started generator

    >>> next(f) # 也可以不传递 None 而是使用 next 执行,两种方式都可以

    >>> f.send('a')

    1 => a

    >>> f.send('b')

    2 => b

    复制代码

    throw

    用法:

    throw(type[, value[, traceback]])

    复制代码

    传递一个 type 类型的异常给生成器,在生成器暂停的时候抛出,并且返回下一次 yield 的值。

    close

    在生成器函数暂停的位置引发 GeneratorExit。如果生成器函数正常退出,已经关闭,或者引发 GeneratorExit(没有捕获该异常),关闭返回给调用者;如果生成器产生一个值,则引发一个 RuntimeError;如果生成器引发其他异常,则传播给调用者;如果生成器由于异常或正常退出而退出,则 close() 不执行任何操作。

    示例

    >>> def echo(value=None):

    ... print("Execution starts when 'next()' is called for the first time.")

    ... try:

    ... while True:

    ... try:

    ... value = (yield value) # 不管 yield 后面是否有表达式,value 的值都是 send 传递进来的参数

    ... except Exception as e:

    ... value = e

    ... finally:

    ... print("Don't forget to clean up when 'close()' is called.")

    ...

    >>> generator = echo(1)

    >>> print(next(generator))

    Execution starts when 'next()' is called for the first time.

    1

    >>> print(next(generator))

    None

    >>> print(generator.send(2))

    2

    >>> generator.throw(TypeError, "spam")

    TypeError('spam',)

    >>> generator.close()

    Don't forget to clean up when 'close()' is called.

    复制代码

    生成器解析

    python3 中的 range 函数就是一个典型的生成器,无论给它一个多么大的数,它占用内存始终很小。但是下面的代码会返回一个占用空间很大的列表:

    [x ** 2 for x in range(100000)]

    复制代码

    当我们想让它返回的结果也像生成器一样可以将中括号换成小括号:

    >>>(x ** 2 for x in range(100000))

    at 0x7fb246656620>

    复制代码

    使用 next 函数就可以查看里面的每个值,当然 for 循环也可以。

    因此将列表解析的中括号变成小括号就是生成器的语法。

    生成器解析其实就是列表解析的扩展,当我们明确需要使用小标访问的时候,使用列表解析。而如果只需要对结果进行迭代的时候,优先使用生成器解析。

    还有一个场景,就是要对结果进行缓存的时候,就只能使用列表解析了。不过使用生成器解析的场景确实要比列表解析来的多。

    暴露生成器内的对象

    如果你想让你的生成器暴露外部状态给用户, 别忘了你可以简单的将它实现为一个类,然后把生成器函数放到 __iter__() 方法中过去。比如:

    from collections import deque

    class linehistory:

    def __init__(self, lines, histlen=3):

    self.lines = lines

    self.history = deque(maxlen=histlen)

    def __iter__(self):

    for lineno, line in enumerate(self.lines, 1):

    self.history.append((lineno, line))

    yield line

    def clear(self):

    self.history.clear()

    复制代码

    为了使用这个类,你可以将它当做是一个普通的生成器函数。然而,由于可以创建一个实例对象,于是你可以访问内部属性值,比如 history 属性或者是 clear() 方法。代码示例如下:

    with open('somefile.txt') as f:

    lines = linehistory(f)

    for line in lines:

    if 'python' in line:

    for lineno, hline in lines.history:

    print('{}:{}'.format(lineno, hline), end='')

    复制代码

    如果行中包含了 python 这个关键字,那就打印该行和前三行的行号以及内容。

    关于生成器,很容易掉进函数无所不能的陷阱。如果生成器函数需要跟你的程序其他部分打交道的话(比如暴露属性值,允许通过方法调用来控制等等),可能会导致你的代码异常的复杂。如果是这种情况的话,可以考虑使用上面介绍的定义类的方式。在 __iter__() 方法中定义你的生成器不会改变你任何的算法逻辑。由于它是类的一部分,所以允许你定义各种属性和方法来供用户使用。

    一个需要注意的小地方是,如果你在迭代操作时不使用 for 循环语句,那么你得先调用 iter() 函数。比如:

    >>>f = open('somefile.txt')

    >>>lines = linehistory(f)

    >>>next(lines)

    Traceback (most recent call last):

    File "", line 1, in

    TypeError: 'linehistory' object is not an iterator

    >>># Call iter() first, then start iterating

    >>>it = iter(lines)

    >>>next(it)

    'hello world\n'

    >>>next(it)

    'this is a test\n'

    >>>

    复制代码

    生成器切片

    你想得到一个由迭代器生成的切片对象,但是标准切片操作并不能做到。函数 itertools.islice() 正好适用于在迭代器和生成器上做切片操作。比如:

    >>>def count(n):

    ... while True:

    ... yield n

    ... n += 1

    ...

    >>>c = count(0)

    >>>c[10:20]

    Traceback (most recent call last):

    File "", line 1, in

    TypeError: 'generator' object is not subscriptable

    >>># Now using islice()

    >>>import itertools

    >>>for x in itertools.islice(c, 10, 20):

    ... print(x)

    ...

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    >>>

    复制代码

    迭代器和生成器不能使用标准的切片操作,因为它们的长度事先我们并不知道(并且也没有实现索引)。函数 islice() 返回一个可以生成指定元素的迭代器,它通过遍历并丢弃直到切片开始索引位置的所有元素。然后才开始一个个的返回元素,并直到切片结束索引位置。

    这里要着重强调的一点是 islice() 会消耗掉传入的迭代器中的数据。必须考虑到迭代器是不可逆的这个事实。所以如果你需要之后再次访问这个迭代器的话,那你就得先将它里面的数据放入一个列表中。

    跳过可迭代对象开始部分

    你想遍历一个可迭代对象,但是它开始的某些元素你并不感兴趣,想跳过它们。itertools 模块中有一些函数可以完成这个任务。首先介绍的是 itertools.dropwhile() 函数。使用时,你给它传递一个函数对象和一个可迭代对象。它会返回一个迭代器对象,丢弃原有序列中直到函数返回 Flase 之前的所有元素,然后返回后面所有元素。

    为了演示,假定你在读取一个开始部分是几行注释的源文件。比如:

    >>>with open('/etc/passwd') as f:

    ...for line in f:

    ... print(line, end='')

    ...

    ##

    # User Database

    #

    # Note that this file is consulted directly only when the system is running

    # in single-user mode. At other times, this information is provided by

    # Open Directory.

    ...

    ##

    nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false

    root:*:0:0:System Administrator:/var/root:/bin/sh

    ...

    >>>

    复制代码

    如果你想跳过开始部分的注释行的话,可以这样做:

    >>>from itertools import dropwhile

    >>>with open('/etc/passwd') as f:

    ... for line in dropwhile(lambda line: line.startswith('#'), f):

    ... print(line, end='')

    ...

    nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false

    root:*:0:0:System Administrator:/var/root:/bin/sh

    ...

    >>>

    复制代码

    这个例子是基于根据某个测试函数跳过开始的元素。如果你已经明确知道了要跳过的元素的个数的话,那么可以使用 itertools.islice() 来代替。比如:

    >>>from itertools import islice

    >>>items = ['a', 'b', 'c', 1, 4, 10, 15]

    >>>for x in islice(items, 3, None):

    ... print(x)

    ...

    1

    4

    10

    15

    >>>

    复制代码

    在这个例子中,islice() 函数最后那个 None 参数指定了你要获取从第 3 个到最后的所有元素。如果 None 和 3 的位置对调,意思就是仅仅获取前三个元素,这个跟切片的相反操作 [3:] 和 [:3] 原理是一样的。

    函数 dropwhile() 和 islice() 其实就是两个帮助函数,为的就是避免写出下面这种冗余代码:

    with open('/etc/passwd') as f:

    # Skip over initial comments

    while True:

    line = next(f, '')

    if not line.startswith('#'):

    break

    # Process remaining lines

    while line:

    # Replace with useful processing

    print(line, end='')

    line = next(f, None)

    复制代码

    跳过一个可迭代对象的开始部分跟通常的过滤是不同的。比如,上述代码的第一个部分可能会这样重写:

    with open('/etc/passwd') as f:

    lines = (line for line in f if not line.startswith('#'))

    for line in lines:

    print(line, end='')

    复制代码

    这样写确实可以跳过开始部分的注释行,但是同样也会跳过文件中其他所有的注释行。换句话讲,我们的解决方案是仅仅跳过开始部分满足测试条件的行,在那以后,所有的元素不再进行测试和过滤了。

    最后需要着重强调的一点是,本节的方案适用于所有可迭代对象,包括那些事先不能确定大小的,比如生成器,文件及其类似的对象。

    展开嵌套的序列

    你想将一个多层嵌套的序列展开成一个单层列表,可以写一个包含 yield from 语句的递归生成器来轻松解决这个问题。比如:

    from collections import Iterable

    def flatten(items, ignore_types=(str, bytes)):

    for x in items:

    if isinstance(x, Iterable) and not isinstance(x, ignore_types):

    yield from flatten(x)

    else:

    yield x

    items = [1, 2, [3, 4, [5, 6], 7], 8]

    # Produces 1 2 3 4 5 6 7 8

    for x in flatten(items):

    print(x)

    复制代码

    在上面代码中,isinstance(x, Iterable) 检查某个元素是否是可迭代的。如果是的话,yield from 就会返回所有子例程的值。最终返回结果就是一个没有嵌套的简单序列了。

    额外的参数 ignore_types 和检测语句 isinstance(x, ignore_types) 用来将字符串和字节排除在可迭代对象外,防止将它们再展开成单个的字符。 这样的话字符串数组就能最终返回我们所期望的结果了。比如:

    >>>items = ['Dave', 'Paula', ['Thomas', 'Lewis']]

    >>>for x in flatten(items):

    ... print(x)

    ...

    Dave

    Paula

    Thomas

    Lewis

    >>>

    复制代码

    之前提到的对于字符串和字节的额外检查是为了防止将它们再展开成单个字符。如果还有其他你不想展开的类型,修改参数 ignore_types 即可。

    最后要注意的一点是,yield from 在涉及到基于协程和生成器的并发编程中扮演着更加重要的角色。

    展开全文
  • Oracle-Oracle数据库模式对象管理

    千次阅读 2019-06-21 21:46:58
    Oracle数据库模式对象管理 下面通过一些简单的例子来熟悉一下在Oracle数据库: 表的创建与管理。 索引的创建与管理。 视图的创建与管理。 序列的创建与应用。 例子来源于:《Oracle数据库基础教程(第2版)》...
  • 下列选项,不属于Python的特点的是()。答:类库少为补偿参考系的非惯性运动,我们引入了一个惯性力-ma_0,则牛顿第二定律应写为()。(假定汽车加速度为a_0。)答:ma=F-ma_0智慧职教: 茶席是茶艺艺术的造型艺术( )...
  • 【单选题】下列Python保留字,不用于表示分支结构的是【单选题】以下程序的输出结果是: j = '' for i in "12345": j += i + ',' print(j)【单选题】在读写文件之前,必须通过哪种方法创建文件对象【单选题】以下程序...
  • 如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to ...
  • public interface ResultSetMetaData可用于获取关于ResultSet对象中列的类型和属性信息的对象。以下代码片段创建 ResultSet 对象 rs,创建 ResultSetMetaData 对象 rsmd,并使用 rsmd 查找rs 有多少列,以及 rs ...
  • java面向对象

    万次阅读 多人点赞 2018-08-21 16:51:59
    包括面向对象概念、类与对象的关系、封装、构造函数、this关键字、static关键字、单例设计模式、继承、多态、内部类、异常、包等java基础知识。 1、面向对象 面向对象是相对面向过程而言 面向对象和面向过程都是...
  • 因此开发获取字节码文件对象即可: Class.forName("com.mysql.jdbc.Driver"); MySQL5之后利用驱动文件自动注册驱动,可省略注册驱动的步骤 static { try { java . sql . DriverManager . ...
  • 实验4 Oracle数据库模式对象管理

    千次阅读 多人点赞 2019-05-03 15:07:51
    一、实验目的: (1)掌握表的创建与管理。 (2) 掌握索引的创建与管理。 (3) 掌握视图的创建与管理。...2、按下列方式创建一个用户bs,并给该用户授权。 3、使用bs用户登录数据库,并进行下面...
  • 与其它的语言相比,JavaScript的“对象”总是显得不是那么合群。一些新人在学习JavaScript面向对象时,往往也会有疑惑:为什么JavaScript(直到ES6)有对象的概念,但是却没有像其他的语言那样,有类的概念呢?为...
  • 面向对象的五大基本原则

    万次阅读 2019-01-06 20:18:24
    面向对象的三大特性:封装、继承、多态 面向对象的七(或五大原则,前五项)大基本原则:单一职责原则(SRP) 、开放封闭原则(OCP) 、里氏替换原则(LSP)、 依赖倒置原则(DIP)、 接口隔离原则(ISP)、迪米特...
  • Python 文件对象的属性和方法简介

    千次阅读 2016-01-11 11:24:25
    Python 文件对象的属性和方法简介 语法 描述 f.close() 关闭文件对象f,并将属性f.closed设置为True f.closed 文件已关闭,则返回True f.encoding bytes与str之间进行转换时使用的编码 f.fileno() 返回...
  • 面向对象编程基本概念

    千次阅读 2018-04-18 15:41:53
    面向对象编程(OOP)为软件社区引入了一场革命,以帮助解决这些问题。 OOP专注于模块化,改变容忍度,代码重用,易于理解和分布式开发。今天大多数项目都使用面向对象的概念。由于C ++引入了OOP,因此用户体验已经...
  • 面向对象复习总结

    千次阅读 2016-12-07 21:11:27
    90年代末,被称为四人帮的GoF发表了在面向对象编程使用模式化方法研究的开创性著作-《设计模式-可复用面向对象软件的基础》(《Design Patterns-Elements of Reusable Object-Oriented Software》)。 其中提出了...
  • 设计模式考题复习

    千次阅读 2021-12-02 15:55:10
    一.定义 设计模式六大基本原则: 里氏替换原则 迪米特原则 开闭原则 单一职责原则 ...结构型模式(7):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式
  • 设计模式试题-答案

    千次阅读 2018-12-25 17:55:27
    2、下列属于面向对象基本原则的是( c ) A.继承 B.封装 C.里氏代换 D都不是 3、Open-Close原则的含义是一个软件实体( a ) A.应当对扩展开放,对修改关闭. B.应当对修改开放,对扩展关闭 C.应当对继承开放,对修改关闭...
  • 设计模式之模板方法模式(行为型)

    千次阅读 2019-01-01 00:02:07
    模板方法模式就是在一个抽象类定义一些骨架方法,然后通过类继承的方法,将一些方法延迟到继承类里。模板方法模式是一种类行为型模式,是一种比较常用的方法。不属于对象行为型模式,因为只是通过类继承实现。 ...
  • 设计模式——适配器模式

    千次阅读 2018-04-06 17:23:43
    将一个类的接口转换成客户希望的另外一个接口。...类适配器模式采用继承的方式来实现,而对象适配器模式则是采用对象组合的方式来实现,开发过程根据实际情况来进行选择。涉及到的角色:目标接口(Tar...
  • 计算机存储的发展(块存储,文件存储,对象存储)

    万次阅读 多人点赞 2018-09-15 15:04:08
    对象存储 1、对象 2、对象存储设备 3、元数据服务器(Metadata Server,MDS) 4、对象存储系统的客户端Client 三者之间异同比较 参考文献 如果要实现一个计算机,那么这个计算机一定要有以下的三个部分构成:...
  • 下列哪项类型数据是不可变化的:

    千次阅读 2020-12-05 00:57:57
    下列哪项类型数据是不可变化的:自顶向下的设计也被称为逐步细化。((2>=2)or(2<2)and 2)的结果是True。以下不能创建一个字典的语句是:字符串是一个字符序列,例如,字符串s,从右侧向左第2个字符用什么索引?...
  • Java的代理对象实例

    千次阅读 2018-05-05 13:57:02
    Java的代理对象,可以通过代理来操作一个正真的实例对象,通过代理模式来重写那些我们需要增强的原对象的方法,下面是一个关于代理的简单实例:1.定义一个接口类public interface MyBusiness { public void ...
  • 1、关于面向过程和面向对象下列说法错误的是(B)。 A.面向过程和面向对象都是解决问题的一种思路 B.面向过程是基于面向对象的 C.面向过程强调的是解决问题的步骤 D.面向对象强调的是解决问题的对象 2、关于类和...
  • 第十章:面向对象分析(2)

    千次阅读 2022-03-28 16:16:15
    3、泛化关系 泛化关系和类找那个的泛化概念是一样的,于用例继承父用例的行为和含义,还可以增加或覆盖父用例的行为,子用例可以出现在任何父用例出现的位置(父和子均有具体的实例) 也可以重载它,...对象模型是面..
  • JAVA练习题二(类与对象

    万次阅读 2020-03-13 10:21:19
    下列关于面向对象的说法,错误的是( )。 A、面向对象思想编程,不仅增强代码了复用性,提供了开发效率,而且为程序的修改补充提供了便利。 B、面向对象就是分析解决问题所需要的步骤,然后用函数把这些步骤一一实现,...
  • 下列哪些做法误的是错,创例对后在运意外动发生伤害事故。 护人应取意书签字情同得学的知生监,使用关习岗实周岁加跟未满的学生参。许可徽淮或销货规定照、键字建类证的品安进货院校园超有营业执《安全管北煤必须...
  • 设计模式期末考试复习客观题

    千次阅读 2021-12-29 14:27:04
    1、设计模式起源于 ( ) A、 机械设计 B、 建筑工程设计 C、 水利工程设计 D、 工业电力化设计 B 2、“不要和陌生人说话” 是 ( ) 原则的通俗表述。 A 、 接口隔离 B 、 里氏 替换 C 、 依赖 倒置 D、迪米特 D...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 129,796
精华内容 51,918
关键字:

下列对象中不是模式对象的是