Python基础2:反射、装饰器、JSON,接口

一、反射

  最近接触到python的反射机制,遂记录下来已巩固。但是,笔者也是粗略的使用了__import__, getattr()函数而已。目前,笔者的理解是,反射可以使用户通过自定义输入来导入响应的module、class等。下面以一个例子说明。

  文件目录如下,

    

      

  reflection文件夹下有Car module,现在main.py下通过反射机制导入Car module.

  Car.py源码如下:

 1 class Car(object):
 2     def __init__(self, name, color, tire, engine):
 3         self.name = name
 4         self.color = color
 5         self.tire = tire
 6         self.__engine = engine
 7     def run(self):
 8         print '{} runs at the street.'.format(self.name)
 9     def stop(self):
10         print '{} stops running.'.format(self.name)
11 
12 class Audi(Car):
13     def __init__(self, name, color, tire, engine):
14         super(Audi, self).__init__(name, color, tire, engine)
View Code

  main.py源码如下: 

 1 #from reflection import Car
 2 #from reflection.Car import *
 3 
 4 string = raw_input('Please input import module(xxx/xxx):')
 5 path = string.split('/')
 6 namespace = __import__('reflection.'+path[0])
 7 module = getattr(namespace, path[1])
 8 Audi = getattr(module, 'Audi')
 9 print namespace
10 print module
11 print Audi
12 
13 
14 my_audi = Audi('A7', 'red', 4, 'wolun')
15 my_audi.run()
View Code

  首先,main中1,2行是一般的导入模式。然后,让用户输入需导入的模块(字符串),通过__import__函数导入module,通过getattr()函数得到module的class,方法等。运行main.py,输入Car/Car,意在导入module Car。运行结果如下,

1 Please input import module(xxx/xxx):Car/Car
2 <module 'reflection' from 'f:\Python\Wing\reflection\reflection\__init__.pyc'>  #print namespace
3 <module 'reflection.Car' from 'f:\Python\Wing\reflection\reflection\Car.py'>    #print module
4 <class 'reflection.Car.Audi'>                              #print Audi
5 A7 runs at the street.

  输出结果很清楚的显示了__import__,getattr()的功能。对于反射机制,笔者也是简单的了解到这些。

二、super

  关于super,首先要注意的是,super并非是一个函数,而是一个类(PySuper_Type)。在bltinmodule.c中有这么一条语句:

 SETBUILTIN("super",  &PySuper_Type);

  然后,在python documention中有这样一段描述:

 Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have  been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

 The __mro__ attribute of the type lists the method resolution search order used by both getattr() and super(). The attribute is dynamic and can c hange whenever the inheritance hierarchy is updated.

 If the second argument is omitted, the super object returned is unbound. If the second argument is an object, isinstance(obj, type) must be true. If the second argument is a type, issubclass(type2, type) must be true (this is useful for classmethods).

  下面,以一个例子来简单说明super是如何实现多继承的。

 1 class A(object):
 2    def __init__(self):
 3     print "enter A"
 4     super(A, self).__init__()  # new
 5     print "leave A"
 6 
 7  class B(object):
 8    def __init__(self):
 9     print "enter B"
10     super(B, self).__init__()  # new
11     print "leave B"
12 
13  class C(A):
14    def __init__(self):
15     print "enter C"
16     super(C, self).__init__()
17     print "leave C"
18 
19  class D(A):
20    def __init__(self):
21     print "enter D"
22     super(D, self).__init__()
23     print "leave D"
24   class E(B, C):
25    def __init__(self):
26     print "enter E"
27     super(E, self).__init__()  # change
28     print "leave E"
29 
30  class F(E, D):
31    def __init__(self):
32     print "enter F"
33     super(F, self).__init__()  # change
34     print "leave F"
35 
36  >>> f = F()
37 
38  enter F
39  enter E
40  enter B
41  enter C
42  enter D
43  enter A
44  leave A
45  leave D
46  leave C
47  leave B
48  leave E
49  leave F
View Code

  可以清楚的看到,F的初始化不仅完成了所有的父类的调用,而且保证了每一个父类的初始化函数只调用一次。关于深度探索super的用法,下面两篇文章值得推荐。

  http://www.jb51.net/article/66912.htm

  https://rhettinger.wordpress.com/2011/05/26/super-considered-super/

三、装饰器

  1、对带参数的函数进行装饰

 1 def deco(func):  
 2     def _deco(a, b):  
 3         print("before myfunc() called.")  
 4         ret = func(a, b)  
 5         print("  after myfunc() called. result: %s" % ret)  
 6         return ret  
 7     return _deco  
 8  
 9 @deco  
10 def myfunc(a, b):  
11     print(" myfunc(%s,%s) called." % (a, b))  
12     return a + b  
13   
14 myfunc(1, 2)  
15 myfunc(3, 4) 
View Code

  2、对参数数量不确定的函数进行装饰  

 1 def deco(func):  
 2     def _deco(*args, **kwargs):  
 3         print("before %s called." % func.__name__)  
 4         ret = func(*args, **kwargs)  
 5         print("  after %s called. result: %s" % (func.__name__, ret))  
 6         return ret  
 7     return _deco  
 8  
 9 @deco  
