171113 Learning Python Chapter 27 Learning Python A More Realistic Example

  • Chapter 25 → 类的蓝图
  • Chapter 26 → 类的基础
  • Chapter 27 → 类的实例
  • Chapter 28 → 类的细节

本章中,我们编写两个类:
- Person 创建并处理关于人员信息的一个类
- 定制一个Person,修改继承的行为

步骤1:创建实例

模块名使用小写字母,类名使用大写字母

# File person.py(start)
class Person:

编写构造函数

  • __init__构造函数方法中将实例对象赋给self,构造函数方法包含了每次创建一个实例的时候Python会自动运行代码。
  • self就是新创建的实例对象,而name、job和pay变成了状态信息,即保存在对象中,随后使用的描述性数据。
# Add record field initialization
class Person:
    def __init__(self,name,job,pay):   # Constructor takes 3 arguments
        self.name = name               # Fill out fields when created
        self.job = job                 # self is the new instance object 
        self.pay = pay
  • 为构造函数中的参数添加默认值
  • 当我们创建Person对象的时候,需要给name传入值,但是job和pay现在是可选的
# Add defaults for constructor arguments
class Person:
    def __init__(self,name,job=None,pay=0): # Normal function args
        self.name = name
        self.job = job
        self.pay = pay

在进行中测试

  • Python是一种增量原型
  • 编写代码,测试,再编写更多的代码,再测试
  • 在进行中测试,要比在大量编写后测试更加自然
  • 等号赋值更加清晰并且不需要严格按照相对顺序,默认赋值需要注意顺序问题
bob = Person('Bob Smith')
sue = Person('Sue Jones',pay=100000,job='dev')
liu = Person('Bruce Liu','eng',pay=20000)
print(bob.name,bob.pay)
print(sue.name,sue.pay)
print(liu.name,liu.pay)
Bob Smith 0
Sue Jones 100000
Bruce Liu 20000

以两种方式使用代码

  • 客户端不关心我们的测试内容
  • 作为测试文件,在执行的时候会运行测试代码
  • 作为模块被导入时,不执行测试代码
  • 测试代码即 if __name__ == '__main__':之后的代码

这里写图片描述

步骤2:添加行为方法

对象的数据属性是可以引用并修改的

# process embedded built-in types: strings, mutability
class Person:
    def __init__(self,name,job=None,pay=0): # Normal function args
        self.name = name
        self.job = job
        self.pay = pay

if __name__=='__main__':
    bob = Person('Bob Smith')
    sue = Person('Sue Jones',job='dev',pay=100000)
    print(bob.name,bob.pay)
    print(sue.name,sue.pay)
    print(bob.name.split()[-1]) # 提取对象的最后一个名字,外部操作
    sue.pay*=1.10               # 改变对象的一个属性值,外部操作
    print(sue.pay)
Bob Smith 0
Sue Jones 100000
Smith
110000.00000000001

编写方法

  • 封装:把对对象的操作方法写在类的定义函数之中;构造代码以删除冗余,并且由此优化维护。对所有对象都适用,而非单个对象。
  • 封装只是重新组织了代码,以便将来科技更容易地修改,而不是修改代码的行为。
  • 方法只是附加给类并旨在处理那些类的实例的常规函数。
  • 实例是方法的调用的主体,并且回自动传递给方法的self参数。
# Add methods to encapsulate operations for maintainability
class Person:
    def __init__(self,name,job=None,pay=0):
        self.name = name
        self.job = job
        self.pay = pay
    def lastName(self):                 # Behavior methods
        return self.name.split()[-1]    # self is implied subject
    def giveRaise(self,percent):
        self.pay = int(self.pay*(1+percent))  # Must change here only

