程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

提問:Java中的注解與Python中的裝飾器是一回事嗎?

編輯:Python

寫在前面

早上剛到公司,吃早點過程中,被群裡這樣一個問題所吸引,如下圖所示:

後來自己就又想了想,感覺自己說的也不全對,於是想從程序角度來做一個佐證。

當然,在寫這篇文章之前,也是查閱了很多文章,關於這個問題的一些觀點,匯總如下:

  • Java 注解也叫元數據,一種代碼級別的說明。Python 裝飾器是一種語法糖。
  • 注解是給別人看的,功能不僅僅由注解決定;裝飾器直接攔截,直接改變被裝飾對象的行為!
  • 注解(Annotation):僅提供附加元數據支持,並不能實現任何操作。需要另外的 Scanner 根據元數據執行相應操作。
  • 裝飾器(Decorator):僅提供定義劫持,能夠對類及其方法的定義並沒有提供任何附加元數據的功能。

講真這些概念性的東西,我是真的看的雲裡霧裡的,建議還是看維基百科或者教材吧。

我個人觀點,肯定是注解和裝飾器不是一回事的。

話不多說,還是直接上代碼,用實際案例來說話吧!

一、表現形式上看

@zhujie('參數')

1、相同點:

都是@開頭,注解、裝飾器都可以自定義、都可以帶參數、都可以被標注代碼塊之前執行。

2、不同點:

  • java注解可以寫在類、方法、變量頭上;
  • python裝飾器可以寫在類、方法頭上。

二、實例對比

1、Java注解

示例代碼如下:

 @Override
public String toString() {
return "PlaylistInfo{" +
"curtime='" + curtime + '\'' +
", issmarter='" + issmarter + '\'' +
", xmusicnum='" + xmusicnum + '\'' +
", picurl=" + picurl +
", playlist=" + playlist +
", systemtime=" + systemtime +
'}';
}

@Override: 重寫的意思,不滿意父類的可以自己在實現下,一般在編譯階段會對方法進行檢查。

很明顯,注解放在方法上方,僅負責編譯、檢查,並未對方法中的內容和該方法的功能做出改變。

2、python裝飾器

實例代碼如下:

class TestClass():
@property
def myValue(self):
return self.value
if __name__=="__main__":
TestClass.myValue = '裝飾器呀!'
print (TestClass.myValue)

@property: 作為屬性的意思

明顯看出,裝飾器直接改變了函數的功能。

3、結論

由上得出,注解和裝飾器的不同:

  • 1、注解對只是干了檢查、校驗的事,不會修改所標注的代碼。
  • 2、裝飾器可以在方法標注,並改變所修飾的代碼功能。

到這裡,你是不是會覺得,他倆根本就不是一回事,因為根本不是一樣的呀。

其實,在java中的注解和反射可以實現python裡裝飾器的效果。

是不是又蒙了?別急,我們接著往後看!

二、注解實現上看

注解的好處:在不改動源代碼的基礎上,對源代碼實現新功能。如果有大面積代碼需要改動同樣功能,可以在方法或者類上面使用注解實現

1、實現的注解場景

分別用python與Java方式,實現對程序計算的校驗,把異常結果寫到error.log文件中

2、Python方式實現

實例代碼如下:

# 此時就是作為寫入錯誤結果使用
def check(func):
def wrapper(*args, **kwargs):
try:
res = func(*args, **kwargs)
return res
except Exception as err:
with open("error.log", mode="at", encoding='utf-8') as f:
f.write("start".center(50, '*'))
f.write('\n')
f.write(str(func))
f.write('\n')
f.write(str(err.__class__))
f.write('\n')
f.write("end".center(50, '*'))
f.write('\n')
return wrapper
@check
def add(a, b):
print(a + b)
@check
def divide(a, b):
print(a / b)
add(50, 50)
divide(100, 0)

3、Java方式實現

示例代碼如下:

public class Calculator {
@Check
public void add() {
System.out.println(50 + 50);
}
@Check
public void divide() {
System.out.println(100 / 0);
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
}

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
public class CheckDemo {
public static void main(String[] args) throws IOException {
Calculator test = new Calculator();
Class<? extends Calculator> c = test.getClass();
Method[] methods = c.getMethods();
BufferedWriter bw = new BufferedWriter(new FileWriter("input.txt"));
for (Method m :
methods) {
if (m.isAnnotationPresent(Check.class)) {
try {
m.invoke(test);
} catch (Exception e) {
bw.newLine();
bw.write(e.getCause().getMessage()+"----");
bw.newLine();
bw.write(String.valueOf(e.getCause().getClass()));
}
}
}
bw.flush();
bw.close();
}
}

分別運行各自編譯器,結果如下圖所示:

4、結論

由上可知,Java中的注解和反射可以實現python裡裝飾器的效果。

三、來個接口開發的例子

1、需求場景

輸入用戶密碼,返回用戶信息接口

2、Python方式實現

示例代碼如下:

from flask import Flask
import json
from flask import request
app = Flask(__name__) #啟動
@app.route('/rongrong/getUserInfo',methods=['GET']) #請求路徑、請求方式
def login():
username = request.args.get("username") #獲取url中參數“username”的值
password = request.args.get("password") #獲取url中參數“password”的值
if username and password: #如果傳入了值為真打印下面信息
data = json.dumps({
"username":username,
"password":password,
"code":"200",
"message":"成功"
},ensure_ascii=False) #解決中文亂碼問題
else: #如果傳參為空打印下面信息
data = json.dumps({
"message":"請傳遞參數"
},ensure_ascii=False)
return data
if __name__ == "__main__":
app.run() #運行

3、Java方式實現

示例代碼如下:

 @RequestMapping(value = "/rongrong/getUserInfo", method = RequestMethod.GET)
public Result<List<Student>> findStudentByName(HttpServletRequest request) {
String username = request.getParameter("username");
String password = request.getParameter("password");
JsonRootBean jsonRootBean = new JsonRootBean();
jsonRootBean.setUsername(username);
jsonRootBean.setPassword(password);
jsonRootBean.setCode("200");
jsonRootBean.setMessage("成功");
Result result = ResultUtils.success(jsonRootBean);
return result;
}

4、啟動各自服務,運行結果如下:

python結果:

Java結果:

5、結論

Python的裝飾器很單一,就是通過一層殼對一個函數的行為進行修飾,而@decorator_func 只是一個語法糖,用以美化裝飾器的寫法。
Java中的注解則不同,它是從語言層面為代碼中的類,函數,字段增加一些運行時可以讀到的元數據,而注解的提供者要在運行時對這些元數據進行讀取,並做相應的處理。

四、寫在最後

筆者才疏學淺,寫這篇文正完全是出於技癢,自然也是查閱了大量文章,才有此文。

以下內容僅代表個人觀點:

  • 長得像,但卻是兩個物種,不過可以讓他們表現得近似;
  • Python 的裝飾器正如他的名稱,很直白,就是實現了裝飾器模式(的一個語法糖)。@部分對應一個返回為函數的函數,可以對目標函數進行輸入、輸出過濾,以及其他干預、包裝;
  • Java 的注解有好幾種,按作用期劃分有編譯期、運行期等,僅僅是給類或方法做個標記,在對應的時期你的程序可以通過反射讀到它們;
  • Java 的注解表面看似乎沒啥子用,但少就是多,稍微包裝一下就可以實現與 Python 裝飾器等同的作用,前提是通過什麼方式調用目標類和方法,只要調用的包裝內對注解進行了解釋,就 OK 了;

通過各種手段可以讓他們變成一回事兒,所以就結果而言,沒錯,可以當成是一回事兒。

換句話說,有時候感覺裝飾器更像是Java的一種設計模式。

你覺得呢?歡迎評論區留言討論!


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved