经验拾忆纯手工-Python黑魔法

48次阅读

共计 2798 个字符,预计需要花费 7 分钟才能阅读完成。

类的继承

 类继承有三种调用方式,其实是 有区别 的,听我慢慢道来
class A:
    def say(self, name):
        print(f'Im {name}')
class B(A):
    def say(self, name):
    # 第一种:父类. 方法 (self, 参数) 直接调用
        A.say(self, name)    
        
    def say(self, name):
    # 第二种:super(). 方法 ( 参数)    直接调用
    # 在谁的类下调用 super,就找此类对应 mro() 的下一个, 就是要继承的
         super().say(name)
         
    def say(self, name):
    # 第三种:super(B, self). 方法 (参数)
    # 找类名 对应的 mro() 的下一个,就是 继承的,一般写本身的类名
        super(B, self).say(name)

B().say('Tom')

上下文管理器

"""上下文管理器可以用两种方式实现:"""
     方式 1:通过类来实现
        主要实现两种协议
            1. __enter__(self)
            2. __exit__(self, *args, **kwargs)
                
        class A():
            def __init__(self, name):
                self.name = name
            def __enter__(self):
                print('进入')
                return self
            def __exit__(self, *args, **kwargs):
                print('退出')
                return True
        
        with A('Tom') as a:
            print(a.name)

    方式 2:通过函数来实现
        from contextlib import contextmanager
        @contextmanager
        def f():
            print('开始')    # yield 之前 对应 with f()
            yield '中间'     # yield 的值 就是    as 之后的值
            print('结束')    # yield 之后 对应 print(str1) 这个语句体
        
        with f() as str1:
            print(str1)
        ------------------Output----------------------
        开始
        中间
        结束 

属性描述符 -property-setter

class A:
@property
def name(self):
    return '123'
@name.setter
def name(self, value):
    self.age=value

a = A()
print(a.name)
a.name = '456'
print(a.age)


__init__()

 实例化对象时自动调用,这里先卖个关子,见下面 __new__()

__call__()

"""对象当做函数执行的时候会自动调用 __call__()"""
class A():
    pass
a = A()    # 此处自动调用了 __init__()
a()        # 此处自动调用了 __call__()

__str__()

"""对对象进行 print 操作的时候 会自动调用 __str__()"""
class A:
    def __str__(self):
        return '5'
a = A()
print(a)  # 此处自动调用了 __str__()

__new__()

"""
    上面说过 __init__() 是实例化对象的时候自动调用,在它之前还隐式调用了 __new__()
    __new__返回的是什么,对象就是什么
"""
In [2]: class A:
   ...:   def __new__(self):
   ...:     print('__new__')    # 初始化对象只调用 __new__ 而不调用 __init__
   ...:     return 1
   ...:   def __init__(self):
   ...:     print(2)
   ...: print(A())
    __new__
    1

__setattr__() 和 __getattr__() 和 __delattr__()

"""
    __setattr__():= 号 属性赋值 会自动调用此方法 
    __getattr__():. 号 属性取值 会自动调用此方法    # 注:找不到属性才会调用此方法
    __delattr__():del 属性删除 会自动调用此方法
"""
class A:

    def __init__(self, name):
        self.name = name        # 赋值操作就会调用 __setattr__()
    
    def __setattr__(self, name, value):
        print(f'{name}:{value}')
    def __getattr__(self, name):
        print(name)
    def __delattr__(self,name):
        print('del 了')
        
a = A('Jack')    # 调用了 __init__
a.name = 'Tom'   # 赋值操作再次调用 __setattr__()
a.name           # 取值操作调用 __getattr__()
---------------------output---------------------
name:Jack
name:Tom
name
del 了 

__getattribute__()

"""和 __getattr__() 一样,只不过 __getattribute__最先调用,并拦截了 __getattr__()"""
class A:
    def __init__(self):
        self.name = 1
    def __getattr__(self,x,*args, **kwargs):
        print(456)
    def __getattribute__(self, x):
        print(123)

a = A()
a.aaaaaa
-----------output---------------
123

__getitem__()

"""对对象进行 切片、索引、遍历 等 会自动调用此方法"""
class A:
def __getitem__(self,x,*args, **kwargs):
    return x

a = A()
触发方式 1:如果直接索引此对象,那么索引值就会传递到上面 x 当作参数
    print(a[5])
    >> 5
触发方式 2:如果直接切片此对象,那么 slice 对象 就会传递到上面 x 当作参数
    print(a[1:5])
    >> slice(1, 5, None)
触发方式 3:如果 for 循环迭代此对象,那么 上面的 x 每次将会被赋予从零开始 自增 1 的自然整数
    for x in a:
        print(x)
    >> 0,1,2,3,4.................... 

__init_subclass__()

"""被继承的类 会自动调用__init_subclass__"""
class A:
    def __init_subclass__(self):
        print('我被继承了')

class B(A):
    pass

__base__()

"""查看基类"""
class A:
    pass
class B(A):
    pass
print(B.__base__)
-----------output---------------
<class '__main__.A'>

__contains__()

"""xx in xx 就会自动调用  __contains__()"""

正文完
 0