if __name__=='__main__':
    bob = Person('Bob Smith')
    sue = Person('Sue Jones',job='dev',pay=100000)
    print(bob.name,bob.pay)
    print(sue.name,sue.pay)
    print(bob.lastName(),sue.lastName()) # Use the new methods
    sue.giveRaise(.10)                   # inside of hardcoding 
    print(sue.pay)
    print(sue)                           # sue is a object
Bob Smith 0
Sue Jones 100000
Smith Jones
110000
<__main__.Person object at 0x0000024B7B0A36D8>

步骤3: 运算符重载

print(sue)
<__main__.Person object at 0x00000212FEC5FB00>

运算符重载的原因:实例对象的默认显示格式(通过print()函数)并不是很好,它仅仅显示对象的类名及其在内存中的地址,在Python中几乎没啥作用。

  • 第一常用运算符重载的方法__init__
  • 第二常用运算符重载的方法__str__

提供打印显示

# Add __str__ overload method for printing objects
class Person:
    def __init__(self,name,job=None,pay=0):
        self.name = name
        self.job = job
        self.pay = pay
    def lastName(self):                 # Behavior methods
        return self.name.split()[-1]    # self is implied subject
    def giveRaise(self,percent):
        self.pay = int(self.pay*(1+percent))  # Must change here only
    def __str__(self):
        return '[Person: %s, %s]'%(self.name,self.pay)


if __name__== '__main__':
    bob = Person('Bob Smith')
    sue = Person('Sue Jones',job='dev',pay=100000)
    print(bob)
    print(sue)
    print(bob.lastName(),sue.lastName()) # Use the new methods
    sue.giveRaise(.10)                   # inside of hardcoding 
    print(sue)                           # sue is a object
[Person: Bob Smith, 0]
[Person: Sue Jones, 100000]
Smith Jones
[Person: Sue Jones, 110000]

步骤4:通过子类定制行为

  • 已经介绍的Python OOP机制:
    • 创建实例
    • 在方法中提供行为
    • 重载运算符,改变str中的打印操作
    • 将数据和逻辑(函数方法)包装在一起
  • 尚未介绍的Python OOP机制:
    • 通过继承来定制化

编写子类

class Manager(Person):                       # Define a subclass of person, Inherit Person attrs
    def giveRaise(self,percent,bonus=0.10):  # Redefine to customize

扩展方法:不好的方式

  • 复制并粘贴Person中giveRaise的代码,然后针对Maneger修改如下所示:
  • 复制并粘贴所带来的问题:如果改变涨工资的方式,两个地方都需要修改代码,而非只是修改一处。代码维护工作增倍
class Manager(Person):
    def giveRaise(self,percent,bonus=0.10):
        self.apy = int(self.pay*(1+percent+bonus)) # Bad:cut and paste

扩展方法:好的方式

  • 通过手动调用
# Add customization of one behavior in a subclass:
class Person:
    def __init__(self,name,job=None,pay=0):
        self.name = name
        self.job = job
        self.pay = pay
    def lastName(self):                 # Behavior methods
        return self.name.split()[-1]    # self is implied subject
    def giveRaise(self,percent):
        self.pay = int(self.pay*(1+percent))  # Must change here only
    def __str__(self):
        return '[Person: %s, %s]'%(self.name,self.pay)

class Manager(Person):
    def giveRasse(self,percent,bonus=0.10):   # Redefine at this level
        Person.giveRaise(self,percent+bonus)  # Call Person's version

if __name__== '__main__':
    bob = Person('Bob Smith')
    sue = Person('Sue Jones',job='dev',pay=100000)
    print(bob)
    print(sue)
    print(bob.lastName(),sue.lastName()) 
    sue.giveRaise(.10)                   
    print(sue)                           
    tom =  Manager('Tom Jones','mgr',50000) # Make a Manager:__init__
    tom.giveRaise(0.10)                     # Runs custom version
    print(tom.lastName())                   # Runs inherited method
    print(tom)                              # Runs inherited __str__
