Python学习笔记(二十七)- 一个更加实际例子(A More Realistic Example)

1.当我们从shelve上取一个Manager对象并打印它时,这里显示格式的逻辑从何而来?
答:在我们的类的最终版本中,Manager类最终在单独的classtools模块中从AttrDisplay类继承其__repr__的打印方法,并在类树(class tree)中继承了两个级别。Manager类本身是没有的,因此继承搜索会爬到其Person超类;因为那里也没有__repr__,搜索爬得更高并在AttrDisplay类中找到它。在类语句的标题行(header line)的括号中列出的类名提供了指向更高级超类的链接。

2.当我们从shelve中获取Person对象而不导入其模块时,对象如何知道它有一个我们可以调用的giveRaise方法?
答:Shelves(实际上,它们使用pickle模块)会自动将实例重新链接到从该实例稍后加载回内存时创建的类。 Python在内部从其模块重新导入类,使用其存储的属性创建实例,并将实例的__class__链接设置为指向其原始类。这样,即使我们没有将实例的类导入到我们的作用域中,加载的实例也会自动获取所有原始方法(如lastName,giveRaise和__repr__)。

3.为什么将处理(processing)转移到方法(method)中这么重要,而不是在类外硬编码(hardcoded)?
答:将处理移动到方法中非常重要,以便将来只更改一个副本,以便可以在任何实例上运行这些方法。这是Python的封装(encapsulation)概念 - 包装接口背后的逻辑,以更好地支持未来的代码维护。如果您不这样做,则可以创建代码冗余,以便在将来代码发展时增加您的工作量。

4.为什么通过子类化而不是复制原始和修改来更好地进行自定义?
答:使用子类进行自定义可以减少开发工作量。在OOP中,我们通过自定义已完成的内容进行编写代码,而不是复制或更改现有代码。这是OOP中真正的“大创意(big ideal)” - 因为我们可以通过编写新的子类来轻松扩展我们以前的工作,我们可以利用我们已经完成的工作。这比从每次从头开始,或者引入可能都需要在将来更新的多个冗余代码副本要好得多。

5.为什么回调超类方法运行默认操作而不是在子类中复制和修改其代码更好?
答:无论上下文(context)如何,复制和修改代码都会使您将来的潜在工作量增加一倍。如果子类需要执行以超类方法编写代码的默认操作,那么通过超类的名称回调原始文件要比复制其代码要好得多。对于超类构造函数也是如此。同样,复制代码会产生冗余,这是代码发展过程中的一个主要问题。

6.为什么使用像__dict__这样的工具可以更好地处理对象,而不是为每种类型的类编写更多的自定义代码?
答:通用工具可以避免硬编码的解决方案,随着时间的推移,这些解决方案必须与class的剩余保持同步。例如,每次将新属性添加到__init__构造函数中的实例时,都不需要更新通用__repr__打印方法。此外,所有类继承的通用打印方法都会出现,只需要在一个地方进行修改 - 通用型版本中的更改由从通用型类继承的所有类获取。同样,消除代码冗余会削减未来的开发工作;这是主要资产类别之一。

扫描二维码关注公众号,回复: 5457918 查看本文章

7.一般来说,您何时可以选择使用对象嵌入和组合(embedding and composition)而不是继承?
答:继承最适合基于直接定制的编码扩展(如我们的Manager类特例化Person类)。组合非常适合于将多个对象聚合成一个整体并由控制器层类定向的场景。继承(inheritance)将调用传递给重用(reuse),并将组合传递给委托的地方。继承和组合并不相互排斥;通常,控制器中的对象本身就是基于继承的自定义。

8.如果本章中编写的对象使用字典作为名字和列表作为职业,您需要更改哪些内容,如本书前面的类似示例所展示的那样?
答:并不多,因为这真的是第一个原型,但是需要为新名称格式更新lastName方法; Person构造函数将job默认值更改为空列表;并且Manager类可能需要在其构造函数中传递job列表而不是单个字符串(当然,自测代码也会改变)。好消息是,这些变化需要在我们的class中的一个地方进行,其中包含了这些细节。数据库脚本应该按原样工作,因为shelves支持任意数据。

9.如何修改本章中的类以在Python中实现个人联系人数据库?
答:本章中的类可用作样板的“模板”代码,以实现各种类型的数据库。基本上,您可以通过修改构造函数来记录不同的属性并提供适合目标应用程序的任何方法,从而重新调整它们的用途。例如,您可以为联系人数据库使用名称,地址,生日,电话,电子邮件等方式,以及适用于此目的的方法。例如,名为sendmail的方法可能会使用Python的标准库smptlib模块在调用时自动向其中一个联系人发送电子邮件(有关此类工具的更多详细信息,请参阅Python手册或应用程序级别的书籍)。我们在这里写的AttrDisplay工具可以逐字地用来打印你的对象,因为它是有意通用的。这里的大多数shelve数据库代码也可用于存储您的对象,只需稍作更改即可。

一些其它的东西:
1.照惯例来说,模块名小写,类名大写

2.封装(encapsulation):将操作逻辑封装在接口后面

3.__repr__ 和 __str__ 

          __repr__:通常用于在出现对象时提供作为代码的低级别显示

          __str__:保留给更多的用户友好的信息显示

