
先定义一个函数,需要使用def关键字,然后跟函数名,函数名可用字母、数字以及下划线,不能出现空格和汉字。
然后调用这个函数,有参数就传参,没有参数就不传。
def say_hello():
print('你好!')
say_hello()输出结果为:
你好!调用函数时传入值的顺序,按照定义函数时的参数顺序,不可错序,传入值和函数参数的数量也要相同。
def say_hello(name, age):
print(f'你好,我是{name},今年是{age}岁。')
say_hello('weiyan', 16)
say_hello(17, 'weiyan')输出结果为:
你好,我是weiyan,今年是16岁。
你好,我是17,今年是weiyan岁。调用函数传参数时指定了每个参数的值,此时参数的顺序可以随意,但是传入值和函数参数的数量要相同。
def say_hello(name, age):
print(f'你好,我是{name},今年是{age}岁。')
say_hello(age=18, name='weiyan')输出结果为:
你好,我是weiyan,今年是18岁。定义函数时可以给部分参数设置默认值,调用函数时如果传了值,就使用传的值,如果没传,就使用默认值。
def say_hello(name, age=19):
print(f'你好,我是{name},今年是{age}岁。')
say_hello('weiyan')
say_hello('youzi', 17)输出结果为:
你好,我是weiyan,今年是19岁。
你好,我是youzi,今年是17岁。注意:定义函数时,设置默认参数,应设置为不可变对象如None、整数、浮点数、字符串等,不要使用可变对象如列表、字典。因为默认参数是在定义函数时计算,而不是在调用函数时计算,如果使用可变对象作为默认参数,那么多次调用这个函数时,这个可变对象的值会保留下来,对后续调用函数产生影响,示例如下:
def my_colors(name, color, colors=[]):
colors.append(color)
print(f'你好,我叫{name},我喜欢的颜色是:{colors}。')
my_colors('魏言', 'red')
my_colors('柚子', 'blue')
my_colors('东东', 'dark')输出结果为:
你好,我叫魏言,我喜欢的颜色是:['red']。
你好,我叫柚子,我喜欢的颜色是:['red', 'blue']。
你好,我叫东东,我喜欢的颜色是:['red', 'blue', 'dark']。可见,输出结果并不符合,原因是每次调用函数,列表colors的值都保留下来,对后续调用产生影响。
可变长度参数,也叫可变参数。定义函数时,使用*args可以接收任意数量的位置参数,使用**kwargs可以接收任意数量的关键字参数。
使用*args可以接收任意数量的位置参数,传入的参数会以元组的形式存储。
def say_hello(*args): # 使用*args可以接收任意数量的位置参数
for name in args:
print(f'{name},', end='')
print(f'你好!')
say_hello('weiyan', 'youzi')输出结果为:
weiyan,youzi,你好!使用**kwargs可以接收任意数量的关键字参数,传入的参数会以字典的形式存储。
def infor(name, **kwargs): # 使用**kwargs可以接收任意数量的关键字参数
print(f'{name}是{kwargs["age"]}岁,目前住在{kwargs["city"]}。')
infor('weiyan', age=17, city='深圳')输出结果为:
weiyan是17岁,目前住在深圳。在函数中,使用return某个对象,作为函数的结果。
注意,return要放在函数中的最后,当代码运行到return时,后面的代码就不会运行了。
def say_hello(name, age=19):
words = '你好,我是' + name + ',今年是' + str(age) + '岁。'
return words
words = say_hello('weiyan')
print(words)输出结果为:
你好,我是weiyan,今年是19岁。lambda 函数,即匿名函数,通常用于比较简单的操作。
lambda 函数的简单使用如下第一个函数,第二个函数是与它有同等效果的:
square = lambda n: n ** 2
print(square(5))
def square(n):
return n ** 2
print(square(5))输出结果为:
25
25可以把函数名也作为参数传入函数。
def higher_fun(m, n):
return m(n)
def fun(n):
return n ** 2
num = higher_fun(fun, 5)
print(num)输出结果为:
25使用 class 关键字创建类,并创建它的对象。比如说,“人类”作为一个类,那么“哪吒”作为人类中的个体,就可以通过“人类”这个类创建一个实例,来描述“哪吒”。
以下,创建了一个非常简单类 Person,并创建一个它的实例 nezha,然后调用一个实例方法,打印了一句话。
class Person:
def __init__(self, name):
self.name = name
def print_infor(self):
print(f'你好,我的名字是:{self.name}。')
nezha = Person('哪吒')
nezha.print_infor()输出结果为:
你好,我的名字是:哪吒。作为一个比较完整的类,它除了类名,可能还有类属性,实例属性,类方法,实例方法,静态方法。
示例如下:
class Person:
meals = 2 # 类属性
hands = 2
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age
def print_infor(self): # 实例方法1
print(f'你好,我的名字是:{self.name}。')
def update_age(self, num): # 实例方法2
self.age = num
@classmethod
def update_meals(cls, num): # 类方法
cls.meals = num
@staticmethod
def say_hello(): # 静态方法
print('Hello!')其中,函数 __init__() 是类的构造函数,在创建类的实例时进行初始化操作。
注:__init__() 函数是每个类都有的,但不是必须写,有时候我们创建简单的类,没有写 __init__() 函数,代码也能正常运行,那是因为 python 会默认给提供一个无参数的构造函数。
类属性:是描绘整个类的,在定义类时设置。
实例属性:实例属性是描绘单独某个实例的,定义类时在 __init__() 函数中设置。
区别:修改类属性,会对所以这个类的所有实例生效;而修改实例属性,只会对单个的实例生效。可以通过实例获取类属性,但是不能通过类去获取实例属性。
类方法:类方法需要使用 @classmethod 装饰,它用来修改和访问类属性,第一个参数是作为类本身的 cls
实例方法:实例方法不需要额外修饰,它用来修改和访问实例属性,第一个参数是作为实例本身的 self。
区别:实例可以调用类方法,但是不能用类去调用实例方法。
类属性和实例属性的修改方式:
1.类属性,可以通过类直接修改类属性,也可以通过实例调用类方法修改类属性。修改后,对所有这个类的实例都有效。
2.实例属性,可以通过实例直接修改实例属性,也可以通过实例调用实例方法修改实例属性。修改后,只对当前这个实例有效。
示例如下,先创建两个实例,然后用不同方法修改了类属性和实例属性,然后展示修改结果:
class Person:
meals = 2 # 类属性
hands = 2
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age
def print_infor(self): # 实例方法1
print(f'你好,我的名字是:{self.name}。')
def update_age(self, num): # 实例方法2
self.age = num
@classmethod
def update_meals(cls, num): # 类方法
cls.meals = num
print('修改前:')
nezha = Person('哪吒', 3)
weiyan = Person('魏言', 16)
print(f'实例:名字是{nezha.name}, {nezha.age}岁, 每天吃{nezha.meals}餐,有{nezha.hands}只手。')
print(f'实例:名字是{weiyan.name}, {weiyan.age}岁, 每天吃{weiyan.meals}餐, 有{weiyan.hands}只手。')
print(f'类:每天吃{Person.meals}餐, 有{Person.hands}只手。')
Person.hands = 6 # 通过类直接修改类属性,对所有实例生效
nezha.update_meals(3) # 通过实例调用类方法修改类属性,对所有实例生效
weiyan.age = 17 # 通过实例之间修改实例属性,对当前实例生效
nezha.update_age(4) # 通过实例调用实例方法修改实例属性,对当前实例生效
print('修改后:')
print(f'实例:名字是{nezha.name}, {nezha.age}岁, 每天吃{nezha.meals}餐,有{nezha.hands}只手。')
print(f'实例:名字是{weiyan.name}, {weiyan.age}岁, 每天吃{weiyan.meals}餐, 有{weiyan.hands}只手。')
print(f'类:每天吃{Person.meals}餐, 有{Person.hands}只手。')输出结果为:
修改前:
实例:名字是哪吒, 3岁, 每天吃2餐,有2只手。
实例:名字是魏言, 16岁, 每天吃2餐, 有2只手。
类:每天吃2餐, 有2只手。
修改后:
实例:名字是哪吒, 4岁, 每天吃3餐,有6只手。
实例:名字是魏言, 17岁, 每天吃3餐, 有6只手。
类:每天吃3餐, 有6只手。特殊情况:类属性和实例属性重名,类方法和实例方法重名
如果类属性和实例属性重名,实例属性会把这个实例对应的类属性覆盖掉,即访问时得到的值是实例属性的值。
如果类方法和实例方法重名,编辑器会提示报错,如果强行运行,后者会生效,前者无效。
class Person:
hands = 2
def __init__(self, name):
self.name = name # 实例属性
self.hands = 6
def print_infor(self): # 实例方法1
print(f'你好,我的名字是:{self.name}。')
def update_hands(self, num): # 实例方法2
self.hands = num
print(66666)
@classmethod
def update_hands(cls, num): # 类方法
cls.hands = num
print('修改前:')
nezha = Person('哪吒')
print(f'实例:名字是{nezha.name}, 有{nezha.hands}只手。')
print(f'类:有{Person.hands}只手。')
Person.hands = 3 # 通过类直接修改类属性
nezha.update_hands(4) # 通过实例调用类方法修改类属性
nezha.hands = 7 # 通过实例直接修改实例属性
nezha.update_hands(8) # 通过实例调用实例方法修改实例属性
print('修改后:')
print(f'实例:名字是{nezha.name}, 有{nezha.hands}只手。')
print(f'类:有{Person.hands}只手。')输出结果为:
修改前:
实例:名字是哪吒, 有6只手。
类:有2只手。
修改后:
实例:名字是哪吒, 有7只手。
类:有8只手。当类中需要一个函数,而它的使用,不访问类属性也不访问实例属性,就像一个普通的函数那样,这时候可以创建一个静态方法。
静态方法使用 staticmethod 关键字装饰,对参数格式无特殊要求。可以使用实例来调用静态方法,不可使用类来调用。
class Person:
hands = 2
def __init__(self, name):
self.name = name
@staticmethod
def say_hello(): # 静态方法
print('Hello!')
nezha = Person('哪吒')
nezha.say_hello()输出结果为:
Hello!注意:静态方法不能访问类属性,也不能访问实例属性,这是它和类方法、实例方法的最大区别。
创建一个子类,这个子类继承一个父类,这就是单继承。
在子类中,要使用 super().__init__() 调用父类构造函数,使父类的属性初始化。
子类会继承父类的属性和方法,还可以对这些属性和方法进行重写,子类的实例可以调用它们。这样大大提高了代码的复用率。
class Person:
hands = 2
def __init__(self, name, age):
self.name = name
self.age = age
def print_infor(self):
print(f'你好,我的名字是:{self.name}。')
class Male(Person):
pass
nezha = Male('哪吒', 3)
print(f'实例属性:名字是{nezha.name}, {nezha.age}岁,有{nezha.hands}只手。')
print(f'父类属性:有{Person.hands}只手。')
print(f'子类属性:有{Male.hands}只手。')
nezha.print_infor()输出结果为:
实例属性:名字是哪吒, 3岁,有2只手。
父类属性:有2只手。
子类属性:有2只手。
你好,我的名字是:哪吒。在上述代码中,我们创建了一个子类 Male,继承父类 Person,子类中什么也没有,但是用子类创建的实例,它可以直接调用类属性、实例属性和方法,这是因为子类继承了父类,父类所有的类属性、类方法、实例属性、实例方法、静态方法,全都继承了。
对于父类中已有的属性和方法,无论是类属性、实例属性、类方法、实例方法或者是静态方法,子类中如果重写了同名的属性、方法,就会覆盖掉前者。
class Person:
hands = 2
def __init__(self, name, age):
self.name = name
self.age = age
def print_infor(self):
print(f'你好,我的名字是:{self.name}。')
class Male(Person):
hands = 6
def __init__(self, name, age):
super().__init__(name, age)
self.name = name
self.age = age + 1
def print_infor(self): # 实例方法1
print(f'你好,哈哈哈哈哈,我的名字是:{self.name}。')
nezha = Male('哪吒', 3)
print(f'实例属性:名字是{nezha.name}, {nezha.age}岁,有{nezha.hands}只手。')
nezha.print_infor()输出结果为:
实例属性:名字是哪吒, 4岁,有6只手。
你好,哈哈哈哈哈,我的名字是:哪吒。在这里,我们在子类中,把类属性 hands 从2改成了6,实例属性 age 加1,实例方法 print_infor() 也进行了重写。最后创建实例时,调用这些属性、方法,发现生效的是重写后的。
所以,修改父类属性和方法时,子类中也会生效,但是如果子类中重写了这个属性和方法,那父类的修改就不会影响子类和子类的实例。
对于一个子类,在必要时,它可能继承多个父类,这就是多继承。
多继承时,子类会继承所有父类的属性和方法,子类的实例可以调用它们。
class PersonA:
def say_hello1(self):
print('Hello A')
class PersonB:
def say_hello2(self):
print('Hello B')
class PersonC(PersonA, PersonB):
def say_hello3(self):
print('Hello C')
weiyan = PersonC()
weiyan.say_hello1()
weiyan.say_hello2()
weiyan.say_hello3()输出结果为:
Hello A
Hello B
Hello C属性和方法重名的情况
当属性和方法重名时,会优先生效子类自己的属性和方法;
如果子类中没有重写,是父类互相重名,则按继承的顺序,排在前面的父类生效。
class PersonA:
def say_hello(self):
print('Hello A')
class PersonB(PersonA):
def say_hello(self):
print('Hello B')
class PersonC(PersonA):
def say_hello(self):
print('Hello C')
class PersonD(PersonC, PersonB):
pass输出结果为:
Hello C当多继承时,父类之间存在父子关系
多继承中,如果父类之间存在父子关系,或者祖孙关系,那么继承时,“辈分”大的,要写在后面。
错误示范:
class PersonA:
def say_hello(self):
print('Hello A')
class PersonB(PersonA):
def say_hello(self):
print('Hello B')
class PersonC(PersonA, PersonB):
pass
weiyan = PersonC()
weiyan.say_hello()输出结果为:
Traceback (most recent call last):
File "F:\python_scripts\isli_tools\base\base.py", line 302, in <module>
class PersonC(PersonA, PersonB):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases PersonA, PersonB正确做法:
class PersonA:
def say_hello(self):
print('Hello A')
class PersonB(PersonA):
def say_hello(self):
print('Hello B')
class PersonC(PersonB, PersonA):
pass
weiyan = PersonC()
weiyan.say_hello()输出结果为:
Hello B假如说,有类A,它有子类B和C,其中类C有子类D,那么现在新建一个类,它通过多继承的方式继承B和D,是否需要考虑顺序呢?答案是不需要,因为他俩互相之间不存在父子关系。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。