10 def myfunc(a, b):  
11     print(" myfunc(%s,%s) called." % (a, b))  
12     return a+b  
13  
14 @deco  
15 def myfunc2(a, b, c):  
16     print(" myfunc2(%s,%s,%s) called." % (a, b, c))  
17     return a+b+c  
18   
19 myfunc(1, 2)  
20 myfunc(3, 4)  
21 myfunc2(1, 2, 3)  
22 myfunc2(3, 4, 5) 
View Code

  3、装饰器带参数

 1 def deco(arg):  
 2     def _deco(func):  
 3         def __deco():  
 4             print "before {} called [{}]." .format(func.__name__, arg)
 5             func()  
 6             print "  after {} called [{}].".format(func.__name__, arg)
 7         return __deco  
 8     return _deco  
 9  
10 @deco("module1")  
11 def myfunc():  
12     print " myfunc() called."
13  
14 @deco("module2")  
15 def myfunc2():  
16     print " myfunc2() called."
17   
18 myfunc()  
19 myfunc2()
View Code

  4、装饰器带 类 参数

 1 #! coding = utf-8
 2 class locker:  
 3     def __init__(self):  
 4         print "locker.__init__() should be not called."
 5          
 6     @staticmethod  
 7     def acquire():  
 8         print "locker.acquire() called.(这是静态方法)"
 9          
10     @staticmethod  
11     def release():  
12         print "  locker.release() called.(不需要对象实例)"
13   
14 def deco(cls):  
15     '''''cls 必须实现acquire和release静态方法'''  
16     def _deco(func):  
17         def __deco():  
18             print "before {} called [{}].".format(func.__name__, cls)  
19             cls.acquire()  
20             try:  
21                 return func()  
22             finally:  
23                 cls.release()  
24         return __deco  
25     return _deco  
26  
27 @deco(locker)  
28 def myfunc():  
29     print " myfunc() called."
30   
31 myfunc()  
View Code

  值得注意的是,类虽然作为了装饰器的参数,但是没有instance,那么__init__()方法不会被执行。

  5、装饰器带类参数,并分拆公共类到其他py文件中,同时演示了对一个函数应用多个装饰器 

 1 '''
 2 mylocker.py ,prepare for the deco.py
 3 '''
 4 class mylocker:  
 5     def __init__(self):  
 6         print "mylocker.__init__() called."
 7          
 8     @staticmethod  
 9     def acquire():  
10         print "mylocker.acquire() called."
11          
12     @staticmethod  
13     def unlock():  
14         print "  mylocker.unlock() called."
15   
16 class lockerex(mylocker):  
17     @staticmethod  
18     def acquire():  
19         print "lockerex.acquire() called."
20          
21     @staticmethod  
22     def unlock():  
23         print "  lockerex.unlock() called."
24   
25 def lockhelper(cls):  
26     '''cls must instance 'acquire' and 'release' static methods'''  
27     def _deco(func):  
28         def __deco2(*args, **kwargs):  
29             print "before {} called." .format(func.__name__)  
30             cls.acquire()  
31             try:  
32                 return func(*args, **kwargs)  
33             finally:  
34                 cls.unlock()  
35         return __deco2  
36     return _deco 
View Code
 1 '''
 2 deco.py
 3 装饰器带类参数,并分拆公共类到其他py文件(mylocker.py)中 
 4 同时演示了对一个函数应用多个装饰器
 5 '''  
 6   
 7 from mylocker import *  
 8   
 9 class example:  
10     @lockhelper(mylocker)  
11     def myfunc(self):  
12         print " myfunc() called."
13  
14     @lockhelper(mylocker)  
15     @lockhelper(lockerex)  
16     def myfunc2(self, a, b):  
17         print " myfunc2() called."
18         return a + b  
19   
20 if __name__=="__main__":  
21     a = example()  
22     #a.myfunc()
23     #print '---------------------------------------------------------'
24     #print a.myfunc()
25     #print '---------------------------------------------------------'
26     #print a.myfunc2(1, 2)
27     #print '---------------------------------------------------------'
28     print a.myfunc2(3, 4)
View Code

  不过,注意到这段程序的输出: 

before __deco2 called.
mylocker.acquire() called.
before myfunc2 called.
lockerex.acquire() called.
 myfunc2() called.
  lockerex.unlock() called.
  mylocker.unlock() called.
7

  为什么有“before __deco2__ called”??这段输出给我的感觉就是,mylocker装饰了__deco2(),而lockerex装饰了myfunc2().是这样理解的么??

四、pickle & json

  pickle & json 都可以存储数据到硬盘,供程序交互。不过,pickle是python特有的,json可以为不同语言所共有。所以,json用得更普遍。下面这个例子分别用pickle,json 来dump,load  & dumps,loads 数据。

 1 import pickle
 2 import json
 3 
 4 mydict = {'name': 'python', 'age': 27, 'height': 178, 'weight': 140}
 5 #pickle dumps, loads
 6 res = pickle.dumps(mydict)
 7 print res
 8 loadres = pickle.loads(res)
 9 print loadres
