zoukankan      html  css  js  c++  java
  • 【python第八日】类

    类、对象、实例

    类:具有相同特征的一类事物(人、狗、老虎)

    对象/实例:具体的某一个事物(隔壁阿花、楼下旺财)

    实例化:类——>对象的过程

    class Person:   #定义一个人类
      “”“类的文档”“” role
    = 'person' #人的角色属性都是人 数据属性 def walk(self): #人都可以走路,也就是有一个走路方法 方法属性 print("person is walking...")

    看属性用Person.__dict__

    新式类与经典类:

    在Python 2及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获得所有“新式类”的特性;反之,即不由任意内置类型派生出的类,则称之为“经典类”。

    “新式类”和“经典类”的区分在Python 3之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”。

    类初始化

    data1 = "外部数据"
    class A:
        data1 = "内部数据"
    
        def __init__(self, name):
            print("这里是初始化方法:", self)
            print("内部数据为:", self.data1)     #加上self表示内部数据
            print("外部数据为:", data1)         #不加self表示外部数据
            self.name = name
            return None                          #一般不谢,但是如果要返回,只可以返回None类型
    
        def __new__(cls, *args, **kwargs):
            print("这里是类构造方法:", cls)
            print("参数为:", *args, **kwargs)
            return object.__new__(cls)
    
    b = A("爸爸")
    • 用类内部数据时候,用self.xxxx,否则指的是外部数据
    • 构造方法和初始化方法分开了

    类方法、静态方法、实例方法、普通方法、抽象方法、属性

    类方法、静态方法、实例方法、普通方法

    class Chinese:
    
        def  c1(self):             #实例方法,只可以被实例调用,类一般不可以调用,除非给一个参数
            print("c1",self)
    
        @classmethod
        def c2(cls):             #类方法。实例和类都可以调用,参数,是调用者的类
            print("c2:",cls)
    
        @staticmethod
        def c3():                #静态方法,类和实例都可以调用
            print("c3:")
    
        def c4():                #类普通方法,只可以被类调用
            print("c4")
    Chinese.c4()      #c4
    Chinese.c3()      #c3:
    Chinese.c2()      #c2: <class '__main__.Chinese'>
    # Chinese.c1()   #需要个东西,所以这个处所
    Chinese.c1("test")   #c1 test
    
    
    a = Chinese()
    a.c1()      #c1 <__main__.Chinese object at 0x00FA10B0>   是对象
    a.c2()      # c2: <class '__main__.Chinese'>   传的是类,不是实例
    a.c3()      #c3:
    # a.c4()   #c4不需要东西所以不能用

    抽象方法与接口

    抽象方法必须在子类中实现,本身基类不可实例化

    import abc
    class A(metaclass = abc.ABCMeta):
        @abc.abstractmethod
        def a1(self):
            print("这里是a1",self)
        def a2(self):
            print("这里是a2",self)
    
    # a = A()         #不可以实例化
    # a.a1()
    # a.a2()
    class A_1(A):
        def a1(self):
            print("这里是是A_1的a1",self)
    
    b = A_1()
    b.a1()
    b.a2()
    输出如下:

    这里是是A_1的a1 <__main__.A_1 object at 0x009A5370>
    这里是a2 <__main__.A_1 object at 0x009A5370>

     

    数据属性和函数属性

    b_data_new = "外部数据区"
    class B():
        b_data = "B的数据区"
        def b(self):
            print("这里是b的活动区,b_data的值为",b_data)
    
    class child_B(B):
        pass
    
    b_instance = B()
    b_child_instance = child_B()
    print(B.__dict__)
    print(child_B.__dict__)
    print(b_instance.__dict__)
    print(b_child_instance.__dict__)
    b_instance.b_data = "这里是实例的数据区"
    child_B.b_data = "这里B儿子的类数据区"
    print(B.__dict__)
    print(child_B.__dict__)
    print(b_instance.__dict__)
    print(b_child_instance.__dict__)
    print(b.b_data_new)   #报错

    • 类只查找自己的数据区,B.XXXXX,如果没有就报错,但是如果前面没有B.表示的外部数据,或者局部变量
    • 实例先查找自己的数据区,如果没有查找B的,再没有报错
    • 儿子类,同上 

    属性的增删改查

    class A:
    data1 = "吃饭"
    list1 = [1,2]
    def a(self):
    print("这是A的a的方法")

    #查看属性
    print(A.__dict__) #{'__module__': '__main__', 'data1': '吃饭', 'list1': [1, 2], 'a': <function A.a at 0x00AB8DF8>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
    print(A.data1, A.a) #吃饭 <function A.a at 0x00AB8DF8>

    #增加
    A.data2 = "游泳" #添加数据

    def a1():
    print("这是外部a1函数:", A.data1) #这是外部a1函数: 吃饭 不能直接用哪个data1 否则是外面的数据
    A.a1 = a1 #添加方法
    A.a1()

    A.a2 = lambda x,y:x+y #添加方法
    print(A.a2(1,2)) #3

    #改同添加
    #删除
    del A.data2

    p = A()
    p.data4 = "4"
    p.data1 = "1"
    print(p.__dict__) # {'data4': '4', 'data1': '1'}
    p.list1.append(3)
    print(p.__dict__) #{'data4': '4', 'data1': '1'}
    print(A.__dict__) #'__module__': '__main__', 'data1': '吃饭', 'list1': [1, 2, 3]
    • 实例修改数据时候,如果是直接赋值,则在实例字典中修改属性
    • 如果是使用append,extend修改数据时候,是修改原有数据,即类中的数据

     组合

    组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合。

    class Weapon:
        def prick(self,obj):  # 这是该装备的主动技能,扎死对方
            obj -= 500  # 假设攻击力是500
            print(obj)
    
    
    class Person:  # 定义一个人类
        role = 'person'  # 人的角色属性都是人
    
        def __init__(self, name):
            self.name = name  # 每一个角色都有自己的昵称;
            self.weapon = Weapon()  # 给角色绑定一个武器;
    
    
    egg = Person('egon')
    obj = 1000
    egg.weapon.prick(obj)

    继承 多态 封装  派生 接口  反射

    继承 派生

    继承:指的是父亲遗传给儿子,类没变,比如上一辈,下一辈

    派生:指的是出现新的类,比如动物变成狗

    父类:子类的基类,用__base__查看,或者超类

    继承顺序 C3算法

    通用计算公式为:

    mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] ) (其中Child继承自Base1, Base2)

      • 表头: 
        列表的第一个元素

      • 表尾: 
        列表中表头以外的元素集合(可以为空)

      • 示例 
        列表:[A, B, C] 
        表头是A,表尾是B和C

    这里写图片描述

    • 1、先拿出第一个合并序列的表头,看是否在后面的表尾巴,如果在后面的队列,进入2,否则进入3
    • 2、如果是在后面的表尾巴,如果当前序列是最后一个序列,报错,否则,进入下一个队列,重新1
    • 3、如果不在后面的队尾序列,则把当前第一个元素拿出来,重新1
    如计算merge( [E,O], [C,E,F,O], [C] )
    有三个列表 :  ①      ②          ③
    
    1、先看1中的E,在后面2.3的队尾中,所以下一个看2中的C,
    2.2中的C,没在其他的队尾,输出【C】+{[E,O],[E,F,O]}
    3、在看E,没在其他队尾,输出E 变成了,【C,E】+{[O],[F,O]}
    4、再看O,在【F,O】的第二个,所以下一个看F,F不在其他队尾,所以输出F,[C,E,F]+{[O][O]}
    5、最后输出【C,E,F,O】

    重要规律:

    1、拓扑图,从左往右,先看第一个序列第一个元素是否有前沿,如果没有就选,选了就刷新重新来,否则看第二个,

    2、选一次要记得刷新,然后再看第一个序列,

    几个训练

    一/

    class A1: pass
    class A2: pass
    class A3: pass
    class B1(A1,A2): pass
    class B2(A2): pass
    class B3(A2,A3): pass
    class C1(B1): pass
    class C2(B1,B2): pass
    class C3(B2,B3): pass
    class D(C1, C2, C3): pass
    
    print("从D开始查找:")
    for s in D.__mro__:
        print(s)
    
    print("从C3开始查找:")
    for s in C3.__mro__:
        print(s)

    这里写图片描述 

    • 第一下选D
    • 选完D的第一个子元素,C1没有前沿,所以选C1, 
    • 然后刷新,查看第一个序列的B1,有C2前沿,所以看第二个序列第一个元素C2
    • 然后刷新,查看第一个序列的第一个元素B1,不是C3
    • 一次类推,以此未 D   C1   C2  B1   A1  C3  B2  B3  A2 A3  O

    第二个训练,

    F  D   E  A  B  C O 

    三/错误示范:

    class A():
        def __init__(self):
            print("这里是A类")
    
    class B():
        def __init__(self):
            print("这里是B类")
    
    class D(A,B):
        def __init__(self):
            print("这里是D类")
    
    class C(D):
        def __init__(self):
            print("这里是C类")
    
    class E(A,C):
        def __init__(self):
            print("这里是E类")
    print(E.__mro__)

    第一个E就是A,A有后续,然后还是最后一个,就错了

    Super()是个什么鬼

     super()可以帮我们执行MRO中下一个父类的方法,通常super()有两个使用的地方: 

        1. 可以访问父类的构造方法

        2. 当子类方法想调用父类(MRO)中的方法

        3.super(A,self)  self的__mro__下的A类下面的类

    class A:
        def func(self):
            print("这是A的类")
    class B:
        def func(self):
            print("这是B的类")
    
    class C(A,B):
        def func(self):
            super().func()      #默认是__mro__的第一个
            super(C, self).func()    #第一个是指定的类,第二个是用谁的__mro__, 用自己的__mro__的C类下一个类
            super(A,self).func()     #self的__mro__中的A的下一个类
    
    c = C()
    c.func()
    class A:
        def __init__(self,name):
            self.name = name
        def func(self):
            print("这是A的类")
    class B:
        def __init__(self,age):
            self.age = age
    
        def func(self):
            print("这是B的类")
    
    class C(A,B):
        def __init__(self,name, age):
            super(C,self).__init__(name)
            super(A,self).__init__(age)
        def func(self):
            super().func()
            super(C, self).func()
            super(A,self).func()
    
    c = C("zhou",18 )
    print(c.__dict__)
    #输出如下
    {'name': 'zhou', 'age': 18}

    多态

    class File:
        def read(self):
            pass
    
        def write(self):
            pass
    
    class Disk:
        def read(self):
            print('disk read')
    
        def write(self):
            print('disk write')
    
    class Text:
        def read(self):
            print('text read')
    
        def write(self):
            print('text write')
    
    disk = Disk()
    text = Text()
    
    disk.read()
    disk.write()
    
    text.read()
    text.write()

    封装


    class People:
    data = "People"
    _name = "人类" #一个_表示约定隐藏,但是并未隐藏
    __age = 100000 # 两个__表示不应该用,初始化用,变量实际会变成_People__age存储

    def bar(self):
    self.__foo()

    def __foo(self):
    print("------People---foo----")
    print(self, self.__dict__)
    print("data,name,age为:", self.data, self._name, self.__age, self._People__age, self._Chinese__age) #self.__age 在什么类中就是对应哪个_People__age


    class Chinese(People):
    data = "Chinese"
    _name = "中国人"
    __age = 1 # 两个__表示不应该用,初始化用,变量实际会变成_Chinese__age存储


    def __foo(self):
    print("------Chinese---foo----")
    print(self, self.__dict__)
    print("data,name,age为:", self.data, self._name, self.__age, self._People__age, self._Chinese__age)

    a = Chinese()
    print(a)
    print(a.__dict__)
    print(Chinese.__dict__)
    print(People.__dict__)
    a.bar()
    a.__x = 3
    print(a.__x) #封装生效,实际就是按照__x存储的
    print(a.__dict__)

    #输出如下:

    <__main__.Chinese object at 0x009CDCB0>
    {}
    {'__module__': '__main__', 'data': 'Chinese', '_name': '中国人', '_Chinese__age': 1, '_Chinese__foo': <function Chinese.__foo at 0x00E78C00>, '__doc__': None}
    {'__module__': '__main__', 'data': 'People', '_name': '人类', '_People__age': 100000, 'bar': <function People.bar at 0x00E78B70>, '_People__foo': <function People.__foo at 0x00E78BB8>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
    ------People---foo----
    <__main__.Chinese object at 0x009CDCB0> {}
    data,name,age为: Chinese 中国人 100000 100000 1
    3
    {'__x': 3}

    变形只在定义是起作用,只有一次,定义后就不再重命名了

    上面两种都不是真正隐藏

    在 python New style class 中, 有一个方法 __getattribute__ 在访问每个类成员时都会被调用,可以覆盖这个方法对名称进行过滤,在发现要访问指定名称变量时检查有无特殊标志,没有则返回其它值,内部需要使用变量时加入特殊标志调用 __getattribute__ 方法

    class HideMemberClass(object):
        def __init__(self):
            self._db = 'this is real value'
        def __getattribute__(self,name,flag=None):
            if name=='_db' and flag != '*':
                return '** No Access **'
            return object.__getattribute__(self, name)
        def getdb(self):
            return self.__getattribute__('_db', '*')
    
    a=HideMemberClass()
    a._db
    '** No Access **'
    a.getdb()
    'this is real value'

    通过内部自己调用self._db也不可以调用,只有通过getdb方法

    接口

    python 没有接口,只有抽象函数,还一种说法,接口指的调用数据的函数

    反射

     反射即想到4个内置函数分别为:getattr、hasattr、setattr、delattr  获取成员、检查成员、设置成员、删除成员下面逐一介绍先看例子:

    class Foo(object):
     
        def __init__(self):
            self.name = 'abc'
     
        def func(self):
            return 'ok'
     
    obj = Foo()
    #获取成员
    ret = getattr(obj, 'func')#获取的是个对象
    r = ret()
    a =1
    ret = getattr(sys.module('__main__'),"a") #也可以调用某个木块的函数或者变量
    print(r) #检查成员 ret = hasattr(obj,'func')#因为有func方法所以返回True print(ret) #设置成员 print(obj.name) #设置之前为:abc ret = setattr(obj,'name',19) print(obj.name) #设置之后为:19 #删除成员 print(obj.name) #abc delattr(obj,'name') print(obj.name) #报错

    @property @x.setter  @x.deleter

    property函数形式

    property函数的声明为

        def property(fget = None, fset = None, fdel = None, doc = None) -> <property object>
    其中fget, fset, fdel对应变量操作的读取(get),设置(set)和删除(del)函数。
    而property对象<property object>有三个类方法,即setter, getter和delete,用于之后设置相应的函数。

    class Student:
        def get_score(self):
            return self.__score
    
        def set_score(self, value):
            if not isinstance(value, int):
                raise  TypeError
            self.__score = value
    
        def del_score(self):
            del self.__score
    
        score = property(get_score, set_score, del_score, "这是说明")
    
    a = Student()
    a.score = 60
    print(a.score)
    del a.score

    修饰器使用

    class Student1:
        # 使用装饰器的时候,需要注意:
        # 1. 装饰器名,函数名需要一致
        # 2. property需要先声明,再写setter,顺序不能倒过来
      # 3 . 如果类内部要使用score,也是只能property类型变量,不再是其他值
    @property def score(self): return self.__score @score.setter def score(self, value): if not isinstance(value, int): raise TypeError self.__score = value @score.deleter def score(self): del self.__score a = Student1() a.score = 61 print(a.score) #60 del a.score

    __setattr__, __getattr__,__getattribute__, __call__

    可以看下这个比较详细

    • __getattribute__的返回值应该是上一层的调用,比如object.__getattribute(self, item)
    • __getattribute__如果抛出AttributeError异常,则进入到__getattr__里面,如果修改了__getattr__,则不会报错,其他的都会报错
    • 如果__getattribute__和__getattr__同时覆盖,当找不到属性的时候,先执行__getattribute__再执行__getattr__

    __getitem__, __setitem__, __delitem__

    这里的item指的字典操作[],如果有字典操作的时候运行,操作的也是self.__dict__

    比如a["age"]="haha"  触发 __setitem__

    print(a["age"])  触发__getitem__, 然后触发__getattribute__

    del a["age"]  触发__delitem__

    class C:
    
        def __getattribute__(self, item):
            print("这里是getattribute")
            return object.__getattribute__(self, item)
    
        def __getitem__(self, item):
            print("这里getitem")
            return self.__dict__[item]
    
        def __setitem__(self, key, value):
            print("这里setitem")
            self.__dict__[key] = value
            # self.key = value
    
        def __delitem__(self, item):
            print("这里delitem")
            del self.item
    
    c = C()
    c["age"] = 18
    
    print(c["age"])

    输出如下:

    这里setitem
    这里是getattribute
    这里getitem
    这里是getattribute
    18

    __get__, __set__,__delete__方法

    class Descriptor:
        def __get__(self, instance, owner):
            print("这里__get__",self,instance, owner)
        def __set__(self, key, value):
            print("这里是__set__",key,value)    
        def __delete__(self, instance):
            print("这里是__delete__")
    class A:
        age = Descriptor()         #只能在别的类中使用,描述数据
    a = A()

    当a.age  A.age时候触发__get__

    当a.age = 10 时候触发__set__    A.age = 10 不触发,因为变成了别的

    当 del a.age 时候触发__delete__  del A.age 不触发,被删除了

    描述符分为两种:

    • 如果一个对象同时定义了__get__()和__set__()方法,则这个描述符被称为 data descriptor 。

    • 如果一个对象只定义了__get__()方法,则这个描述符被称为 non-data descriptor 。

    描述符只可以是类中数据,不可以是实例属性

    我们对属性进行访问的时候存在下面四种情况:

    • data descriptor
    • instance dict
    • non-data descriptor
    • __getattr__()

    它们的优先级大小是:

    类属性> 数据描述符>实例属性>非数据描述符>__getattr__

    data descriptor > instance dict > non-data descriptor > __getattr__()
    

    这是什么意思呢?就是说如果实例对象obj中出现了同名的 data descriptor->d 和 instance attribute->d , obj.d 对属性 d 进行访问的时候,由于data descriptor具有更高的优先级,Python便会调用 type(obj).__dict__['d'].__get__(obj, type(obj)) 而不是调用obj.__dict__[‘d’]。但是如果描述符是个non-data descriptor,Python则会调用 obj.__dict__['d'] 。

    描述符触发

    上面这个例子中,我们分别从实例属性和类属性的角度列举了描述符的用法,下面我们来仔细分析一下内部的原理:

    • 如果是对 实例属性 进行访问,实际上调用了基类object的__getattribute__方法,在这个方法中将obj.d转译成了 type(obj).__dict__['d'].__get__(obj, type(obj)) 。

    • 如果是对 类属性 进行访问,相当于调用了元类type的__getattribute__方法,它将cls.d转译成 cls.__dict__['d'].__get__(None, cls) ,这里__get__()的obj为的None,因为不存在实例。

    描述符含义:

    class Int_validation:
        def __getattribute__(self, item):         #即使用字典也会用到这个函数,顺序比getitem低
            print("这是attribute")
        def __get__(self, instance, owner):       #self指的C类的实例,也就是stu.age,    instance指的是D的实例,也就是stu ,  owner指的D类
            print("11111")
            return  self.value
    
        def __set__(self, instance, value):      #self指的C的实例,也就是stu.age,   instance指的是D的实例,也就是stu, value是赋的值    
            print("222222")
            if  isinstance(value,int) and 0<value<100:
                self.value=value        #这个要注意 要用value,不能用instance.name 否则会陷入死循环   可以这么用instance.__dict__["name"]=value修改实例属性
            else:
                print("请输入合法的数字")
    
        def __delete__(self, instance):
            print("3333")
            pass
    
    class Student:
        age=Int_validation()          #只能作为属性的时候才可以触发
    
    stu=Student()
    stu.age = 50
    stu.age = 60
    stu.age = 60
    print(Student.__dict__)
    print(stu.age)
    
    #输出如下
    222222
    222222
    222222
    {'__module__': '__main__', 'age': <__main__.Int_validation object at 0x0092DCF0>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
    11111
    这是attribute
    None

      描述符只能在类中属性实例化的时候才可以触发,直接对其它类中的属性进行描述,如果定义了__get__,一旦读取age就会调用__get__,如果定义了__set__,一但对age复制就会触发

    •   stu.age = 10 会调用__set__,但是不会修改,也不会修改stu字典, 如果是数据描述符(get,set都存在)则什么也不会发生,  如果是非数据描述符(只有get)则会修改stu的属性字典,Student的age不会改变
    •       stu.age     会调用__get__,比__getAttribute的值还要优先度搞
    •   Student.age 会调用__get__
    •        Student.age =10  不会调用__set__ ,真修改了age的值, 因为类属性优先级最高

    __del__方法:

     几种消亡方式都会调用__del__,1、程序结束,2、实例结束3、其他类中有这个类的实例, 4.其他类(其中有这个类的实例属性)的实例消亡   注意:类如果没实例化不会触发

       在定义的类中存在__del__方法时,当类被删除的时候,程序会自动执行__del__当中的代码(正好与__init__方法相反).

    object._getattr_(self, name)

    实例instance通过instance.name访问属性name,只有当属性name没有在实例的__dict__或它构造类的__dict__或基类的__dict__中没有找到,才会调用__getattr__。当属性name可以通过正常机制追溯到时,__getattr__是不会被调用的。如果在__getattr__(self, attr)存在通过self.attr访问属性,会出现无限递归错误。

    object.__getattribute__(self, name)

    实例instance通过instance.name访问属性name__getattribute__方法一直会被调用,无论属性name是否追溯到。如果类还定义了__getattr__方法,除非通过__getattribute__显式的调用它,或者__getattribute__方法出现AttributeError错误,否则__getattr__方法不会被调用了。如果在__getattribute__(self, attr)方法下存在通过self.attr访问属性,会出现无限递归错误。如下所示,ClassA中定义了__getattribute__方法,实例insA获取属性时,都会调用__getattribute__返回结果,即使是访问__dict__属性。

    object.__setattr__(self, name, value)

    如果类自定义了__setattr__方法,当通过实例获取属性尝试赋值时,就会调用__setattr__。常规的对实例属性赋值,被赋值的属性和值会存入实例属性字典__dict__中。

    object.__delattr__(self, name)

    对象删除的时候,执行的操作,必须加上del self.name 否则没用

    class A:
        x = 1
        def __init__(self):
            self.y = 2
        def __delattr__(self, item):
            print("已经删除")
    a = A()
    print(a.__dict__)
    del a.y       #执行  __delattr__ ,但是上面没删除
    del A.x       #不执行__delattr__
    print(a.__dict__)
    
    #输出如下
    {'y': 2}
    已经删除
    {'y': 2}

    Like __setattr__() but for attribute deletion instead of assignment. This should only be implemented if del obj.name is meaningful for the object.

    __str__, __repr__ , __format__

    __str__的优先级高于__repr__,如果输出的时候找不到__str__,就找__repr__,都是用来控制输出格式的

    class  Student:
        name = "zgl"
        def __str__(self):
            return "我的str名字是%s" % self.name
        def __repr__(self):
            return "我的repr名字是%s" % self.name
    
    stu = Student()
    print(stu)        #我的str名字是zgl   优先输出
    print(repr(stu)) #我的repr名字是zgl

    __format__

    class A:
        def __init__(self, name, school, addr):
            self.name = name
            self.school = school
            self.addr = addr
    
        def __format__(self, format_spec):
            # format_spec = '{obj.name}-{obj.addr}-{obj.school}'
            return format_spec.format(obj=self)  # 此行的format_spec等同于上面一行
    
    a = A("大表哥", "哈工大", "南岗区")
    format_spec = "{obj.name}-{obj.school}-{obj.addr}"
    print(format(a, format_spec))           #大表哥-哈工大-南岗区

     __dict__

    关于__dict__的修改,好像只实例的可以修改__dict__,类的__dict__是不可以使用update或者赋值的,想要修改的话,修改类的属性,不能直接操作类的字典

    可以使用setattr(obj, key, value)修改

    __module__, __class__

    __module__ 返回实例或者类出自哪个模块

    __class__    返回实例的类,或者类的类型

    from day6tmp.a  import E
    c = E()
    print(c.__module__)
    print(c.__class__)
    print(E.__module__)
    print(E.__class__)
    
    #输出如下
    day6tmp.a
    <class 'day6tmp.a.E'>
    day6tmp.a
    <class 'type'>

    __doc__

    子类不继承

    object.__dir__(self)

    dir()作用在一个实例对象上时,__dir__会被调用。返回值必须是序列。dir()将返回的序列转换成列表并排序。

    object.__call__(self[, args...])

    Called when the instance is “called” as a function; if this method is defined, x(arg1, arg2, ...) is a shorthand for x.__call__(arg1, arg2, ...).

    Python中有一个有趣的语法,只要定义类型的时候,实现__call__函数,这个类型就成为可调用的。换句话说,我们可以把这个类的对象当作函数来使用,相当于重载了括号运算符。

    通过使用__setattr____getattr____delattr__可以重写dict,使之通过“.”调用键值。
    class Dict(dict):
        '''
        通过使用__setattr__,__getattr__,__delattr__
        可以重写dict,使之通过“.”调用
        '''
    
        def __setattr__(self, key, value):
            print("In '__setattr__")
            self[key] = value
    
        def __getattr__(self, key):
            try:
                print("In '__getattr__")
                return self[key]
            except KeyError as k:
                return None
    
        def __delattr__(self, key):
            try:
                del self[key]
            except KeyError as k:
                return None
    
        # __call__方法用于实例自身的调用,达到()调用的效果
        def __call__(self, key):  # 带参数key的__call__方法
            try:
                print("In '__call__'")
                return self[key]
            except KeyError as k:
                return "In '__call__' error"
    
    
    s = Dict()
    print(s.__dict__)
    # {}
    
    s.name = "hello"  # 调用__setattr__
    # In '__setattr__
    
    print(s.__dict__)  # 由于调用的'__setattr__', name属性没有加入实例属性字典中。
    # {}
    
    print(s("name"))  # 调用__call__
    # In '__call__'
    # hello
    
    print(s["name"])  # dict默认行为
    # hello
    
    # print(s)
    print(s.name)  # 调用__getattr__
    # In '__getattr__
    # hello
    
    del s.name  # 调用__delattr__
    print(s("name"))  # 调用__call__
    # None

    属性描述符、property(@setter,@deleter)和__setattr__

    我这是么理解的,

    • property用于的是少数属性的控制,1个2个
    • 属性描述符用于的是某些的相同属性的控制   具有相同属性
    • __setattr__ 全部属性的控制,当然也可以部分,不够代码结构复杂

    类中类

    class A:
        name = "A"
        data1 = "A的数据"
        class B:
            data2 = "B的数据"
    a = A.B()
    # print(a.name)       #访问不到A的数据
    print(a.data2) 
    # print(a.data1)      #访问不到A的数据

     子类和类互转

    子类实例是父类的实例,相反不行

    动态加载模块

    第一种方式:python解释器内部使用,不建议用

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:CarsonLi
    '''Python 解释器内部动态导入方式'''
    module_name='import_lib.metaclass' #模块名的字符串
    import_lib=__import__(module_name) #这是解释器自己内部用的
    '''import_lib代表的其实是这个模块,而不是下面的metaclass'''
     
    c=import_lib.metaclass.Ccc("Bert")#调用下面的方法
    print(c.name) #运行结果:Bert

    第二种方式:与上面效果一样,官方建议用这个

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # Author:CarsonLi
    '''官方建议用这个'''
    import importlib
    module_name='import_lib.metaclass' #模块名的字符串
    metaclass=importlib.import_module(module_name) #导入的就是需要导入的那个metaclass
    c=metaclass.Ccc("Bert") #调用下面的方法
    print(c.name)  #运行结果:Bert

    支付宝     
    您的资助是我最大的动力!
    金额随意,欢迎来赏!
    微信

    如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的关注我

    如果,想给予我更多的鼓励,求打       付款后有任何问题请给我留言!!!

    ------------------------------------------------------------------------------------------
    作者:【周sir】
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    多重背包POJ1276不要求恰好装满 poj1014多重背包恰好装满
    哈理工1053完全背包
    求最小公倍数与最大公约数的函数
    Bus Pass ZOJ 2913 BFS 最大中取最小的
    POJ 3624 charm bracelet 01背包 不要求装满
    HavelHakimi定理(判断一个序列是否可图)
    z0j1008Gnome Tetravex
    ZOJ 1136 Multiple BFS 取模 POJ 1465
    01背包 擎天柱 恰好装满 zjut(浙江工业大学OJ) 1355
    zoj 2412 水田灌溉,求连通分支个数
  • 原文地址:https://www.cnblogs.com/zhouguanglu/p/10230246.html
Copyright © 2011-2022 走看看