测试开发之Python核心笔记(20): 类内置高级方法

当我们定义了一个类之后,Python会自动为我们提供一些方法,这些方法大部分是从object类或者type类继承来的。我们可以覆盖这些方法实现特定的操作。

20.1 让对象打印出来更易读

用print()打印对象,会展示__str__()函数的内容,直接运行实例的时候,打印的对象,会展示__repr__()函数的内容。因此可以通过实现__str__()__repr__()这两方法,让对象打印出来更符合人类阅读。比如

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
​
    def __str__(self):  # print()时调用
        return 'Student object (name=%s, age=%d)' % (self.name, self.age)
​
    __repr__ = __str__  

​
print(Student("Jim", 20))  # 打印__str__函数的内容,Student object (name=Jim, age=20)

20.2 让类对象支持迭代

我们知道容器类型都支持for … in… 进行迭代循环。for语句其实做了两件事。第一件事是获得一个迭代器,即调用了__iter__()函数。第二件事是循环的过程,循环调用__next__()函数。其实,自定义的类,只要实现了这两个方法,那么类的对象也是可以被for循环迭代的。

比如斐波那契数列,用类实现:

class Fib:
    def __init__(self):
        self.a, self.b = 0, 1  # 初始化两个计数器a,bdef __iter__(self):
        return self  # 返回一个迭代对象,实例本身就是迭代对象,故返回自己def __next__(self):  # for循环时就是调用这个方法获取下一个值
        self.a, self.b = self.b, self.a + self.b  # 计算下一个值
        if self.a > 10000:  # 退出循环的条件
            raise StopIteration()
        return self.a  # 返回下一个值
​
​
for i in Fib():
    if i > 20: 
        break
    print(i)

20.3 让对象可以被调用

我们平时自定义的函数、内置函数和类都属于可调用对象,直观的感受就是可以在他们后面加上一对小括号,但凡是可以把一对括号()应用到某个对象身上,这个对象就可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable()。

callable(0)      # 函数返回 False
def add(a, b):
    return a + b
callable(add)    # 函数返回 True

如果在类中实现了 __call__ 方法,那么实例对象也将成为一个可调用对象。即可以实例后跟小括号了,调用后的结果就是__call__方法的内容。看个例子:

class Student:
    def __init__(self, name):
        self.name = name
​
    def __call__(self):
        print('My name is %s.' % self.name)
​
​
s = Student('Michael')
s()  # 实例变成了Callable的了,输出My name is Michael

这有什么实际用处呢?下面看一个例子,利用__getattr____call__,实现动态调用,动态生成url字符串。

class Chain:def __init__(self, path=''):
        self._path = path
​
    def __getattr__(self, path):
         """调用不存在的属性时,会执行这个方法,方法效果是将path用/拼接起来,返回一个实例"""
        return Chain('%s/%s' % (self._path, path))def __call__(self, path):
        """当实例被调用时,会执行这个方法,方法效果是实例里面的参数也用/拼接起来,返回一个实例"""
        return Chain('%s/%s' % (self._path, path))def __str__(self):
        return self._path
​
    __repr__ = __str__
​
​
if __name__ == '__main__':
    print(Chain().status.user.timeline.list)  # 每一个"."就是一次调用__getattr__方法
    print(Chain().users('michael').repos) # Chain().users根据__getattr__的作用会返回一个实例,加上()后回到用__call__方法

20.4 手动创建一个实例对象

__new__方法负责创建一个实例对象,在对象被创建的时候Python解释器自动调用该方法,它是一个类方法。__new__方法在返回一个实例之后,Python解释器会继续自动的调用__init__方法,对实例进行初始化。如果__new__方法不返回值,或者返回的不是实例,那么Python解释器就不会自动的去调用__init__方法。__new__方法主要是当继承一个class时(比如int, str, tuple), 给程序员提供一个自定义这些类的实例化过程的机会。还有就是实现自定义的元类metaclass。

__new__的一个典型应用是创建单例模式。

单例模式的原理,就是通过在类属性中添加一个单例判定位flag,通过这个flag判断类是否已经被实例化过了,如果类已经被实例化过了就返回实例化的对象。

class Singleton:
    # 重写父类的__new__方法,__new__是个类方法,第一个参数是cls,必须有返回值
    def __new__(cls, *args, **kwargs):  # 自定义类实例化对象的过程
        # __new__生成的对象放入cls的_instance属性中, 如果cls不存在_instance
        if not hasattr(cls, "_instance"):
            cls._instance = super().__new__(cls, *args, **kwargs)  # 调用父类__new__创建实例
        # 如果cls存在_instance,直接返回,不要生成新的对象
        return cls._instance
​
​
class MyClass(Singleton):
    pass
​
​
s1 = MyClass()
s2 = MyClass()
s3 = MyClass("s3")
s4 = MyClass("s4")
print(id(s1), id(s2), id(s3), id(s4))

继承至Singleton的类,在不重写__new__的情况下都将是单例模式。

20.5 自定义两个对象比较逻辑

当判断两个对象是否相等时,触发__eq__方法。可以在这个方法中定义两个对象相等的规则。另外还有__lt____gt__方法,用来定义两个对象大小比较的规则。例如:

class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age
​
    def __eq__(self, other):  # 定义内置方法,自定义两个对象相等的逻辑
        return self.__dict__ == other.__dict__  # 两对象空间的属性值都相等,两个对象被认为相等。def __lt__(self, other):
        return self.age < other.age
​
​
if __name__ == '__main__':
    s1 = Student("李四", 20)
    s2 = Student("李四", 20)
    print(s2 == s1)  # True
    print(s2 is s1)  # False
    s3 = Student("王五", 19)
    print(s1 > s3)  # True
  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值