最近、仕事の関係で Python の開発を始めました。以前から Javascript を使っていたため、無意識のうちに Javascript の概念や構文などを使用してしまい、よく落とし穴に落ちます。 JavascriptからPythonに乗り換える際には両者の違いをまとめておく必要があると思います。
基本概念
Python と Javascript は両方ともスクリプト言語であるため、多くの共通機能があり、どちらも実行にはインタープリターが必要で、どちらも動的型であり、どちらも自動メモリ管理をサポートし、どちらも eval() を呼び出してスクリプトを実行できます。などのスクリプト言語に共通の機能。
しかし、それらは大きく異なります。JavaScript は元々クライアント側のスクリプト言語として設計され、主にブラウザーで使用されます。一方、Python はその「エレガント」、「明快さ」、「それ」によるものです。はその「シンプル」なデザインで人気があり、教育、科学技術コンピューティング、Web 開発などのさまざまなシナリオで使用されています。
プログラミング パラダイム
Python と Javascript は両方とも、さまざまな異なるプログラミング パラダイムをサポートしていますが、オブジェクト指向プログラミングという点では大きく異なります。 JavaScript のオブジェクト指向のアプローチはプロトタイプに基づいています。オブジェクトの継承はプロトタイプによって作成されます (オブジェクトも)。プロトタイプ オブジェクトによって作成されたオブジェクトは、プロトタイプ チェーン上のメソッドを継承します。一方、Python はクラス (クラス) の継承に基づいた非常に標準的なものであり、ポリモーフィズム (ポリモーフィン) を当然サポートしています。
OO in Pyhton
class Employee: 'Common base class for all employees' empCount = 0 ##类成员 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary ## 创建实例 ea = Employee("a",1000) eb = Employee("b",2000) OO in Javascript var empCount = 0; //构造函数 function Employee(name, salary){ this.name = name; this.salary = salary; this.empCount += 1; } Employee.prototype.displayCount = function(){ console.log("Total Employee " + empCount ); } Employee.prototype.displayEmployee = function(){ console.log("Name " + this.name + ", Salary " + this.salary ); } //创建实例 var ea = new Employee("a",1000); var eb = new Employee("b",2000);
オブジェクトの継承をベースとしているため、JavaScriptではクラスメンバempCountを使用することができませんので、当然実際の開発ではグローバル変数を宣言することになります。より適切な範囲。 Javascript ではオブジェクトを作成するために new キーワードが必要ですが、Python では必要ないことに注意してください。
ネイティブのプロトタイプベースの継承に加えて、クロージャやプロトタイプを使用してクラス継承をシミュレートする多くの Javascript OO ツールがあります。これは言語自体のプロパティではないため、ここでは説明しません。
スレッド モデル
JavaScript の世界にはマルチスレッドの概念はありません。すべての JavaScript プログラムはイベント駆動型で実行されます。 HTML5 での Web ワーカーの導入により、タスクを同時に処理できますが、JavaScript のシングルスレッド制限は変わりません。
Python は、スレッド パッケージを通じてマルチスレッドをサポートします。
不変型 (不変型)
Python では、一部のデータ型は不変です。つまり、この型のデータは変更できず、すべての変更は新しいオブジェクトを返します。 Javascript のすべてのデータ型は変更できます。 Python はスレッド セーフをサポートするために不変型を導入したと思いますが、JavaScript はシングルスレッド モデルであるため、不変型を導入する必要はありません。
もちろん、JavaScript ではオブジェクトのプロパティを読み取り専用として定義できます。
var obj = {};Object.defineProperty(obj, "prop", { value: "test", writable: false});
ECMAScript5 のサポートでは、Object のフリーズ メソッドを呼び出してオブジェクトを変更不能にすることもできます。
Object.freeze(obj)
データ型
JavaScript のデータ型は比較的単純で、オブジェクト、文字列、ブール値、数値、null、未定義の合計 6 つの型があります
Python ではすべてがオブジェクトです。 module と function 、class などがすべてです。
Python には、bool、int、long、float、complex の 5 つの単純なデータ型が組み込まれており、コンテナ型、コード型、内部型などもあります。
ブール
JavaScriptにはtrueとfalseがあります。 PythonにはTrueとFalseがあります。大文字と小文字を除いて、両者に違いはありません。
文字列
JavaScriptはUTF16でエンコードされています。
PythonはASCIIコードを使用します。エンコード変換を実行するには、encode および decode を呼び出す必要があります。文字列が Unicode エンコードを使用することを指定するには、プレフィックスとして u を使用します。
数値
JavaScript のすべての数値型は 64 ビット浮動小数点数として実装されます。 NaN (非数値)、プラスまたはマイナス無限大 (+/-Infiity) をサポートします。
Pythonには多くの数値型があり、その中でも複数型は非常に便利であるため、Pythonは科学研究や教育の分野で非常に人気があります。これも理由の 1 つであるはずです。 NaN は Python では定義されていないため、ゼロ除算演算では例外がスローされます。
List
Javascriptには組み込みの配列型があります(配列もオブジェクトです)
Pythonのリスト(List)はJavaScriptのArrayに比較的近いですが、タプル(Tuple)は不変のリストとして理解できます。
組み込みメソッド len を使用する Python での長さを見つけることを除いて、基本的に Javascript と Python はどちらもリストを操作するための同様のメソッドを提供します。 Python でのリスト添字の操作は非常に柔軟で便利ですが、これは Javascript にはないものです。たとえば、l[5:-1]、l[:6]などです。
辞書、ハッシュ テーブル、オブジェクト
{} は、オブジェクトの作成に Javascript で広く使用されており、 [] または を使用してオブジェクトのメンバーにアクセスできます。メンバーは動的に追加、変更、削除できます。オブジェクトは、JavaScript 辞書またはハッシュ テーブルと考えることができます。オブジェクトのキーは文字列である必要があります。
Python には組み込みのハッシュ テーブル (dictS) があり、JavaScript とは異なり、dictS はさまざまな種類のキー値を持つことができます。
Null値
JavaScriptでは2種類のNull値を定義しています。未定義は変数が初期化されていないことを意味し、null は変数は初期化されているが値が空であることを意味します。
Python中不存在未初始化的值,如果一个变量值为空,Python使用None来表示。
Javascript中变量的声明和初始化
v1; v2 = null; var v3; var v4 = null; var v5 = 'something';
在如上的代码中v1是全局变量,未初始化,值为undefined;v2是全局变量,初始化为空值;v3为局部未初始化变量,v4是局部初始化为空值的变量;v5是局部已初始化为一个字符处的变量。
Python中变量的声明和初始化
v1 = None
v2 = 'someting'
Python中的变量声明和初始化就简单了许多。当在Python中访问一个不存在的变量时,会抛出NameError的异常。当访问对象或者字典的值不存在的时候,会抛出AttributeError或者KeyError。因此判断一个值是否存在在Javascript和Python中需要不一样的方式。
Javascript中检查某变量的存在性:
if (!v ) { // do something if v does not exist or is null or is false } if (v === undefined) { // do something if v does not initialized }
注意使用!v来检查v是否初始化是有歧义的因为有许多种情况!v都会返回true
Python中检查某变量的存在性:
try: v except NameError ## do something if v does not exist
在Python中也可以通过检查变量是不是存在于局部locals()或者全局globals()来判断是否存在该变量。
类型检查
Javascript可以通过typeof来获得某个变量的类型:
typeof in Javascript 的例子:
typeof 3 // "number" typeof "abc" // "string" typeof {} // "object" typeof true // "boolean" typeof undefined // "undefined" typeof function(){} // "function" typeof [] // "object" typeof null // "object"
要非常小心的使用typeof,从上面的例子你可以看到,typeof null居然是object。因为javscript的弱类型特性,想要获得更实际的类型,还需要结合使用instanceof,constructor等概念。具体请参考这篇文章
Python提供内置方法type来获得数据的类型。
>>> type([]) is list True >>> type({}) is dict True >>> type('') is str True >>> type(0) is int True
同时也可以通过isinstance()来判断类的类型
class A: pass class B(A): pass isinstance(A(), A) # returns True type(A()) == A # returns True isinstance(B(), A) # returns True type(B()) == A # returns False
但是注意Python的class style发生过一次变化,不是每个版本的Python运行上述代码的行为都一样,在old style中,所有的实例的type都是‘instance’,所以用type方法来检查也不是一个好的方法。这一点和Javascript很类似。
自动类型转换
当操作不同类型一起进行运算的时候,Javascript总是尽可能的进行自动的类型转换,这很方便,当然也很容易出错。尤其是在进行数值和字符串操作的时候,一不小心就会出错。我以前经常会计算SVG中的各种数值属性,诸如x,y坐标之类的,当你一不小心把一个字符串加到数值上的时候,Javascript会自动转换出一个数值,往往是NaN,这样SVG就完全画不出来啦,因为自动转化是合法的,找到出错的地方也非常困难。
Python在这一点上就非常的谨慎,一般不会在不同的类型之间做自动的转换。
语法
风格
Python使用缩进来决定逻辑行的结束非常具有创造性,这也许是Python最独特的属性了,当然也有人对此颇具微词,尤其是需要修改重构代码的时候,修改缩进往往会引起不小的麻烦。
Javascript虽然名字里有Java,它的风格也有那么一点像Java,可是它和Java就好比雷峰塔和雷锋一样,真的没有半毛钱的关系。到时语法上和C比较类似。这里必须要提到的是coffeescript作为构建与Javascript之上的一种语言,采用了类似Python的语法风格,也是用缩进来决定逻辑行。
Python风格
def func(list): for i in range(0,len(list)): print list[i] Javascript风格 function funcs(list) { for(var i=0, len = list.length(); i < len; i++) { console.log(list[i]); } }
从以上的两个代码的例子可以看出,Python确实非常简洁。
作用范围和包管理
Javascript的作用域是由方法function来定义的,也就是说同一个方法内部拥有相同的作用域。这个严重区别与C语言使用{}来定义的作用域。Closure是Javascript最有用的一个特性。
Python的作用域是由module,function,class来定义的。
Python的import可以很好的管理依赖和作用域,而Javascript没有原生的包管理机制,需要借助AMD来异步的加载依赖的js文件,requirejs是一个常用的工具。
赋值逻辑操作符
Javascript使用=赋值,拥有判断相等(==)和全等(===)两种相等的判断。其它的逻辑运算符有&& 和||,和C语言类似。
Python中没有全等,或和与使用的时and 和 or,更接近自然语言。Python中没有三元运算符 A :B ?C,通常的写法是
(A and B) or C
因为这样写有一定的缺陷,也可以写作
B if A else C
Python对赋值操作的一个重要的改进是不允许赋值操作返回赋值的结果,这样做的好处是避免出现在应该使用相等判断的时候错误的使用了赋值操作。因为这两个操作符实在太像了,而且从自然语言上来说它们也没有区别。
++运算符
Python不支持++运算符,没错你再也不需要根据++符号在变量的左右位置来思考到底是先加一再赋值呢还是先赋值再加一。
连续赋值
利用元组(tuple),Python可以一次性的给多个变量赋值
(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
函数参数
Python的函数参数支持命名参数和可选参数(提供默认值),使用起来很方便,Javascript不支持可选参数和默认值(可以通过对arguments的解析来支持)
def info(object, spacing=10, collapse=1):
... ...
其它
立即调用函数表达式 (IIFE)
Javascript的一个方便的特性是可以立即调用一个刚刚声明的匿名函数。也有人称之为自调用匿名函数。
下面的代码是一个module模式的例子,使用闭包来保存状态实现良好的封装。这样的代码可以用在无需重用的场合。
var counter = (function(){ var i = 0; return { get: function(){ return i; }, set: function( val ){ i = val; }, increment: function() { return ++i; } }; }());
Python没有相应的支持。
生成器和迭代器(Generators & Iterator)
在我接触到的Python代码中,大量的使用这样的生成器的模式。
Python生成器的例子
# a generator that yields items instead of returning a list def firstn(n): num = 0 while num < n: yield num num += 1 sum_of_first_n = sum(firstn(1000000))
Javascript1.7中引入了一些列的新特性,其中就包括生成器和迭代器。然而大部分的浏览器除了Mozilla(Mozilla基本上是在自己玩,下一代的Javascript标准应该是ECMAScript5)都不支持这些特性
Javascript1.7 迭代器和生成器的例子。
function fib() { var i = 0, j = 1; while (true) { yield i; var t = i; i = j; j += t; } }; var g = fib(); for (var i = 0; i < 10; i++) { console.log(g.next()); }
列表(字典、集合)映射表达式 (List、Dict、Set Comprehension)
Python的映射表达式可以非常方便的帮助用户构造列表、字典、集合等内置数据类型。
下面是列表映射表达式使用的例子:
>>> [x + 3 for x in range(4)] [3, 4, 5, 6] >>> {x + 3 for x in range(4)} {3, 4, 5, 6} >>> {x: x + 3 for x in range(4)} {0: 3, 1: 4, 2: 5, 3: 6}
Javascript1.7开始也引入了Array Comprehension
var numbers = [1, 2, 3, 4]; var doubled = [i * 2 for (i of numbers)];
Lamda表达式 (Lamda Expression )
Lamda表达式是一种匿名函数,基于著名的λ演算。许多语言诸如C#,Java都提供了对lamda的支持。Pyhton就是其中之一。Javascript没有提供原生的Lamda支持。但是有第三方的Lamda包。
g = lambda x : x*3
装饰器(Decorators)
Decorator是一种设计模式,大部分语言都可以支持这样的模式,Python提供了原生的对该模式的支持,算是一种对程序员的便利把。
Decorator的用法如下。
@classmethod def foo (arg1, arg2): ....