FreezeJ' Blog

python特殊方法

2019-04-28

Python 特殊方法

以双下划线开头和结尾的方法称为特殊方法,__xxxx__。

在定义类对象时,经常会重写一个或多个特殊方法,例如__init__。通常特殊方法都是自动调用的。


__dict__ 获取对象信息

# __dict__  查看对象信息
class Animal(object):
    def __init__(self):
        self.name = 'Animal'
    def eat(self):
        print('eat')
animal = Animal()
print(Animal.__dict__)
'''
结果:
{
    '__module__': '__main__',
    '__init__': <function Animal.__init__ at 0x000001CE58A28D90>, 
    'eat': <function Animal.eat at 0x000001CE58A28E18>, 
    '__dict__': <attribute '__dict__' of 'Animal' objects>, 
    '__weakref__': <attribute '__weakref__' of 'Animal' objects>,
    '__doc__': None
}
'''
print(animal.__dict__)
# {'name': 'Animal'}

__len__ 获取实例对象长度

# __len__ 返回对象长度
class Animal(object):
    def __init__(self, name):
        self.name = name
    def __len__(self):
        return len(self.name)

dog = Animal('dog')
elephant = Animal('elephant')
print(len(dog))  # 3
print(len(elephant))  # 8

__iter__ 和 __next__ 使实例对象可迭代

# __iter__ 和 __next__ 使实例对象可迭代
class Student(object):
    def __init__(self):
        self.book = ['Math','English','Chinese','Physical']
    def __iter__(self):
        self.count = 0
        self.book_list_len = len(self.book)
        return self  # 通常返回的是self
    def __next__(self):
        if self.count < self.book_list_len:
            book_name = self.book[self.count]
            self.count += 1
            return book_name
        else:
            raise StopIteration  # 停止迭代
xiaoming = Student()
for i in xiaoming:
    print(i)

__add__ 运算符重载

算术运算符可以用于自定义类对象的实例对象,必须在自定义类对象中实现标准算术运算符对应的以下特殊方法:

  1. +对应的特殊方法是__add__()和__radd__();
  2. -对应的特殊方法是__sub__()和__rsub__();
  3. *对应的特殊方法是__mul__()和__rmul__();
  4. /对应的特殊方法是__truediv__()和__rtruediv__();
  5. //对应的特殊方法是__floordiv__()和__rfloordiv__()
# 实例对象实现加法
class Myclass(object):
    def __init__(self, data):
        self.data = data
    def __add__(self, other):  # other指的是加号右边的对象
        return self.data + other.data
a = Myclass(10)
b = Myclass(20)
print(a + b)

__str__和__repr__ 输出字符

# __str__ 和 __repr__
class Myclass(object):
    def __init__(self, data):
        self.data = data
    def __str__(self):
        return self.data
    def __repr__(self):
        return self.data

a = Myclass('123')
print(a)  # 123
print(str(a))  # 123
print(repr(a))  # 123

str()和repr()都返回对象字符串,其区别在于:

  1. str()是给用户看的,显示更加友好。
  2. repr()是给程序开发者看的,为调试服务的。
>>> str('Hello!\nWorld')
'Hello!\nWorld'
>>> print(str('Hello!\nWorld'))
Hello!
World

>>> repr('Hello!\nWorld')
"'Hello!\\nWorld'"
>>> print(repr('Hello!\nWorld'))
'Hello!\nWorld'

__new__ 创建实例方法

当使用“类名(实参)”创建实例对象时,python解析器的主要处理过程包括:

  1. 调用特殊方法__new__()创建实例对象。
  2. 调用特殊方法__init__()对创建的实例对象进行初始化。

__init__中接收的self其实就是__new__中返回的对象。

# __new__ 创建实例调用方法
class Animal(object):
    def __new__(cls, *args, **kwargs):
        new_object = object.__new__(cls)
        print('New object id is %s' % id(new_object))
        return new_object
    def __init__(self, name):
        print('Init object id is %s' % id(self))

dog = Animal('123')

'''
结果:
New object id is 2650305182240
Init object id is 2650305182240
'''

__del__ 对象删除方法

可以定义__del__来执行当对象被删除时所需的操作。

# __del__ 删除方法
import time
class Animal(object):
    def __init__(self, name):
        self.name = name
    def __del__(self):
        print('%s对象被删除!' % self.name)

dog = Animal('dog')
print(dog.name)
print('dog对象会在3秒后被删除')
time.sleep(3)  # 程序结束,必定会删除对象

==当引用计数器为0时,对象不会立即被销毁(垃圾回收),所以__del__执行的时间也是不确定的。==


__getattr__ 获取对象属性或方法

# __getattr__
class Animal(object):
    def __init__(self, name):
        self.name = name
    def __getattr__(self, item):
        if item == 'name':
            return self.name
        elif item == 'say_name':
            return self.say_hi
        else:
            raise AttributeError('No attribute "%s"' % item)
    def say_hi(self, value):
        print('Hi %s!' % value)

dog = Animal('dog')
print(dog.name)  # dog
dog.say_hi('cat')  # Hi cat!
print(dog.age)  # AttributeError: No attribute "age"

__getitem__、__setitem__、__deltitem__ 索引设置

使实例对象实现像列表或者字典索引操作的三个方法。

# __getitem__、__setitem__、__delitem__
class Animal(object):
    def __init__(self):
        self.data = {}
    def __getitem__(self, item):
        return self.data.get(item)
    def __setitem__(self, key, value):
        self.data[key] = value
    def __delitem__(self, key):
        del self.data[key]
dog = Animal()
dog['name'] = 'dog'
print(dog['name'])
del dog['name']
print(dog['name'])

__call__ 函数调用

使实例对象可以像函数一样被调用。

# __call__
class Animal(object):
    def __call__(self, *args, **kwargs):
        print(args)
        print(kwargs)
dog = Animal()
dog(18, 'yellow', name='dog')
print(callable(dog))

'''
结果:
(18, 'yellow')
{'name': 'dog'}
True
'''

==可以通过函数callable()来判断对象是否可以被调用。==


__doc__ 文档字符串

与函数的文档字符串类似,类对象的第一行字符串表示文档字符串。它是对类对象的功能的简要描述。

# __call__
class Animal(object):
    '''这是一个动物类'''
    pass
dog = Animal()
print(Animal.__doc__)
print(dog.__doc__)

'''
结果:
这是一个动物类
这是一个动物类
'''

__slots__ 限制实例对象属性或方法

# __slots__
class Animal(object):
    def __init__(self):
        self.name = 'animal'
    __slots__ = ('age', 'eat', 'name')

dog = Animal()
print(dog.name)  # animal
dog.age = 3
def eat(self):
    print('%s eat!' % self.name)
Animal.eat = eat
dog.eat()  # animal eat!
Animal.color = 'withe'  # 对于类对象没有影响
dog.color = 'withe'  # AttributeError: 'Animal' object has no attribute 'color'

__slots__对于子类的实例对象是不生效的,如果子类也有__slots__,那么子类的对象可用实例属性或方法则为父类__slots__加子类__slots__。

Tags: Python