[Person: Bob Smith, 0]
[Person: Sue Jones, 100000]
Smith Jones
[Person: Sue Jones, 110000]
Jones
[Person: Tom Jones, 55000]

多态的作用

多态:Python自动运行相应的giveRaise,针对bob和sue使用Person中最初的版本,对tom使用Manager中定制的版本

if __name__=='__main__':
    print('--All three--') # print内容并非实例对象,故一般性处理
    for object in (bob,sue,tom):
        object.giveRaise(0.10)
        print(object)
--All three--
[Person: Bob Smith, 0]
[Person: Sue Jones, 121000]
[Person: Tom Jones, 60500]

继承、定制和拓展(代码虽小,但功能完备)

class Person:
    def lastName(self):...
    def giveRaise(self):...
    def __str__(self):...

class Manager(Person):               # Inherit    继承
    def giveRaise(sef,...):...       # Customize  定制
    def someThingElse(self,...):...  # Extend     扩展

tom = Manager()    # Inherited verbatim
tom.lastName()     # Customized version
tom.giveRasie()    # Extension here
tom.somThingElse() # Inherited overload method
print(tom)

OOP:大思路

通常,剪切复制的方法现在可能看上去很快,但是,会使未来的工作量倍增。

步骤5:定制构造函数

问题:当创建Manager对象的时候,需要手动填写mgr,然而这是冗余的信息,如果可以自动填入,那将会更好。
- 通过类名直接调用并显示地传递self实例,从而运行超类的版本。
- 以这种方式调用重定义的超类构造函数,在Python中是一种常用的编码方式。
- Python自身使用继承来查找并调用唯一的一个__init__方法,也就是类树中最低的一个。
- 回忆:类树→继承查找→自下而上,自左向右 → __init__就是函数(只不过在命名上稍微特殊了点)

# Embedding-based Manager alternative
class Person:
    def __init__(self,name,job=None,pay=0):
        self.name = name
        self.job = job
        self.pay = pay
    def lastName(self):                 # Behavior methods
        return self.name.split()[-1]    # self is implied subject
    def giveRaise(self,percent):
        self.pay = int(self.pay*(1+percent))  # Must change here only
    def __str__(self):
        return '[Person: %s, %s]'%(self.name,self.pay)

class Manager(Person):
    def __init__(self,name,pay):
        Person.__init__(self,name,'mgr',pay) # 通过类名直接调用并显示地传递self实例,从而运行超类的版本。
    def giveRasse(self,percent,bonus=0.10):   # Redefine at this level
        Person.giveRaise(self,percent+bonus)  # Call Person's version

if __name__== '__main__':
    bob = Person('Bob Smith')
    sue = Person('Sue Jones',job='dev',pay=100000)
    print(bob)
    print(sue)
    print(bob.lastName(),sue.lastName()) 
    sue.giveRaise(.10)                   
    print(sue)                           
    tom =  Manager('Tom Jones',50000) # Job name not needed:
    tom.giveRaise(0.10)               # Implied/set by class
    print(tom.lastName())                   
    print(tom)                              
[Person: Bob Smith, 0]
[Person: Sue Jones, 100000]
Smith Jones
[Person: Sue Jones, 110000]
Jones
[Person: Tom Jones, 55000]
tom
<__main__.Manager at 0x24b7b0c8d68>

OOP比我们认为的要简单

  • 实例创建 - 填充实例属性
  • 行为方法 - 在类方法中封装逻辑
  • 运算符重载 - 为打印这样的内置操作提供行为
  • 定制行为 - 重新定义类中的方法以使其特殊化
  • 定制构造函数 - 为曹磊步骤添加初始化逻辑

组合类的其他方式 (非重点)

  • 较大的程序中的一些技术在于组合类的方式
  • 将Manager嵌入到一个Person中,而不是继承Person
  • 使用内置getattr来拦截未定义属性的访问,并将它委托给嵌入的对象

  • 基于委托的类可能通常hi重新定义运算符重载方法以委托它们去包装Python3.0中的对象,或者手动,或者通过工具或超类。

