zoukankan      html  css  js  c++  java
  • python 核心编程 第十三章

    python面对对象

    类和实例:类是对象的定义,实例是真真的实物。

    创建一个类:

    class AddrBookEnttry(object):
        def __init__(self, nm, ph):
            self.name = nm
            self.phone = ph
            print"Created instance for:", self.name
        def updatePhone(self, newph):
            self.phont = newph
            print "Update phone for:", self.name
    john = AddrBookEnttry("John", "408-34324")
    jane = AddrBookEnttry("Jane Doe", "42345423-32")
    john.updatePhone("1376478763")
    print john.phone
    print john.name
    

    定义类后,创建实例,可以查看实例的属性,以及调用实例的方法进行操作属性

    创建子类:

    class AddrBookEnttry(object):
        def __init__(self, nm, ph):
            self.name = nm
            self.phone = ph
            print"Created instance for:", self.name
        def updatePhone(self, newph):
            self.phont = newph
            print "Update phone for:", self.name
    class EmplAddrBookEntry(AddrBookEnttry):
        def __init__(self, nm, ph, id, em):
            AddrBookEnttry.__init__(self, nm, ph)
            self.empid = id
            self.email = em
        def updateEmail(self, newem):
            self.email = newem
            print "Updated email address for:", self.name
    
    john = EmplAddrBookEntry("john Doe", "408-555-1212", 42,"Jojn@qq.com")
    print john, john.name, john.phone
    john.updatePhone("1376478763")
    john.updateEmail("Join@163.com")
    print john.phone, john.email
    

    Created instance for: john Doe
    <main.EmplAddrBookEntry object at 0x027B14F0> john Doe 408-555-1212
    Update phone for: john Doe
    Updated email address for: john Doe
    408-555-1212 Join@163.com

    子类继承了父类的方法,但不会继承构造器,需要显示的调用还需要传入self参数。

    特殊类属性

    对于类C
    C.name 类C的名字(字符串)
    C.doc 类C的文档字符串
    C.bases 类C的所有父类构成的元组
    C.dict 类C的属性
    C.module 类C定义所在的模块(1.5 版本新增)
    C.class 实例C对应的类(仅新式类中)

    del()解构器方法:这个函数要直到该实例对象所有的引用都被清除掉后才会执行。

    class C(object):
        def __init__(self):
            print"initialized"
        def __del__(self):
            print"deleted"
    c1 = C()
    c2 = c1
    del c2
    del c1
    raw_input()
    

    当清楚c1实例的全部引用后,就会执行__del__(),加上raw的原因是,程序运行结束会自动回收实例。
    核心笔记:跟踪实例
    Python 没有提供任何内部机制来跟踪一个类有多少个实例被创建了,或者记录这些实例是些什
    么东西。如果需要这些功能,你可以显式加入一些代码到类定义或者__init__()和__del__()中去。
    核心笔记:跟踪实例
    Python 没有提供任何内部机制来跟踪一个类有多少个实例被创建了,或者记录这些实例是些什
    么东西。如果需要这些功能,你可以显式加入一些代码到类定义或者__init__()和__del__()中去。
    最好的方式是使用一个静态成员来记录实例的个数。靠保存它们的引用来跟踪实例对象是很危险的,
    因为你必须合理管理这些引用,不然,你的引用可能没办法释放(因为还有其它的引用) ! 例子:

    class InstCt(object):
        count = 0
        def __init__(self):
            InstCt.count += 1
        def __del__(self):
            InstCt.count -= 1
        def howMany(self):
            print InstCt.count
            return InstCt.count
    
    a = InstCt()
    b = InstCt()
    b.howMany()
    a.howMany()
    del b
    a.howMany()
    del a
    print InstCt.count
    

    2
    2
    1
    0

    类的静态方法和类方法

    经典类创建静态方法和类方法:

    class TestStaticMethod():
        def foo():
            print 'calling static method foo()'
        foo = staticmethod(foo)
    class TestClassMethod:
        def foo(cls):
            print 'calling class method foo()'
            print 'foo() is part of class:', cls.__name__
        foo = classmethod(foo)
    TestClassMethod.foo()
    

    使用staticmethod()和classmethed()函数创建。

    来看看另一种创建的方法(使用装饰器):

    class TestStaticMethod():
        @staticmethod
        def foo():
            print 'calling static method foo()'
    class TestClassMethod:
        @classmethod
        def foo(cls):
            print 'calling class method foo()'
            print 'foo() is part of class:', cls.__name__
    TestClassMethod.foo()
    TestStaticMethod.foo()
    

    类的继承覆盖方法:

    class P(object):
        def foo(self):
            print "Hi, I am P-foo"
    
    class C(P):
        def foo(self):
            super(C, self).foo()
            print "Hi I am C-foo"
    
    c = C()
    c.foo()
    

    Hi, I am P-foo
    Hi I am C-foo

    这里子类C覆盖了基类的方法,但是使用super()可以调用已经被覆盖的基类的方法。

    从标准类型派生

    class RoundFloat(float):
        def __new__(cls, val):
            return super(RoundFloat, cls).__new__(cls, round(val, 2))
    print RoundFloat(2.3333)
    

    这里使用super()函数捕获对应的基类,并且调用__new__()

    另一个例子,一个新的字典类型,他的keys()方法会自动排序结果

    class SortedKey(dict):
        def keys(self):
            return sorted(super(SortedKey, self).keys())
    
    d = SortedKey((('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2)))
    print 'By iterator:'.ljust(12), [key for key in d]
    print 'By keys():'.ljust(24), d.keys()
    

    多重继承

    class P1(object):
        def foo(self):
            print"called P1-foo()"
    
    class P2(object):
        def foo(self):
            print"called P2-foo()"
        def bar(self):
            print"called P2-bar()"
    
    class C1(P1, P2):
        pass
    
    class C2(P2, P1):
        pass
    
    class GC(C1, C2):
        pass
    
    test = GC()
    test.foo()
    

    TypeError: Error when calling the metaclass bases
    Cannot create a consistent method resolution
    order (MRO) for bases P2, P1
    产生了一个所谓的菱形效应,mrojiu错误了

    这里有些看不太懂,不过如果删除object使用以前的继承方式就不会出现这个问题,还是想不通╮(╯▽╰)╭。

    内建函数

    表 13.3 类,实例及其它对象的内建函数
    内建函数 描述

    1. issubclass(sub, sup) 如果类 sub 是类 sup 的子类,则返回 True,反之,为 False。
      isinstance(obj1, obj2) 如果实例obj1是类obj2或者obj2子类的一个实例; 或者如果obj1
      是 obj2 的类型,则返回 True;反之,为 False。
    2. hasattr(obj, attr) 如果 obj 有属性 attr(用字符串给出) ,返回 True,反之,返回
      表 13.3 类,实例及其它对象的内建函数(续)
      内建函数 描述
    3. getattr(obj, attr[, default]) 获取 obj 的 attr 属性;与返回 obj.attr 类似;如果 attr
      不是 obj 的属性, 如果提供了默认值, 则返回默认值; 不然,
      就会引发一个 AttributeError 异常。
    4. setattr(obj, attr, val) 设置obj的 attr 属性值为 val, 替换任何已存在的属性值;
      不然,就创建属性;类似于 obj.attr=val
    5. delattr(obj, attr) 从 obj 中删除属性 attr(以字符串给出) ;类似于 del
      obj.attr。
    6. dir(obj=None) 返回 obj 的属性的一个列表;如果没有给定 obj,dir()则
      显示局部名字空间空间中的属性, 也就是 locals().keys()
    7. super(type, obj=None)
      a
      返回一个表示父类类型的代理对象;如果没有传入 obj,
      则返 回的 super 对象是非绑定的;反之,如果 obj 是一个
      type , issubclass(obj,type) 必 为 True ; 否 则 ,
      isinstance(obj,type)就必为 True。
    8. vars(obj=None) 返回 obj 的属性及其值的一个字典;如果没有给出 obj,
      vars()显示局部名字空间字典(属性及其值) ,也就是
      locals()。

    用特殊方法定制类

    特殊方法 描述
    基本定制型

    1. C.init(self[, arg1, ...]) 构造器(带一些可选的参数)
    2. C.new(self[, arg1, ...])
      a
      构造器(带一些可选的参数) ;通常用在设置不变数据类
      型的子类。
    3. C.del(self) 解构器
    4. C.str(self) 可打印的字符输出;内建 str()及 print 语句
    5. C.repr(self) 运行时的字符串输出;内建 repr() 和‘ ‘ 操作符
    6. C.unicode(self)
      b
      Unicode 字符串输出;内建 unicode()
    7. C.call(self, *args) 表示可调用的实例
    8. C.nonzero(self) 为 object 定义 False 值;内建 bool() (从 2.2 版开始)
    9. C.len(self) “长度” (可用于类) ;内建 len()
      一个修改默认输出的例子:
    class RoundFloat(object):
        def __init__(self, val):
            self.value = round(val, 2)
        def __str__(self):
            return str(self.value)
    
    rfm = RoundFloat(4.5353535)
    print rfm
    

    4.54

    __str()__方法,覆盖了默认的行为。

    数值定制的例子

    class Time60(object):
        def __init__(self, hr, min):
            self.hr = hr
            self.min = min
        def __str__(self):
            return "%d:%d" % (self.hr, self.min)
        __repr__ = __str__
    
        def __add__(self, other):
            return self.__class__(self.hr + other.hr, self.min +other.min)
        def __iadd__(self, other):
            self.hr += other.hr
            self.min +=other.min
            return self
    
    mon = Time60(10, 30)
    tue = Time60(11, 15)
    print mon + tue
    mon += tue
    print mon
    

    21:45
    21:45

    这个例子我们重新定义了 + 和+=的方法,使它支持更有趣的操作。

    练习

    13-3. 对类进行定制。写一个类,用来将浮点数值转换为金额。
    基本任务: 编写一个 dollarize()函数,它以一个浮点数值作为输入,返回一个字符串形式的金额数。

    class MoneyFmt(object):
        def __init__(self, value=0.0):
            self.dollarize(value)
        def dollarize(self, valus):
            val = "$"
            valus = round(valus, 2)
            valus = str(valus)
            if valus[0] == "-":
                val = "-$"
                valus = valus[1:]
            strmoney = valus.split(".")
            valus = ""
            if (len(strmoney[0])) % 3:
                strHead = strmoney[0][0:(len(strmoney[0])) % 3]
            else:
                strHead = strmoney[0][0, 3]
            for i in range(0, (len(strmoney[0]) + 1) / 3 - 1):
                valus += "," + strmoney[0][len(strHead) + i * 3:len(strHead) + i * 3 + 3]
            valus = val + strHead + valus + "." + strmoney[1]
            self.value = valus
    
        def update (self, value=None):
            if value:
                self.dollarize(value)
        def __str__(self):
            return self.value
        def __nonzero__(self):
            return int(self.value)
        def __repr__(self):
            return self.value
    text = MoneyFmt(-11333311111.22)
    print text
    
    -$11,333,311,111.2
    

    13-7. 数据类。提供一个 time 模块的接口,允许用户按照自己给定时间的格式,比如:
    “MM/DD/YY,” “MM/DD/YYYY,” “DD/MM/YY,” “DD/MM/ YYYY,” “Mon DD, YYYY,” 或是标准
    的 Unix 日期格式: “Day Mon DD, HH:MM:SS YYYY” 来查看日期。你的类应该维护一个日期值,并
    用给定的时间创建一个实例。如果没有给出时间值,程序执行时会默认采用当前的系统时间。还包
    括另外一些方法:
    update() 按给定时间或是默认的当前系统时间修改数据值
    display() 以代表时间格式的字符串做参数,并按照给定时间的格式显示:
    'MDY' ==> MM/DD/YY
    'MDYY' ==> MM/DD/YYYY
    'DMY' ==> DD/MM/YY
    'DMYY' ==> DD/MM/YYYY
    'MODYY' ==> Mon DD, YYYY

    import datetime
    class myTime(object):
        def __init__(self, year=2016, month=11, day=1, hour=0, minute=0, second=0 ):
            self.datas = {"MDY": "%M-%d-%y", "MDYY": "%M-%d-%Y", "DMY": "%d-%M-%y", "DMYY": "%d-%M-%Y", "MODYY": "%m-%d-%y"}
            if minute and second and hour:
                self.dt = datetime.datetime.now()
            else:
                self.dt = datetime.datetime(year, month, day, hour, minute, second)
        def update(self, year=2016, month=11, day=0, hour=0, minute=0, second=0 ):
            self.dt = datetime.datetime(year, month, day, hour, minute, second)
        def display(self,data=None):
            try:
                strtemp = self.datas[data]
                print self.dt.strftime((strtemp))
            except:
                print self.dt.ctime()
    
    text = myTime()
    text.update(2016, 1, 1, 1, 1, 1)
    text.display()
    
    Fri Jan  1 01:01:01 2016
    

    13-10. 堆栈和队列。编写一个类,定义一个能够同时具有堆栈(FIFO)和队列(LIFO)操作行为
    的数据结构。这个类和 Perl 语言中数组相像。需要实现四个方法:
    shift() 返回并删除列表中的第一个元素,类似于前面的 dequeue()函数。
    unshift() 在列表的头部"压入"一个新元素
    push() 在列表的尾部加上一个新元素,类似于前面的 enqueue()和 push()方法。
    pop() 返回并删除列表中的最后一个元素,与前面的 pop()方法完全一样。

    class StackQueue(object):
        def __init__(self, sq=[]):
            self.sq = []+sq
        def shift(self):
            str = self.sq[0]
            self.sq.pop(0)
            return str
        def unshift(self,x):
            self.sq.insert(0, x)
        def push(self, x):
            self.sq.append(x)
        def pop(self):
            str = self.sq[-1]
            self.sq.pop()
            return str
        def __str__(self):
            return str(self.sq)
    

    13-20. 类的定制。改进脚本time60.py,见13.13.2 节,示例13.3.
    (a) 允许“空”实例化: 如果小时和分钟的值没有给出,默认为零小时、零分钟。
    (b) 用零占位组成两位数的表示形式,因为当前的时间格式不符合要求。如下面的示例,wed
    应该输出为“12:05.”
    (c)除了用hours (hr) 和minutes (min)进行初始化外,还支持以下时间输入格式:
    一个由小时和分钟组成的元组(10, 30)
    一个由小时和分钟组成的字典({'hr': 10, 'min': 30})
    一个代表小时和分钟的字符串("10:30")
    附加题: 允许不恰当的时间字符串表示形式,如 “12:5”.
    (d) 我们是否需要实现__radd__()方法? 为什么? 如果不必实现此方法,那我们什么时候可
    以或应该覆盖它?
    (e) repr()函数的实现是有缺陷而且被误导的。我们只是重载了此函数,这样我们可以省
    去使用print 语句的麻烦,使它在解释器中很好的显示出来。但是,这个违背了一个原则:对于可估
    值的Python 表达式,repr()总是应该给出一个(有效的)字符串表示形式。12:05 本身不是一个合法
    的Python 表达式,但Time60('12:05')是合法的。请实现它。
    (f) 添加六十进制(基数是60)的运算功能。下面示例中的输出应该是19:15,而不是18:75:

    class Time60(object):
        def __init__(self,  *args, **kwargs):
            if len(args) == 0:
                args = (None,None)
            if type(args[0]) is str:
                self.hr, self.min = args[0].split(":")
            elif type(args[0]) is tuple:
                self.hr, self.min = args[0]
            elif type(args[0]) is dict:
                self.hr = args[0]["hr"]
                self.min = args[0]["min"]
            elif type(args[0]) is int and type(args[1]) is int:
                self.hr = args[0]
                self.min = args[1]
            elif len(kwargs) == 2:
                self.hr = kwargs["hr"]
                self.min = kwargs["min"]
            else:
                self.hr, self.min = (0, 0)
            self.hr = int(self.hr)
            self.min = int(self.min)
            if self.min >= 60:
                self.hr += self.min/60
                self.min = self.min%60
        def __str__(self):
            return "%d-%d" % (self.hr, self.min)
        def __add__(self, other):
            hr = self.hr + other.hr
            min = self.min + other.min
            if min >= 60:
                hr += min/60
                min = min%60
            return hr, min
        def __iadd__(self, other):
            self.hr += other.hr
            self.min += other.min
            if self.min >= 60:
                self.hr += self.min/60
                self.min = self.min%60
            return self
    
    s1 = Time60(hr=23, min=77)
    s2 = Time60(33, 50)
    s3 = Time60("6:22")
    s4 = Time60({"hr": 43, "min": 27})
    s5 = Time60((54, 46))
    print s1, s2, s3, s4, s5
    print s1 + s5
    s1+=s2
    print s1
    
    24-17 33-50 6-22 43-27 54-46
    (79, 3)
    58-7
    
  • 相关阅读:
    scrapy中selenium的应用
    Django的锁和事务
    redis
    【leetcode】187. Repeated DNA Sequences
    【leetcode】688. Knight Probability in Chessboard
    【leetcode】576. Out of Boundary Paths
    【leetcode】947. Most Stones Removed with Same Row or Column
    【leetcode】948. Bag of Tokens
    【leetcode】946. Validate Stack Sequences
    【leetcode】945. Minimum Increment to Make Array Unique
  • 原文地址:https://www.cnblogs.com/jikeboy/p/6021480.html
Copyright © 2011-2022 走看看