Java 帝国对 Python 的渗透能成功吗?
提示您,本文原题为 -- Java 帝国对 Python 的渗透能成功吗?
作者 | 刘欣
责编 | 屠敏
本文经授权转载自码农翻身( ID:coderising)
引子
Java 帝国已经成立20多年 , 经过历代国王的励精图治 , 可以说是地大物博 , 码农众多 。
可是国王依然不满足 , 整天想着如何继续开拓疆土 , 这一天晚上他又把几个重臣招来商议了 。
IO大臣说:“陛下 , 现在天下大势初定 , 我Java帝国已经占据了后端开发 , 大数据 , Android开发等重要地盘 , 再想拓展殊为不易!”
“是啊 , 前端被Java所盘踞 , 我们很难渗透啊 。 ” 线程大臣补充 。
国王点点头 , 这话不错 , Java一统前端 , Flash消失了 , Applet不见了 。 想到Applet , 国王就一阵心痛 , 当时Java是靠了Applet才引起码农的关注 , 一炮走红 , 后来怎么就不行了呢?
“那人工智能呢?” 国王狠狠地问道 。
“陛下明鉴 , 人工智能底层都是C/C++的地盘 , 应用层被Python等所侵占 。 ” JDBC大臣回答 。
“云计算呢?”
“似乎是Go语言的地盘 。 ”
“嘶——” 国王觉得有点牙疼 。
IO大臣赶紧为君主分忧:“陛下 , 现在群雄涿鹿 , 八分天下 , 边境战火连年不息 , 陛下不仅维持住祖宗的基业 , 还有不小的扩展 , 已经是一代圣主了 , 不过多年征战 , 民力维艰 , 老臣有一计 , 也许能换来奇效 。 ”
“爱卿快讲!”
“老臣以为不战而屈人之兵才是上策 , 作为世界最强之王国 , 不仅要武力上震慑群雄 , 更要输出我堂堂Java帝国之文化和价值观 。 ”
“什么文化和价值观?”
“首先我们要大肆宣扬静态语言的种种好处 , 比如编译期检查发现错误 , 代码适合阅读和维护 , 适合大规模团队合作 , 口号我都想好了 , 就叫‘动态一时爽 , 重构火葬场!’ ”
“嗯 , 这口号不错!” 国王赞许 , “爱卿真是老成谋国 。 ”
“可是有些语言也是静态的啊!你怎么宣传?” 老对头线程大臣发难 。
“陛下您想想 , 我们有很多宝贝 , ” IO大臣根本不理线程大臣 , 继续侃侃而谈:“ 比如IoC、AOP、反射、动态代理、泛型、注解、JDBC、JMS......还有我们引以为豪的JVM 。 这些东西 , 那些国家可不一定有 , 我们派出老师 , 把这些东西灌输给他们的臣民 , 让他们体会到Java的种种好处 , 慢慢地就把他们给同化了!到时候他们的码农自然而然就会加入我Java帝国 。 ”
“陛下万万不可 , 不同的语言有不同的特点 , 我们的文化别人是接受不了的 , 到时候只会引起群雄耻笑 。 ” 线程大臣觉得IO大臣脑洞大开 , 简直是胡闹 , 非要误国不可 。
“可以一试嘛!” 国王牙不疼了 , “此事由IO大臣全权负责 , 一年后看效果 。 ”
泛型
作为被派往Python王国的老师 , 吉森带着IO大臣的重托 , 风尘仆仆 , 终于来到了Python 王国 。
IO大臣在挑选人选的时候 , 有个重要的原则:是Java的死忠粉丝 , 最好是对其他语言根本不了解 , 省得思想被污染 。 这吉森就是其中的佼佼者 。
吉森先找到一个地方安顿下来 , 然后边四处闲逛 , 他惊奇地发现 , 这里类方法中的self满天飞 , 还有强制代码缩进 , 果然和我大Java不同 , 颇有异域风情 。
前面是个茶馆 , 人声鼎沸 , 吉森走了进去 , 看看能不能牛刀小试 , 宣扬一下Java的文化 。
“小二 , 我观察了半天 , 你们这里怎么没有讨论泛型啊?” 吉森拉住上茶的店小二 。
“泛型? 那是什么东西? ” 小二大惑不解 。
“你肯定是个外乡人 , 不是来自C++就是Java , 我说得没错吧?” 旁边不知道什么时候来了一个老头儿 。
“老先生眼光不错 , 我确实从Java王国来 , 我很纳闷 , 这里怎么没有泛型啊 , 据我所知 , 泛型可以在编译期做类型检查 , 码农们在写代码的时候也不需要做类型的转换 , 非常好用的啊 。 ” 吉森开始灌输Java的种种好处 。
List< String> files = newArrayList< String>();
Stringfile = files. get( 0); //不必做强制类型转换
files.add( newFile(.....)) ; // 编译错误
“外乡人 , 我们Python中的变量是不需要声明类型的 , 不会做编译期类型检查 , 只有在运行时才会检查这个变量到底是什么类型 , 能否调用它的方法 , 你说 , 我们要泛型有什么用?”
吉森大惊 , 卧槽 , 这IO大臣怎么没告诉自己啊 , 人家根本就没这个需求!
想想我大Java费了那么大劲儿去实现泛型 , 没想到在Python这里完全无用武之地 , 还输出什么文化! 传什么教!
反射
吉森觉得有点被IO大臣坑了! 不过多年的历练只是让他稍微慌乱 , 他马上稳住神 , 转移话题: “先生所言极是 , 晚生还有一个问题 , 这Python能支持反射吗? ”
在Java王国 , 人们经常通过反射的方式来获取一个类的属性、方法 , 然后根据一个字符串的名称来调用某个类的方法 。
比如有个url : /user?action=Login
系统根据约定解析它 , 确定类是User, 方法是Login 。 然后就可以把User对象创建起来 , 通过反射调用Login 方法 。
publicclassUser{
publicvoidlogin(...){
......
}
}
“哈哈哈 , 你这个外乡人啊 , 你知道为什么我们Python是动态语言吗? 我们Python的反射功能不知道比你们Java强到哪里去了!来来来 , 我给你看个例子 。 ”
classUser:
deflogin(self):
print( "this is login")
“现在我打印他所有的方法:”
methods = [x forx, y inUser.__dict__.items() iftype(y) == FunctionType]
print(methods) #输出 ['login']
“接下来我通过反射调用Login方法, 老夫很久没写代码了 , 可能不太严谨 , 你明白意思就行 。 ”
url = "/user?action=login"
#从url解析得到类和action , 代码略
clz = "User"
action = "login"
#根据名称获得User对象和方法
user = globals()[clz]()
func = getattr(user,action) #获取login方法
func() #输出This is login
吉森看到这么寥寥几行代码 , 就实现了基本的反射 , 真是灵活啊 , 这Python真是不错 , 他都有点羡慕了 。
动态代理
不 , 我肩负IO大臣的重托 , 我是来传教的 , 不能让这老头儿给洗脑了!
吉森想起来了一个大杀器:动态代理 , 这可是Java的一个非常基础的技术 , 可以在运行时实现类和方法的增强 , 比如在调用业务方法的前后加上事务管理 , 日志管理等功能 , 没有动态代理 , AOP就别想了 。
Java 帝国对 Python 的渗透能成功吗?// //
吉森说道:“老先生 , Python怎么去实现动态代理啊?”
老头儿微微一笑:“Java Class有个缺点 , 一旦被装入Java虚拟机 , 就没法修改了 , 想对他做增强 , 只能修改字节码创建新的类 , 对老的类做封装 , 就是代理 。 但是Python是个动态语言 , 在运行时就可以修改啊 , 比如我可以动态地给User类增加一个新的属性 , 这一点你的Java做不到吧?”
setattr(User, "name", 'andy')
print(user.name) #andy
吉森看得目瞪口呆 , 这真是颠覆了自己从小养成的世界观:一个类在运行期是不能改变的 , 更不可能去增加什么属性 。
老头儿又接着说:“你看看这个User类 , 和Proxy类 , 每次调用Login方法的时候 , 我都可以动态地创建一个新的方法出来 , 在这个新的方法中 , 就可以做各种手脚了 。 ”
classUser:
deflogin(self):
print( 'user login')
deflogout(self):
print( 'user logout')
classProxy:
def__init__(self, target):
self.target = target
def__getattribute__(self, name):
target = object.__getattribute_ _( self, "target")
attr = object.__getattribute_ _(target, name)
ifname == 'login':
defnewFunc(*args, **kwargs):
print ( "login start")
result = attr(*args, **kwargs)
print( "login end")
returnresult
returnnewFunc
else:
returnattr
u = User()
p = Proxy(u)
p.login() #实际上调用的是动态创建的方法
p.logout() #调用的是原来的方法
“你那个Proxy中的__getattribute__是什么东西啊? ” 吉森看到魔法都在这里 , 不由得发问 。
“每当你去调用一个方法(如login/logout) , 或者访问一个字段的时候 , Python都会通过__getattribute__先找到这个方法或者字段 , 然后才是真正的调用 。 ”
“奥 , 原来如此 , 你通过__getattribute__做了手脚 , 如果名称是Login , 就创建新的方法 , 在新的方法中除了调用老方法之外 , 还输出了日志 。 ”
“不错 , 孺子可教!”
吉森现在是真心佩服动态语言了 , 在Java中必须得在运行时通过操纵字节码来增强 , 字节码啊 , 那可不是一般人能玩的 。 这Python居然在源码级别就把功能给增强了!
锦囊妙计
吉森有点怀疑自己此次Python王国之行的效果了 , 这可如何是好? 怎么回去向IO大臣复命? 当初可是立下军令状的!
他突然想起临行前 , IO大臣曾经送给自己三个锦囊 , 嘱咐自己只有到了最危急的时刻才能打开 , 现在不开 , 更待何时?
往怀中一摸 , 就发现锦囊只剩下了两个 , 丢了一个 , 这回去估计要杀头 , 管不了那么多了 , 吉森迅速掏出一个 , 只见上面写着一段话:GIL(全局解释锁) , GIL是Python的命门 , 这把超级大锁只允许一个线程获得Python解释器的控制权 , 简单来说 , 同一时刻 , 只有一个线程能运行!
没想到老头儿淡淡一笑:“Python确实有GIL , 可是这程序的瓶颈啊 , 它不在CPU , 而在于IO , 就是用户的输入 , 数据库的查许 , 网络的访问 , 线程等到有IO操作的时候 , 放弃GIL这个超级大锁 , 让别的线程去执行就是了 。 再说了 , 你真想利用多核的时候可以用多个进程啊!”
第一个锦囊妙计被轻松化解 , 吉森赶紧掏出第二个 , 上面几个字:“动态一时爽 , 重构火葬场 。 ”
“哈哈哈 , ”老头儿狡黠地笑了起来:“这都是不了解情况的外人的误解 , 听说过Quora没有?奥 , 上不了是吧!这Quora就是Python写的 , 人家那测试用例写得非常充分 , 重构也不怕! 所以啊关键是测试用例!”
第二个妙计又被化解 , 吉森彻底没辙了 。
真相大白
看到吉森的神色变化 , 老头儿开始表明身份:“实不相瞒 , 老夫乃是Python国王的特使 , 我们的探子早就听说你们Java那什么破老师计划了 , 你一进入我国 , 就被盯上了 , 国王特地派我来 , 看看能不能说服你 , 留在我国 。 ”
吉森想想 , 回去也无法交差 , 这Python似乎还不错 , 进退两难之际 , 不妨先妥协 , 以图将来 , 于是点点头答应了 。
一年以后 , IO大臣开始盘点老师计划 , 发现回来复命的寥寥无几 , 尤其是去Python王国的吉森 , 他怎么一点消息都没有呢? 是时候再派一个人去了......
*本故事纯属虚构 , 如有雷同 , 纯属巧合 。
声明:作者独立观点 , 不代表 CSDN 立场 。
推荐阅读
- 《圣斗士星矢》重病的伊利亚斯为什么还能对冥斗士产生重大威胁?
- 八国联军侵华, 列强要求瓜分中国, 只有一个国家反对, 原因不简单
- 回忆当年炮声隆,旌旗飘扬分外红——老战士马万湘对越自卫反击战亲历记
- 美髯公朱仝:对国家忠心却无奈被迫上梁山的好汉
- 民间五对门神,能捉鬼的只有第一对,最后一对最出名
- 中国古今官职对照表,涨知识了!
- 对于当督粮官,杨戬是否有怨言?他和哪吒谁更适合当先锋官?
- 东北野战军最后组建的三个步兵纵队司令员都是谁,军衔相对都不高
- 朱元璋曾是明教一员,一统天下后为何知恩图报,对明教大开杀戒?
- 盘点中国古代对女子的美称