# Add customization of constructor in a subclass
class Person:
    def __init__(self,name,job=None,pay=0):
        self.name = name
        self.job = job
        self.pay = pay
    def lastName(self):                 # Behavior methods
        return self.name.split()[-1]    # self is implied subject
    def giveRaise(self,percent):
        self.pay = int(self.pay*(1+percent))  # Must change here only
    def __str__(self):
        return '[Person: %s, %s]'%(self.name,self.pay)

class Manager(Person):                       # Embed a Person object 
    def __init__(self,name,pay):
        self.person = Person(name,'mgr',pay) # Intercept abd degate 拦截+委派
    def giveRise(self,percent,bonux=.10):
        self.person.giveRaise(percent+bonus)
    def __getattr__(self,attr):
        return getattr(self.person,attr)     # Delegate all other attrs
    def __str__(self):                       # Must overload again( in 3.0)
        return str(self.person)

# Aggregate embedded objects into a composite
class Department:
    def __init__(self,*args):
        self.members = list(args)
    def addMember(self,person):
        self.members.append(person)
    def giveRaises(self,percent):
        for person in self.members:
            person.giveRaise(percent)
    def showAll(self):
        for person in self.members:
            print(person)

if __name__ == '__main__':
    bob = Person('Bob Smith')
    sue = Person('Sue Jones',job='dev',pay=100000)
    print(bob)
    print(sue)
    print(bob.lastName(),sue.lastName()) 
    sue.giveRaise(.10)                   
    print(sue)                           
    tom =  Manager('Tom Jones',50000) # Job name not needed:
    tom.giveRaise(0.10)               # Implied/set by class
    print(tom.lastName())                   
    print(tom)      

    print('\n---Aggregate embedded objects into a composite---')
    development = Department(bob,sue)  # Embed objects in a composite
    development.addMember(tom)
    development.giveRaises(0.10)       # Runs Embedded objects' giveRaise
    development.showAll()              # Runs Embedded objects' __str__s
[Person: Bob Smith, 0]
[Person: Sue Jones, 100000]
Smith Jones
[Person: Sue Jones, 110000]
Jones
[Person: Tom Jones, 50000]

---Aggregate embedded objects into a composite---
[Person: Bob Smith, 0]
[Person: Sue Jones, 121000]
[Person: Tom Jones, 50000]

在Python3.0 中捕获内置属性

  • 这个主题太高深,不是重点,后续在第38章介绍类装饰符也会再次回顾。

步骤6:使用内省工具

  • 两个问题
    • 属性问题:打印tom的类,是Person而不是Manager
    • 函数问题:当前格式只包含str,而没有考虑未来的目标
  • 侯面会遇见更加强大的类工具装饰器+元类),配合Python的内省工具,允许我们编写代码,从而以结构化和可维护的方式来拓展和管理类

特殊类属性

  • 用内省工具解决上面两个问题
    • 属性
    • 函数
  • 内省工具允许我们访问对象实现的一些内部机制

  • 内置的instance.__class__属性提供了一个从实例到创建它的类的链接

  • 内置的object.__dict__属性提供了一个字典,带有一个键/值对,以便每个属性都附加到一个命名空间对象(包括模块、类和实例)
bob  = Person('Bob Smith')
print(bob)                      # show bob's __str__
print(bob.__class__)            # show bob's class 
print(bob.__class__.__name__)   # show bob's class's name 
[Person: Bob Smith, 0]
<class '__main__.Person'>
Person
list(bob.__dict__.keys())       # Attributes are really dict keys. Use list to force list in 3.0
['name', 'job', 'pay']
for key in bob.__dict__:
    print(key,'→',getattr(bob,key))  # obj.attr, but attr is a var
name → Bob Smith
job → None
pay → 0

