侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 748 篇文章
  • 累计创建 65 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

Python基础(29)之对象的一些内置钩子方法

zze
zze
2019-06-17 / 0 评论 / 0 点赞 / 766 阅读 / 11327 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

内置方法

str() & repr()

重写 __str__() 函数类似重写 Java 类中的 toString() 方法。当没有重写 __str__() 但重写了 __repr__() 方法时,__repr__() 方法会充当一个 __str__() 方法的替代方法执行。

class Person1:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return "name:{} age:{}".format(self.name, self.age)


p1 = Person1('张三', 18)
print(p1)  # name:张三 age:18


class Person2:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return "name:{} age:{}".format(self.name, self.age)

p2 = Person2('张三', 18)
print(p1)  # name:张三 age:18

del()

销毁一个对象的时候执行,类似 Java 中的析构函数。

class A:
    def __del__(self):
        print("from del")

a = A()
del a  # from del

getitem() & setitem() & delitem()

对象[] 的形式操作对象属性时会执行。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __getitem__(self, item):
        print("from __getitem__:{}".format(item))
        return self.__dict__[item]

    def __setitem__(self, key, value):
        print("from __setitem__:{} = {}".format(key, value))
        self.__dict__[key] = value

    def __delitem__(self, key):
        print("from __delitem__:{}".format(key))


p = Person('张三', 18)
name = p['name']  # from __getitem__:name
print(name)  # 张三
print(p.age)  # 18
p['age'] = 20  # from __setitem__:age = 20
print(p.age)  # 20
# 和@property.deleter相似 del时只是触发对应方法 并不是真的删除
del p['age']  # from __delitem__:age
print(p.age)  # 20

new()

创建对象,类似 Java 中的构造函数,在 __init__() 函数之前执行。

class Person:
    def __init__(self, name, age):
        print('from __init__()')
        self.name = name
        self.age = age

    def __new__(cls, *args, **kwargs):
        print('from __new__()')
        return object.__new__(cls)

p = Person('张三', 18)

# result:
# from __new__()
# from __init__()

call()

让一个类的实例成为一个 callable 对象。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __call__(self, *args, **kwargs):
        print('name:{} age:{}'.format(self.name, self.age))

p = Person('张三', 18)
print(callable(p))  # True
p()  # name:张三 age:18

len()

将一个对象传入 len() 函数实际上就是调用这个对象的 __len__() 方法。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __len__(self):
        return len(self.name)


print(len(Person('张三', 18)))  # 2

hash()

hash() 函数传入一个对象实际上就是调用这个对象的 __hash__() 方法。

class Person:
    def __init__(self, no, name, age):
        self.no = no
        self.name = name
        self.age = age

    def __hash__(self):
        return self.no


p = Person(1, '张三', 18)
print(hash(p))  # 1

eq()

使用 == 判断两个对象是否相等时,依据 __eq__() 函数返回的值。类似 Java 中的 equals() 方法。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.name == other.name


p1 = Person('张三', 19)
p2 = Person('张三', 18)
print(p1 == p2)  # True

add()

在两个对象之间使用 + 连接时会调用这个对象的 __add__() 方法。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.name == other.name

    def __add__(self, other):
        return self.age + other.age

p1 = Person('tom', 12)
p2 = Person('jerry', 18)
print(p1 + p2) # 30

enter() & exit()

当使用 with 关键字修饰对象执行一个代码块时,在执行代码块之前会调用这个对象的 __enter__() 方法,在代码块中的代码执行完后退出代码块之前会执行这个对象的 __exit__() 方法。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.name == other.name

    def __enter__(self):
        print('from __enter__')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('fron __exit__')

p = Person('tom', 12)
with p:
    print('from 代码块')

# from __enter__
# from 代码块
# fron __exit__

doc()

使用 obj.__doc__ 能够获取到 obj 所属类的注释文档信息。

class Person:
    """
    这是一段注释
    """
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person('tom', 12)
print(p.__doc__)


#     这是一段注释

dict()

使用 obj.__dict__ 能够以字典类型获取到 obj 对象中所有的字段及其值。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person('tom', 12)
print(p.__dict__,type(p.__dict__))

# {'name': 'tom', 'age': 12} <class 'dict'>

iter()

在类的内部定义 __iter__() 方法可以将该类的实例转为可迭代的对象。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __iter__(self):
        # 必须返回一个迭代器,生成器也是迭代器的一种,所以可以使用 yield
        return iter([1, 2, 3, 4])

p = Person('tom', 12)
for i in p:
    print(i)
    
# 1
# 2
# 3
# 4

补充

单例模式

class Single:
    instance = None

    def __new__(cls, *args, **kwargs):
        if cls.instance:
            return cls.instance
        cls.instance = object.__new__(cls)
        return cls.instance

o1 = Single()
o2 = Single()
print(o1)  # <__main__.Single object at 0x00000000021EDAC8>
print(o2)  # <__main__.Single object at 0x00000000021EDAC8>

扑克牌

from collections import namedtuple
from random import choice, shuffle

CardTuple = namedtuple('Card', ['suit', 'rank'])


class Card:
    def __init__(self):
        suit_list = ['红桃', '黑桃', '梅花', '方块']
        rank_list = [str(i) for i in range(2, 11)] + ['J', 'Q', 'K', 'A']
        self.card_list = [CardTuple(suit, rank) for rank in rank_list for suit in suit_list]

    def __str__(self):
        return str(self.card_list)

    def __len__(self):
        return len(self.card_list)

    def __getitem__(self, item):
        return self.card_list[item]

    def __setitem__(self, key, value):
        self.card_list[key] = value


