Python零基础入门(九)——函数,类和对象
系列文章目录
个人简介:机电专业在读研究生,CSDN内容合伙人,博主个人首页
Python入门专栏:《Python入门》欢迎阅读,一起进步!🌟🌟🌟
码字不易,如果觉得文章不错或能帮助到你学习,可以点赞👍收藏📁评论📒+关注哦!😊😊😊
文章目录
导语
欢迎来到 Python 零基础入门系列的第九篇!前面的文章中,已经介绍了 Python 的基本语法、控制流程和数据类型等内容。这一篇博客将继续探索 Python 编程的核心概念——函数,类和对象。
函数
Python 编程中,函数的应用非常广泛。在前面我们已经多次接触过函数。如,用于输出的 print()
函数、用于输入的 input()
函数,以及用于生成一系列整数的 range()
函数。这些都是 Python 内置的标准函数,可以直接使用。除了可以直接使用的标准函数外,Python 还支持自定义函数。即通过将一段有规律的、 重复的代码定义为函数,来达到一次编写多次调用的目的。使用函数可以提高代码的重复利用率。
函数的创建与调用
在 Python 中,def
关键字用来定义函数。语法如下:
def fuctionname(parameter1, parameter2, ...):
['''comment''']
[fuctionbody]
‘comments’:可选参数,表示为函数指定注释,注释的内容通常是说明该函数的功能、要传递的参数的作用等。如果指定了 comments
参数,那么在调用函数时,输入函数名称及左侧的小括号时,就会显示该函数的帮助信息。这些帮助信息就是通过定义的注释提供的。
函数的定义由函数名、参数列表和函数体组成。函数名应该是一个描述性的名字,体现函数的作用。参数列表也可以不指定参数,不指定则表示该函数没有参数。在调用时,也不指定参数。
如果想定义一个什么也不做的空函数,可以使用 pass
语句作为占位符。在 Python3.x 版本中,允许在可以使用表达式的任何地方使用 ...
(3 个连续的点号)来省略代码,由于省略号自身什么都不做,因此,可以当作是 pass
语句的一种替代方案。
调用函数也就是执行函数。调用函数时,使用函数名后加上括号来调用。在括号内,传递函数需要的参数。参数的数量和类型应该与函数定义中的参数列表一致。
参数传递
位置参数与关键字参数
函数可以接受参数,参数是函数的输入。Python 中有两种类型的参数:位置参数和关键字参数。位置参数是必须按照参数在函数定义中的顺序传递的;而关键字参数则是通过指定参数名来传递的,需要将参数名写对。
def greet(name, greeting):
return f"{greeting}, {name}!"
# 位置参数传递
print(greet("Alice", "Hello")) # 输出:Hello, Alice!
# 关键字参数传递
print(greet(greeting="Hi", name="Bob")) # 输出:Hi, Bob!
为参数设置默认值
调用函数时,如果没有指定某个参数将抛出异常,而为函数参数设置默认值允许我们在调用函数时不传递该参数,直接使用参数的默认值。这在某些情况下非常有用,特别是当函数有一些常用的选项时,可以避免频繁传递相同的值。
def greet(name, greeting="Hello"):
print(f"{greeting}, {name}!")
# 不传递greeting参数时,将使用默认值"Hello"
greet("Alice") # 输出:Hello, Alice!
# 传递greeting参数时,将使用传递的值
greet("Bob", "Hi") # 输出:Hi, Bob!
上面的例子为 greeting
参数设置了默认值 “Hello”。当调用 greet
函数时,如果不传递 greeting
参数,它将使用默认值,否则将使用传递的值。
- 注意:在定义函数时,指定默认的参数必须在所有参数的最后,否则将产生语法错误。
- 在 Python 中,可以使用
函数名.__defaults__
查看函数的默认值参数的当前值,其结果是一个元组。
可变参数
在 Python 中,还可以定义可变参数。可变参数也称为不定长参数,即传入函数中的实际参数可以是 0 个、一个、两个到任意个。
定义可变参数时,主要有两种形式:一种是 *args
,另一种是 **kwargs
。下面分别进行介绍。
-
*args
这种形式表示接收任意多个位置参数并将其放到一个元组中。示例代码如下:
def printplayer(*name): #定义输出我喜欢的NBA球员的函数 print('\n我喜欢的NBA球员有: ') for item in name: print(item) #输出球员名称 printplayer('邓肯') printplayer('乔丹','科比','詹姆斯','库里') ''' 输出: 我喜欢的NBA球员有: 邓肯 我喜欢的NBA球员有: 乔丹 科比 詹姆斯 库里 '''
如果想要使用一个已经存在的列表作为函数的可变参数,可以在列表的名称前加
*
。 -
**kwargs
这种形式表示接收任意多个关键字参数,并将其放到一个字典中。示例代码如下:
def printsign(**sign): # 定义输出姓名和绰号的函数 for key, value in sign.items(): # 遍历字典 print("[" + key + "]的绰号是:" + value) # 输出组合后的信息 printsign(邓肯='石佛') printsign(吉诺比利='妖刀',帕克='跑车',邓肯='石佛') ''' 输出: [邓肯]的绰号是:石佛 [吉诺比利]的绰号是:妖刀 [帕克]的绰号是:跑车 [邓肯]的绰号是:石佛 '''
如果想要使用一个已经存在的字典作为函数的可变参数,可以在字典的名称前加
**
。
返回值
函数可以通过 return
语句返回一个值。如果没有指定 return
语句,函数将默认返回 None
。示例如下:
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 输出:8
注意:无论
return
语句出现在函数的什么位置,只要得到执行,就会直接结束函数的执行。
变量的作用域
在函数中定义的变量拥有自己的作用域。这意味着,函数内部的变量只能在函数内部访问,称为局部变量;而函数外部的变量则能在函数内部直接访问,称为全局变量。
def my_function():
x = 10
print(x)
my_function() # 输出:10
# 在函数外部访问函数内部的变量将引发错误
print(x) # NameError: name 'x' is not defined
当局部变量与全局变量重名时,对函数体的变量进行赋值后,不影响函数体外的变量。但是在实际开发时,不建议这么做。
在函数体内定义,并且使用 global
关键字修饰后的变量也可以变为全局变量。在函数体外也可以访问到该变量,并且在函数体内还可以对其进行修改。
匿名函数
Python 支持使用 lambda
关键字创建匿名函数,也称为 lambda 函数。lambda 表达式的首要用途是指定短小的回调函数,它们是一行代码的函数。如下所示:
multiply = lambda x, y: x * y
result = multiply(3, 4)
print(result) # 输出:12
使用 lambda
表达式时,参数可以有多个,用逗号 “,” 分隔,但是表达式只能有一个,即只能返回一个值。而且也不能出现其他非表达式语句(如 for
或 while
)。
常见Python内置函数
除了 print()
用于打印输出、range()
用于生成一系列数字等,Python 还提供了许多内置函数,包括如下:
内置函数 | 功能 | 内置函数 | 功能 |
---|---|---|---|
abs() | 返回一个数的绝对值 | len() | 返回一个对象的长度(元素个数) |
max() | 返回一组数或可迭代对象中的最大值 | min() | 返回一组数或可迭代对象中的最小值 |
sum() | 返回一组数或可迭代对象中所有元素的和 | round() | 对一个数进行四舍五入 |
str() | 将一个对象转换为字符串 | int() | 将一个对象转换为整数 |
float() | 将一个对象转换为浮点数 | list() | 将一个可迭代对象转换为列表 |
tuple() | 将一个可迭代对象转换为元组 | set() | 将一个可迭代对象转换为集合 |
dict() | 创建一个字典 | sorted() | 对一个可迭代对象进行排序 |
format() | 格式化输出文本 | zip() | 将多个可迭代对象打包为元组的列表 |
enumerate() | 枚举一个可迭代对象的元素及其索引 | map() | 对一个可迭代对象的每个元素应用一个函数 |
filter() | 根据指定条件过滤一个可迭代对象的元素 | any() | 判断一个可迭代对象中是否至少有一个元素为True |
all() | 判断一个可迭代对象中的所有元素是否都为True | callable() | 判断一个对象是否可调用(函数或方法) |
type() | 返回一个对象的类型 | dir() | 返回一个对象的所有属性和方法 |
getattr() | 获取一个对象的属性值 | setattr() | 设置一个对象的属性值 |
hasattr() | 判断一个对象是否有指定的属性 | delattr() | 删除一个对象的属性 |
open() | 打开文件并返回文件对象 | input() | 从用户输入读取一行文本 |
类与对象
面向对象概述
面向对象编程(Object-Oriented Programming,OOP)是一种重要的编程范式,它将数据和操作数据的方法封装在一起,形成对象。OOP 的核心思想是将现实世界的事物抽象成一个个对象,并通过定义类来描述这些对象的特征和行为。类是对象的蓝图,而对象是类的实例。在 Python 中,一切皆为对象。
OPP 有三大基本特征,分别是封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism)。
-
封装(Encapsulation):
- 封装是指将数据和操作(方法)组合在一起形成一个独立的单元,对外部隐藏内部实现细节。通过封装可以保护数据的安全性,只能通过预定义的接口(方法)访问和修改数据。
- 封装可以使代码更加模块化和可维护,减少了对外部的依赖性,提高了代码的可重用性和安全性。
-
继承(Inheritance):
-
继承是指一个类(子类)可以继承另一个类的属性和方法,从而避免了重复编写相同的代码。被继承的类称为父类或基类,继承的类称为子类或派生类。
-
通过继承,子类可以拥有父类的属性和方法,并且可以在此基础上进行扩展或修改。
-
-
多态(Polymorphism):
- 多态是指同一种操作或方法可以应用于不同类型的对象,而产生不同的行为。通过多态,可以以统一的方式对不同的对象进行操作,无需关心对象具体的类型。
- 多态性使得程序更加灵活和可扩展,可以通过定义抽象类、接口或基类来实现统一的方法签名,然后由不同的子类实现自己的具体行为。这样可以提高代码的可读性、可维护性和可扩展性。
这三大特性是面向对象编程的基础,共同支持着代码的重用、封装和抽象,使得我们能够以更高效和结构化的方式进行软件开发。
类的定义与使用
定义一个类需要使用 class
关键字,类中可以包含属性(也称为成员变量)和方法(也称为成员函数)。class
语句本身并不创建该类的任何实例。所以在类定义完成以后,可以创建类的实例,即实例化该类的对象。通过创建类的实例,可以使用该类中定义的属性和方法。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hello(self):
print(f"Hello, my name is {self.name} and I am {self.age} years old.")
# 创建类的实例
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
# 调用实例方法
person1.say_hello() # 输出:Hello, my name is Alice and I am 25 years old.
person2.say_hello() # 输出:Hello, my name is Bob and I am 30 years old.
__init__()
方法
在创建类后,类通常会自动创建一个__init__()
方法。该方法是一一个特殊的方法,每当创建-一个类的新实例时,Python 都会自动执行它。__init__()
方法必须包含一个 self
参数,并且必须是第一个参数。self
参数是一个指向实例本身的引用,用于访问类中的属性和方法。在方法调用时会自动传递实际参数 self
。因此,当 __init__()
方法只有一个参数时,在创建类的实例时,就不需要指定实际参数了。
class Geese:
''' 大雁类 '''
def __init__(self): # 构造方法
print("我是大雁类!")
wildGoose = Geese() # 创建大雁类的实例
'''
输出:
我是大雁类!
'''
访问限制
在类的内部可以定义属性和方法,而在类的外部则可以直接调用属性或方法来操作数据,从而隐藏了类内部的复杂逻辑。但是 Python 并没有对属性和方法的访问权限进行限制。为了保证类内部的某些属性或方法不被外部所访问,可以在属性或方法名前面添加单下划线(_foo
)、双下划线(__ foo
)或首尾加双下划线(__foo__
), 从而限制访问权限。其中,单下划线、双下划线、首尾双下划线的作用如下:
__ foo__
:首尾双下划线表示定义特殊方法,一般是系统定义名字,如__init__()
。_foo
: 以单下划线开头的表示 protected(保护)类型的成员,只允许类本身和子类进行访问,但不能使用from module import *
语句导入。__foo
:双下划线表示 private(私有)类型的成员,只允许定义该方法的类本身进行访问,而且也不能通过类的实例进行访问,但是可以通过类的实例名.类名_xxx
方式访问。
属性
这里介绍的属性与上面介绍的类属性和实例属性不同。上面介绍的属性将返回所存储的值。而这里要介绍的属性则是一种特殊的属性,访问它时将计算它的值。另外,该属性还可以为属性添加安全保护机制。下面分别进行介绍。
创建用于计算的属性
在 Python 中,可以通过 @property
(装饰器)将一个方法转换为属性,从而实现用于计算的属性。将方法转换为属性后,可以直接通过方法名来访问方法,而不需要再添加一对小括号 “()",这样可以让代码更加简洁。
通过 @property
创建用于计算的属性的示例如下:
class Rect:
def __init__(self,width,height):
self.width = width #矩形的宽
self.height = height #矩形的高
@property #将方法转换为属性
def area(self): #计算矩形的面积的方法
return self.width*self.height #返回矩形的面积
rect = Rect(800,600) #创建类的实例
print("面积为: ",rect.area) #输出属性的值
'''
输出:
面积为: 480000
'''
注意:通过
@property
转换后的属性不能重新赋值。如果对其重新赋值,将抛出AttributeError
异常。
为属性添加安全保护机制
在 Python 中,默认情况下,创建的类属性或者实例,是可以在类体外进行修改的,如果想要限制其不能在类体外修改,可以将其设置为私有的,但设置为私有后,在类体外也不能获取它的值。如果想要创建一个 可以读取,但不能修改的属性,那么可以使用 @property
实现只读属性。
class TVshow: #定义电视节目类
def __init__(self,show):
self.__show = show
@property #将方法转换为属性
def show(self): #定义show()方法
return self.__show #返回私有属性的值
tvshow = TVshow("正在播放《封神》") #创建类的实例
print("默认:",tvshow.show) #获取属性值
'''
输出:
默认: 正在播放《封神》
'''
通过上面的方法创建的 show
属性是只读的。
继承
在编写类时,并不是每次都要从空白开始。当要编写的类和另一个已经存在的类之间存在一定的继承关系时,就可以通过继承来达到代码重用的目的,提高开发效率。被继承的类称为父类或基类,继承的类称为子类或派生类。子类可以重写父类的方法或添加新的方法。以下是一个示例:
class Animal:
def __init__(self, name):
self.name = name
def sound(self):
pass
class Dog(Animal):
def sound(self):
return "Woof!"
class Cat(Animal):
def sound(self):
return "Meow!"
d = Dog("Buddy")
print(d.sound()) # 输出:Woof!
c = Cat("Kitty")
print(c.sound()) # 输出:Meow!
在上述代码中,定义了一个名为 Animal
的父类,它具有一个属性 name
和一个未实现的方法 sound()
。然后,定义了两个子类 Dog
和 Cat
,它们继承了父类 Animal
并实现了自己的 sound()
方法。通过创建子类的实例,可以调用其方法并输出相应的结果。
注意:在派生类中定义
__init__()
方法后,不会再自动调用基类的__init__()
方法。
结语
以上是关于函数、类和对象的知识介绍。希望本篇教程能够帮助你更好地理解和应用 Python 编程语言的相关概念和技巧。