zoukankan      html  css  js  c++  java
  • Python--深入理解Python特性 第4章

    第4章 类与面向对象

    4.1 对象比较:is 与 ==

      is比较的是两个变量是否指向同一个对象,表示相同。

      ==比较的是两个变量所指向的对象是否具有相同的值(内容相同),表示相等。

    a = [1, 2, 3]
    b = a
    c = [1, 2, 3]
    d = [a]
    e = [b]
    f = [c]
    
    print(f'a == b: {a == b}')
    print(f'a == c: {a == c}')
    print(f'a is b: {a is b}')
    print(f'a is c: {a is c}')
    
    print(f'd == e: {d == e}')
    print(f'd == f: {d == f}')
    print(f'd is e: {d is e}')
    print(f'd is f: {d is f}')
    
    ''' 输出结果
    a == b: True
    a == c: True
    a is b: True
    a is c: False
    d == e: True
    d == f: True
    d is e: False
    d is f: False
    '''
    View Code

    4.2 字符串转换(每个类都需要__repr__)

      python中内置的strrepr函数可以将对象转字符串,它们分别调用的是对象的__str____repr__方法,通常是使用str或者repr而不是直接调用对象的__str__和__repr__。

      在格式化字符串的时候如果指定了!r则是按__repr__输出字符串

      自定义类如果没有实现__str__或__repr__方法,默认转字符串输出的是包含类名和对象实列id的字符串。

      默认情况下,如果没有定义__str__,则__str__调用的是__repr__方法,因此定义了__repr__总是能正常的转换成字符串。

    class Car:
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __repr__(self):
            return (f'{self.__class__.__name__}('
                    f'{self.color!r}, {self.mileage!r})')
    
        def __str__(self):
            return f'a {self.color} car'
    
    
    car = Car('red', '37281')
    print(car)  # 按str输出
    print('{!r}'.format(car))  # 按repr输出
    
    ''' 默认的输出结果
    <__main__.Car object at 0x000001CEB075C2E8>
    <__main__.Car object at 0x000001CEB075C2E8>
    '''
    
    ''' 自定义了__str__和__repr__方法的输出结果
    a red car
    Car('red', '37281')
    '''
    
    ''' 把自定义的__str__注释后的输出结果
    Car('red', '37281')
    Car('red', '37281')
    '''
    View Code

      通常情况下,__str__的结果侧重于可读性,面向用户;而__repr__的结果侧重于无歧义,面向开发人员。

    import datetime
    
    
    today = datetime.date.today()
    print(str(today))  # 输出普通人可理解的字符串
    print(repr(today))  # 输出更专业的字符串,并且此结果可直接创建对象,恢复对象的状态(通常情况我们自定义类不用做地这么麻烦)
    
    ''' 输出结果
    2021-08-29
    datetime.date(2021, 8, 29)
    '''
    View Code

      python2中__str__返回的是字节,而__unicode__返回的是字符串(它对应内置函数unicode)。

    # --encoding=utf8--
    
    class Car(object):
        def __init__(self, color, mileage):
            self.color = color
            self.mileage = mileage
    
        def __repr__(self):
            return '{}({!r}, {!r})'.format(
                self.__class__.__name__, self.color, self.mileage)
    
        def __unicode__(self):
            return u'a {self.color} car'.format(self=self)
    
        def __str__(self):
            return unicode(self).encode('utf-8')
    
    
    car = Car('red', '37281')
    print(car)  # 按str输出
    print('{!r}'.format(car))  # 按repr输出
    
    ''' 默认的输出结果
    a red car
    Car('red', '37281')
    '''
    View Code

    4.3 自定义异常

      定义自己的异常类型能让代码清楚地表达出自己的意图,并易于调试。

      要从Python内置的Exception类或特定的异常类(如ValueError或KeyError)派生出自定义异常。

      可以使用继承来根据逻辑对异常分组,组成层次结构。

    4.4 克隆对象

      创建的浅副本不会克隆子对象,因此副本和原对象并不完全独立。

      对象的深副本将递归克隆子对象。副本完全独立于原对象,但创建深副本的速度较慢。

      使用copy模块,copy.copy(x)进行浅复制,copy.deepycopy(x)进行深复制。

      对于内置的容器,只需要使用list、dict、set这样的工厂函数就能创建浅副本,这样更据Python特色。

    4.5 用抽象基类避免继承错误

        抽象基类(ABC)能在派生类实例化时检查其是否实现了基类中某些特定的方法。

        是用ABC可以帮助避免bug并使类层次易于理解和维护。

        抽象基类在abc模块。

    代码todo

    4.6 namedtuple的优点

        namedtuple和普通元组一样是不可变容器。

        namedtuple就是具有名称的元组,可以使用标识符来访问,当然还是可以使用索引来访问的。

        依旧可以使用*来对namedtuple进行解包。

        collection.namedtuple能够方便地在Python中手动定义一个内存占用较小的不可变类。

        是用namedtuple能够按照更易于理解的结构组织数据,进而简化了代码。

        namedtuple提供了一些有用的辅助方法,虽然这些方法以单下划线开头,但实际上是公共接口的一部分,可以正常使用。

    todo代码

    4.7 类变量与实例变量的陷阱

        类变量属于类,在类的所有实例对象之间共享数据。

        实例变量是特定于每个实例的数据,属于单个对象实例。

        实例变量可以在对象实例化之后动态添加???

        实例变量能够覆盖同名的类变量,所以很容易(意外地)由于覆盖类变量而引入bug和奇怪的行为。

    4.8 实例方法、类方法和静态方法揭秘

        实例方法第一个参数self是实例对象本身,通过它可以访问实例对象的其他实例方法和实例变量。

        在实例方法中可以通过self.__class__访问类本身。

        类方法第一个参数cls是类本身,通过它可以访问其他的类方法和类变量,也可以通过cls实例化对象。

        可以利用类方法定义额外的构造函数。

         静态方法不接收self和cls参数,因此它改变不了实例对象的状态和类的状态,其作用与普通函数相同,但属于类的名称空间。

        其实,实例对象可以调用实例方法,类方法和静态方法。那应该self也可以调用吧??

    TODO 代码

  • 相关阅读:
    Codeigniter:如何写一个好的Model
    CodeIgniter
    CodeIgniter
    Codeigniter CRUD代码快速构建
    html适配Anroid手机
    使用malloc分别分配2KB,6KB的内存空间,打印指针地址
    大话spring.net之IOC
    Spring2.5学习3.3_@Autowire注解实现手动装配
    OPPO通过AWS节约大量成本提供海外服务
    mysql 父子结构排序
  • 原文地址:https://www.cnblogs.com/yarightok/p/15202917.html
Copyright © 2011-2022 走看看