一种通用的显示工具

  • 文档字符串可以放在简单函数和模块的顶部,并且也可以放在类及其方法的开始出;
  • help函数PyDoc工具会自动地提取和显示他们。
# File classtools.py(new)
# Assorted class utilities and tools
class AttrDisplay:
    """
    Provides an inheritable print overload method that displays
    instances with their class names and aa name=value pair for 
    each attibute stored on the instance itself(but not attrs 
    inherited from its classes). Can be mixed into any class,
    and will work on any instance.
    """
    def gatherAttrs(self):
        attrs = []
        for key in sorted(self.__dict__):
            attrs.append('%s=%s' % (key,getattr(self,key)))
        return ', '.join(attrs)
    def __str__(self):
        return '[%s: %s]'%(self.__class__.__name__,self.gatherAttrs())

if __name__ == '__main__':
    class TopTest(AttrDisplay):
        count = 0
        def __init__(self):
            self.attr1 = TopTest.count
            self.attr2 = TopTest.count+1
            TopTest.count+=2
    class SubTest(TopTest):
        pass
X,Y= TopTest(),SubTest()
print(X) # Show all instance attrs
print(Y) # Show all lowest class name 
[TopTest: attr1=0, attr2=1]
[SubTest: attr1=2, attr2=3]
help(AttrDisplay)
Help on class AttrDisplay in module __main__:

class AttrDisplay(builtins.object)
 |  Provides an inheritable print overload method that displays
 |  instances with their class names and aa name=value pair for 
 |  each attibute stored on the instance itself(but not attrs 
 |  inherited from its classes). Can be mixed into any class,
 |  and will work on any instance.
 |  
 |  Methods defined here:
 |  
 |  __str__(self)
 |      Return str(self).
 |  
 |  gatherAttrs(self)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

实例与类属性的关系

工具类的命名考虑

AttrDisplay 旨在和其他任意类混合的通用工具,所以我们必须注意与客户类潜在的无意的命名冲突

  • 两种方法
    • _gatherAttrs (单下划线)
    • __gatherAttrs (双下划线)

类的最终形式

classtools.py → 自定义显示工具类
    ↓
person.py
    ↓
    Person类继承classtools.py模块中的AttrDisplay类
    ↓
    Manager继承Person类
# File person.py(final)
# from classtools import AttrDisplay # Use generic display tool  # Use genetic display tool
class Person(AttrDisplay):
    """
    Create and process person records
    """
    def __init__(self,name,job=None,pay=0):
        self.name = name
        self.job = job
        self.pay = pay
    def lastName(self):# Assumes last is last
        return self.name.split()[-1]
    def giveRaise(self,percent):
        self.pay = int(self.pay*(1+percent))
class Manager(Person):
    """
    A customized Person with special requirements
    """
    def __init__(self,name,pay):
        Person.__init__(self,name,'mgr',pay)
    def giveRaise(self,percent,bonus=0.10):
        Person.giveRaise(self,percent + bonus)

if __name__ == '__main__':
    bob = Person('Bob Smith')
    sue = Person('Sue Jones',job ='dev',pay=100000)
    print(bob)
    print(sue)
    print(bob.lastName(),sue.lastName())
    sue.giveRaise(0.10)
    print(sue)
    tom = Manager('Tom Jones',50000)
    tom.giveRaise(0.10)
    print(tom.lastName())
    print(tom)
[Person: job=None, name=Bob Smith, pay=0]
[Person: job=dev, name=Sue Jones, pay=100000]
Smith Jones
[Person: job=dev, name=Sue Jones, pay=110000]
Jones
[Manager: job=mgr, name=Tom Jones, pay=60000]

步骤7(最后一步):把对象储存到数据库中

对象持久化:让对象在创建它们的程序在推出之后依然存在,以文件的形式更加持久的保存在内存中。

