Python基础学习文档(2)

目录

五、函数

1、函数的定义和调用

1、函数的定义

2、函数的调用

2、函数参数

1、参数传递

2、参数类型

3、参数传递的序列解包

3、特殊函数

1、匿名函数

2、嵌套函数

3、递归函数

4、变量作用域

1、变量类型:

2、全局变量与局部变量

3、关键字global,nonlocal

六、面向对象程序设计

1、类与对象

2、成员

1、公有成员

2、私有成员

3、方法

1、方法的类型

2、特殊方法

4、封装、继承与多态

1、封装

2、继承

3、多态

5、抽象类与抽象方法

1、抽象类

2、抽象方法


五、函数

1、函数的定义和调用

1、函数的定义

(1)函数关键字:关键字必须以def开头,后接函数名与()
(2)函数名:遵守标识符命名规则。
(3)返回值:使用“return[表达式]”结束函数,返回一个值给调用方。如果没有返回值,默认返回None。
(4)函数体:函数体可以实现函数功能,也可以为pass语句,表示什么工作都不做,比如抽象类中的抽象函数。
(5)参数:参数是可选的,可以有,可以没有,可以有多个参数。

def sayhello():
    print("Hello,Python")

sayhello()
# Hello,Python

def none():
    pass
# 无函数体

def hi(name):
    print("hi,",name)

hi("李华")
# hi, 李华

2、函数的调用

(1)函数定义完成之后,可以在程序中调用。函数调用时需要指出函数名称,并传入相应的参数。
(2)函数调用时传入的参数为实际参数,简称为实参。
(3)在默认情况下,函数调用时传入的实参个数,顺序等必须和函数定义时形参个数,顺序一致。

def sayhello():
    print("Hello,Python")

sayhello() # 该行调用了函数 sayhello()
# Hello,Python

2、函数参数

1、参数传递

Python中的对象可分为不可变对象(数字、字符串、元组等)和可变对象(列表、字典、集合等)

(1)当实参为不可变对象时。函数调用是将实参的值复制一份给形参,在函数调用中修改形参时,不会改变函数外的实参。

a = 1
b = 2
def swap(m,n):
    print(f"交换前m = {m},n = {n}")
    x = m
    m = n
    n = x
    print(f"交换后m = {m},n = {n}")

swap(a,b)
print(f"函数调用后:a = {a},b = {b}")
# 交换前m = 1,n = 2
# 交换后m = 2,n = 1
# 函数调用后:a = 1,b = 2

(2)当实参为可变对象时。函数调用是将实参引用给形参,形参改变时,函数外实参也会跟着改变。

a = [1,2]

def swap(m):
    print(f"添加元素前:m = {m}")
    m.append(4)
    print(f"添加元素后:m = {m}")

swap(a)
print(f"函数调用后:a = {a}")
# 添加元素前:m = [1, 2]
# 添加元素后:m = [1, 2, 4]
# 函数调用后:a = [1, 2, 4]

2、参数类型

(1)位置参数:调用函数时根据函数定义的参数位置来传递参数

def test(name,age,gender):
    print(f"名字{name},年龄{age},性别{gender}")

test("TOM",20,"男")


输出:
名字TOM,年龄20,性别男

注意:传递参数和定义参数的顺序与个数必须一致。


(2)关键字参数:函数调用时通过”键=值“形式传递参数
作用:可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求

def test(name,age,gender):
    print(f"姓名{name},年龄{age},性别{gender}")
# 关键字传递参数
test(name = "小明",age = 20,gender = "男")
# 可以不按固定顺序
test(gender = "男",age = 20,name = "小明")
# 可以和位置参数混用,位置参数必须在前,且匹配参数顺序
test("小明",gender = "男",age = 20)

输出:
姓名小明,年龄20,性别男
姓名小明,年龄20,性别男
姓名小明,年龄20,性别男


(3)缺省参数:缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数时课不传该默认参数的值
(注意:所有位置参数,必须出现在默认参数前,包括函数定义和调用)
作用:当调用函数没有调用参数,就会使用默认是缺省参数对应的值

def test(name,age,gender = "男"):
    print(f"姓名{name},年龄{age},性别{gender}")

test("TOM",20)
test("Rose",20,"女")

输出:
姓名TOM,年龄20,性别男
姓名Rose,年龄20,性别女

注意:函数调用时,如果为缺省参数传值,则修改默认参数值,否则就是用这个默认值

(4)不定长参数:不定长参数也叫可变参数,用于不确定调用的时候会传递多少个参数(不传参也可以)的场景
作用:当调用函数时不确定参数个数时,可以使用不定长参数
不定长参数类型:
1.位置传递

def test(*args):
    print(f"args = {args}")

test("TOM")
test("TOM",18)


输出:
args = ('TOM',)
args = ('TOM', 18)
 

2.关键字传递

def test(**kwargs):
    print(f"kwargs = {kwargs}")

