2017年7月30日 星期日

[ Python 常見問題 ] How to detect whether a python variable is a function?

Source From Here 
Question 
I have a variable, x, and I want to know whether it is pointing to a function or not
>>> def x(a, b):
... return a + b
...
>>> type(x)


How-To 
If this is for Python 2.x or for Python 3.2+, you can also use callable(). It used to be deprecated, but is now undeprecated, so you can use it again. You can read the discussion here: http://bugs.python.org/issue10518. You can do this with: 
>>> callable(x)
True

If this is for Python 3.x but before 3.2, check if the object has a __call__ attribute. You can do this with: 
>>> hasattr(x, '__call__')
True

The oft-suggested types.FunctionType approach is not correct because it fails to cover many cases that you would presumably want it to pass, like with builtins
>>> import types
>>> isinstance(x, types.FunctionType)
True
>>> isinstance(open, types.FunctionType) // Negative example
False
>>> type(open)

The proper way to check properties of duck-typed objects is to ask them if they quack, not to see if they fit in a duck-sized container. Don't use types.FunctionType unless you have a very specific idea of what a function is. 

Supplement 
Python可調用對象 __call__ 方法的用法分析

2017年7月29日 星期六

[ Python 常見問題 ] argparse option for passing a list as option

Source From Here 
Question 
I am trying to pass a list as an argument to a command line program. Is there an argparse option to pass a list as option? 

How-To 
Use the nargs option or the append option (depending on how you want the user interface to behave). 

nargs: The number of command-line arguments that should be consumed. 
For example: 
- test.py 
  1. #!/usr/bin/env python3  
  2. import argparse  
  3.   
  4. parser = argparse.ArgumentParser()  
  5. # nargs='+' takes 1 or more arguments, nargs='*' takes zero or more.  
  6. parser.add_argument('-l','--list', nargs='+', help=' Set flag', required=True)  
  7. args = parser.parse_args()  
  8. print("Given list: {}".format(args.list))  
Execution output: 
# ./test.py -l 1234 2345 3456 4567 
Given list: ['1234', '2345', '3456', '4567']


action(append): This stores a list, and appends each argument value to the list. 
For example: 
- test_append.py 
  1. #!/usr/bin/env python3  
  2. import argparse  
  3.   
  4. parser = argparse.ArgumentParser()  
  5. # This is useful to allow an option to be specified multiple times.  
  6. parser.add_argument('-l','--list', action='append', help=' Set flag', required=True)  
  7. args = parser.parse_args()  
  8. print("Given list: {}".format(args.list))  
Execution output: 
# ./test_append.py -l 1234 -l 2345 -l 3456 -l 4567 
Given list: ['1234', '2345', '3456', '4567']

Notes. Don't use type=list!!! - There is probably no situation where you would want to use type=list with argparse. Ever. 

Let's take a look in more detail at some of the different ways one might try to do this, and the end result. 
- test_all.py 
  1. #!/usr/bin/env python3  
  2. import argparse  
  3.   
  4. parser = argparse.ArgumentParser()  
  5.   
  6. # By default it will fail with multiple arguments.  
  7. parser.add_argument('--default')  
  8.   
  9. # Telling the type to be a list will also fail for multiple arguments,  
  10. # but give incorrect results for a single argument.  
  11. parser.add_argument('--list-type', type=list)  
  12.   
  13. # This will allow you to provide multiple arguments, but you will get  
  14. # a list of lists which is not desired.  
  15. parser.add_argument('--list-type-nargs', type=list, nargs='+')  
  16.   
  17. # This is the correct way to handle accepting multiple arguments.  
  18. # '+' == 1 or more.  
  19. # '*' == 0 or more.  
  20. # '?' == 0 or 1.  
  21. # An int is an explicit number of arguments to accept.  
  22. parser.add_argument('--nargs', nargs='+')  
  23.   
  24. # To make the input integers  
  25. parser.add_argument('--nargs-int-type', nargs='+', type=int)  
  26.   
  27. # An alternate way to accept multiple inputs, but you must  
  28. # provide the flag once per input. Of course, you can use  
  29. # type=int here if you want.  
  30. parser.add_argument('--append-action', action='append')  
  31.   
  32. # To show the results of the given option to screen.  
  33. for _, value in parser.parse_args()._get_kwargs():  
  34.     if value is not None:  
  35.         print(value)  
Here is the output you can expect: 
# ./test_all.py --default 1234 2345 3456 4567 
usage: test_all.py [-h] [--default DEFAULT] [--list-type LIST_TYPE] 
...
 
test_all.py: error: unrecognized arguments: 2345 3456 4567 

# ./test_all.py --list-type 1234 2345 3456 4567 
... 
test_all.py: error: unrecognized arguments: --list-type 1234 2345 3456 4567 

# ./test_all.py --list-type '1234 2345 3456 4567' // Quotes won't help here... 
['1', '2', '3', '4', ' ', '2', '3', '4', '5', ' ', '3', '4', '5', '6', ' ', '4', '5', '6', '7'] 