10 print '----------------------------------------------------------'
11 #pickle dump,load
12 pickle.dump(mydict, open('C:\Users\Administrator\Desktop\jason.txt', mode='w'))
13 loadres = pickle.load(open('C:\Users\Administrator\Desktop\jason.txt', mode='r'))
14 print loadres
15 print '----------------------------------------------------------'
16 #json dumps,loads
17 jsonres = json.dumps(mydict, skipkeys=False, ensure_ascii=True, 
18                     check_circular=True, allow_nan=True, 
19                     cls=None, indent=None, 
20                     separators=None, encoding='utf-8', 
21                     default=None)
22 print jsonres
23 load_json_res = json.loads(jsonres, encoding=None, cls=None, object_hook=None, 
24                           parse_float=None, 
25                           parse_int=None, 
26                           parse_constant=None, 
27                           object_pairs_hook=None)
28 print load_json_res
29 print '----------------------------------------------------------'
30 #json dump,load
31 json.dump(mydict, open('C:\Users\Administrator\Desktop\jason.txt', mode='w'), skipkeys=False, ensure_ascii=True, check_circular=True, 
32          allow_nan=True, cls=None, indent=None, separators=None, 
33          encoding='utf-8', default=None)
34 fileres = json.load(open('C:\Users\Administrator\Desktop\jason.txt', 'r'), encoding=None, cls=None, object_hook=None, 
35                    parse_float=None, parse_int=None, 
36                    parse_constant=None, 
37                    object_pairs_hook=None)
38 print fileres
View Code

五、接口

  在类的定义中用abc.ABCMeta作为metaclass写自己的抽象基类。示例代码如下: 

 1 from abc import ABCMeta, abstractmethod
 2 class interface(object):    #这里填不填object????
 3     __metaclass__ = ABCMeta
 4     
 5     @abstractmethod
 6     def show(self):
 7         pass
 8     
 9 class Fighting(interface):
10     def __init__(self, message):
11         self.message = message
12         
13     def show(self):
14         Fighting.mystatic()
15         print 'overwrite the function of show in interface'
16     def __str__(self):
17         return self.message
18     @staticmethod
19     def mystatic():
20         print 'call static method in class'
21         
22 class MyException(Exception):
23     def __init__(self, message):
24         self.message = message
25     def __str__(self):
26         return self.message
27 
28 try:
29     input_message = raw_input('Please input the fighting message:')
30     f = Fighting(input_message)
31     print f
32     f.show()
33     string = f.__str__()
34     if 'Any questions?' == string:
35         raise MyException("No thanks!")
36     else:
37         print 'You are a good man.'
38 except MyException, e :
39     print e
40 finally:
41     print 'finally must be called.'
View Code

  更多关于abc module,在python documention中讲解的很清楚。abc.ABCMeta,abc.abstractmethod,abc.abstractproperty等...

六、property

  property,笔者理解为class的一个特性吧。先以一段示例程序,看看property是如何工作的。

 1 class Car(object):
 2     
 3     company = 'aodi'
 4     __engine = 'wolunzengya'
 5     def __init__(self, name, color, style):
 6         self.name = name
 7         self.color = color
 8         self.__style = style
 9     def start(self):
10         print self.name + ' run the road.'
11     def stop(self):
12         print self.name + ' stop the engine.'
13     
14     @staticmethod
15     def engine():
16         print 'we all have engines.'
17     @property
18     def Car_company(self):
19         print 'Our company is {},engine is {} '.format(Car.company, Car.__engine)
20     def __changeEngine():
21         Car.__engine = 'shuangwolunzengya'
22     
23     @property
24     def style(self):
25         return self.__style
26     @style.setter
27     def style(self, value):
28         self.__style = value
29     
30     @property   
31     def haha(self):
32         return self.color
33     
34     def __call__(self):
35         print '{}\'s call method is called.'.format(self.name)
36         
37 aodi_a6 = Car('a6', 'white', 'tesila')
38 
39 print aodi_a6.style
40 aodi_a6.style = 'bujiadi'
41 print aodi_a6.style
42 print
43 
44 print aodi_a6.haha  #notian that the function 'haha' has no parathinese'()'
45 aodi_a6.haha = 'red'  #tips: 新式类不可以在这里赋值,旧式类可以
46 print aodi_a6.haha
47 
48 aodi_a6()
View Code

  在上述程序中,如果Car(object)为新式类,将会产生AttributeError: can't set attribute.产生这个错误的语句在:aodi_a6.haha = 'red'。。如果使用新式类,就要使用@XXX.setter 标记函数,达到赋值效果。如程序中的style方法:

@property
    def style(self):
        return self.__style
@style.setter
    def style(self, value):
        self.__style = value

  再提一下,调用@property修饰的方法,不加()。

  静下心来博客,也理清了自己的思路,坚持~

  

  

 

转载于:https://www.cnblogs.com/letgo/p/5326758.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值