test(name = "TOM",age = 18,id = 110)
# kwargs = {'name': 'TOM', 'age': 18, 'id': 110}

注意:参数是“键=值”形式的情况下,所有“键=值”都会被kwargs接收,同时会根据“键=值”组成字典
 

3、参数传递的序列解包

参数传递的序列解包针对的是实参,有*和**两种形式。实参前加入了*或**后会将列表、元组、字典等迭代对象中的元素分别传递给形参中的多个变量。

def test(a,b,c):
    print(f"a = {a},b = {b},c = {c}")

test(*[1,2,3])
# a = 1,b = 2,c = 3
test(**{'a' : 1,'b' : 2,'c' : 3 } )
# a = 1,b = 2,c = 3
test(**{'c' : 1, 'b' : 2, 'a' : 3})
# a = 3,b = 2,c = 1

3、特殊函数

1、匿名函数

lambda匿名函数:
有名函数,可以基于名称重复使用。
无名称的匿名函数,只能临时使用一次。

语法:
lambda 传入参数:函数体(一行代码)

lambda是关键字,表示定义匿名函数。
传入参数表示匿名函数的形式参数,如x,y表示接收两个形式参数

def test1(t2):
    result = t2(1,2)
    print(result)

test1(lambda x,y : x + y)
# 3

使用def和使用lanbda,定义函数功能完全一致,只是lambda关键字定义的函数是匿名的,无法二次使用

函数作参数传递:

def test1(t2):
    result = t2(1,2)
    print(result)

def test2(x,y):
    return x + y

test1(test2)
# 3

2、嵌套函数

嵌套函数是指在一个函数(称为外函数)内部调用另一个函数(称为内函数)。嵌套函数中的内函数只能在外函数中调用,不能在外函数外面直接调用。

def outer():
    def inner():
        print("我是内函数")
    print("我是外函数")
    inner()

outer()
# 我是外函数
# 我是内函数
inner()
# 无法在外函数外部调用内函数,会报错

3、递归函数

如果一个函数在函数体中直接或间接调用自身,那么这个函数就被称为递归函数。

例题:使用递归函数,求斐波那契函数前20项之和。

def fib(n):
    if n == 1 or n == 2 :
        return 1
    else:
        return fib(n - 1) + fib(n - 2)

sum = 0
for i in range(1,21):
    sum = sum + fib(i)
print("斐波那契函数前20项之和:",sum)
# 斐波那契函数前20项之和: 17710

4、变量作用域

1、变量类型:

(1)局部变量与局部作用域:局部变量是定义在函数内部的变量,作用域是从函数定义的位置知道该函数结束。当函数被调用时变量被定义,当函数别表用结束时,局部变量消失。

(2)全局变量与全局作用域:全局变量是定义在模块函数外的变量。全局作用域仅限于单个模块文件内。

(3)闭包变量与闭包作用域:闭包变量被定义在嵌套函数的内函数外部并且在外函数内部。闭包作用域为定义该变量的位置开始的整个函数内。

(4)内建变量与内建作用域*:系统内固定模块里定义的变量,一般为预定义在内建模块内的变量。

2、全局变量与局部变量

局部变量只能在其声明的函数内部使用,全局变量可以在整个模块中使用。

a = 100
def func():
    b = 1000
    print("a = ",a)
    print("b = ",b)
func()
# a =  100
# b =  1000
print("a = ",a)
# a =  100
print("b = ",b)
# 局部变量不能在定义该变量的外部使用,会报错

3、关键字global,nonlocal

global:可以将变量修改为全局变量。

def func():
    global a
    a = "我变为了全局变量"
    print(f"a = {a}")
func()
# a = 我变为了全局变量
print(f"a = {a}")
# a = 我变为了全局变量

nonlocal:可以将变量修改为闭包变量。

def outter():
    a = "111"
    def inner():
        nonlocal a
        print(f"a = {a}")
        a = "222"
        print(f"a = {a}")
    print(f"a = {a}")
    inner()
outter()
# a = 111
# a = 111
# a = 222

六、面向对象程序设计

1、类与对象

class:是关键字,表示定义类
类的属性:定义在类中的变量(成员变量)
类的行为:定义在类中的方法(成员方法)

类中,不仅可以定义属性来记录数据,也可以定义函数来记录行为

def(self,形参1,形参2......):
    方法体

self:关键字是成员方法定义的时候,必须填写的。
它用来表示类对象自身的意思
当我们使用类对象调用方法的时候,self会自动别python传入
在方法内部,想要访问成员变量,必须使用self
 


class student:
    name = None
    sex = None
# 可以省略

    def __init__(self , name , sex):
        self.name = name
        self.sex = sex
        print("我是构造方法")
    def say_hi(self,h):
        print(f"我的名字是{self.name},{h}")

# stu_1 = student()
# stu_1.name = "李华"
# stu_1.sex = "男"
# stu_1.say_hi("hi")
# 在未定义构造方法时,可以正常运行