Pcikle和Shelve

  • pickle:一种非常通用的对象格式化和解格式化的工具

    • 通过在文件中存储一个对象的pickle字符串,我们可以将其持久化
    • 随后直接载入它并进行unpickle操作,皆可以重构最初的对象
  • shelve: 相比pickle而言,shelves提供了一个额外的键结构来存储pickle处理后的对象

  • dbm:pickle(字符串)→shelve→dbm文件

  • 类实例 提供了数据(属性)和行为(方法),实际上等同于记录行为

在shelve数据库中存储对象

import shelve
db = shelve.open('persondb')  # Filename where objects are stored
for object in (bob,sue,tom):  # Use object's name attr as key
    db[object.name]=object    # Store object on shelve by key,
db.close()                    # Close after making changes
  • 将对象的名字用做键,从而把它们赋给shelve,这样仅仅只是为了方便
  • 实际上键可以是任意字符串,包括时间戳和ID
  • 但键必须是唯一的,从而保证键名和对象一一对应
  • 存储在键下面的值可以是Python的任意对象

交互地探索shelve

# Directory listing modle:verify files are present
import glob
glob.glob('person*')
['persondb.bak', 'persondb.dat', 'persondb.dir']
print(open('persondb.dir').read()) # 文本字符串文件
'Bob Smith', (0, 82)
'Sue Jones', (512, 94)
'Tom Jones', (1024, 93)
print(open('persondb.dat','rb').read()) # 二进制文件
b'\x80\x03c__main__\nPerson\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\t\x00\x00\x00Bob Smithq\x04X\x03\x00\x00\x00jobq\x05NX\x03\x00\x00\x00payq\x06K\x00ub.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x03c__main__\nPerson\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\t\x00\x00\x00Sue Jonesq\x04X\x03\x00\x00\x00jobq\x05X\x03\x00\x00\x00devq\x06X\x03\x00\x00\x00payq\x07J\xb0\xad\x01\x00ub.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x03c__main__\nManager\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\t\x00\x00\x00Tom Jonesq\x04X\x03\x00\x00\x00jobq\x05X\x03\x00\x00\x00mgrq\x06X\x03\x00\x00\x00payq\x07M`\xeaub.'

交互模式有效的成为一个数据库客户端

import shelve
db = shelve.open('persondb')
len(db)
3
list(db.keys())
['Bob Smith', 'Sue Jones', 'Tom Jones']
bob = db['Bob Smith']
print(bob)
[Person: job=None, name=Bob Smith, pay=0]
bob.lastName()
'Smith'
for key in db:
    print(key,'→',db[key])
Bob Smith → [Person: job=None, name=Bob Smith, pay=0]
Sue Jones → [Person: job=dev, name=Sue Jones, pay=110000]
Tom Jones → [Manager: job=mgr, name=Tom Jones, pay=60000]
for key in sorted(db):
    print(key,'→',db[key])
Bob Smith → [Person: job=None, name=Bob Smith, pay=0]
Sue Jones → [Person: job=dev, name=Sue Jones, pay=110000]
Tom Jones → [Manager: job=mgr, name=Tom Jones, pay=60000]

优点 vs 缺点

更新shelve中的对象

# File updatedb.py: update Person object on database
import shelve
db = shelve.open('persondb')        # Reopen shelve with same filename
for key in sorted(db):              # Iterate to display database objects
    print(key, '\t=>', db[key])     # Prints with custom format
sue = db['Sue Jones']               # Index by key to fetch
sue.giveRaise(.10)                  # Update in memory using class's method
db['Sue Jones'] = sue               # Assign to key to update in shelve
db.close()                          # Close after making changes
Bob Smith   => [Person: job=None, name=Bob Smith, pay=0]
Sue Jones   => [Person: job=dev, name=Sue Jones, pay=177156]
Tom Jones   => [Manager: job=mgr, name=Tom Jones, pay=60000]

未来方向

  • GUI
  • Web站点
  • Web服务
  • 数据库
  • ORM
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GuokLiu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值