# ./test_all.py --list-type-nargs 1234 2345 3456 4567 
[['1', '2', '3', '4'], ['2', '3', '4', '5'], ['3', '4', '5', '6'], ['4', '5', '6', '7']] 

# ./test_all.py --nargs 1234 2345 3456 4567 
['1234', '2345', '3456', '4567'] 

# ./test_all.py --nargs-int-type 1234 2345 3456 4567 
[1234, 2345, 3456, 4567] 

# ./test_all.py --nargs-int-type -1234 2345 -3456 4567 // Negative numbers are handled perfectly fine out of the box. 
[-1234, 2345, -3456, 4567] 

# ./test_all.py --append-action 1234 --append-action 2345 --append-action 3456 --append-action 4567 
['1234', '2345', '3456', '4567']

Takeaways: 
- Use nargs or action='append' 
nargs can be more straightforward from a user perspective, but it can be unintuitive if there are positional arguments because argparse can't tell what should be a positional argument and what belongs to the nargs; if you have positional arguments then action='append' may end up being a better choice. The above is only true if nargs is given '*', '+', or '?'. If you provide an integer number (such as 4) then there will be no problem mixing options with nargs and positional arguments because argparse will know exactly how many values to expect for the option.

- Don't use type=list, as it will return a list of lists 
For request here, this option is not useful here. The unexpected result happens because under the hood argparse uses the value of type to coerce each individual given argument to your chosen type, not to aggregate of all arguments. Instead, You can use type=int (or whatever) to get a list of integers.


[ Python 常見問題 ] What is the difference between @staticmethod and @classmethod in Python?

Source From Here 
Question 
What is the difference between a function decorated with @staticmethod and one decorated with @classmethod? 

How-To 
Maybe a bit of example code will help: Notice the difference in the call signatures of foo, class_foo and static_foo: 
  1. class A(object):  
  2.     def foo(self,x):  
  3.         print "executing foo(%s,%s)"%(self,x)  
  4.   
  5.     @classmethod  
  6.     def class_foo(cls,x):  
  7.         print "executing class_foo(%s,%s)"%(cls,x)  
  8.   
  9.     @staticmethod  
  10.     def static_foo(x):  
  11.         print "executing static_foo(%s)"%x      
  12.   
  13. a=A()  
Below is the usual way an object instance calls a method. The object instance, a, is implicitly passed as the first argument: 
>>> a.foo(1) 
executing foo(,1)

With classmethods, the class of the object instance is implicitly passed as the first argument instead of self: 
>>> a.class_foo(1) 
executing class_foo(,1)

You can also call class_foo using the class. In fact, if you define something to be a classmethod, it is probably because you intend to call it from the class rather than from a class instance. A.foo(1) would have raised a TypeError, but A.class_foo(1) works just fine: 
>>> A.class_foo(1) 
executing class_foo(,1)

One use people have found for class methods is to create inheritable alternative constructors. 

With staticmethods, neither self (the object instance) nor cls (the class) is implicitly passed as the first argument. They behave like plain functions except that you can call them from an instance or the class: 
>>> a.static_foo(1) 
executing static_foo(1) 
>>> A.static_foo(1) 
executing static_foo(1)

Staticmethods are used to group functions which have some logical connection with a class to the class. 

foo is just a function, but when you call a.foo you don't just get the function, you get a "partially applied" version of the function with the object instance a bound as the first argument to the function. foo expects 2 arguments, while a.foo only expects 1 argument. a is bound to foo. That is what is meant by the term "bound" below: 
>>> print(a.foo) 
>

With a.class_foo, a is not bound to class_foo, rather the class A is bound to class_foo. 
>>> print(a.class_foo) 
>

Here, with a staticmethod, even though it is a method, a.static_foo just returns a good 'ole function with no arguments bound. static_foo expects 1 argument, and a.static_foo expects 1 argument too. 
>>> print(a.static_foo) 
 
>>> print(A.static_foo) 


2017年7月27日 星期四

[OO 設計模式] Gossip@DesignPattern : Behavioral - Chain of Responsibility 模式

轉載自 這裡 
前言 : 
如果您有一個應用程式,必須對輸入的字元作不同的處理,例如 : 
  1. char c = 'A';  
  2. if (Character.isLetter(c)) {  
  3.    System.out.println("處理字母資料");  
  4. }  
  5. if (Character.isDigit(c)) {  
  6.    System.out.println("處理數字資料");  
  7. }  
  8. System.out.println("處理符號資料");  
使用結構化的方式,用 if..else 來判斷是否應處理,雖然直覺,壞處是如果要調整處理方式,例如要增加或減少處理方式、調整處理順序等,都必須對程式作出修改

Chain of Responsibility 模式 : 
您可以改為以下的方式 : 
- Handler.java : Handler 的抽象類別, 定義介面 API.
  1. package dp.behavior.chainofresp;  
  2.   
  3. public abstract class Handler {  
  4.     protected Handler next;  
  5.     Handler(Handler next) {  
  6.         this.next = next;  
  7.     }      
  8.     void doNext(char c) {  
  9.         if(next != null) {  
  10.            next.handle(c);  
  11.         }  
  12.     }  
  13.     abstract void handle(char c);  
  14. }  

