python中的魔术方法

魔术方法

在Python中,所有用"__"包起来的方法,都称为【魔术方法】(eg: len, init)。
魔术方法一般是为了让显示器调用的,你自己并不需要调用它们。

01特殊属性

魔术方法名称功能
name类、函数、方法等的名字
class对象或类所属的类
module类定义所在的模块
bases当前类的基类(父类)
doc类、函数的文档帮助,没有定义为None
mroMethod Resolution Order 方法解析顺序
dict类或实例的属性,可写的字典

dir
查看属性
返回类或者对象的所有成员名称列表。dir() 函数就是调用__dir__()。
1). 如果dir([obj]) 参数obj包含方法 dir(),该方法将被调用。
2). 如果Obj 不包含 dir(),该方法将最大限度收集属性信息

在这里插入图片描述
在这里插入图片描述

02 创建,初始化与销毁

面试常问: python 中__new__ , init , __call__的区别?
1). new的功能是在生成对象之前执行的内容,接受的参数是cls 类, 负责对象的创建
2). init的功能是在对象生成之后执行的内容, 接受的参数是self 对象, 负责对象的初始化
3). call的功能是在调用对象时执行的内容, 可以模拟函数的行为.

当我们新建一个对象 x=someclass() 的时候,经历的步骤:
1). 第一: __new__先创建类并返回类的实例。
2). 第二: 自动调用__init__来初始化函数的值。
3). 汇总: 第一步和第二步共同构成了【构造函数】。
4). 第三步: 对象生命周期调用结束时,del 方法(构析函数)会被调用。
def del(self):析构方法: 当对象被删除或者从内存释放时自动执行

class Person(object):
    def __new__(cls):
        print("__new__")
        return  object.__new__(cls)

    def __init__(self):
        print("__init__")

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

    def __del__(self):
        # 析构方法: 当对象被删除或者从内存释放时自动执行
        print("__del__")
p1 = Person()
p1()

new
init
call
del

call魔术方法应用范例

应用范例一: call魔术方法实现缓存

使用lru_cache实现

from functools import lru_cache
class Fib(object):
    @lru_cache(maxsize=1000) # maxsize最大的缓存数
    def __call__(self,n):
        if n in (1,2):
            return 1
        else:
            return self(n-1)+self(n-2)
fib = Fib()
print(fib(100))

直接使用字典实现

class Factorial:
#     """实现Fib数列的第三种方式"""
    def __init__(self):
        # 缓存信息:{1:1,2:1,3:2,4:3,5:5}
        self.cache = {}
    def __call__(self,n):
        if n not in self.cache.keys():
            if n in (1,2):
                self.cache[n] = 1
            else:
                self.cache[n] = self(n-2) + self(n-1)
        return self.cache[n]
fact = Factorial()
print(fact(20))

应用范例二:call方法实现类装饰器
类装饰器:装饰器需要传递的参数通过__init__传递进入
被装饰函数执行的内容在__call__魔术方法中编写

from functools import wraps
import time
class TimeIt(object):
    def __init__(self,unit='s'):
        self.unit = unit
    def __call__(self, fun):
        @wraps(fun)
        def wrapper(*args,**kwargs):
            if self.unit == 's':
                start_time = time.time()
                result = fun(*args,**kwargs)
                end_time = time.time()
                print("%s函数运行时间为%.2f s" %(fun.__name__,end_time-start_time))
                return result
            else:
                print('当前功能不支持。。。')
        return wrapper
@TimeIt(unit='s')
def add(num1,num2):
    time.sleep(3)
    return num1+num2
add(173583497597,25494746541)

类装饰器调用的过程:

@TimeIt(unit=‘h’)
1). TimeIt_obj = TimeIt(unit=‘h’)
2). @TimeIt_obj
3). add=TimeIt_obj(add)
4). add = wrapper

普通装饰器如果需要传入参数的话,要在装饰器外边在嵌套一层wrapper1函数如下:

from functools import wraps
import time
def timeit(unit='s'):
    def wrapper1(fun):   # 当装饰器中需要传入参数时,可以在外边嵌套一层函数
        @wraps(fun)
        def wrapper(*args,**kwargs):
            if unit == 's':
                start_time = time.time()
                result = fun(*args,**kwargs)
                end_time = time.time()
                print('%s函数运行时间为%.2f s' %(fun.__name__,end_time-start_time))
                return result
            else:
                print('当前功能不支持。。。')
        return wrapper
    return wrapper1

应用案例三:call方法实现偏函数
偏函数(2.5+) partial function。通过有效地“冻结”预先确定的参数,来缓存函数参数。运行时获得剩余参数后,解冻并传递到函数中。系统内置的偏函数操作范例如下:

from functools import partial
max100 = partial(max,10,100)
max_num = max100(1,2,4)
print(max_num)  #100

应用案例四:基于call魔术方法和filter实现文件过滤器

import os
# 作为基类/父类
class FileAcceptor(object):
    def __init__(self, accepted_extensions):
        """
        eg: ['.png', '.jpg']
        :param accepted_extensions: 可以接受的扩展名
        """
        self.accepted_extensions = accepted_extensions

    def __call__(self, filename):
        """
        eg: hello.jpg
        :param filename: 需要判断的文件名
        :return:
        """
        # base = 'hello', ext='.jpg'
        base, ext = os.path.splitext(filename)
        return ext in self.accepted_extensions
# 子类
class ImageFileAcceptor(FileAcceptor):
    def __init__(self):
        image_ext = ('.jpg', '.jepg', '.png')
        super(ImageFileAcceptor, self).__init__(image_ext)
# 子类
class ExcelFileAcceptor(FileAcceptor):
    def __init__(self):
        image_ext = ('.xls', '.xlsx')
        super(ExcelFileAcceptor, self).__init__(image_ext)
if __name__ == '__main__':
    filenames = [
        'hello.jpg',
        'hello.xls',
        'hello.txt'
    ]
    """
    1). ImageFileAcceptor() 实例化对象, 执行__new__和__init__魔术方法。
    2). imagefileacceptor_obj
    3). imagefileacceptor_obj('hello.jpg')  True
    3). imagefileacceptor_obj('hello.xls')  False
    3). imagefileacceptor_obj('hello.txt')  False
    4). ['hello.jpg']

    """
    images_file = filter(ImageFileAcceptor(), filenames)
    excels_file = filter(ExcelFileAcceptor(), filenames)
    print(list(images_file))
    print(list(excels_file))

filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。python3中通过list查看

03可视化

类型判断要使用type或isinstance, 不能通过判断print输出是否带引号来判断输出值的类型。
1). str()与repr()都是python中的内置函数,是直接用来格式化字符串的函数。
2). 当使用内置函数str(obj)时, 自动执行obj.str()魔术方法。
3). 当使用内置函数repr(obj)时, 自动执行obj.repr()魔术方法。
4). 当__str__魔术方法不存在时, 自动执行__repr__()魔术方法的内容。

class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __int__(self):
        return int(self.age)
    # def __str__(self):
    #     return 'Person<%s>' %(self.name)
    def __repr__(self):
        return 'Person<%s>' %(self.name)
p1 = Person('fentiao','100')
print(p1)
print(int(p1))

04类型转换

在这里插入图片描述

05 索引与切片

拓展小知识: slice() 函数实现切片对象,主要用在切片操作函数里的参数传递。
在这里插入图片描述
在这里插入图片描述
索引&切片魔术方法:
setitem:当属性被以索引、切片方式赋值的时候会调用该方法
getitem:一般如果想使用索引、切片访问元素时,就可以在类中定义这个方法
delitem:当使用索引、切片删除属性时调用该方法
mul: 当需要重复操作时,调用该方法
add:当需要连接操作时,调用该方法
contains:当需要成员操作符做判断时,调用该方法
iter:
通常我们在使用for循环语句时,python内部其实是把for后面的对象使用了内建函数iter,iter返回的是一个迭代器,主要映射到类里面的__iter__函数。__iter__函数返回的一定要是iter类型的数据(一个实现了__next__的对象),每次for循环都要执行一次__next__方法

class Student(object):
    def __init__(self,name,scores):
        self.name = name
        self.scores = scores
    def __getitem__(self, index):
        """实现获取索引和 切片值的魔术方法"""
        print(index)
        return self.scores[index]
    def __setitem__(self, index, value):
        """实现修改/设置索引和切片值的魔术方法"""
        self.scores[index] = value
    def __delitem__(self, index):
        del self.scores[index]
    def __mul__(self, other):
        """重复操作"""
        return self.scores*other
    def __add__(self, other):
        """连接操作,传入时的对象"""
        return [ item[0]+item[1] for item in zip(self.scores,other.scores)]
    def __contains__(self, item):
       """成员操作符"""
       return item in self.scores
    def __iter__(self):
        # iter可以将可迭代对象转换成迭代器(可以调用next方法)
        return iter(self.scores)
stu1 = Student('张三',[100,90,100])
stu2 = Student('里斯',[100,80,100])
# print(stu1[1:])
# stu1[1:] = (88,66)
# print(stu1.scores)
# del stu1[1:]
# print(stu1.scores)

# 2).连接、重复、成员操作
# print(stu1*3)
# print(stu1+stu2)
# print(150 in stu1)
for item in stu1:
    print(item)

with语句安全上下文

https://blog.csdn.net/zwqjoy/article/details/91432737
面试题: with语句操作的对象必须是上下文管理器。那么,到底什么是上下文管理器呢?
1). 简单的理解,拥有 enter() 和 exit() 方法的对象就是上下文管理器。
enter(self):进入上下文管理器自动调用的方法,在 with 执行之前执行。如果 有 as子句,该方法的返回值被赋值给 as 子句后的变量;该方法可以返回多个值。
exit(self, exc_type, exc_value, exc_traceback):退出上下文管理器自动调用的方法。在with 执行之后执行(不管有无异常)。
2). 当 with as 操作上下文管理器时,就会在执行语句体之前,先执行上下文管理器的 enter() 方法,然后再执行语句体,最后执行 exit() 方法。

方法一: 基于类的上下文管理器: 只要一个类实现了 enter() 和 exit() 这 2 个方法,程序就可以使用 with as 语句来管理它

class Connect(object):
    def __init__(self,filename):
        self.filename = filename
    def __enter__(self):
        self.f = open(self.filename)
        print(self.f.read())
        return self.f
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with语句执行之后。。。。。')
        self.f.close()
# Connect就是上下文管理器。
# 拥有__enter__()和__exit__()方法的对象就是上下文管理器
with Connect('/etc/passwd') as conn:
    pass

构建上下文管理器,常见的有 2 种方式:基于类实现和基于生成器实现。
方法二: 装饰器 contextlib.contextmanager,来定义自己所需的基于生成器的上下文管理器。

# contextlib模块用于创建和使用上下文管理器的模块
import contextlib
# tempfile模块用于生成临时文件和目录
import tempfile
# shutil模块用于拷贝文件和文件夹、删除文件和文件夹、修改文件权限、时间、状态信息
import shutil
import time


@contextlib.contextmanager
def make_temp_directory():
    # tempfile.mkdtemp 创建临时目录
    temp_dir = tempfile.mkdtemp()
    # print(temp_dir) # 在/tmp/创建临时的文件
    try:
        yield temp_dir
    finally:
        # shutil.rmtree()表示递归删除文件夹下的所有字文件夹和字文件
        time.sleep(5)
        shutil.rmtree(temp_dir)
if __name__ == '__main__':
    with make_temp_directory() as dirname:
        print(dirname)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值