# 一幅扑克牌
card = Card()
print(
    card)  # [Card(suit='红桃', rank='2'), Card(suit='黑桃', rank='2'), Card(suit='梅花', rank='2'), Card(suit='方块', rank='2'), Card(suit='红桃', rank='3'), Card(suit='黑桃', rank='3'), Card(suit='梅花', rank='3'), Card(suit='方块', rank='3'), Card(suit='红桃', rank='4'), Card(suit='黑桃', rank='4'), Card(suit='梅花', rank='4'), Card(suit='方块', rank='4'), Card(suit='红桃', rank='5'), Card(suit='黑桃', rank='5'), Card(suit='梅花', rank='5'), Card(suit='方块', rank='5'), Card(suit='红桃', rank='6'), Card(suit='黑桃', rank='6'), Card(suit='梅花', rank='6'), Card(suit='方块', rank='6'), Card(suit='红桃', rank='7'), Card(suit='黑桃', rank='7'), Card(suit='梅花', rank='7'), Card(suit='方块', rank='7'), Card(suit='红桃', rank='8'), Card(suit='黑桃', rank='8'), Card(suit='梅花', rank='8'), Card(suit='方块', rank='8'), Card(suit='红桃', rank='9'), Card(suit='黑桃', rank='9'), Card(suit='梅花', rank='9'), Card(suit='方块', rank='9'), Card(suit='红桃', rank='10'), Card(suit='黑桃', rank='10'), Card(suit='梅花', rank='10'), Card(suit='方块', rank='10'), Card(suit='红桃', rank='J'), Card(suit='黑桃', rank='J'), Card(suit='梅花', rank='J'), Card(suit='方块', rank='J'), Card(suit='红桃', rank='Q'), Card(suit='黑桃', rank='Q'), Card(suit='梅花', rank='Q'), Card(suit='方块', rank='Q'), Card(suit='红桃', rank='K'), Card(suit='黑桃', rank='K'), Card(suit='梅花', rank='K'), Card(suit='方块', rank='K'), Card(suit='红桃', rank='A'), Card(suit='黑桃', rank='A'), Card(suit='梅花', rank='A'), Card(suit='方块', rank='A')]
# 扑克牌张数
print(len(card))  # 52
# 取第十张
print(card[10 - 1])  # Card(suit='黑桃', rank='4')
# 随机抽取一张
print(choice(card))  # Card(suit='方块', rank='7')
# 洗牌
shuffle(card)
print(
    card)  # [Card(suit='黑桃', rank='8'), Card(suit='梅花', rank='6'), Card(suit='黑桃', rank='2'), Card(suit='红桃', rank='4'), Card(suit='梅花', rank='4'), Card(suit='红桃', rank='K'), Card(suit='方块', rank='9'), Card(suit='梅花', rank='7'), Card(suit='梅花', rank='9'), Card(suit='方块', rank='4'), Card(suit='红桃', rank='7'), Card(suit='黑桃', rank='J'), Card(suit='红桃', rank='8'), Card(suit='梅花', rank='K'), Card(suit='红桃', rank='J'), Card(suit='黑桃', rank='6'), Card(suit='红桃', rank='A'), Card(suit='红桃', rank='10'), Card(suit='梅花', rank='5'), Card(suit='方块', rank='6'), Card(suit='方块', rank='10'), Card(suit='方块', rank='8'), Card(suit='方块', rank='7'), Card(suit='黑桃', rank='Q'), Card(suit='方块', rank='A'), Card(suit='红桃', rank='6'), Card(suit='梅花', rank='8'), Card(suit='梅花', rank='J'), Card(suit='梅花', rank='3'), Card(suit='方块', rank='J'), Card(suit='方块', rank='5'), Card(suit='梅花', rank='2'), Card(suit='黑桃', rank='4'), Card(suit='梅花', rank='A'), Card(suit='黑桃', rank='3'), Card(suit='黑桃', rank='5'), Card(suit='方块', rank='K'), Card(suit='红桃', rank='Q'), Card(suit='方块', rank='3'), Card(suit='方块', rank='2'), Card(suit='黑桃', rank='A'), Card(suit='黑桃', rank='7'), Card(suit='方块', rank='Q'), Card(suit='黑桃', rank='9'), Card(suit='红桃', rank='2'), Card(suit='红桃', rank='9'), Card(suit='黑桃', rank='10'), Card(suit='梅花', rank='10'), Card(suit='红桃', rank='3'), Card(suit='红桃', rank='5'), Card(suit='黑桃', rank='K'), Card(suit='梅花', rank='Q')]

对象去重

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age


p1 = Person('张三', 18)
p2 = Person('张三', 18)
print(set([p1, p2]))  # {<__main__.Person object at 0x000000000273DBA8>, <__main__.Person object at 0x000000000273DAC8>}


class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __eq__(self, other):
        return self.name == other.name and self.age == other.age

    def __hash__(self):
        return hash(self.name + str(self.age))


p1 = Person('张三', 18)
p2 = Person('张三', 18)
print(set([p1, p2]))  # {<__main__.Person object at 0x0000000002702860>}

使用 set() 给对象的去重是同时依赖对象的 __hash__()__eq__() 函数的。

0

评论区