stu_2 = student("小明","男")
# 创建对象
stu_2.say_hi("你好啊")

# 我是构造方法
# 我的名字是小明,你好啊

2、成员

1、公有成员

公有成员:不以下划线开头,在类的内部、外部都可以访问。

2、私有成员


私有成员变量:变量名以__开头(两个下划线)
私有成员方法:方法名以__开头(两个下划线)


使用私有成员:
私有成员无法被类对象使用,但是可以被其他的成员使用。

class student:
    __name = None
    __age = None

    def __str__(self):
        return f"student类,name:{self.__name},age:{self.__age}"

    def __init__(self,name,age):
        self.__age = age
        self.__name = name

    def __self(self):
        print("我是私有方法")
    def print(self):
        print("我是公有有方法")
        self.__self();

stu1 = student("李华",19)
stu1.print()
print(stu1)

# 我是公有有方法
# 我是私有方法
# student类,name:李华,age:19

3、方法

1、方法的类型

公有方法:不以下划线开头,在类的外部通过类名或对象名调用。

私有方法:方法名以__开头(两个下划线或更多下划线),在类的内部可以使用self调用,在类外不能直接调用。

2、特殊方法

__init__:构造方法
__str__:字符串方法
__lt__:小于,大于符号比较
__le__:小于等于,大于等于符号比较
__eq__:==符号比较
 


class student:
    name = None
    age = None
# 可以省略

    def __init__(self , name , age):
        self.name = name
        self.age = age
        print("我是构造方法")

    def __str__(self):
        return f"student类对象,name:{self.name},age:{self.age}"

    def __lt__(self, other):
        return self.age < other.age

    def __le__(self,other):
        return self.age <= other.age

    def __eq__(self,other):
        return self.age == other.age

stu1 = student("李华",18)
print(stu1)
print(str(stu1))

stu2 = student("小明",18)
print(f"李华年龄大于小明吗?{stu1 > stu2}")
print(f"李华年龄大于等于小明吗?{stu1 >= stu2}")
print(f"李华年龄等于小明吗?{stu1 == stu2}")

# 我是构造方法
# student类对象,name:李华,age:18
# student类对象,name:李华,age:18
# 我是构造方法
# 李华年龄大于小明吗?False
# 李华年龄大于等于小明吗?True
# 李华年龄等于小明吗?True

4、封装、继承与多态

1、封装

封装表示的是,将现实世界事物的:
属性
行为
封装到类中,描述为:
成员变量
成员方法
从而完成程序对现实世界事物的描述

例如:私有成员,私有方法等

2、继承

单继承:一个子类继承一个父类
多继承:一个子类继承多个父类
多继承中,如果有重名的属性或者方法,先继承的优先级高于后继承的


class a:
    pass
class c:
    pass
class b(a,c):
    pass
# 定义的b类继承a,c类。

pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思。

一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果需要使用被复写的父类成员,需要用特殊的调用方式:
方式1:
使用父类成员变量:父类名.成员变量
使用父类成员方法:父类名.成员方法(self)

方式2:
使用父类成员变量:super().成员变量
使用父类成员方法:super().成员方法()


class a:
    name = "我是父类成员"
class b(a):
    name = "我是子类成员"
    print(f"子类name = {name}")
    print(f"父类name = {a.name}")
# 子类name = 我是子类成员
# 父类name = 我是父类成员


注意:
只可以在子类内部调用父类的同名成员,子类的实体类对象调用默认是调用子类复写的相关内容。
 

3、多态

什么是多态:
多态是指,同一行为,使用不同的对象获得不同状态。
如:定义函数(方法),通过类型注解声明需要父类对象,实际传入子类对象进行工作,从而获得不同工作状态。

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        print("汪汪汪")

class Cat(Animal):
    def speak(self):
        print("喵喵喵")

def make_noise(animal:Animal):
    animal.speak()

dog = Dog()
cat = Cat()

make_noise(cat)
# 喵喵喵
make_noise(dog)
# 汪汪汪

多态常作用在继承关系上,比如:
(1)函数(方法)形参声名接受父类对象
(2)实际传入父类的子类对象进行工作
即:
(1)以父类做定义声明
(2)以子类做实际工作
(3)用以获得同一行为,不同状态

5、抽象类与抽象方法

1、抽象类

抽象类的作用:
多用于顶层设计(设计标准),以便子类做具体实现。
也是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法,并配合多态使用,获得不同的工作状态。

抽象类(接口)

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        print("汪汪汪")

class Cat(Animal):
    def speak(self):
        print("喵喵喵")

父类Animal的speak方法,是空实现
这种设计的含义是:
(1)父类来确定有哪些方法
(2)具体的方法实现,由子类自行决定

这种写法就叫做抽象类(也可以称之为接口)

抽象类:含有抽象方法的类,称为抽象类

2、抽象方法

抽象方法:方法体是空实现的(pass)称之为抽象方法。

你可能感兴趣的:(python,python,pycharm,学习)