0
点赞
收藏
分享

微信扫一扫

python-函数和面向对象程序设计

waaagh 2022-02-20 阅读 88

形式参数和实际参数


在使用函数时,经常会用到形式参数和实际参数,两者都叫作参数。
1.通过作用理解
形式参数:在定义函数时,函数名后面括号中的参数为“形式参数”。
实际参数:在调用一个函数时,函数名后面括号中的参数为“实际参数”,也就是将函数的调用者提供给函数的参数称为实际参数。
def demo (ob):
print (obj)
定义或创建函数,此时函数参数obj为形式参数
mot = “唯有在被追赶的时候,你才能真正地奔跑。
demo (mot)
listl = [绮梦’,'冷伊一','香凝,'黛兰’]
demo (list1)
调用函数,此时的函数参数mot和list1是实际参数

根据实际参数的类型不同,可以分为将实际参数的值传递给形式参数,将实际参数的引用传递给形式参数两种情况。

其中,当实际参数为不可变对象时,进行的是值传递;当实际参数为可变对象时,进行的是引用传递。

值传递和引用传递的基本区别

进行值传递后,改变形式参数的值,实际参数的值不变;

进行引用传递后,改变形式参数的值,实际参数的值也一同改变。

函数定义时参数列表中的参数就是形式参数,而函数调用时传递进来的参数就是实际参数。

def demo(obj=None):
    if obj==None:
       obj = []
    print("obj的值:",obj)
    obj.append(1)

运行结果:

obj的值: [ ]

obj的值: [ ] 

说明:在定义函数时,为形式参数设置默认值时,默认参数必须指向不可变对象


可变参数

传入函数中的实际参数可以是0个,1个,2个或任意个

在定义可变参数时,有两种形式,一种是*parameter,另一种是**parameter

1.*parameter

表示接收任意多个实际参数并将其放入一个元组中。

def printcoffee(*coffeename):#定义输出我喜欢的咖啡名称的函数
    print('\n我喜欢的咖啡有:')
    for item in coffeename:
        print(item) #输出咖啡名称

如果想要使用一个已经存在的列表作为函数的可变参数,可以在列表的名称前加“*”。例 

01 param =['蓝山','卡布奇诺','土耳其'] #定义一个列表
02 printcoffee (*param)               #通过列表指定函数的可变参数


通过上面的代码调用printcoffee()函数后,将显示以下运行结果: 

我喜欢的咖啡有:
蓝山
卡布奇诺
土耳其


2. **parameter


这种形式表示接收任意多个类似关键字参数一样显式赋值的实际参数,并将其放到一个字典中。例如,定义一个函数,让其可以接收任意多个显式赋值的实际参数,代码如下:

01 def printsign (**sign): #定义输出姓名和星座的函数
02    print () #输出一个空行
03    for key, value in sign.items (): #遍历字典
04       print("[" + key + "]的星座是: "+ value) #输出组合后的信息

调用两次printsign()函数,代码如下:

01 printsign (绮梦='水瓶座',冷伊-='射手座)
02 printsign (香凝='双鱼座',黛兰='双子座',冷伊-='射手座)

执行结果如下:
[绮梦]的星座是:水瓶座
[冷伊一]的星座是:射手座

[香凝]的星座是:双鱼座
[黛兰]的星座是:双子座
[冷伊一]的星座是:射手座

如果想要使用一个已经存在的字典作为函数的可变参数,可以在字典的名称前加“*
例如下面的代码:

01 dictl = {'绮梦': '水瓶虚','冷伊一':射手座','香凝':'双鱼座'} #定义一个字典
02 printsign (dictl) #通过字典指定函数的可变参数

通过上面的代码调用printsign()函数后,将显示以下运行结果:

[绮梦]的星座是:水瓶座 
[冷伊一]的星座是:射手座 
[香凝]的星座是:双鱼座

返回值


到目前为止,我们创建的函数都只是为我们做一些事,做完了就结束。但实际上,有时还需要对事情的结果进行获取,这类似于主管向下级职员下达命令,职员去做,最后需要将结果报告给主管。为函数设置返回值的作用就是将函数的处理结果返回给调用它的程序。

在Python中,可以在函数体内使用return语句为函数指定返回值。该返回值可以是任意类型,并且无论returm 语句出现在函数的什么位置,只要得到执行,就会直接结束函数的执行。
return 语句的语法格式如下:

result = return [value] 

result: 用于保存返回结果,如果返回一个值,那么result中保存的就是返回的一个值,,该值可以是任意类型。如果返回多个值,那么result中保存的是一个元组
.
value: 可选参数,用于指定要返回的值,可以返回一个值,也可以返回多个值。
说明:当函数中没有return语句时,或者省略了return语句的参数时,将返回None,即返回空值。
变量的作用域
变量的作用域是指程序代码能够访问该变量的区域,如果超出该区域,再访问时就会出现错误。在程序中,一般会根据变量的有效范围将变量分为全局变量和局部变量。


想要在函数体内部改变全局变量的值,需要在定义局部变量时,使用global关键字修饰


面向对象程序设计

概括的讲,面向对象技术是一种从组织结构上模拟客观世界的方法

对象

对象表示任意存在的事物

类是封装对象的属性和行为的载体,具有相同属性和行为的一类实体被称为类

面向程序设计的三大特征:封装,继承和多态

封装

封装是面向对象编程的核心思想,将对象的属性和行为封装起来,其载体就是类,类会对客户隐藏其实现细节,这就是封装思想。

采用封装思想保证了类内部数据结构的完整性,使用该类的用户不能直接看到类中的数据结构,而只能执行该类中允许公开的数据,提高了程序的可维护性。

继承

是实现重复利用的手段。子类通过继承复用了父类的属性和行为的同时,又添加了子类特有的属性和行为。

多态

将父类对象应用于子类的特征就是多态。
例如,创建一个螺丝类,螺丝类有两个属性:粗细和螺纹密度;然后再创建两个类,一个是长螺丝类,另一个是短螺丝类,并且它们都继承了螺丝类。这样长螺丝类和短螺丝类不仅具有相同的特征(粗细相同,且螺纹密度也相同),还具有不同的特征(一个长,一个短,长的可以用来固定大型支架,短的可以固定生活中的家具)。
综上所述,一个螺丝类衍生出不同的子类,子类继承父类特征的同时,也具备了自己的特征。
并且能够实现不同的效果,这就是多态化的结构。



定义类



在Python中,类的定义使用class关键字来实现,语法如下:

class ClassName:
    '''类的帮助信息'''  #类文档字符串
    statement          #类体

参数说明如下。
.
ClassName:用于指定类名,一般使用大写字母开头,如果类名中包括两个单词,第二个单词的首字母也大写,这种命名方法也称为“驼峰式命名法”,也可根据自己的习惯命名,但是一般推荐按照惯例来命名。
.
'"类的帮助信息"':用于指定类的文档字符串,定义该字符串后,在创建类的对象时 输入类名和左侧的括号“(”后,将显示该信息。
.
statement:类体,主要由类变量(或类成员)、方法和属性等定义语句组成。如果在定义类时,没想好类的具体功能,也可以在类体中直接使用pass语句代替。
例如,下面以大雁为例声明一个类,代码如下;

01 class Geese:
02 '''大雁类'''
03 pass

创建类的实例

python创建实例时不使用new关键字

创建定义的Geese类的实例

wildGoose = Geese() #创建大雁类的实例
print(wildGoose)

创建_init_()方法

在创建类后,类通常会自动创建一个_init_()方法,该方法类似于java的构造方法

每当创建一个类的新实例时,Pyhon会自动执行它。_init_()方法必须包含一个self参数,并且必须是第一个参数。self参数是一个指向实例本身的引用,用于访问类中的属性和方法。在方法调用时会自动传递实际参数self。当_init_()方法只有一个参数时,在创建类的实例时,就不需要指定实际参数了。

class Geese:
    '''大雁类'''
    def _init_(self): #构造方法
        print("我是大雁类!")
wildGoose = Geese() #创建大雁类的实例

创建类的成员并访问
类的成员主要由实例方法和数据成员组成。在类中创建了类的成员后,可以通过类的实例进行访问。
1.创建实例方法并访问
所谓实例方法是指在类中定义的函数,该函数是一种在类的实例上操作的函数。同 init_0方法一样,实例方法的第一个参数必须是self,并且必须包含一个self参数。创建实 例方法的语法格式如下:

def functionName (self, parameterlist): block

参数说明如下。
•functionName:用于指定方法名,一般使用小写字母开头。
•self:必要参数,表示类的实例,其名称可以是self以外的单词,使用self只是一个惯 例而已。
•parameterlist:用于指定除 self参数以外的参数,各参数间使用逗号“,”进行分隔。
•block:方法体,实现的具体功能。
说明:实例方法和Python中的函数的主要区别就是,函数实现的是某个独立的功能, 而实例方法是实现类中的一个行为,是类的一部分。
实例方法创建完成后,可以通过类的实例名称和点“.”操作符进行访问。

具体的语法格式如

instanceName. functionName (parametervalue)

其中, instanceName为类的实例名称; functionName为要调用的方法名称; parametervalue 表示为方法指定对应的实际参数,其值的个数为parameterlist的个数减1。
2.创建数据成员并访问
数据成员是指在类中定义的变量,即属性,根据定义位置,又可以分为类属性和实例属性。

(1)类属性
类属性是指定义在类中,并且在函数体外的属性。类属性可以在类的所有实例之间共享值, 也就是在所有实例化的对象中公用。
说明:类属性可以通过类名或者实例名访问。
例如,定义一个雁类Geese,在该类中定义3个类属性,用于记录雁类的特征,代码如下:
 

class Geese:
    '''雁类'''
    neck = "脖子较长"      #定义类属性(脖子)
    wing = "振超频率高"    #定义类属性(翅膀)
    leg = "腿位于身体的中心支点,行走自如" #定义类属性(腿)
    def __init_(self):    #实例方法(相当于构造方法)
        print ("我属于雁类!我有以下特征:")
        print (Geese.neck) #输出脖子的特征
        print (Geese.wing) #输出翅膀的特征
        print (Geese.leg)  #输出腿的特征

创建上面的类Geese,然后创建该类的实例,代码如下:

geese = Geese() #实例化一个雁类的对象

应用上面的代码创建Geese类的实例后,将显示以下内容: 

美属于雁类!我有以下特征:
脖子较长
振翅频率高
腿位于身体的中心支点,行走自如

(2)实例属性
实例属性是指定义在类的方法中的属性,只作用于当前实例中。
例如,定义一个雁类Geese,在该类的_init_()方法中定义3个实例属性,用于记录雁类的特征,代码如下:

01 class Geese:
02     '''雁类'''
03     def init(self): #实例方法(相当于构造方法)
04     self.neck = "脖子较长" #定义实例属性(脖子)
05     self.wing = "振翅频率高" #定义实例属性(翅膀)
06     self.leg = "腿位于身体的中心支点,行走自如" #定义实例属性(腿)
07     print ("我属于雁类!我有以下特征: ")
08     print (self.neck) #输出脖子的特征
09     print (self.wing) #输出翅膀的特征
10     print (self.leg) #输出腿的特征

创建上面的类Geese,然后创建该类的实例,代码如下:

geese = Geese()

创建用于计算的属性

在Python中,可以通过@proper(装饰器)将方法转换为属性,可以直接通过方法名来访问方法,而不需要再添加一对小括号 “()”.
通过@property 创建用于计算的属性的语法格式如下:

@property
def methodname (self): 
    block


参数说明如下。
•methodname:用于指定方法名,一般使用小写字母开头。该名称最后将作为创建的藏
性名。
self:必要参数,表示类的实例。
•block:方法体,实现的具体功能。在方法体中,通常以return语句结束,用于返回计算结果。
例如,定义一个矩形类,在_init_()方法中定义两个实例属性,然后再定义一个计算矩形面积的方法,并应用@property将其转换为属性,最后创建类的实例,并访问转换后的属性, 代码如下:

01 class Rect:
02     def init(self, width, height):
03         self.width = width  #矩形的宽
04         self.height = height #矩形的高
05     @property #将方法转换为属性
06     def area (self): #计算矩形的面积的方法
07        return self.width*self.height #返回矩形的面积
08 rect = Rect (800,600)  #创建类的实例
09 print ("a积: ",rect.area)  #输出属性的值


运行上面的代码,将显示以下运行结果: 面积为: 480000
注意:通过@property转换后的属性不能重新赋值,如果对其重新赋值,将抛出异常信息。


为属性添加安全保护机制
在Python中,在默认情况下,创建的类属性或者实例是可以在类体外进行修改的,如果想要限制其不能在类体外修改,可以将其设置为私有的,但设置为私有后,在类体外也不能获取它的值。如果想要创建一个可以读取,但不能修改的属性,那么可以使用@property实现只读属性
例如,创建一个电视节目类TVshow,再创建一个show属性,用于显示当前播放的电视节目,代码如下:

01 class TVshow: #定义电视节目类
02 def init_(self, show):
03 self.show = show
04 @property  #将方法转换为属性
05 def show (self):  #定义show ()方法
06 return self.show #返回私有属性的值
07 tvshow = TVshow ("正在播放《战狼2》 ") #创建类的实例 
08 print ("默认: ",tvshow.show) #获取属性值


执行上面的代码,将显示以下内容:
默认:正在播放《战狼2》
通过上面的方法创建的show属性是只读的,尝试修改该属性的值,再重新获取。在上面代码的下方添加以下代码:

01 tvshow.show = "正在播放《红海行动》 " #修改属性值
02 print ("修改后: ", tvshow.show)  #获取属性值


运行后,将出现的异常信息就是修改属性show时抛出的异常。
不仅可以将属性设置为只读属性,而且可以为属性设置拦截器,即允许对属性进行修改, 但修改时需要遵守一定的约束。
继承
在编写类时,并不是每次都要从空白开始。当要编写的类和另一个已经存在的类之间存在 一定的继承关系时,就可以通过继承来达到代码重用的目的,提高开发效率。下面将介绍如何在Python中实现继承。
 


 继承的基本语法
我们每一个人都从祖浆和父母那里继承了一些体貌特征,但是每个人却又不同于父母,因为每个人都存在自己的一些特性,这些特性是独有的,在父母身上并没有体现。在程序设计中实现继承,表示这个类拥有它继承的类的所有公有成员或者受保护成员。
在面向对象编程中,被继承的类称为父类或基类,新的类称为子类或派生类。

通过继承不仅可以实现代码的重用,还可以通过继承来理顺类与类之间的关系。在Python 中,可以在类定义语句中的类名右侧使用一对小括号将要继承的基类名称括起来,从而实现类的继承。具体的语法格式如下:
class ClassName (baseclasslist):
'''类的都助信息''' #类文档字符串
statement #类体

参数说明
• ClassName:用于指定类名。
•baseclasslist:用于指定要继承的基类,可以有多个,类名之间用逗号“,”进行分隔。
如果不指定,将使用所有Python对象的根类object。
*"类的帮助信息”:用于指定类的文档字符串,定义该字符串后,在创建类的对象时, 输入类名和左侧的括号“(”后,将显示该信息。
•statement:类体,主要由类变量(或类成员)、方法和属性等定义语句组成。如果在定义类时,没想好类的具体功能,也可以在类体中直接使用pass语句代替。

方法重写
基类的成员都会被派生类继承,当基类中的某个方法不完全适用于派生类时,就需要在派生类中重写父类的这个方法,这和Java语言中的方法重写是一样的。
在基类中定义一个harvest()方法,无论派生类是什么水果,都显示“水果……”,如果想要针对不同水果给出不同的提示,可以在派生类中重写harvest(方法。例如,在创建派生类 Orange 时,重写harvest()方法的代码如下:

01 class Orange (Fruit): #定义橘子类(派生类)
02 color = "色"
03 def init(self):
04 print ("An 我是橘子")
05 def harvest (self, color):
06 print ("子是: "+ color + "!")# 输出的是形式参数color
07 print("橘子已经收获……")
08 print ("子原来是: "+ Fruit.color + "的! "); #输出的是类属性color 

派生类中调用基类的_init_()方法

在派生类中定义_init_()方法时,不会自动调用基类的_init_()方法。例如,定义一个 Fruit类,在_init_()方法中创建类属性color,然后在Fruit类中定义一个harvest()方法,在该方法中输出属性color的值,再创建继承自Fruit类的Apple类,最后创建Apple类的实例,并调用harvest()方法,代码如下:

01 class Fruit:
02     def _init_(self,color = "色"):
03         Fruit.color = color
04     def harvest (self):
05         print ("水果原来是: "+ Fruit.color + "的!"); #输出的是类属性 color
06 class Apple (Fruit):
07     def _init_(self): #定义革果类(派生类)
08         print ("我是苹果")
09 apple = Apple () #创建类的实例(苹果)
10 apple.harvest () #调用基类的harvest ()方法


让派生类调用基类的_init_()方法进行必要的初始化,需要在派生类中使用 super()函数调用基类的_init_()方法。例如,在上面的第8行代码的下方添加以下代码:
super ()._init_() #调用基类的_init_()方法

注意:在添加上面的代码时,一定要注意缩进的正确性。
 

举报

相关推荐

0 条评论