2021.09.05 - Python重难点总结

2021/9/5 22:08:24

本文主要是介绍2021.09.05 - Python重难点总结,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

  • 多重继承
    • 顺序问题&同名方法
  • 类的魔法方法(`class.__fun__()`)
  • 详解装饰器
    • 函数装饰器
      • 无参数
      • 有参数
    • 类装饰器

多重继承

  • 基本概念:多重继承-廖雪峰

顺序问题&同名方法

问题:如果不同的父类中存在 同名的方法,子类对象在调用方法时,会调用哪一个父类中的方法呢?

  • Python 中的 MRO (方法搜索顺序)

    • Python 中针对 类 提供了一个内置属性 mro 可以查看方法搜索顺序
    • MRO 是 method resolution order,主要用于在多继承时判断 方法、属性 的调用 路径
    • print(C.__mro__) #C是多继承后的类名
    • 参考:Python多继承与super使用详解
  • 子类从多个父类派生,而子类又没有自己的构造函数时:

    • 按顺序继承,哪个父类在最前面且它又有自己的构造函数,就继承它的构造函数;
    • 如果最前面第一个父类没有构造函数,则继承第2个的构造函数,第2个没有的话,再往后找,以此类推。
  • super()与调用父类方法:

    • super().__init__相对于类名.init,在单继承上用法基本无差;但在多继承上,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次。
    • 对于多重继承,如果有多个构造函数需要调用, 我们必须用传统的方法:父类.__init__(self)

类的魔法方法(class.__fun__())

这归功于动态语言的“鸭子类型”,不需要强制继承某个接口。

  • 初始化/实例化:__init__
  • len():__len__
  • with: __enter____exit__
  • 限制示例属性:__slots__:定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
  • str() / print():__str__
  • 调试时:__repr__
  • 返回一个迭代对象,for...in__iter__
  • next()拿到生成器下一个值:__next__
  • 列表按下标访问 或 字典按键访问 a[1]__getitem__
  • 把对象视作list或dict来对集合赋值:__setitem__
  • 删除元素del xxx__delitem__
  • getattr()__getattr__
    • 只有在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找。
    • 实现链式调用
  • 调用:__call__
    • 当我们调用实例方法时,不用instance.method()来调用,直接在实例本身上调用。
    • 通过callable():判断一个对象是否是“可调用”对象。
class Student(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        print('My name is %s.' % self.name)

>>> s = Student('Michael')
>>> s() # self参数不要传入
My name is Michael.
  • 参考:定制类-廖雪峰

详解装饰器

  • 本质:装饰器实际上就是一个函数,因为:
    • 参数是一个函数
    • 返回值也是一个函数

函数装饰器

无参数

from functools import wraps

def my_log(fun):
	@wraps(func)
	def wrapper(self, *args, **kwargs):
		print('hello world')
		print(self)  # 获取原函数的实例,从而调用对应实例的一些方法
		return func(*args, **kwargs)  # 原函数可能有返回值
	return wrapper

@my_log		# 等同于 run = my_log(run),即 run = wrapper。
def run():
	print('run')

@my_log
def add(a, b):
	print(u'结果是:%s' % (a+b))

run()
# run.__name__代表的是 run这个函数的名称
print(run.__name__)

add(1, 2)

有参数

# 有参数
def my_log(param):
	def decorator(fun):
		@wraps(func)
		def wrapper(self, *args, **kwargs):
			print(param)
			print('hello world')
			print(self)  # 获取原函数的实例,从而调用对应实例的一些方法
			return func(*args, **kwargs)  # 原函数可能有返回值
		return wrapper
	return decorator

@my_log("参数")  # 等同于 add = decorator,也就是 add = decorator(add),即 add = wrapper?????????
def add(a, b):
	print(u'结果是:%s' % (a+b))

add(1, 2)
  • 装饰器的使用是:@符号,放在函数之前。
  • *args, **kwargs:位置传参 与 关键字传参 组合起来即可表示任何参数。解决传参时参数不确定的问题。
  • @wraps(func) 保证了函数相关的__name__ 等私有属性不丢失。
  • 通过self获取原函数的实例,从而调用对应实例的一些方法

类装饰器

class logit(object):
    def __init__(self, logfile='out.log'):
        self.logfile = logfile
 
    def __call__(self, func):
        @wraps(func)
        def wrapped_function(self_func, *args, **kwargs):
            print("装饰器!!!")
            print(self_func)  # 获取原函数的实例,从而调用对应实例的一些方法
            self.notify()  # 类的方法
            return func(*args, **kwargs)
        return wrapped_function
 
    def notify(self):
        # logit只打日志,不做别的
        pass
        
@logit()  # 可以传参
def myfunc1():
    pass


这篇关于2021.09.05 - Python重难点总结的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程