Python面向对象中的双下方法

这两天看了下面向对象中的一些双下方法,虽然平时很不用双下方法,看完之后感觉如果能熟悉并且很好的运用双下方法的话,可以写出很漂亮的代码。

python-oop

0x00 __str__与__repr__

在打印一个对象的时候其实就是调用其__str__方法,由于没有重写__str__,则会调用父类的__str__方法,如果没有的话,最终调用了Object类的__str__方法。

class Foo():
    def __str__(self):
        return 'This is Class Foo'

f = Foo()
print(f) #This is Class Foo
#如果没有__str__方法的话会打印一个内存地址
# <__main__.Foo object at 0x00000227CFD33128>

__str__方法主要的作用一般是用来对类、对象进行描述;一般情况下都会返回一个字符串。其实在使用str(f)的时候就是调用了类中的__str__方法。

提到__repr__方法呢,肯定会想到内置函数repr()方法。

s = 'test'
print(repr(s))  #'test'

从输出结果上看,其可以将字符串的引号也输出。其主要作用是将对象转化为供解释器读取的形式。

class Foo():
    def __repr__(self):
        return 'This is Class Foo repr'

f = Foo()
print(repr(f))  #This is Class Foo repr

在对类或者对象调用repr()方法的时候,其就是调用了类内部的__repr__方法。

格式化输出中的应用

class Foo():
    def __str__(self):
        return 'This is Class Foo'

    def __repr__(self):
        return 'This is Class Foo repr'

f = Foo()
print('%r !!!!!  %s'%(f,f))  #This is Class Foo repr !!!!!  This is Class Foo

在使用格式化输出的时候使用%r的时候也是默认调用了__repr__方法,而使用%s的时候则是调用__str__方法。

__repr__备胎方法

准确的说__repr__是__str__的备胎方法,当需要调用__str__的时候,会在类中寻找__str__,如果没有寻找到__str__方法,则会调用__repr__方法。

class Foo():
    def __repr__(self):
        return 'This is Class Foo repr'

f = Foo()
print(str(f))  #This is Class Foo repr
print('%s'%f)  #This is Class Foo repr

上面的例子就是__repr__成为了__str__的备胎。真是没有想到在编程世界中还有备胎的存在。

0x01 __len__、__del__和__call__

在对一个对象进行长度计算的时候通常都是调用了其的__len__方法,因而实现了__len__方法才可以使用len()函数。

class Classes():
    def __init__(self,student):
        self.student = student

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

stuList = ['xzy','moe','xzymoe']
c = Classes(stuList)
print(len(c))   #3

上面__len__的作用就是统计Classes对象里的学生的人数,因而实现__len__方法即可。

class Classes():
    def __init__(self,student):
        self.student = student

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

    def __del__(self):
        print('lalalala')

stuList = ['xzy','moe','xzymoe']
c = Classes(stuList)
print(len(c))
del c   #lalalala
print(c)    #NameError: name 'c' is not defined

从输出结果上看,在使用del的时候就先调用了__del__之后就自动删除了对象,不用在__del__中写删除的动作,与__delitem__不同,__delitem__方法需要在方法内部写删除动作。

__call__方法可以让实例能够像函数一样被调用,同时不影响实例本身的生命周期,不影响一个实例的构造和解析,不过可以用来改变其内部函数。

class Foo():
    def __call__(self, *args, **kwargs):
        print('This is call func!')

Foo()() #This is call func!

这样生成的对象就可以直接加上括号就使用了!!当然__call__函数也可以在函数内部对属性进行修改操作。

0x02 item系列的函数

item系列的函数主要有三个:__getitem__、__setitem__和__delitem__,其主要作用就是可以让操作对象像操作字典一样的方便。

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

    def __getitem__(self, item):
        if hasattr(self,item):
            return self.__dict__[item]

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

    def __delitem__(self, key):
        del self.__dict__[key]

p = Person('xzymoe',20)
print(p['name'])    #xzymoe
p['country'] = 'China'
print(p.__dict__)   #{'country': 'China', 'age': 20, 'name': 'xzymoe'}
del p['age']
print(p.__dict__)   #{'country': 'China', 'name': 'xzymoe'}

这样就可以通过字典的操作方式来完成对对象属性的操作了。

0x03 __eq__和__hash__方法

在两个对象进行比较时候调用的就是__eq__方法,比如两个对象我们打算当其的name属性相同就判断为两个对象相等,那么可以通过重新__eq__方法。

内置函数中有一个hash()方法,默认情况下是对对象的内存地址进行hash的,而我们可以重写__hash__来修改hash的方法。

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

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

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

p = Person('xzymoe',20)
q = Person('xzymoe',18)
print(p == q)   #True
print(hash(p))  #-619876054969235157
print(hash(q))  #3494228422336944401
q.age = 20
print(hash(q))  #-619876054969235157

0x04 __new__方法

当创建一个对象的时候,是调用__init__方法,而在__init__方法之前,默认调用__new__方法,只是一般情况下都很不用__new__所以经常被忽略。

不过有一种设计模式——单例模式,这个就需要对__new__进行重写了。单例模式为,第一次实例化这个类时,就创建一个实例化的对象,当之后再来实例化的时候,就用第一次实例化的那个对象。

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

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

p = Person('xzymoe',20)
print(id(p))    #2348200246240
d = Person('moe',18)
print(id(d))    #2348200246240

发表评论