python技巧

有时候面试时会被问到一些细节问题,还是把琐碎的知识点有必要总结整理一下。

9、 函数

9.1 定义函数

在使用函数之前必须先定义(声明)函数,然后才能调用它。使用关键字def 定义函数,语法格式如下:

def 函数名 (参数列表):

<函数语句>

return 返回值

其中,参数列表和返回值不是必需的。如果return 后没有返回值,也没有return 语句,这样的函数会返回None值。使用缩进以语句表示函数体。

【注意】:当函数没有参数时,包含参数的圆括号也必须写上,圆括号后也必须有冒号“:”。

与C语言相比,在python 中声明一个函数不需要声明函数的返回值类型,也不需要声明参数的类型。

调用函数:

 

91f3737bab384430cfbcb73e432923da.png

函数的参数:

在调用某个函数时,可以向其传递参数,也可以不传递参数,但都不影响函数的使用。

python中,有必须参数、关键字参数、默认参数、不定长参数。

(a)关键字参数

在使用关键字参数时,允许在调用函数时参数的顺序与声明时不一致,因为python解释器能够使用参数名匹配参数值。输出的顺序与形参顺序保持一致。

 

903e25c7c4e3c8d54b0798ab639affcd.png

关键字参数

如果没有传递参数,则使用默认参数。

此外,可选参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

 

97fe27cc5d7dc7c56e41bef70b74437a.png

关键字参数

默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!

要注意定义可变参数和关键字参数的语法:

*args是可变参数,args接收的是一个tuple,此种情况类似于不定长参数;

**kw是关键字参数,kw接收的是一个dict。

(b)默认参数

在函数定义时给定一个初始值,在函数调用时可以不传这个参数,采用默认参数的值;下例中的age就是默认参数;

如果在声明一函数时,其参数列表中既包含无默认值的参数,又包含有默认值的参数,那么,在声明函数的参数时,必须先声明无默认值的参数,后声明有默认值的参数。

 

d4b1268a75eae1a69715a0d82848ec3a.png

使用默认参数

(c)不定长参数

在python中,可能需要一个函数能处理比当初声明时更多的参数,这些参数叫“不定长参数”。不定长参数也叫可变参数。

在自定义函数时,如果在参数名前加上一个星号“*”,则表示该参数就是一个可变长参数。

在调用该函数时,如果依次序将所有的其他变量都赋予值之后,剩下的参数将会收集在一个元组中,元组的名称就是前面带星号的参数名。

 

d4a5091c13e752cb0d309d9c85328df3.png

不定长参数

(d)可选参数

如下面例子中,如果实参个数少于等于形参个数,为了使程序正确运行,需要给“缺失”的实参指定一个默认值:空字符串,并且可以提供也可以不提供这个实参。

也即:可选参数要在形参中指定一个空字符串的默认值。

 

bb0f6daa56fe37460c3db4e48a3d6513.png

让实参变成一个可选参数(不提供实参)

 

6bf5c482259e137e18aca9475361e767.png

让实参变成一个可选参数(提供实参)

按值传递参数与按引用传递参数:

 

dab7be38ccc3f1a23fba9c0ba7e9f9a4.png

按值传递

 

8dd0505cc25aceeac06d319f0c516914.png

按引用传递

Python函数参数支持按值还是按引用传递?

根据具体情况,Python的函数参数既支持按值传递也支持按引用传递。

实际上,解释器会查看对象引用(内存地址)指示的那个值的类型,如果变量指示一个可变的值,就会按引用调用语义。如果所指示的数据的类型是不可变的,则会应用按值调用语义。

列表 字典 集合

总是会按引用传入函数,函数代码组中对变量数据结构的任何改变都会反映到调用代码中。

字符串 整数 元组

总是会按值传入函数,函数中对变量的任何修改是这个函数私有的,不会反映到调用代码中。

【注意】:

在 python 中,字符串strings, 元组tuples, 和 整数numbers 是不可更改的对象,而 列表list, 字典dict,集合set 等则是可以修改的对象。

参考:

https://blog.csdn.net/weixin_41798450/article/details/89306399​blog.csdn.net

 

e5ffd491f477bd2e590f47cea2e4bfe3.png

 

af584316c97922163be5c4e77446ebd2.png

注意以上两种方式的区分。

python 函数的参数传递

  • 不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
  • 可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响。

python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

python函数中按值传递参数按引用传递参数的区别:

按值传递:函数内改变,函数外不改变原参数值;

按引用传递:函数内、外都改变原参数的值;

变量的作用域:

分为局部作用域、全局作用域、内置作用域。

局部作用域:定义在函数内部的变量拥有一个局部作用域,表示只能在声明它的函数内部访问。

全局作用域:定义在函数外的变量拥有全局作用域,表示可以在整个程序范围内访问。

内置作用域:python预先定义的作用域。

【注意】:

在函数内外可以有同一个名称的变量而相互不影响。

 

0c2345a8fd4ca92e7ca100bc4d9341dc.png

函数内外使用相互不影响的同名变量

但是在函数中引用全局变量并进行操作,也即在函数中使用函数外的变量,需要在变量名前加上关键字global。

 

a4ff428ba86047596c917f7e2c6d19ec.png

使用关键字global在函数内部使用全局变量的过程

在python中,函数可以返回任意类型的值,包括列表和字典以及比较复杂的数据结构。

 

9753a79a3e45935e9831c8786dcd16f1.png

函数返回一个字典

使用函数传递列表:

使用函数传递列列表,在这类列表中可能包含名字、数字或更复杂的对象(例如字典)。将列表传递给函数后,函数就可以直接访问其内容。所以,可以使用函数来提高处理列表的效率。

 

8b61a99fca000e325f7a44a80113bad2.png

使用函数传递列表

通过在函数中对列表进行修改,可以高效的处理大量的数据。

 

c344909af44ad3ae9505e3ee2fd99816.png

在函数中修改列表(第一个函数实现复制功能,第二个函数负责输出复制到“relatives”群组中的好友信息)

使用匿名函数:(为了使代码清晰,不复用的函数)

可以使用lambda 来创建匿名函数。所谓匿名,是指不再使用def语句这样标准的形式定义一个函数。也可以将匿名函数赋给一个变量供调用。它是python中一类比较特殊的声明函数方式。其语法格式如下:

lambda params:expr

参数params相当于声明函数时的参数列表找中用逗号分隔的参数,参数“expr”是函数要返回值的表达式,而表达式中不能包含其他语句,也可以返回元组(要用括号),并且还允许在表达式中调用其他函数。

 

f92ad02a675e5d9a1aea83e574a9cb56.png

使用lambda创建匿名函数

函数和模块开发: 

模块是扩展名为".py"格式的文件。将函数存储在模块的独立文件中,再将模块导入到主程序中。好处:(a)将函数存储在独立的文件中,可以隐藏代码的细节,将重点放在程序的高层逻辑上。(b)在众多不同的程序中可以重用该函数,从而可以与别人共享这些文件而不是整个程序。

 

bacfd6e69f7667bcd23ea0cc3c72ecf5.png

 

0d1a75391982091d149928ca89dffdaf.png

导入整个模块文件格式为:

import 模块名

模块名.函数名

只导入指定的函数:

from 模块名 import 函数名1,函数名2,......

使用as指定函数别名:

from 模块名 import函数名 as 别名1

使用as指定模块别名:

import 模块名 as 模块别名

导入所有函数:(但是不推荐这种方式,容易出错)

from 模块名 import * 

10. 面向对象(上)

10.1 定义并使用类

把具有相同属性和方法的对象归为一个类。在使用类之前必须先创建这个类。

格式为:

class ClassName:

语句

注意:类的首字母必须大写。

类只有实例化之后才能使用。使用类名加小括号的形式就可以实例化一个类。一个类可以实例化多个实例,实例与实例之间不会互相影响。类实例化之后就可以直接使用了。

10.2 类对象

 

774823bb286cef9744a5591b34cd7e3d.png

10.3 类方法

可以使用关键字def 在类的内部定义一个方法。在定义类的方法后,可以让类具有一定的功能。在类外部调用该类的方法就可以完成相应的功能,或改变类的状态。

10.3.1 定义类方法的方式与其他一般函数的定义方式相似,但有以下区别:

(a)方法中的第一个参数必须为self,且不能省略。但是在调用方法时,不用提供self参数。

(b)方法的调用需要实例化类,并以“实例名.方法名(参数列表)”的形式进行调用。

(c)必须整体进行一个单位的缩进,表示这个方法属于这个类。

10.3.2 构造方法

在定义类时,可以定义一个特殊的构造方法,即__init__()方法。

注意:init前后分别是两条下划线“__”。

如果在类中定义了__init__()方法,那么类的实例化操作会自动调用__init__()方法。

也即:使实例自动具有构造函数功能。

【注意】:在python中,以self为前缀的变量都可以供类中所有的方法使用,并且还可以通过类的实例来访问这些变量。通过实例访问的变量称为属性。

 

bdf5e4e7e4a5c9e3324fa45852ae71fb.png

使用类对象

10.3.3方法调用

类中的方法既可以调用本类中的方法,也可以调用全局函数来实现相关功能。

调用本类中的方法格式如下:

self.方法名(参数列表)

 

8267e2aeec675b3efa0870870f8e2b2d.png

调用类自身的方法和全局函数

10.3.5 使用私有方法

与大多数语言不同,在python中,函数,方法或属性是私有还是公有,完全取决于它的名字。以两条下划线“__”开始(注意,不是结束),那么该函数、方法或属性就是私有的,其他都是公有的。当在类的内部调用私有成员时,可以用点“.”运算符实现。

在类内部调用私有方法格式:

self.__方法名

【注意】在python中,私有函数,方法和属性具有以下特点:

私有函数不可以从它们的模块外部调用。

私有类方法不可以从它们的类外部调用。

私有属性不可以从它们的类外部访问。

 

c28d9aa8d63869ebda126545f4e249af.png

10.3.6析构方法

析构方法为_del()_,前后分别有两条下划线"_”。当使用内置方法del()删除对象时,会调用它本身的析构函数。此外,当一个对象在某个作用域调用完毕后,在跳出其作用域的同时也会调用析构函数一次,这样可以使用析构函数_del()__释放内存空间。

10.3.7 静态方法和类方法

类中方法分为多种,最常见的有实例方法,类方法和静态方法。类方法和静态方法的定义方式与实例方法不同,它们的调用方式也不同。在调用类方法和静态方法时,可以直接由类名进行调用,在调用前无需实例化类。当然,也可以使用类的实例进行调用。

  • 实例方法。前面用到的类中所有的方法都是实例方法,其隐含调用的参数是类的实例。
  • 类方法。隐含调用的参数是类。在定义类方法时,要使用装饰器@classmethod进行修饰,并且必须有默认参数“cls”。
  • 静态方法。没有隐含调用参数。在定义静态方法时,要使用修饰符@staticmethod进行修饰,并且没有默认参数。 

 

ce699543aaf30cc6fcf9f3da9156bb6a.png

10.4 类属性

既可以在构造方法中定义属性,也可以在类的其他方法中使用定义的属性。

类属性和实例属性:

  • 实例属性:如果是同一个类的不同实例,其值是不相关的,也不会互相影响。在定义时使用

“self.属性名”的格式定义,在调用时也使用这种格式调用。

  • 类属性: 是同一个类的所有实例所共有的。在引用是要使用“类名.类变量名”的格式,只要某个实例对其进行修改,就会影响这个类的其他实例。

【注意】:

对于实例属性来说,两个实例之间并不联系,可以各自独立的修改为不同的值

对于类属性来说,无论哪个实例修改了它,都会导致所有实例的类属性值发生变化。

 

288349099d62d570a1e3b8d182a780f1.png

使用类属性和实例属性

 

e0ac8ea78b5a907f998d6ed84df5dddb.png

10.4.3 设置属性的默认值

类中的每个属性都必须有初始值。可以在方法_init__()中指定某个属性的初始值是0或空字符串。如果设置了某个属性的初始值,就不需要在_init__()中提供为属性设置初始值的形参。

 

cbcd15e534bfaa1e58886bb5080027ba.png

设置属性的默认值

10.4.4 修改属性的值

有两种方式修改属性的值:

  • 直接通过实例进行修改
  • 通过自定义方法修改

 

e792694dad2725bf3b0452d253ec4b02.png

10.5 继承

  • 类的继承:指新类从已有的类中取得已有的特性,诸如属性,变量和方法等。
  • 类的派生:是指从已有的类产生新类的过程。

这个已有的类称为基类或者父类,而新类称为派生类或者子类。

语法格式为:

class ClassName1(ClassName2):

其中,ClassName1表示子类(派生类)名,ClassName2表示基类(父类)名。

【注意】:

在创建子类时,父类必须包含在当前文件中,且位于子类的前面。

 

97fca1fecf7e10ba8c7570aa619d5119.png

在以上代码中的super( )是一个特殊的函数,功能是将父类和子类关联起来,可以让python调用Car父类的方法__init__(),可以让子类的实例包含父类中的所有属性。父类也称为超类(superclass)。

10.5.2 在子类中定义方法和属性

子类除了可以继承使用父类中的属性和方法外,还可以单独定义自己的新的属性和新的方法。

 

e776b742225522908dbd92638c078e88.png

在子类中定义新的方法和属性

10.5.3 子类可以继续派生新类

可以基于一个子类继续创建一个子类。

 

8e0706ded27074d4c4fb1432800470ed.png

10.5.4 私有属性和私有方法

当子类继承了父类之后,虽然子类具有了父类的属性和方法,但是不能继承父类中的私有属性和私有方法(属性和方法名的前缀为两条下划线)。在子类中还可以使用重写的方式来修改父类的方法,以实现与父类不同的行为表现或能力。

10.5.5 多重继承

多重继承是指一个类可以继承多个,在实现多重继承定义时,以逗号“,”分割开要多重继承的父类。具体语法格式:

class 子类名(父类1,父类2,父类3,......)

在多重继承中,继承顺序是个很重要的因素。如果继承的多个父类中有相同的方法名,但在类中使用时未指定父类名,则python解释器将从左到右搜索,即调用先继承的类中的同名方法。

10.6 方法重写

当子类在使用父类中的方法时,如果发现父类中的方法不符合子类的需求,可以对父类中的方法进行重写。在重写时需要先在子类中定义一个这样的方法,与要重写的父类中的方法同名,这样python程序将不会再使用父类中的这个方法,而只使用在子类中定义的和父类中重名的方法(重写方法)。

面向对象(下)

11.1 模块架构

不能随便导入编写好的外部模块,只有被python找到的模块才能导入。

当在程序中导入一个模块时,python解释器首先在当前目录中查找要导入的模块。如果没有找到这个模块,python解释器会从“sys”模块的path变量指定的目录中查找这个要导入的模块。在大多数情况下,python解释器会在运行程序前将当前目录添加到sys.path路径的列表中,所以在导入模块时首先查找的路径是当前目录下的模块。

在调用模块时,如果外部模块文件和测试文件在同一个目录中,运行成功后会在本目录中生成一个名为“_pycache__”的文件夹目录,在这个目录下还有一个名为“模块名.cpython-36.pyc”文件。

 

7c0dae961235e99738a4ff88287e8073.png

“XXX.pyc”格式的文件是一个可以直接运行的文件,这是python将文件“XXX.py”编译成字节码的文件。对于外部文件来说,python总是在第一次调用后将其编译成字节码的形式,以提高程序的启动速度。

如果不想将某个源文件发布,那么可以发布编译后的程序(.pyc文件),这样可以起到一定的保护源文件的作用。也可以调用系统内置模块去编译指定的文件:

 

fa924d32aa21ecb6f192d6dc61d7c0bb.png

编译指定的文件

 

2823e0c9e8337fdbe683adf67eddd973.png

运行.pyc 文件和.py文件的执行效果是相同的,编译后生成的.pyc 文件并没有改变程序的功能,只是一python字节码的形式存在而已,起到了一个防止源码泄漏的作用。

11.1.3 使用__name__属性

在python程序中,当一个程序第一次导入一个模块时,将会运行主程序。如果想在导入模块时不执行模块中的某一个程序块,可以用“__name__”属性使该程序块仅在该模块自身运行时执行。

  • 如果程序独立运行,则将其“__name__”属性设置为“__main__”
  • 如果程序作为一个模块导入,则将其“__name__”属性设置为模块名。

因此,可以通过查看“__name__”属性来判断程序的运行状态。

包:(同目录保存同类功能的程序文件)

包其实是个文件夹或目录,但其中必须包含一个名为“__init__.py”的文件。该文件可以是一个空文件,表示这个目录是个包。

在编程过程中,可以将包看作是同一个目录中的模块。

当在python中使用包时,需要首先使用目录名,然后再使用模块名导入所需要的模块。如果需要导入子包,则必须按照包的顺序(目录顺序)使用“.”运算符进行分割,并使用import 语句进行导入。

当使用“from package import item”这种形式的时候,对应的item既可以是包里的子模块(子包),也可以是包里面定义的其他名称,比如函数、类或变量。

posted @ 2021-11-05 22:20  physique  阅读(79)  评论(0编辑  收藏  举报