4.无论何时,只要你使用剪切和粘贴方式复制代码,你在未来的维护工作中会增加一倍

5.在Python中,instance.method(args...) 被自动翻译为 class.method(instance, args...)

6.Pthon的super就像一盒巧克力——你永远不知道你会得到什么。

7.Python的OOP机制:
(1)实例创建——填充实例属性

(2)行为方法——用类的方法封装逻辑

(3)操作符重载——为内建操作(如print)提供行为

(4)自定义行为——重新定义子类中的方法以特例化它们

(5)自定义构建函数——添加初始化逻辑

实质:

(1)继承搜索,在对象树中的属性

(2)方法中特别的self参数

(3)操作符重载自动调度到方法

8.永久保存对象:pickle,dbm,shelve

注:转载《Learning Python 5th Edition》[奥莱理]

1. When we fetch a Manager object from the shelve and print it, where does the display format logic come from?
2. When we fetch a Person object from a shelve without importing its module, how does the object know that it has a giveRaise method that we can call?
3. Why is it so important to move processing into methods, instead of hardcoding it outside the class?
4. Why is it better to customize by subclassing rather than copying the original and modifying?
5. Why is it better to call back to a superclass method to run default actions, instead of copying and modifying its code in a subclass?
6. Why is it better to use tools like __dict__ that allow objects to be processed generically than to write more custom code for each type of class?
7. In general terms, when might you choose to use object embedding and composition instead of inheritance?
8. What would you have to change if the objects coded in this chapter used a dictionary for names and a list for jobs, as in similar examples earlier in this book?
9. How might you modify the classes in this chapter to implement a personal contacts database in Python?

1. In the final version of our classes, Manager ultimately inherits its __repr__ printing method from AttrDisplay in the separate classtools module and two levels up in the class tree. Manager doesn't have one itself, so the inheritance search climbs to its Person superclass; because there is no __repr__ there either, the search climbs higher and finds it in AttrDisplay. The class names listed in parentheses in a class statement's header line provide the links to higher superclasses.
2. Shelves (really, the pickle module they use) automatically relink an instance to the class it was created from when that instance is later loaded back into memory. Python reimports the class from its module internally, creates an instance with its stored attributes, and sets the instance's __class__ link to point to its original class. This way, loaded instances automatically obtain all their original methods (like lastName, giveRaise, and __repr__), even if we have not imported the instance's class into our scope.
3. It's important to move processing into methods so that there is only one copy to change in the future, and so that the methods can be run on any instance. This is Python's notion of encapsulation—wrapping up logic behind interfaces, to better support future code maintenance. If you don't do so, you create code redundancy that can multiply your work effort as the code evolves in the future.
4. Customizing with subclasses reduces development effort. In OOP, we code by customizing what has already been done, rather than copying or changing existing code. This is the real “big idea” in OOP—because we can easily extend our prior work by coding new subclasses, we can leverage what we've already done. This is much better than either starting from scratch each time, or introducing multiple redundant copies of code that may all have to be updated in the future.
5. Copying and modifying code doubles your potential work effort in the future, regardless of the context. If a subclass needs to perform default actions coded in a superclass method, it's much better to call back to the original through the superclass's name than to copy its code. This also holds true for superclass constructors. Again, copying code creates redundancy, which is a major issue as code evolves.
6. Generic tools can avoid hardcoded solutions that must be kept in sync with the rest of the class as it evolves over time. A generic __repr__ print method, for example, need not be updated each time a new attribute is added to instances in an _init__ constructor. In addition, a generic print method inherited by all classes appears and need be modified in only one place—changes in the generic version are picked up by all classes that inherit from the generic class. Again, eliminating code redundancy cuts future development effort; that's one of the primary assets classes bring to the table.
7. Inheritance is best at coding extensions based on direct customization (like our Manager specialization of Person). Composition is well suited to scenarios where multiple objects are aggregated into a whole and directed by a controller layer class. Inheritance passes calls up to reuse, and composition passes down to delegate. Inheritance and composition are not mutually exclusive; often, the objects embedded in a controller are themselves customizations based upon inheritance.
8. Not much since this was really a first-cut prototype, but the lastName method would need to be updated for the new name format; the Person constructor would have change the job default to an empty list; and the Manager class would probably need to pass along a job list in its constructor instead of a single string (self-test code would change as well, of course). The good news is that these changes would need to be made in just one place—in our classes, where such details are encapsulated. The database scripts should work as is, as shelves support arbitrarily nested data.
9. The classes in this chapter could be used as boilerplate “template” code to implement a variety of types of databases. Essentially, you can repurpose them by modifying the constructors to record different attributes and providing whatever methods are appropriate for the target application. For instance, you might use attributes such as name, address, birthday, phone, email, and so on for a contacts database, and methods appropriate for this purpose. A method named sendmail, for example, might use Python's standard library smptlib module to send an email to one of the contacts automatically when called (see Python's manuals or application-level books for more details on such tools). The AttrDisplay tool we wrote here could be used verbatim to print your objects, because it is intentionally generic. Most of the shelve database code here can be used to store your objects, too, with minor changes.

猜你喜欢

转载自blog.csdn.net/Enderman_xiaohei/article/details/88303972