python基础 -33- 面向对象(类的双下线方法和单例,len,hash,eq,item,str,repr,del,new,call)

len方法
class Person:

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

    def __len__(self):
        return 5
    
    
person = Person("小贵", 25)
print(len(person))

 输出

5

hash方法
class Person:

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

    def __len__(self):
        return 5

    def __hash__(self):
        return 55555
    
person = Person("小贵", 25)

print("-----len-----")
print(len(person))

print("-----hash-----")
print(hash(person))

 输出

-----len-----
5
-----hash-----
55555

eq方法
class Person:

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

    def __len__(self):
        return 5

    def __hash__(self):
        return 55555

    def __eq__(self, other):
        return True
    
    
person = Person("小贵", 25)

print("-----len-----")
print(len(person))

print("-----hash-----")
print(hash(person))

print("-----eq-----")
print(person.__eq__("你好"))

 输出

-----len-----
5
-----hash-----
55555
-----eq-----
True

item系列

可以把一个对象变成dict, 可以像dict一样增删改查

class Person:

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


    names = {"name": "小龟龟"}
    
    def __getitem__(self, item):
        return Person.names[item]

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

    def __delitem__(self, key):
        Person.names.pop(key)
        

person = Person("小贵", 25)

print("-----getitem-----")
print(person["name"])

print("-----setitem-----")
person["age"] = 20
print(Person.names)

print("-----delitem-----")
del person["age"]
print(Person.names)

 输出

-----getitem-----
小龟龟
-----setitem-----
{'name': '小龟龟', 'age': 20}
-----delitem-----
{'name': '小龟龟'}

str & repr
class Person:

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

    def __repr__(self):
        return "Person %s %s" % (self.name, self.age)

    def __str__(self):
        return "%s %s" % (self.name, self.age)


person = Person("小贵", 25)

# repr&str
print("-----repr&str-----")
'''
str函数或者print函数调用时--->obj.__str__()
repr或者交互式解释器中调用时--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
'''
print(repr(person), person.__repr__())
print(str(person), person.__str__(), person)

 输出

Person 小贵 25 Person 小贵 25
小贵 25 小贵 25 小贵 25

del 析构方法

 析构方法,当对象在内存中被释放时,自动触发执行。

 注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class Person:

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

    def __repr__(self):
        return "Person %s %s" % (self.name, self.age)

    def __str__(self):
        return "%s %s" % (self.name, self.age)

    def __del__(self):
        print("销毁对象(析构)...")
        
        
        
        
person = Person("小贵", 25)

# repr&str
print("-----repr&str-----")
print(repr(person), person.__repr__())
print(str(person), person.__str__(), person)



print("-----del(析构)-----")
# 析构方法
del person

 输出

-----repr&str-----
Person 小贵 25 Person 小贵 25
小贵 25 小贵 25 小贵 25
-----del(析构)-----
销毁对象(析构)...

new方法
使用

 我们知道实例化init会自动执行, 其实在init方法之前,还有一个new方法也会自动执行,你可以在new里执行一些实例化前的定制动作

class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age
        print("init")

    def __new__(cls, *args, **kwargs):
        print(cls, args, kwargs)


person = Person("小贵", 15)

 输出

<class '__main__.Person'> ('小贵', 15) {}

为什么init没有执行?

因为init方法是由new方法调用的,我们重写了new方法,此时并没有执行init方法

class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age
        print("init")

    def __new__(cls, *args, **kwargs):
        print(cls, args, kwargs)
        return super().__new__(cls)


person = Person("小贵", 15)

 输出

<class '__main__.Person'> ('小贵', 15) {}
init

new方法实现单例模式

 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。**通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,**从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

什么情况下用单例?

 对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要

 如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。

class Person:

    instance = None

    def __init__(self, name, age):
        self.name = name
        self.age = age
        print("init")



    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
             instance = super().__new__(cls)
             cls.instance = instance
        return cls.instance



person1 = Person("小贵", 15)
person2 = Person("小贵", 15)
person3 = Person("小贵", 15)
person4 = Person("小贵", 15)
print(id(person1))
print(id(person2))
print(id(person3))
print(id(person4))

 输出

init
init
init
init
1260870865056
1260870865056
1260870865056
1260870865056

call方法

 对象后面加括号,触发执行。

 注:构造方法new的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class School:

    def __init__(self, name):
        self.name = name

    def __call__(self, *args, **kwargs):
        print(self, args, kwargs)

school = School("呼呼呼")
school("好学校", flag="世界一流")

 输出

<__main__.School object at 0x0000029FB38A8460> ('好学校',) {'flag': '世界一流'}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值