- SymbolHandler.java : 處理 Symbol 的 Handler.
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class SymbolHandler extends Handler {  
  4.     SymbolHandler(Handler next) {  
  5.         super(next);  
  6.     }  
  7.     void handle(char c) {  
  8.         System.out.printf("(%c)Symbol has been handled!\n", c);  
  9.         doNext(c);  
  10.     }  
  11. }  

- CharacterHandler.java : 處理 Char 的 Handler
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class CharacterHandler extends Handler {  
  4.     CharacterHandler(Handler next) {  
  5.         super(next);  
  6.     }      
  7.     void handle(char c) {  
  8.         if(Character.isLetter(c)) {  
  9.             System.out.printf("\t(%c)Character has been handled!\n", c);   
  10.         }  
  11.         doNext(c);  
  12.     }  
  13. }  

- DigitHandler.java : 處理數字的 Handler
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class DigitHandler extends Handler {  
  4.     DigitHandler(Handler next) {  
  5.         super(next);  
  6.     }      
  7.     void handle(char c) {   
  8.        if(Character.isDigit(c)) {  
  9.             System.out.printf("\t(%c)Digit has been handled!\n", c);   
  10.        }  
  11.        doNext(c);  
  12.     }  
  13. }  

- Main.java : 測試主類別
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class Main {  
  4.     public static void main(String[] args) {  
  5.         Handler handler = new SymbolHandler(  
  6.                             new CharacterHandler(  
  7.                               new DigitHandler(null)));  
  8.         handler.handle('A');  
  9.         handler.handle('1');  
  10.     }  
  11. }  

執行結果 : 
(A)Symbol has been handled!
(A)Character has been handled!
(1)Symbol has been handled!
(1)Digit has been handled!

在上例中,在每個特定處理器物件處理過後,可以決定是否交給下一個物件作處理(如果有的話),您可以自由設定下一個處理器,調整處理的順序等,而不用修改程式! 這是 Chain of Responsibility 模式的一個例子,多個物件都有機會處理請求,除了可以自由組合處理請求的物件之外,也可以避免請求的發送者與接收者之間的耦合關係,將這些物件組合為一個鏈,並沿著這個鏈傳遞該請求,每個物件都可以處理請求與決定是否傳遞給下一個處理物件. 

在組織物件之間的職責時,通常是從細粒度至粗粒度的方式來組織,從特殊到抽象化,就像程式中將數字視為字元的特殊化,字元又為符號的特殊化. Chain of Responsibility 的 UML 結構圖如下所示 : 
 

在更一般的情況下,可以將請求包裝為一個物件,並提供 getType() 之間的方法,以讓 Chain of Responsibility 中的物件進行比對,例如 : 
- Request.java : 請求物件, 可以將請求包裝於此物件進行傳遞.
  1. package dp.behavior.chainofresp;  
  2.   
  3. public abstract class Request {  
  4.     private String type;   
  5.   
  6.     Request(String type) { this.type=type; }  
  7.     String getType() { return type; }  
  8.   
  9.     abstract void execute();  
  10. }  

- Handler.java : 新增處理 Request 物件的 API
  1. package dp.behavior.chainofresp;  
  2.   
  3. public abstract class Handler {  
  4.     protected Handler next;  
  5.       
  6.     Handler(Handler next) {  
  7.         this.next = next;  
  8.     }  
  9.       
  10.     void doNext(Request request)  
  11.     {  
  12.          if(next != null)   
  13.          {  
  14.                next.handle(request);  
  15.          }  
  16.     }  
  17.     void doNext(char c) {  
  18.         if(next != null)   
  19.         {  
  20.            next.handle(c);  
  21.         }  
  22.     }  
  23.     abstract void handle(Request request);  
  24.     abstract void handle(char c);  
  25. }  

- ConcreteHandler.java : 如果請求的類型是 "concrete" 則執行請求並停止 chain, 否則將該請求傳遞下去.
  1. package dp.behavior.chainofresp;  
  2.   
  3. public class ConcreteHandler extends Handler{  
  4.     ConcreteHandler(Handler next) {  
  5.         super(next);  
  6.     }  
  7.   
  8.     @Override  
  9.     void handle(Request request) {  
  10.         if(request.getType().equals("concrete")) {  
  11.             request.execute();  
  12.         }  
  13.         else {  
  14.             doNext(request);  
  15.         }  
  16.     }  
  17.   
  18.     @Override  
  19.     void handle(char c) {  
  20.         doNext(c);  
  21.     }  
  22. }  

在 Gof 的書中所舉的例子為輔助說明系統,在一個介面中希望使用者一定可以得到相關的說明主題,如果子元件有說明的話,就顯示相關說明,否則的話就轉發給 包括它的容器元件或父元件,以保證使用者的輔助說明請求一定可以得到回應. 

Supplement 
Tutorialspoint - Chain of Responsibility Pattern

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...