美文网首页Python
Python 的一些细节

Python 的一些细节

作者: Vector_Wan | 来源:发表于2021-03-09 22:51 被阅读0次

    1. Python 是一个强类型语言吗?

    Python 到底是一个强类型语言还是一个弱类型语言网上众说纷纭,大多数人认为Python是一个强类型语言,但是也有人持反对观点。比如我看到的这篇博客

    在说我自己的观点之前呢还是先看看比较权威的对强类型和弱类型的定义好了。

    这段引用自《流畅的python》
    强类型: 如果一门语言很少隐式转换类型,说明它是强类型语言。比如Java、C++、Python。
    弱类型:如果语言经常隐式转换类型,说明是如弱类型语言。比如PHP、JS。

    静态语言:在编译时检查类型的语言是静态类型语言。
    动态语言:在运行时检查类型的语言是动态型语言。

    上面我提到的博文(不管是正方还是反方)大多都认同这个定义,并举出一些例子证明自己的观点。在看了这些文章之后我认为 Python 在设计的时候的确倾向于少做隐式类型转换,但是确实也有一些情况下有 “隐式类型转换” 的情况,比如 "123" * 10 在python中是合法的。出现这种情况的原因我觉得也很好分析:

    首先需要知强态类型的好处,简单来说就是可以及早发现 bug,除了自己看代码不容易出现问题外,也方便了编译器和 IDE 分析代码和找出错误。当然代价就是程序员要多写点代码了。这就像是一场博弈,减少了代码就要增加出现 bug 的风险。

    Python 显然倾向于让我们多写两行代码而减少一些奇奇怪怪的 bug 的出现。我们再来看诸如 "123" * 10 的情况我们就可以看到,这行代码语义是如此的明显以至于我们很少会在这里出现错误,所以可以在这里为程序员减少一些工作。其他的情况我想也是大体如此。

    综上,其实我们不必纠结 Python 到底是强类型还是弱类型,更重要的是强类型有什么好处?弱类型有什么好处?用在什么地方可以发挥出最大优势?为什么这里弱化了类型?为什么这里强类型?

    2. type、object 和 class 的关系

    这三者的关系就是一张图和三句话:
    图片在下面,实线是继承关系( the subclass-superclass relationship),虚线是生成实例(生成对象)( the type-instance relationship )。 图片来源和相关说明

    三句话是:

    • type 是 object 的类 (type 是所有类的爸爸)
    • type 继承自 object (object 是所有对象的超类)
    • type 是 type 自己的类

    可见 type 是一个元类,所谓元类,就是类的类。也可以这么解释,对象是类实例化生成的,那类又是谁生成的?含无疑问,类是元类生成的。

    那么问题来了 元类是谁生成的呢?元类是由自己生成的 -。-’ 因为在底层 type 是由 C 语言编写的,type 的实例指针指向了自己。。。

    所以知道这玩意有啥用,我也不知道,大概是为了看懂大佬程序员写的奇怪的代码吧。。。

    3. 一切皆对象和所引发的深浅拷贝问题

    一切皆对象的好处就是:不同类型之间的变量可以相互赋值。比如这样

    a = 10
    a = "xxx"
    

    的操作是合法的。发生的过程如下所示:

    变量名指向地址再指向值,而不是变量名直接指向值,这是因为在python中 int 也是一个对象。

    这是由于这种机制出现了深浅拷贝的问题。

    浅拷贝就是:不管多么复杂的数据结构,浅拷贝都只会copy一层地址。(copy.copy)
    结果就是新的变量指向的还是原来的地址,最终两个变量指向了同一个对象。带来的问题也很明显,有时候我们修改一个变量的时候另一个也随着变化了。
    这种情况发生在字典套字典、列表套字典、字典套列表,列表套列表,以及各种复杂数据结构的嵌套中,所以当我们的数据类型很复杂的时候,用copy去进行浅拷贝就要非常小心。

    如果我们想要内存中有两个对象, 那么我们就要使用深拷贝,深拷贝会完全复制原变量相关的所有数据,在内存中生成一套完全一样的内容,在这个过程中我们对这两个变量中的一个进行任意修改都不会影响其他变量。(copy.deecopy)

    但同时在使用深拷贝的时候也要考虑它带来的内存占用过多的问题。

    4. Python中参数传递的方式

    基本的参数传递有两种:
    值传递:(pass-by-value)被调函数的形式参数作为被调函数的局部变量处理,需要在堆栈中开辟内存空间来存放由主调函数放进来的实参的值,从而形成了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。

    引用传递:(pass-by-reference)被调函数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形式参数的任何操作都被处理成间接寻址。所以被调函数对形式参数做的任何操作都影响了主调函数中的实参变量。

    Python 参数传递采用的只能是是传递对象引用的方式。如果函数收到的是一个可变对象(字典、列表)那么就可以修改对象的原始值,相当于“引用传递”。如果函数收到的是不可变对象(数字、字符串、元组)的引用,就不能直接修改原始对象,相当于通过“值传递”来传递对象。

    5. is 和 == 运算符

    is 比较的是地址,== 比较的是值

    相关文章

      网友评论

        本文标题:Python 的一些细节

        本文链接:https://www.haomeiwen.com/subject/ydobqltx.html