一、参数分类
函数,在定义的时候,可以有参数的,也可以没有参数。
1.1 从函数调用的角度来看,参数可以分为两种:
- 位置参数:调用时,不使用关键字参数的 key-value 形式传参,这样传参要注意按照函数定义时参数的顺序来。
- 关键字参数:调用时,使用 key=value 形式传参的,这样传递参数就可以不按定义顺序来。
1.2 从函数定义的角度来看,参数可以分为四种:
- 必选参数:调用函数时必须要指定的参数,在定义时没有等号
- 可选参数:也叫默认参数,调用函数时可以指定也可以不指定,不指定就默认的参数值来。
- 可变位置参数:*args:接收到的所有按照位置参数方式传递进来的参数,是一个元组类型
- 可变关键字参数:**kw :接收到的所有按照关键字参数方式传递进来的参数,是一个字典类型
1.3 从参数传递机制来看,参数可以分为两种:
- 形参:是定义函数时在括号里定义的变量,它只是申明用的,是没有值的,位于定义函数中;形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。
- 实参:是调用函数时传给形参的值,是有值的,位于主调函数中;实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。
1.4 根据实际参数的类型不同,函数参数的传递方式分为值传递和引用传递(又称为地址传递)
- 值传递:将实际参数值的副本(复制品)传入函数,而参数本身不会受到任何影响。值传递的方式,类似于《西游记》里的孙悟空,它复制一个假孙悟空,假孙悟空具有的能力和真孙悟空相同,可除妖或被砍头。但不管这个假孙悟空遇到什么事,真孙悟空都不会受到任何影响。与此类似,传入函数的是实际参数值的复制品,不管在函数中对这个复制品如何操作,实际参数值本身不会受到任何影响。
- 引用传递:如果实际参数的数据类型是可变对象(列表、字典),则函数参数的传递方式将采用引用传递方式。需要注意的是,引用传递方式的底层实现,采用的依然还是值传递的方式。
二、实例演示
2.1 必选参数:形参与实参一一对应,多少均出错
2.2 可选参数:形参有默认值,实参传值就覆盖形参得默认值
2.3 位置传参:顺序入座
2.4 关键字传参:对号(关键字)入座
2.5 位置 + 关键字混合传参:排队入场,先序后号(关键字)
混合传参要求位置传参在前,一旦开始关键字传参,后面所有参数必须用关键字传参。
2.6 可变位置参数:*args,无号(关键字)者全收入元组
2.7 可变关键字参数:**kw,有号(关键字)者全收入字典
2.8 三种参数类型可以在一个函数中出现,但一定要注意顺序
位置 + *args + **kw
2.9 引用类型的数据类型(列表、字典等)传参,函数内修改,函数外也变
函数参数传递的是实际对象的内存地址。如果参数是引用类型的数据类型(列表、字典等),在函数内部修改后,就算没有把修改后的值返回回去,外面的值其实也已经发生了变化。
2.99 所有代码
"""
def my_function(arg):
print(arg)
my_function(10) #################
def my_function(arg=10):
print(arg)
my_function(60) #################
def my_function(a, b, c, d):
print(a, b, c, d)
print('位置传参:', end='')
my_function(10, 20, 30, 40) #################
def my_function(a, b, c, d):
print(a, b, c, d)
print('关键字传参:', end='')
my_function(d=10, c=20, b=30, a=40) #################
def my_function(a, b, c, d):
print(a, b, c, d)
print('关键字传参:', end='')
my_function(10, d=20, c=30, b=40) #################
def my_function(*args):
print(args)
print(type(args))
print('可变位置参数:', end='')
my_function(60, 70, 80) #################
def my_function(**kw):
print(kw)
print(type(kw))
print('可变关键字参数:', end='')
my_function(a=60, b=70, c=80) #################
def my_function(a, b, c, *args, **kw):
print(f'位置参数:{a},{b},{c}')
print(f'可变位置参数:{args}')
print(type(args))
print(f'可变关键字参数:{kw}')
print(type(kw))
my_function(60, 100, 200, 300, 400, g=70, d=80, e=90, f=99) #################
def my_function(my_list):
my_list.append('我是函数内追加的哦')
list_a = [1, 2, 3]
print('函数调用前', list_a)
my_function(list_a)
print('函数调用后', list_a) #################
三、python类的调用与参数传递
python类的调用有三大方法,分别是实例方法,类方法和静态方法。
3.1 实例方法
在类编程中,一般情况下在类中定义的方法/函数默认都是实例方法。python的类编程中实例方法最大的特点就是最少要包含一个 self 参数,该self参数的作用是绑定调用此方法的实例对象。
self参数便是指向实例myhouse,类比C++中的this指针。
实例方法除了能够被实例本身调用外,还能够通过类名直接调用,但需要指定调用的实例对象,
3.2 类方法
Python 中的类方法和实例方法类似,但类方法需要满足以下要求:
类方法至少需要包含一个参数,与实例方法不同的是该参数并非self,而是python程序员约定俗成的参数:cls。Python 会自动将类本身绑定到cls参数(非类对象),故在调用类方法时,无需显式为 cls 参数传递参数。类方法需要使用修饰语句: @classmethod
类方法cls_func()即使通过实例对象my_house调用,其调用者也依然是__main__.House,而不是对象my_house
3.3 静态方法
类中的静态方法,实际上就是大家众所周知的普通函数,存在的唯一区别是:静态方法在类命名空间中定义,而函数则在程序的全局命名空间中定义。静态方法需要使用修饰语句: @staticmethod
需要注意的是:
- 静态方法没有 self、cls 这样的特殊参数,故 Python 解释器不会对其包含的参数做任何类或对象的绑定。
- 静态方法中无法调用任何类和对象的属性和方法,类静态方法与类的关系不大。
3.99 完整代码
class House:
# 类构造方法,也是实例方法
def __init__(self, area, price):
self.area = area
self.price = price
def cls_func(self, arg):
print(arg)
my_house = House('America', 330) # 实例化类对象,需要传入init中的两个参数
print(f'类属性, my_house.price:{my_house.price}, my_house.area:{my_house.area}')
my_house.cls_func('通过实例化后的类对象调用类方法,忽略self')
House.cls_func(my_house, '通过未实例化的类名调用实例方法,需要给self传递实例化后的类对象名')
class House:
# 类构造方法,也是实例方法
def __init__(self, area, price):
self.area = area
self.price = price
@classmethod
def cls_func(cls, arg):
print(f'类方法:{cls}')
print(f'类方法中第二个参数:{arg}')
House.cls_func('我是类方法的第二参数')
my_house = House('America', 330) # 实例化类对象,需要传入init中的两个参数
print(f'类属性, my_house.price:{my_house.price}, my_house.area:{my_house.area}')
my_house.cls_func('通过实例化后的类对象调用类方法,忽略cls')
House.cls_func(my_house, '类方法的调用,不同于实例方法,无需传入实例化对象作为第一参数')
class House:
# 类构造方法,也是实例方法
def __init__(self, area, price):
self.area = area
self.price = price
@staticmethod
def stat_func(arg):
print(f'静态方法中参数:{arg}')
# print(self.area) # 语法错误,静态方法中没有self
House.stat_func('未通过实例化,直接类名调用静态方法,不需要传入实例化对象作为第一参数')
my_house = House('America', 330) # 实例化类对象,需要传入init中的两个参数
print(f'类属性, my_house.price:{my_house.price}, my_house.area:{my_house.area}')
my_house.stat_func('通过实例化后的类对象调用静态方法')
House.stat_func(my_house, '静态方法的调用,不同于实例方法,无需传入实例化对象作为第一参数')