• Python-面向对象之魔术方法


    阅读目录:

      1、特殊属性:Python的精华之一

      2、查看属性

      3、魔术方法

      1. 创建,初始化,销毁 (__new__, __init__, __del__)
      2. hash
      3. bool
      4. 可视化
      5. 运算符重载
      6. 可调用对象
      7. 上下文管理
      8. 反射
      9. 描述器
      10. 其他杂项

      

    1、特殊属性:Python的精华之一:

     

    属性                                 含义
    __name__ 类,函数,方法等的名字,实例没有
    __module__ 类定义所在的模块名
    __class__ 对象或类所属的 类
    __bases__ 类的基类的元组,顺序为它们在基类列表中出现的顺序
    __doc__ 类,函数的文档字符串,如果没有定义则为None
    __mro__ 类的mro,class.mro()返回的结果保存在__mro__中
    __dict__ 类或实例的属性,可写的字典

    测试:
     1 class A:pass
     2 
     3 class B(A):
     4     def bb(self):pass
     5 
     6 class C(B, A):
     7     def cc(self):pass
     8 
     9 a = A()
    10 b = B()
    11 c = C()
    12 
    13 print(A.__name__)
    14 print(B.__name__)
    15 print(C.__name__)
    16 print(b.bb.__name__)
    17 print('-'*40)
    18 # 因为是在当前类中调用,所以是返回值 __main__
    19 # 如果该模块 a.py 被导入到其他地方,那么打印 就是模块名 a
    20 print(A.__module__)
    21 print(B.__module__)
    22 print(C.__module__)
    23 print('-'*40)
    24 print(A.__bases__)
    25 print(A.__base__)
    26 print(B.__bases__)
    27 print(B.__base__)
    28 print(C.__bases__)
    29 print(C.__base__)
    30 print('-'*40)
    31 print(A.__doc__)
    32 print(a.__doc__)
    33 print(b.bb.__doc__)
    34 print('-'*40)
    35 print(A.mro())
    36 print(A.__mro__)
    37 print(B.mro())
    38 print(B.__mro__)
    39 print(C.mro())
    40 print(C.__mro__)
    41 print('-'*40)
    42 print(A.__dict__)
    43 print(a.__dict__)
    44 print(B.__dict__)
    45 print(b.__dict__)
    46 print(C.__dict__)
    47 print(c.__dict__)
    测试
      结果:
     1 A
     2 B
     3 C
     4 bb
     5 ----------------------------------------
     6 __main__
     7 __main__
     8 __main__
     9 ----------------------------------------
    10 (<class 'object'>,)
    11 <class 'object'>
    12 (<class '__main__.A'>,)
    13 <class '__main__.A'>
    14 (<class '__main__.B'>, <class '__main__.A'>)
    15 <class '__main__.B'>
    16 ----------------------------------------
    17 None
    18 None
    19 None
    20 ----------------------------------------
    21 [<class '__main__.A'>, <class 'object'>]
    22 (<class '__main__.A'>, <class 'object'>)
    23 [<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
    24 (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
    25 [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
    26 (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
    27 ----------------------------------------
    28 {'__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
    29 {}
    30 {'__module__': '__main__', 'bb': <function B.bb at 0x0000000002240268>, '__doc__': None}
    31 {}
    32 {'__module__': '__main__', 'cc': <function C.cc at 0x00000000022402F0>, '__doc__': None}
    33 {}
    结果

    2、查看属性
        方法————————————————————意义
    __dicr__:(double under ---> dunder,双下划线)
    类或实例的属性不一定都在dict中
    print(dir(ClassName)) ---->属性key,放置在列表中,在dict中没有的,都是从objecct中来的,或者继承下来的
    print(ClassName.__dict__):

    def __dir__(self):# 返回可迭代对象,但是是实例方法,与类没关系,所以,调用类的dir,并没有覆盖,只有实例调用dir才有变化
    return iterableObj

    print(dir()): 当前作用域的标识符,如果在函数中,就是形参的名称,不管是函数还是方法,一般用在模块上
      测试
     1 class A:pass
     2 
     3 class B(A):
     4     def bb(self):pass
     5 
     6 class C(B, A):
     7     def __init__(self):
     8         self.x = 10
     9     # def __dir__(self):
    10     #     pass # return None
    11     pass
    12 
    13 #  类只收集类的属性
    14 print(C.__dict__)
    15 print(dir(C)) # 尽可能收集属性key,dict中的也收集过来,还会收集跟当前对象继承的类的属性也会收集过来
    16 ###############################################
    17 print('-' * 40)
    18 # 注意self,只影响实例,不影响 类!
    19 # 收集实例的属性,包括类,继承的类的属性
    20 # 没有提供 __dir__(self)
    21 c = C()
    22 print(c.__dict__)
    23 print(dir(c)) # 等价 c.__dir__()
    24 # 提供 __dir__(self)
    25 # def __dir__(self):
    26     #     pass # return None --------> 报错,要一个可迭代对象
    27     #     return ('a','b','c') -----> ['a','b','c']
    28 ###############################################
    29 print('-' * 40)
    30 # 收集当前作用域的标识符,如果在函数中,就是形参的名称,不管是函数还是方法,一般用在模块上
    31 print(dir()) #而且,只会打印之前的,之后的不会收集到
    32 def foo():
    33     print(dir())
    34 foo()
    35 
    36 def foo(a):
    37     print(dir())
    38 foo(1)
    39 # 如果a.py被导入,在被导入的地方,a.py中的内容会重载一次,该运行的云行一次,该打印的也会打印
    40 # 在被导入的地方,执行dir(a) 把模块a中的属性(标识符)都打印
    41 # 如果被导入的地方执行dir(), 模块名a 也会被收集
    42 # 如果 from a import C 执行dir(),C也会被收集到,这样就可以用这个类C,否则无法使用
    43 ###############################################
    44 print('-' * 40)
    45 c = C()
    46 print(c.__dir__())
    47 # 因为字典的key是类set,所以可以 并集
    48 print(object.__dict__.keys() | c.__class__.__dict__.keys() | c.__dict__.keys())
    49 # 可以看到,两者结果差不多,所以实例收集到的就是这些东西的并集
    测试代码
      结果:

     1 {'__module__': '__main__', '__init__': <function C.__init__ at 0x00000000029502F0>, '__doc__': None}
     2 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bb']
     3 ----------------------------------------
     4 {'x': 10}
     5 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bb', 'x']
     6 ----------------------------------------
     7 ['A', 'B', 'C', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'c']
     8 []
     9 ['a']
    10 ----------------------------------------
    11 ['x', '__module__', '__init__', '__doc__', 'bb', '__dict__', '__weakref__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
    12 {'__repr__', '__class__', '__ge__', '__subclasshook__', '__sizeof__', '__hash__', '__le__', '__setattr__', '__reduce_ex__', '__init_subclass__', '__init__', '__module__', '__delattr__', '__new__', '__eq__', '__reduce__', 'x', '__ne__', '__doc__', '__dir__', '__lt__', '__str__', '__gt__', '__format__', '__getattribute__'}
    打印结果
      总结:
        __dir__:
            返回类或者对象的所有成员名称列表,dir()函数就是调用__dir__()
            使用实例调用时,如果提供__dir__(),则返回其返回值,要求是可迭代对象
            如果没有提供__dir__(),则会从实例和类及祖先类中收集信息
        如果dir([obj])参数obj包含方法__dir__() ,该方法将被调用,如果参数obj不含__dir__ ,该方法将最大限度的收集属性信息
        dir(obj) 对于不同类型的对象obj具有不同的行为。
        • 如果对象是模块对象,返回的列表包含模块的属性名和变量名
        • 如果对象是类型或者类对象,返回的列表包含类的属性名,及它的基类属性名
        • 如果obj 不写,返回列表包含内容不同
          • 在模块中,返回模块的属性和变量名
          • 在函数中,返回本地作用域的变量名
          • 在方法中,返回本地作用域的变量名
    3、魔术方法: 处理new是与cls有关,其他的都是属于实例的方法        

      分类:
      1. 创建,初始化,销毁 (__new__, __init__, __del__)
      2. hash
      3. bool
      4. 可视化
      5. 运算符重载
      6. 可调用对象
      7. 上下文管理
      8. 反射
      9. 描述器
      10. 其他杂项
        ①、创建,初始化,销毁:
    __new__:目前写法固定,一般不用自定义,是staticmethod,元类编程时用
        
    def __new__(cls, *args, **kwargs):
         return super().__new__(cls)

            

        ②、   hash:

                
        
     1 class A:pass
     2 
     3 class B(A):pass
     4 
     5 class C(B):
     6     def __hash__(self):
     7         # return 'abc' # 这种是抛异常的,因为hash 返回的是一个数字
     8         return  hash('abc')
     9     def __init__(self, name):
    10         self.name = name
    11         print("__________________")
    12 
    13 
    14 c = C('tom')
    15 print(hash(c))
    注意
        总结:
          hash(z) z 都一样,求得hash应该不变的,幂等性,一般来说,z 不一样,hash应该不一样

    不同的hash算法,都有hash冲突(因为只有一个hash空间),不同的z求得同样的hash值。
    hash空间满了,就会出现hash冲突。
    出现冲突后,要考虑去重了,如果出现冲突,判断是否eq,如果eq是相等,返回True就会去重。
    先说hash,再说eq

    如果不提供hash 和 eq 就用object的hash,但是使用的是内存地址求hash的
    如果提供eq,不提供hash,默认是hash返回值是None,也就是 不可hash,这个时候提供一个hash方法就可以
    提供一个__hash__ = None ,就不可hash,list就是这样实现不可hash的

    如果只提供hash,冲突就用到eq处理,是否相等,再去重


    先比较is, 在比较== ,is相等,内存地址都一样,就没必要再看==了

     因此,一般来说,提供__hash__方法是为了作为set或者dict的key,所以去重要同时提供EQ方法
           不可hash对象 isinstance(p1, collections,Hashable) 一定是False
           去重 需要提供__eq__方法
                
               


    ③、bool:
           __bool__内建函数bool(),或者对象放在逻辑表达式的位置,调用这个函数返回布尔值
                如果没有定义__bool__(self),就找len()返回长度,非 0 为真,
                如果__len__(self)也没有定义,那么所有实例都返回真

         如果有,__bool__(self) 类 真, 实例,看里边返回什么(True 还是False,只能返回布尔值)
    __len__(self)return 整数>=0或者布尔值
    有了bool 就不看len!,全没有,都是真。
                如果len都是等价True,那就看bool返回什么




    ④、可视化:
    __repr__(self)必须是字符串
                内建函数repr()对一个对象获取字符串表达
                调用__repr__方法返回字符串表达式,如果__repr__也没有定义,就直接返回object的定义就显示内存地址信息
                如果只提供repr,都转为repr

    __str__(self)
                str() 函数,format() 函数,print()函数调用,需要返回对象的字符串表达,如果没有定义,就去调用__repr__方法,
                返回字符串表达,如果__repr__没有定义,返回内存地址信息

    直接作用到实例上,用str ,如果没有str,都是repr,如果没有repr,该找str的找str,找repr的如果找不到就去找object,打印内存地址
    如果都没有,找到的都是内存地址,去父类,或object找的。

    __bytes__(self) return bytes类型
                bytes() 函数调用,返回一个对象的bytes表达,即返回bytes对象
          测试:
     1 class A:
     2     def __init__(self, name):
     3         self.name = name
     4 
     5     def __repr__(self):
     6         return 'repr name={}'.format(self.name)
     7 
     8     def __str__(self):
     9         return 'str name={}'.format(self.name)
    10 
    11     def __bytes__(self):
    12         return self.name.encode()
    13 
    14 print(A)
    15 print(A('tom'))
    16 print(str(A('tom')))
    17 print("{}".format(A('jerry')))
    18 
    19 print(1,repr(A('tom')))
    20 print(2,repr('{}'.format(A('jerry')))) # 因为先format的,所以先调用str
    21 
    22 a = A('tom')
    23 print([a,a]) # print,没有直接作用到实例上
    24 print(str({a, a})) # print,没有直接作用到实例上
    25 print('{}'.format(*{a, a})) # *{a, a} 参数解析 先去重,*{a} 还是a,format直接作用上去
    26 
    27 print(bytes(a))
    测试
          结果:
     1 <class '__main__.A'>
     2 str name=tom
     3 str name=tom
     4 str name=jerry
     5 1 repr name=tom
     6 2 'str name=jerry'
     7 [repr name=tom, repr name=tom]
     8 {repr name=tom}
     9 str name=tom
    10 b'tom'
    结果
        注:不能通过print输出,来判断类型,类型判断要用 type 或isinstance


    ⑤、运算符重载:
      

           __iadd__ 这里的i 就地修改,其他 i也是该意思


    不同类型之间是可以==比较的。

    没有定义的话,是不可以比较大小的,报错

           虽然可以返回其他类型,但是一般返回本类型

      测试1:减法实现
     1 class A:
     2     def __init__(self, name, age=18):
     3         self.name = name
     4         self.age  = age
     5 
     6     def __sub__(self, other):
     7         return self.age - other.age
     8 
     9 tom = A('tom')
    10 jerry = A('jerry', 20)
    11 
    12 # 实现了实例减法
    13 print(tom - jerry)
    14 
    15 # 这相当于 tom被重新赋值了,因为没有提供isub
    16 tom -= jerry
    17 print(tom) # -2
    18 
    19 ###################################################3
    20 
    21 class A:
    22     def __init__(self, name, age=18):
    23         self.name = name
    24         self.age  = age
    25 
    26     def __sub__(self, other):
    27         return self.age - other.age # 这里可以使用-号 是因为作用到age上,而不是self本身上,所以不会出现自己调自己
    28 
    29     def __isub__(self, other):
    30         return A(self.name,self- other) # 这里调用了sub
    31 
    32 tom = A('tom')
    33 jerry = A('jerry', 20)
    34 
    35 # 实现了实例减法
    36 print(tom - jerry)
    37 
    38 # 这调用了isub 返回一个新的A 实例赋值给tom
    39 # 当然直接使用sub 也可以返回一个A 实例,活学活用
    40 tom -= jerry
    41 print(tom) # -2
    测试1
      结果:
    1 -2
    2 -2
    3 -2
    4 <__main__.A object at 0x0000000002928668>
    结果
      测试2:比较大小,使用装饰器,只需要提供两个 比较符号
     1 from functools import total_ordering
     2 
     3 @total_ordering
     4 class Point:
     5     def __init__(self, x, y):
     6         self.x = x
     7         self.y = y
     8 
     9     def __hash__(self):
    10         return hash((self.x , self.y))
    11 
    12 
    13 
    14     def __add__(self, other):
    15         x = self.x + other.x
    16         y = self.y + other.y
    17         return Point(x, y)
    18 
    19     def __sub__(self, other):
    20         x = self.x - other.x
    21         y = self.y - other.y
    22         return Point(x, y)
    23 
    24     def distance(self):
    25         pass
    26 
    27     def __eq__(self, other):
    28         return True
    29         # if self.x == other.x and self.y == other.y:
    30         #     return  True
    31         # else:
    32         #     return False
    33     def __gt__(self, other):#这里只是为了测试,数学上比较大小是不对的
    34         return self.x > other.x
    35 
    36 p1 = Point(1,2)
    37 p2 = Point(3,4)
    38 p3 = Point(1,2)
    39 
    40 # z调用eq,只能解决等 或 不等,不能解决 谁大谁小
    41 print(p1 == p2)
    42 print(p1 != p2)
    43 print(p1 >= p2)
    44 print(p1 <= p2)
    45 print(p1 > p2)
    46 print(p1 < p2)
    使用装饰器的
      结果:
    1 True
    2 False
    3 True
    4 True
    5 False
    6 False
    View Code
      测试3:不是用装饰器,只需要三个比较符
     1 class Point:
     2     def __init__(self, x, y):
     3         self.x = x
     4         self.y = y
     5 
     6     def __hash__(self):
     7         return hash((self.x , self.y))
     8 
     9 
    10 
    11     def __add__(self, other):
    12         x = self.x + other.x
    13         y = self.y + other.y
    14         return Point(x, y)
    15 
    16     def __sub__(self, other):
    17         x = self.x - other.x
    18         y = self.y - other.y
    19         return Point(x, y)
    20 
    21     def distance(self):
    22         pass
    23 
    24     def __eq__(self, other):
    25         return True
    26         # if self.x == other.x and self.y == other.y:
    27         #     return  True
    28         # else:
    29         #     return False
    30     def __gt__(self, other):#这里只是为了测试,数学上比较大小是不对的
    31         return self.x > other.x
    32 
    33     def __ge__(self, other):
    34         return self.x >= other.x
    35 
    36 p1 = Point(1,2)
    37 p2 = Point(3,4)
    38 p3 = Point(1,2)
    39 
    40 # z调用eq,只能解决等 或 不等,不能解决 谁大谁小
    41 print(p1 == p2)
    42 print(p1 != p2)
    43 print(p1 >= p2)
    44 print(p1 <= p2)
    45 print(p1 > p2)
    46 print(p1 < p2)
    不使用装饰器
      结果
    1 True
    2 False
    3 False
    4 True
    5 False
    6 True
    View Code
          总结:
            往往是用面向对象实现类的,需要做大量的运算,而运算符是这种运算在数学上最常见的表达方式
            通过重载,重新定义 Point + Point
            提供运算符重载,比直接提供加法方法更加合适该领域内使用者的习惯
            int类 几乎实现了所有操作符,可以参看
            只需要三个,是因为,大于可以推断小于等于,以此类推。。。。。。

       ⑥容器相关方法:
      
    方法                                         意义
    __len__ 内建函数len(),返回对象的长度 >= 0,如果把对象当做容器类型看,就如同list或者dict,bool()函数调用的时候,如果没有__bool__()方法,则会看__len__()方法是否存在,存在返回非0 为真
    __iter__ 迭代容器,调用,返回一个新的迭代器对象
    __contains__ in成员运算符,没有实现,就调用__iter__方法遍历,所以,可以不实现
    __getitem__ 实现self[key] 访问,序列对象,key接受整数位索引,或者切片,对于set 和dict,key为hashbale,key不存在引发 KeyError异常
    __setitem__ 和__getitem__的访问类似,是设置的方法
    __missing__ 字典或其子类使用__getitem__()调用时,key不存在执行该方法

      测试:
    1 class A(dict):
    2     def __missing__(self, key):
    3         print('missing key', key)
    4         return 0
    5 
    6 a = A()
    7 print(a['k']) # 如果没有missing方法,报KeyError
    8 print(a.get('k'))
    missing
      结果:
    1 missing key k
    2 0
    3 None
      空list,set,dict,str等效False:
          因为为空,不实现bool(),往往实现len()返回为0 等效False

      举例:购物车作为容器:
     1 class Cart:
     2     def __init__(self):
     3         self.item = []
     4 
     5     def additem(self, item):
     6         self.item.append(item)
     7 
     8     def getallitem(self):
     9         return self.item
    10 
    11     def __getitem__(self, index):
    12         return self.item[index]
    13 
    14     def __iter__(self):
    15         yield from self.item
    16         #return iter(self.item)
    17 
    18     def __setitem__(self, key, value):
    19         self.item[key] = value
    20 
    21     def __str__(self):
    22         return '{}'.format(self.item)
    23 
    24     def __len__(self):
    25         return len(self.item)
    26 
    27     def __bool__(self):
    28         return True
    29 
    30     def __add__(self, other): # car + 5
    31         self.item.append(other)
    32         return self
    33 
    34 
    35 
    36 c = Cart()
    37 c.additem(1)
    38 c.additem(2)
    39 c.additem(3)
    40 c.additem(4)
    41 
    42 
    43 print('----',len(c))
    44 print('++++',bool(Cart))
    45 print(bool(c))
    46 
    47 for x in c:
    48     print(x)
    49 
    50 print(3 in c) #  __iter__  不需要contaions
    51 
    52 
    53 print(c[1]) # getitem
    54 
    55 c[2] = 'sdasda' # setitem
    56 print(c)
    57 
    58 # 链式加法
    59 print(c + 6)
    60 print(c + 7 + 8 + 9)
    61 print(c.__add__(20).__add__(22))
    View Code

      结果:

     1 ++++ True
     2 True
     3 1
     4 2
     5 3
     6 4
     7 True
     8 2
     9 [1, 2, 'sdasda', 4]
    10 [1, 2, 'sdasda', 4, 6]
    11 [1, 2, 'sdasda', 4, 6, 7, 8, 9]
    12 [1, 2, 'sdasda', 4, 6, 7, 8, 9, 20, 22]
    View Code

        ⑦ 、可调用对象:

        Python中一切皆对象,函数也不例外。    

    1 def foo():
    2     print(foo.__module__, foo.__name__)
    3 
    4 foo()
    5 
    6 #等价于
    7 
    8 foo.__call__()
        函数即对象,对象foo加上(),就是调用此函数对象的__call__()方法
        可调用对象:
          
    方法         意义
    __call__ 类中定义一个该方法,实例就可以向函数一样调用

      可调用对象:定义一个类,并实例化得到其实例,将实例像函数一样调用。

    举例:

      举例:定义一个斐波那契数列,方便调用,计算第n项,并实现了长度,迭代,支持索引
     1 class Fib:
     2     def __init__(self):
     3         self.items = [0, 1, 1] # 而且使用了缓存
     4 
     5     def __call__(self, index):
     6         if index >= len(self.items):#但是注意长度,否则f(10)之后再f(4) 还会执行append
     7             for i in range(3, index + 1):
     8                 self.items.append(self.items[i-1] + self.items[i-2])
     9         return self.items[index]
    10 
    11     def __iter__(self):
    12         yield  from self.items
    13 
    14     def __len__(self):
    15         return len(self.items)
    16 
    17     def __getitem__(self, item):
    18         return self.items[item]
    19 
    20     def __str__(self):
    21         return str(self.items)
    22 
    23 
    24 
    25 f = Fib()
    26 print(f(10))
    27 print(f.items)
    28 print(f(4))注意这两项,一个是可调用, 一个是支持索引
    29 print(f[4])
    30 print(f.items)
    31 print(len(f))
        ⑧、上下文管理:
          class A:
      pass
      with A() as f:
      print(f)

            3.6 提示少 __enter__, 之前的提示 __exit__,正常情况下,两个一起用
      
      
    pt = Point()
    with pt as f:
    print(pt == f)
    如果使用as, 则f 其值为enter的返回值
      


    参数问题:
    enter方法不可添加参数,因为传不进去,传进去给谁啊???,所以。。。。

    exit的参数:excption
    exc_type
    exc_val
    exc_tb
    做一些清理工作

    retrun一个等效True,就可以压制异常,
    看图:



    有没有as,都会调 enter exit,但是里边没法引用,只有with知道,所以给了一个as
    但是这个as,要看enter的返回值怎么写,如果是self,就是实力本身。


    enter做资源申请,exit 做一些清理工作 (区别__del__做资源清零工作)

    实例化,和 实力消亡是一次性的,分别创建和消亡是调用,而with语法可以对一个实例操作很多次。

    使用exit ,保证资源的释放,下次很久之后,再次使用这个对象,在这段长时间中,也不会占用这个资源,比如,文件
          但是del,直接消亡了,必须重新实例化。


        上下文管理对象:
          当一个对象同时实现了 __enter__ 和 __exit__ 方法,它就属于上下文管理的对象
          
           enter 和 exit 都是在执行with语句的时候才会执行。
            
           with可以开启一个上下文运行环境,在执行前做一些准备工作,执行后做一些首尾工作、
          
            注:with 并不开启一个新的作用域。
        

          即便调用 sys.exit(100)   0-256,它会退出当前解释器,直接敲,窗口会关闭,但是
          遇到with,依然还是会执行 exit语句


      举例: 类做装饰器,类装饰器和函数装饰器同时使用顺序问题!!!!
      1 ####################################################################
      2 
      3 import  time
      4 import datetime
      5 from  functools import wraps, update_wrapper
      6 
      7 def timeit(fn):
      8     @wraps(fn)#  update_wrapper(wapper)(fn)
      9     def wrapper(*args, **kwargs):
     10         start = datetime.datetime.now()
     11         ret = fn(*args, **kwargs)
     12         delta = (datetime.datetime.now() - start).total_seconds()
     13         print(delta)
     14         return ret
     15     return wrapper
     16 
     17 @timeit
     18 def add(x, y):
     19     time.sleep(1)
     20     return x + y
     21 
     22 #####################################################################
     23 class TimeIt:
     24     def __init__(self):
     25         pass
     26 
     27     def __enter__(self):
     28         self.start = datetime.datetime.now()
     29         return  self
     30 
     31     def __exit__(self, exc_type, exc_val, exc_tb):
     32         delta = (datetime.datetime.now() - self.start).total_seconds()
     33         print(delta)
     34 
     35 with TimeIt() as f:
     36     print('*', add(4, 5))
     37     # 此 add 非彼 add,这里只看print('*', add(4, 5))执行了多少秒,
     38     # 也就是with开始后,进入enter到退出exit执行了多少秒
     39 ######################################实现对象的可调用################################
     40 class TimeIt:
     41     def __init__(self, fn):
     42         self.fn = fn
     43 
     44     def __enter__(self):
     45         self.start = datetime.datetime.now()
     46         return  self
     47 
     48     def __exit__(self, exc_type, exc_val, exc_tb):
     49         delta = (datetime.datetime.now() - self.start).total_seconds()
     50         print(delta)
     51 
     52     def __call__(self, *args, **kwargs):
     53         return self.fn(*args, **kwargs)
     54 
     55 f = TimeIt(add)
     56 print('*', f(4, 5))
     57 
     58 ######################################类作为装饰器################################
     59 
     60 class TimeIt:
     61     def __init__(self, fn):
     62         self.fn = fn
     63 
     64     def __enter__(self):
     65         self.start = datetime.datetime.now()
     66         return  self
     67 
     68     def __exit__(self, exc_type, exc_val, exc_tb):
     69         delta = (datetime.datetime.now() - self.start).total_seconds()
     70         print(delta)
     71 
     72     def __call__(self, *args, **kwargs):
     73         start = datetime.datetime.now()
     74         ret = self.fn(*args, **kwargs)
     75         delta = (datetime.datetime.now() - start).total_seconds()
     76         print(delta)
     77         return ret
     78 
     79 @TimeIt # add=TimeIt(add) 一看发现 是 实例化
     80 def add(x, y):
     81     time.sleep(1)
     82     return x + y
     83 
     84 add(4, 5) # 相当于实例 调用,如果作为一个计时器的还,进调用开始计时,退出调用,结束计时
     85 
     86 ##################  处理字符串文档  ################################
     87 class TimeIt:
     88     ''' this is class'''
     89     def __init__(self, fn):
     90         # 方法 1
     91         # self.__doc__ = fn.__doc__
     92         # self.__name__ = fn.__doc__
     93         # 方法 2
     94         # update_wrapper(self, fn)
     95         # 方法 3 这里并不是装饰器,使用的是等价方式。
     96         wraps(fn)(self)
     97         self.fn = fn
     98 
     99     def __enter__(self):
    100         self.start = datetime.datetime.now()
    101         return  self
    102 
    103     def __exit__(self, exc_type, exc_val, exc_tb):
    104         delta = (datetime.datetime.now() - self.start).total_seconds()
    105         print(delta)
    106 
    107     def __call__(self, *args, **kwargs):
    108         start = datetime.datetime.now()
    109         ret = self.fn(*args, **kwargs)
    110         delta = (datetime.datetime.now() - start).total_seconds()
    111         print(delta)
    112         return ret
    113 
    114 @TimeIt # add=TimeIt(add) 一看发现 是 实例化
    115 def add(x, y):
    116     '''this is add function'''
    117     time.sleep(1)
    118     return x + y
    119 
    120 print(add.__doc__)
    121 
    122 
    123 # 此时,上面这个例子的类,可以做装饰器,又可以用在上下文管理。都实现了同样的功能
    124 
    125 
    126 
    127 
    128 ############# 两个装饰器同时使用 ############################
    129 import  time
    130 import datetime
    131 from  functools import wraps, update_wrapper
    132 
    133 def timeit(fn):
    134     @wraps(fn)#  update_wrapper(wapper)(fn)
    135     def wrapper(*args, **kwargs):
    136         start = datetime.datetime.now()
    137         ret = fn(*args, **kwargs)
    138         delta = (datetime.datetime.now() - start).total_seconds()
    139         print('{}  tooks {}'.format(fn.__name__, delta), '==+++++++=')
    140         return ret
    141     return wrapper
    142 
    143 class TimeIt:
    144     def __init__(self, fn):
    145         self.__fn = fn
    146 
    147     def __call__(self, *args, **kwargs):
    148         start = datetime.datetime.now()
    149         ret = self.__fn(*args, **kwargs)
    150         delta = (datetime.datetime.now() - start).total_seconds()
    151         print('{}  tooks {}'.format(self.__fn.__name__, delta), '===============')
    152         return ret
    153 
    154 @timeit #  add=timeit(add)=wrapper
    155 @TimeIt # add=TimeIt(add)
    156 def add(x, y):
    157     '''this is add function'''
    158     time.sleep(1)
    159     return x + y
    160 
    161 add(4, 5)
    View Code
    
    

          如下是正确的:因为通过wraps装饰器,给self提供了一个__name__属性
     1 import  time
     2 import datetime
     3 from  functools import wraps, update_wrapper
     4 
     5 def timeit(fn):
     6     @wraps(fn)#  update_wrapper(wapper)(fn)
     7     def wrapper(*args, **kwargs):
     8         start = datetime.datetime.now()
     9         ret = fn(*args, **kwargs)
    10         delta = (datetime.datetime.now() - start).total_seconds()
    11         print('{}  tooks {}'.format(fn.__name__, delta), '==+++++++=')
    12         return ret
    13     return wrapper
    14 
    15 class TimeIt:
    16     def __init__(self, fn):
    17         wraps(fn)(self) # self.__name__ = fn.__name__   这是 给了实例一个__name__属性
    18         self.__fn = fn
    19 
    20     def __call__(self, *args, **kwargs):
    21         start = datetime.datetime.now()
    22         ret = self.__fn(*args, **kwargs)
    23         delta = (datetime.datetime.now() - start).total_seconds()
    24         print('{}  tooks {}'.format(self.__fn.__name__, delta), '===============')
    25         return ret
    26 
    27 @timeit #  add=timeit(add) # 此时, add是一个实例
    28 @TimeIt # add=TimeIt(add) 一看发现 是 实例化
    29 def add(x, y):
    30     '''this is add function'''
    31     time.sleep(1)
    32     return x + y
    33 
    34 add(4, 5)
    View Code
    
    
    

            上下文应用场景:
        1. 增强功能:在代码执行的前后增加代码,以增强其功能,类似装饰器的功能
        2. 资源管理:打开了资源管理需要关闭,例如文件对象,网络连接,数据库连接
        3. 权限验证:在执行代码之前,做权限的验证,在__enter__中处理  
         ** contextlib.contextmanager   
            它是一个装饰器实现上下文管理,装饰一个函数,而不用像类一样实现__enter__和__exit__方法
            对下面的函数要求,必须有yield,也就是这个函数必须返回一个生成器,且只有yield一个值
            也就是这个装饰器接受一个生成器对象作为参数。

          举例:
     1 import contextlib
     2 
     3 @contextlib.contextmanager
     4 def foo():
     5     print('enter')
     6     yield
     7     print('exit')
     8 
     9 with foo() as f:
    10     print(f)
    11 print('-----------------------------')
    12 @contextlib.contextmanager
    13 def foo():
    14     print('enter')
    15     yield 5
    16     print('exit')
    17 
    18 with foo() as f:
    19     print(f)
    View Code
          结果:
    1 enter
    2 None
    3 exit
    4 -----------------------------
    5 enter
    6 5
    7 exit
    View Code

      






    只要后面能加括号就能调用!!!!!!

    inspect他看一下类的签名,可调用对象才有签名
      ⑨、反射:
        概念:
          运行时区别于编译时,指的是程序被加载到内存中执行的时候。
          反射,reflection,指的是运行时获取类型定义信息。
          一个对象能够在运行时,能够像照镜子一样,反射出其类型信息。
          简单说在Python中,能够通过一个对象,找出其type,class,attribute,或method的能力
          称为反射或者自省
          具有反射能力的函数有,type(), isinstance(),callable(),dir(),getattr()
       编译时:

       运行时:
            解释器直接运行,或者 转换为.exe 文件直接运行。

        反射相关的函数和方法:
          需求:有一个Point类,查看他的属性,并修改它,动态为实例增加属性
          测试:
     1 ########################################### 简单的使用内建函数 ####################################
     2 class Point:
     3     def __init__(self, x, y):
     4         self.x = x
     5         self.y = y
     6 
     7     def __str__(self):
     8         return 'Point {}, {}'.format(self.x, self.y)
     9 
    10 p = Point(4, 5)
    11 print(p)
    12 print(p.__dict__)
    13 p.__dict__['y'] = 16
    14 print(p.__dict__)
    15 print(dir(p)) #  拿到的都是字符串
    16 print(p.__dir__())
    17 
    18 print('-' * 40)
    19 for n in dir(p):
    20     print(getattr(p, n)) # p.n的意思,但是n是字符串,只不过通过点调用不用加引号
    21     print()
    22 
    23 print('-' * 40)
    24 if hasattr(p, 'x'):
    25     print(getattr(p, 'y'))
    26 
    27 print(getattr(p, 'o', 100000))# 如果没有可以提供一个默认值
    28 
    29 setattr(p, 'b', 1000)
    30 print(p.__dict__)
    内建函数基本测试

          结果:

     1 D:python3.7python.exe E:/code_pycharm/code_test_daye/a测试.py
     2 Point 4, 5
     3 {'x': 4, 'y': 5}
     4 {'x': 4, 'y': 16}
     5 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y']
     6 ['x', 'y', '__module__', '__init__', '__str__', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
     7 ----------------------------------------
     8 <class '__main__.Point'>
     9 
    10 <method-wrapper '__delattr__' of Point object at 0x0000000001D65400>
    11 
    12 {'x': 4, 'y': 16}
    13 
    14 <built-in method __dir__ of Point object at 0x0000000001D65400>
    15 
    16 None
    17 
    18 <method-wrapper '__eq__' of Point object at 0x0000000001D65400>
    19 
    20 <built-in method __format__ of Point object at 0x0000000001D65400>
    21 
    22 <method-wrapper '__ge__' of Point object at 0x0000000001D65400>
    23 
    24 <method-wrapper '__getattribute__' of Point object at 0x0000000001D65400>
    25 
    26 <method-wrapper '__gt__' of Point object at 0x0000000001D65400>
    27 
    28 <method-wrapper '__hash__' of Point object at 0x0000000001D65400>
    29 
    30 <bound method Point.__init__ of <__main__.Point object at 0x0000000001D65400>>
    31 
    32 <built-in method __init_subclass__ of type object at 0x0000000000482AC8>
    33 
    34 <method-wrapper '__le__' of Point object at 0x0000000001D65400>
    35 
    36 <method-wrapper '__lt__' of Point object at 0x0000000001D65400>
    37 
    38 __main__
    39 
    40 <method-wrapper '__ne__' of Point object at 0x0000000001D65400>
    41 
    42 <built-in method __new__ of type object at 0x000007FEE0208EC0>
    43 
    44 <built-in method __reduce__ of Point object at 0x0000000001D65400>
    45 
    46 <built-in method __reduce_ex__ of Point object at 0x0000000001D65400>
    47 
    48 <method-wrapper '__repr__' of Point object at 0x0000000001D65400>
    49 
    50 <method-wrapper '__setattr__' of Point object at 0x0000000001D65400>
    51 
    52 <built-in method __sizeof__ of Point object at 0x0000000001D65400>
    53 
    54 <bound method Point.__str__ of <__main__.Point object at 0x0000000001D65400>>
    55 
    56 <built-in method __subclasshook__ of type object at 0x0000000000482AC8>
    57 
    58 None
    59 
    60 4
    61 
    62 16
    63 
    64 ----------------------------------------
    65 16
    66 100000
    67 {'x': 4, 'y': 16, 'b': 1000}
    68 
    69 Process finished with exit code 0
    结果

          测试2:给实例,类分别动态添加属性

     1 class Point:
     2     def __init__(self, x, y):
     3         self.x = x
     4         self.y = y
     5 
     6 setattr(Point, 'show', lambda self:print(self.x, self.y)) # 定义一个类属性
     7 
     8 p = Point(4, 5)
     9 
    10 p.show() # 或者
    11 getattr(p, 'show')()
    12 
    13 setattr(p, 'show', lambda self:print(self, '---------'))# 在实例上定义了一个方法
    14 getattr(p, 'show')(p) # p.show(p) # 可以看出,定义在实例上,没有绑定实例需要手动传入
    测试2

          结果2:

    1 D:python3.7python.exe E:/code_pycharm/code_test_daye/a测试.py
    2 4 5
    3 4 5
    4 <__main__.Point object at 0x0000000002978320> ---------
    5 
    6 Process finished with exit code 0
    结果2

           这种动态增加属性的方式 和装饰器修饰一个类,Mixin方式的差异

         装饰器和Mixin 定义时决定,而且不能修改实例属性而反射,可以运行时定义,修改类 或 实例的属性。

         装饰器在定义时,加载到内存中的时候,就已经将原函数修饰了

         Mixin类,是一种继承类,需要之前就定义好。对一些方法增强或者覆盖掉了。

         这种动态增删属性的方式,是运行时改变类或者实例的方式。
      
          因此,反射能力具有更大的灵活性。
      
          在 if __name__ == '__main__': 下面可以对类进行属性的增删,但是添加装饰器??Mixin类??肯定不行啊!!!!

        举例:使用类封装实现一个命令分发器:
     1 ########################### 命令分发器#################################
     2 # 简单实现 函数注册,并且传入参数
     3 class Dispatcher:
     4     def __init__(self):
     5         pass
     6 
     7     def reg(self, cmd, fn):
     8         setattr(self, cmd, fn)
     9 
    10     def run(self, *args, **kwargs):
    11         while True:
    12             cmd = input('>>>').strip()
    13             if cmd == '':
    14                 break
    15             else:
    16                 getattr(self, cmd, lambda :print('unkonw'))(*args, **kwargs)
    17 
    18 def add(x, y):
    19     print(x + y)
    20 
    21 def sub(x, y):
    22     print(x - y)
    23 
    24 dis = Dispatcher()
    25 dis.reg('add', add)
    26 dis.reg('sub', sub)
    27 dis.run(4, y = 5)
    28 
    29 # # 实现函数注册,并且传入参数
    30 class Dispatcher:
    31     def __init__(self):
    32         # self.commands = {}
    33         pass
    34 
    35     def reg(self, cmd):# 风险,万一人家实例本身有相同的属性名,这样就会冲突,覆盖,最好的方式是使用一个字典存
    36         def wrapper(fn):
    37             setattr(self, cmd, fn)
    38             return fn
    39         return wrapper
    40 
    41     def run(self, *args, **kwargs):
    42         while True:
    43             cmd = input('>>>').strip()
    44             if cmd == '':
    45                 break
    46             else:
    47                 getattr(self, cmd, lambda :print('unkonw'))(*args, **kwargs)
    48 
    49 dis = Dispatcher()
    50 
    51 # 这样的话,加载的时候,函数已经被注册进去了,运行的时候,根据cmd直接调用
    52 @dis.reg('add') # add = dis.reg('add')(add)
    53 def add(x, y):
    54     print(x + y)
    55 
    56 @dis.reg('sub') # add = dis.reg('add')(add)
    57 def sub(x, y):
    58     print(x - y)
    59 
    60 dis.run(4, y = 5)
    类,实现命令分发器
    
    
    
        反射相关的魔术方:都是实例相关的与类没有关系 self
           __getattr__, __setattr__, __delattr__

          单独使用__getattr__:


            测试 :__setattr__


            容易犯的递归调用!!!!!!!!!!!!
      


                正常使用:只要是 点 属性的方式,都会到__setattr__设置,包括等价方式setattr(self, 'y', y) #self.y = y
      
                比较灵活的使用:

              
           测试: __delattr__的使用:


          测试:__getattribute__



          总结:

          
          属性查找顺序:(没有描述器)
             实例调用__getattribute__() ---> instance.__dict__ ---> instance.__class__.__dict__
             ---> 继承的祖先类(直到object)的__dict__ ——> 最后调用__getattr__()

              当找不到属性后,没有__getattr__就抛异常,有,就先不抛,进入,处理之后,如果不需要抛,那就不会再抛异常,如果没处理了,异常抛出去,结束属性查找

        *** 前后都有下划线,解释器管的


        ⑩、描述器:Descriptors
          描述器的表现:
        用到三个方法:__get__() __set__(), __delete__()
           测试: 只测get,而且x都是作为类属性来测试

     1 class A:
     2     def __init__(self):
     3         print('A() init')
     4         self.a1 = 100
     5 
     6     def __get__(self, instance, owner):
     7         print('****************************')
     8         print(1, self)
     9         print(1, instance)
    10         print(1, owner)
    11         print('****************************')
    12 
    13         return self
    14 
    15     def __set__(self, instance, value):
    16         print('****************************')
    17         print(2, self)
    18         print(2, instance)
    19         print(2, value)
    20         print('****************************')
    21 
    22     def __delete__(self, instance):
    23         print(3, self)
    24         print(3, instance)
    25 
    26     def __repr__(self):
    27         return '<A 实例 {}>'.format(self.a1)
    28 
    29 class B:
    30     x = A()
    31     def __int__(self):
    32         print('B() init')
    33 
    34 print(B.x) # 就会触发__get__
    35 print(B.x.a1)
    36 
    37 print('---' * 50)
    38 b = B()
    39 print(b.x)
    40 print(b.x.a1)
    只测get
           结果:
     1 D:python3.7python.exe E:/code_pycharm/code_test_daye/a测试.py
     2 A() init
     3 ****************************
     4 1 <A 实例 100>
     5 1 None
     6 1 <class '__main__.B'>
     7 ****************************
     8 <A 实例 100>
     9 ****************************
    10 1 <A 实例 100>
    11 1 None
    12 1 <class '__main__.B'>
    13 ****************************
    14 100
    15 ------------------------------------------------------------------------------------------------------------------------------------------------------
    16 ****************************
    17 1 <A 实例 100>
    18 1 <__main__.B object at 0x0000000002938400>
    19 1 <class '__main__.B'>
    20 ****************************
    21 <A 实例 100>
    22 ****************************
    23 1 <A 实例 100>
    24 1 <__main__.B object at 0x0000000002938400>
    25 1 <class '__main__.B'>
    26 ****************************
    27 100
    28 
    29 Process finished with exit code 0
    View Code
          

           测试: 非数据描述器
     1 ###非数据描述器
     2 class A:
     3     x = 1000000000
     4     def __init__(self):
     5         print('A() init')
     6         self.a1 = 100
     7 
     8     def __get__(self, instance, owner):
     9         print('****************************')
    10         print(1, self)
    11         print(1, instance)
    12         print(1, owner)
    13         print('****************************')
    14         # return self
    15 
    16     # def __set__(self, instance, value):
    17     #     print('\\\\\\\\\\\\\\\')
    18     #     print(2, self)
    19     #     print(2, instance) # B的实例
    20     #     print(2, value)
    21     #     print('\\\\\\\\\\\\\\\')
    22 
    23     def __repr__(self):
    24         return '<A 实例 {}>'.format(self.a1)
    25 
    26 class B:
    27     x = A()
    28     def __init__(self):
    29         print('B() init')
    30         self.x = 1000
    31 
    32 b = B()
    33 print(b.__dict__)
    34 print(B.__dict__)
    35 
    36 print(b.x) # 实例的x
    37 
    38 print(B.x) # 类的x
    39 
    40 非数据描述器,如果类访问 类属性,直接跳到 描述器的get
    41 如果实例调用 ,先找自己有没有,没有在找 类的, 再跳到描述器的get
    非数据描述器
           结果:
     1 A() init
     2 B() init
     3 {'x': 1000}
     4 {'__module__': '__main__', 'x': <A 实例 100>, '__init__': <function B.__init__ at 0x0000000002960400>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None}
     5 1000
     6 ****************************
     7 1 <A 实例 100>
     8 1 None
     9 1 <class '__main__.B'>
    10 ****************************
    11 None
    View Code

           测试:数据描述器

     1 ###################数据描述器
     2 
     3 class A:
     4     x = 1000000000
     5     def __init__(self):
     6         print('A() init')
     7         self.a1 = 100
     8 
     9     def __get__(self, instance, owner):
    10         print('****************************')
    11         print(1, self)
    12         print(1, instance)
    13         print(1, owner)
    14         print('****************************')
    15         return self
    16 
    17     def __set__(self, instance, value):
    18         print('\\\\\\\\\\\\\\\')
    19         print(2, self)
    20         print(2, instance) # B的实例
    21         print(2, value)
    22         print('\\\\\\\\\\\\\\\')
    23 
    24     def __repr__(self):
    25         return '<A 实例 {}>'.format(self.a1)
    26 
    27 class B:
    28     x = A()
    29     def __init__(self):
    30         print('B() init')
    31         self.x = 1000
    32         self.__dict__['y'] = 20000
    33 
    34 b = B()
    35 print(b.__dict__)
    36 print(B.__dict__)
    37 
    38 
    39 # 实例:
    40 print(b.x ) # 数据描述器,优先使用描述器的 数据
    41 print(b.y) #不同命,正常访问
    数据描述器

            结果:

     1 A() init
     2 B() init
     3 \\\\\\\
     4 2 <A 实例 100>
     5 2 <__main__.B object at 0x0000000002958400>
     6 2 1000
     7 \\\\\\\
     8 {'y': 20000}
     9 {'__module__': '__main__', 'x': <A 实例 100>, '__init__': <function B.__init__ at 0x0000000002950488>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None}
    10 ****************************
    11 1 <A 实例 100>
    12 1 <__main__.B object at 0x0000000002958400>
    13 1 <class '__main__.B'>
    14 ****************************
    15 <A 实例 100>
    16 20000
    View Code
         总结:
      1. 描述器的定义:
               只实现了get,就是非数据描述器,实现了,get 和 set 或 delete 就是数据描述器

         


          Python中的描述器:
          
            描述器在 Python中应用非常广泛,Python的方法(包括staticmethod() 和classmethod都实现为非数据描述器
            因此,实例可以重新定义和覆盖方法。这允许单个实例获取与同一类的其他实例不同的行为
            
            property() 函数实现为一个数据描述器,因此,实例不能覆盖属性的行为,

        实现了:classmethod(), staticmethod()

     1 ##### staticmethod
     2 class StaticMethod: # 非数据描述器
     3     def __init__(self, fn):
     4         self.fn = fn
     5 
     6     def __get__(self, instance, owner):
     7         return self.fn
     8 
     9 class B:
    10     def __init__(self):
    11         pass
    12 
    13     @StaticMethod # foo = StaticMethod(foo)
    14     def foo():
    15         print('static method')
    16 
    17 
    18 B.foo() # 直接打印
    19 
    20 ############# classmethod
    21 class ClassMethod: # 非数据描述器
    22     def __init__(self, fn):
    23         self.fn = fn
    24 
    25     def __get__(self, instance, owner):
    26         ret =  partial(self.fn, owner)
    27         return ret
    28 
    29 class B:
    30     def __init__(self):
    31         pass
    32 
    33     @ClassMethod # foo = ClassMethod(foo)
    34     def foo(cls):
    35         print('class method')
    36 
    37 
    38 B.foo() # 直接打印
    classmethod,staticmethod

           如果是保护变量,或者 私有变量,直接加到属性列表中

        
















































     

    为什么要坚持,想一想当初!
  • 相关阅读:
    [转]Java compiler level does not match解决方法
    Ubuntu使用MyEclipse闪退的解决办法
    支付宝AR红包引出Python中的PIL小试
    Neural Style学习3——操作
    Neural Style学习2——环境安装
    Neural Style学习1——简介
    mac下需要安装旧 Java SE 6 才能打开程序解决办法
    Linux system 函数的一些注意事项
    关于在android 4.2.2 上运行runlmbench
    linux kernel 字符设备详解
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9672032.html
Copyright © 2020-2023  润新知