python基础——超类&反射&装饰器&生成器


一、超类

1.1 什么时候用到超类?
如果子类需要复用父类的代码(属性、代码)时,需要通过超类实现

class A:
    class_name = "A"  # 类的属性

    def __init__(self, name, age):
        self.name = name  # 实例的属性
        self.age = age  # 实例的属性

    def show_me(self):
        print(f"Hello,我的name是 {self.name}")
        print(f"Hello,我的age是 {self.age}")


a = A("austin", 18)
a.show_me()

# 类A 进行【扩展】:增加一个 国家 属性
class B(A):  # 继承实现扩展
    class_name = "B"
    def __init__(self, country, *args, **kwargs):
        self.country = country
        super().__init__(*args, **kwargs)  # 通过超类,实现对父类代码复用

b= B(country='China', name="sunny", age=18)
b.show_me()

 

  • super 不是代表父类;
  • super 是一个内置函数,返回了超类;
  • 沿着继承关系,从祖上一系列类中,寻找成员;
class C(B):
    class_name = "C"
    def show_class_name(self):
        print("自己class_name属性", self.class_name)
        print("继承来的class_name属性", super().class_name) # 超类的class_name
        # print("继承来的class_name属性", super(B,self).class_name)

c= C(country='China', name="sunny", age=18)
c.show_class_name()

>>>

自己class_name属性 C
继承来的class_name属性 B 

1.2 super 可以接收参数:

  • 从哪个类的祖先中找成员
  • 传递实例对象
class C(B):
    class_name = "C"
    def show_class_name(self):
        print("自己class_name属性", self.class_name)
        # print("继承来的class_name属性", super().class_name) # 超类的class_name
        print("继承来的class_name属性", super(B,self).class_name)

c= C(country='China', name="sunny", age=18)
c.show_class_name()

>>>

自己class_name属性 C
继承来的class_name属性 A

1.3 类继承关系

print(C.__mro__)

>>>
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)

二、反射

反射:允许使用变量的值(而不是变量的名),对成员进行访问
 
1. 设置属性

setattr(A, attr_name, "B") #设置属性

2.读取属性

print(getattr(A, attr_name)) # 读取属性

3.删除属性

delattr(A,attr_name)  #删除属性

4. 判断属性

f hasattr(A,attr_name):   #属性是否存在

举例:

class A:
    class_name='A' #类属性
    age=18

attr_name="class_name"  
# attr_name="age"
print(getattr(A,attr_name))    #通过变量值访问属性

setattr(A,attr_name,'B')  #通过变量值设置属性
print(getattr(A,attr_name))   #获取属性值
delattr(A,attr_name)  #删除属性


if hasattr(A,attr_name):   #属性是否存在
    print(A.class_name)
else:
    print(f"属性:{attr_name},不存在")

三、装饰器

3.1 装饰器的原理

  • 是一个函数,参数是函数,返回值是函数
from datetime import datetime
def logs(func): # 装饰器 def f(): print(datetime.now(), func.__name__, "开始调用") func() print(datetime.now(), func.__name__, "调用结束") return f @logs # 装饰 def add(): # 被装饰函数 print("add is calling") add()

>>>

2022-08-16 23:22:43.221348 add 开始调用
add is calling
2022-08-16 23:22:43.221348 add 调用结束

规则的原因(装饰器的装饰过程)

@logs # 装饰
def add(): # 被装饰函数
    print("add is calling")

等同于

def add():  # 被装饰函数
    print("add is calling")

# 装饰的过程,被装饰函数作为参数,传递给装饰器,并且将返回值覆盖原函数
add = logs(add)  

 

3.2 被装饰函数有参数

装饰器的返回值,接收参数,并传递给【被装饰函数】

from datetime import datetime

def logs(func):  # 装饰器
    def f(*args, **kwargs):
        print(datetime.now(), func.__name__, "开始调用")
        func(*args, **kwargs)
        print(datetime.now(), func.__name__, "调用结束")

    return f

@logs
def add(x, y):  # 被装饰函数
    print("add is calling:", f"{x=}, {y=}")

add(x=2, y=2)

 3.3 装饰器怎么接收自己的参数

  创建一个函数来接收参数,然后返回原来的装饰器

from datetime import datetime

def logs(level):
    def _logs(func):  # 装饰器
        def f(*args, **kwargs):
            print(level,datetime.now(), func.__name__, "开始调用")
            func(*args, **kwargs)
            print(level,datetime.now(), func.__name__, "调用结束")

        return f
    return _logs

@logs(level="debug")
def add(x, y):  # 被装饰函数
    print("add is calling:", f"{x=}, {y=}")

add(x=2, y=2)
@logs(level="debug")
def add(x, y):  # 被装饰函数
    print("add is calling:", f"{x=}, {y=}")

 

 等同于

def add(x, y):  # 被装饰函数
    print("add is calling:", f"{x=}, {y=}")
    
add = logs(level="debug")(add)

 四 生成器

如果函数中有yield关键字,其调用结果,则返回一个生成器
生成器是一个可迭代对象,可以被for循环遍历使用

在遍历时才执行,并计算返回值

def add(a, b):
    c = a + b
    print(c)
    yield c

c = add(1, 2) 
print(c) # c是生成器

for i in c: # 生成器:在使用数据时,才产生数据
  print(f"{i=}")

>>>

3
i=3

 

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/280994.html

(0)
上一篇 2022年8月17日
下一篇 2022年8月17日

相关推荐

发表回复

登录后才能评论