学习Python第三周总结

2021/8/7 12:05:54

本文主要是介绍学习Python第三周总结,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

学习Python第三周总结

一、函数和模块

1.1 函数的定义

​ Python中的函数的自变量称为函数的参数,而因变量称为函数的返回值

在Python中可以使用def关键字来定义函数,命名规则跟变量的命名规则是一致的。在函数名后面的圆括号中可以放置传递给函数的参数,就是我们刚才说到的函数的自变量,而函数执行完成后我们会通过return关键字来返回函数的执行结果,就是我们刚才说的函数的因变量。一个函数要执行的代码块(要做的事情)也是通过缩进的方式来表示的,跟之前分支和循环结构的代码块是一样的。

1.2函数的参数

如果函数中没有return语句,那么函数默认返回代表空值的None。另外,在定义函数时,函数也可以没有自变量,但是函数名后面的圆括号是必须有的。

  • 位置参数——在没有特殊处理的情况下,函数的参数都是位置参数

  • 关键字参数——我们在设计函数时,如果既不知道调用者会传入的参数个数,也不知道调用者会不会指定参数名,那么同时使用可变参数和关键字参数。关键字参数会将传入的带参数名的参数组装成一个字典,参数名就是字典中键值对的键,而参数值就是字典中键值对的值

重点提醒:关键字参数一定要在位置参数的后面。

代码例子如下:

# *args--->可变参数--->可以接收零个或任意多个位置参数--->将位置参数打包成元组
# **kwargs--->可以接收零个或任意多个关键字参数--->将所有的关键字参数打包成一个字典


def add(*args, **kwargs):
    print(args, type(args))
    # print(kwargs, type(kwargs))
    total = 0
    for arg in args:
        if type(arg) in (int, float):
            total += arg
    for value in kwargs.values():
        if type(value) in (int, float):
            total += value
    return total


print(add(1, 2, 4, a=3))


def mul(*args, **kwargs):
    # print(args, type(args))
    # print(kwargs, type(kwargs))
    total = 1
    for arg in args:
        if type(arg) in (int, float):
            total *= arg
    for value in kwargs.values():
        if type(value) in (int, float):
            total *= value
    return total


print(mul(1, 2, 4, a=3))

函数的例题一:

玩家摇两颗骰子,如果第一次摇出了7点或11点,玩家胜;如果摇出了2点、3点、12点,庄家胜;
如果摇出了其他的点数,游戏继续,玩家重新摇色子;如果玩家摇出了第一次摇的点数,玩家胜;
如果玩家摇出了7点,庄家胜;如果玩家摇出其他点数,游戏继续,玩家重新摇色子,直到分出胜负。

游戏开始之前,玩家有1000元的初始资金,玩家可以下注,赢了获得下注的金额,输了就扣除下注的金额,
游戏结束的条件是玩家把钱输光。
import random


def roll_dice(num):
    """
    摇骰子

    :param num: 骰子的数量
    :return: 摇出的点数
    """
    total = 0
    for _ in range(num):
        total += random.randrange(1, 7)
    return total


def win():
    global x
    print('玩家胜')
    x += z


def lose():
    global x
    print('庄家胜')
    x -= z


x = 1000
while x > 0:
    print(f'玩家总资产为{x}元')
    z = 0
    while z <= 0 or z > x:
        z = int(input('请下注'))
        m = roll_dice(3)
    print(f'玩家摇出了{m}点')
    if m in (7, 11):
        win()
    elif m in (2, 3, 12):
        lose()
    else:
        while True:
            n = roll_dice(3)
            print(f'玩家摇出了{n}点')
            if n == m:
                win()
                break
            elif n == 7:
                lose()
                break
print('玩家已破产,游戏结束')

例题二:

# 求阶乘
def fac(num):
    """求阶乘"""
    result = 1
    for i in range(2, num + 1):
        result *= i
    return result


m = int(input('m = '))
n = int(input('n = '))
print(fac(m) // fac(n) // fac(m - n))

1.3标准库中的模块和函数

Python标准库中提供了大量的模块和函数来简化我们的开发工作,random模块可以提供生成随机数和进行随机抽样的函数;而time模块则可以提供和时间操作相关的函数。在Python标准库中的math模块中还包括了计算正弦、余弦、指数、对数等一系列的数学函数。随着我们进一步的学习Python编程知识,我们还会用到更多的模块和函数。

Python标准库中还有一类函数是不需要import就能够直接使用的,我们将其称之为内置函数,这些内置函数都是很有用也是最常用的,下面的表格列出了一部分的内置函数。

函数说明
abs返回一个数的绝对值,例如:abs(-1.3)会返回1.3
bin把一个整数转换成以'0b'开头的二进制字符串,例如:bin(123)会返回'0b1111011'
chr将Unicode编码转换成对应的字符,例如:chr(8364)会返回'€'
hex将一个整数转换成以'0x'开头的十六进制字符串,例如:hex(123)会返回'0x7b'
input从输入中读取一行,返回读到的字符串。
len获取字符串、列表等的长度。
max返回多个参数或一个可迭代对象(后面会讲)中的最大值,例如:max(12, 95, 37)会返回95
min返回多个参数或一个可迭代对象(后面会讲)中的最小值,例如:min(12, 95, 37)会返回12
oct把一个整数转换成以'0o'开头的八进制字符串,例如:oct(123)会返回'0o173'
open打开一个文件并返回文件对象(后面会讲)。
ord将字符转换成对应的Unicode编码,例如:ord('€')会返回8364
pow求幂运算,例如:pow(2, 3)会返回8pow(2, 0.5)会返回1.4142135623730951
print打印输出。
range构造一个范围序列,例如:range(100)会产生099的整数序列。
round按照指定的精度对数值进行四舍五入,例如:round(1.23456, 4)会返回1.2346
sum对一个序列中的项从左到右进行求和运算,例如:sum(range(1, 101))会返回5050
type返回对象的类型,例如:type(10)会返回int;而type('hello')会返回str

二、高阶函数

​ Python中的函数是一等函数,但是函数本身也可以作为函数的参数或返回值,而且还可以赋值给变量。这就是所谓的高阶函数。通常使用高阶函数可以实现对原有函数的解藕合操作。

Lambda函数——没有名字而且一句话就能写完的函数,唯一的表达式就是函数的返回值。也被称为匿名函数

例如:

# fn ---> 一个实现二元运算的函数(可以做任意的二元运算)
def calc(*args, op, init_value=0, **kwargs):
    total = init_value
    for arg in args:
        if type(arg) in (int, float):
            total = op(total, arg)
    for value in kwargs.values():
        if type(value) in (int, float):
            total = op(total, value)
    return total


# def add(x, y):
#     return x + y
#
#
# def mul(x, y):
#     return x * y


# print(calc(11, 22, 33, 44, op=add))
print(calc(11, 22, 33, 44, op=lambda x, y: x + y))
# print(calc(11, 22, 33, 44, op=mul, init_value=1))
print(calc(11, 22, 33, 44, init_value=1, op=lambda x, y: x * y))
fn = lambda x, y: x - y
print(calc(11, 22, 33, 44, init_value=100, op=fn))

三、递归调用

​ 函数如果直接或者间接的调用了自身,那么这种调用就被称为递归调用。

递归函数的两个要点:

  • 递归公式(第n次跟第n-1次的关系)
  • 收敛条件(什么时候停止递归调用)
# 不管函数是调用别的函数,还是调用自身,一定要做到快速收敛。
# 在比较有限的调用次数内能够结束,而不是无限制的调用函数。
# 如果一个函数(通常指递归调用的函数)不能够快速收敛,那么就很有可能产生下面的错误
# RecursionError: maximum recursion depth exceeded
# 最终导致程序的崩溃。


def fac(num: int) -> int:
    """求阶乘(递归写法)"""
    if num == 0:
        return 1
    return num * fac(num - 1)


if __name__ == '__main__':
    # return 5 * fac(4)
    # return 4 * fac(3)
    # return 3 * fac(2)
    # return 2 * fac(1)
    # return 1 * fac(0)
    # return 1
    print(fac(5))



def fib(n):
    if n in (1, 2):
        return 1
    return fib(n - 1) + fib(n - 2)


if __name__ == '__main__':
    for i in range(1, 21):
        print(i, fib(i))

例题一:编写实现对列表元素进行冒泡排序的函数

def bubble_sort(items, ascending=True, gt=lambda x, y: x > y):
    """
    冒泡排序
    :param items: 待排序的列表
    :param ascending:
    :param gt:
    :return:
    """
    items = items[:]
    for i in range(1, len(items)):
        swapped = False
        for j in range(0, len(items) - i):
            if gt(items[j], items[j + 1]):
                items[j], items[j + 1] = items[j + 1], items[j]
                swapped = True
        if not swapped:
            break
    if not ascending:
        items = items[::-1]
    return items


if __name__ == '__main__':
    nums = [35, 96, 12, 7, 20, 8, 15]
    print(bubble_sort(nums, ascending=False))
    print(nums)

例题二:编写实现查找列表元素的函数:

def seq_search(items: list, key) -> int:
    """
    顺序查找
    :param items: 待查找的元素
    :param key: 要找的元素
    :return: 找到了返回元素的索引,找不到返回-1
    """
    for index, item in enumerate(items):
        if item == key:
            return index
    return -1


def bin_search(items: list, key) -> int:
    """
    二分查找
    :param items:待查找的元素(元素有序)
    :param key: 要找的元素
    :return: 找到了返回元素的索引,找不到返回-1
    """
    start, end = 0, len(items) - 1
    while start <= end:
        mid = (start + end) // 2
        if key > items[mid]:
            start = mid + 1
        elif key < items[mid]:
            end = mid - 1
        else:
            return mid
    return -1


if __name__ == '__main__':
    nums1 = [5, 4, 7, 20, 8, 15]
    print(seq_search(nums1, 20))
    print('_' * 20)
    nums2 = [4, 5, 7, 8, 15, 20]
    print(bin_search(nums2, 15))
    print(bin_search(nums2, 45))

四、面向对象编程

1、定义

面向对象编程是一种编程范式(程序设计的方法论)。

如果要用一句话来概括面向对象编程,我认为下面的说法是相当精准的。

面向对象编程:把一组数据和处理数据的方法组成对象,把行为相同的对象归纳为,通过封装隐藏对象的内部细节,通过继承实现类的特化和泛化,通过多态实现基于对象类型的动态分派。

对象:对象是可以接收消息的实体,面向对象编程就行通过给对象发消息达到解决问题的目标。对象 = 数据 + 函数(方法),即对象将数据和操作数据的函数从逻辑上变成了一个整体。

对象有以下四个特征:

  • 一切皆为对象
  • 对象都有属性和行为
  • 每个对象都是独一无二的
  • 对象一定属于某个类

:将有共同特征(静态特征和动态特征)的对象的共同特征抽取出来之后得到的一个抽象概念。简单的说,类是对象的蓝图(模板),有了类才能够创建出这种类型的对象。

2、创建和使用对象

1、定义类:类的命名使用驼峰命名法(每个单词首字母大写)

​ 数据抽象:找到和对象相关的静态特征(属性)

​ 行为抽象:找到和对象相关的动态特征(方法)

2、创建对象

3、给对象发消息

例如:

# 第一步:定义类
class Student:
    """学生"""

    # 数据抽象(属性)
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 行为抽象(方法)
    def eat(self, name):
        """吃饭"""
        print(f'{self.name}正在吃{name}')

    def study(self, course_name):
        """
        学习
        :param course_name: 课程名字
        """
        print(f'{self.name}正在学习{course_name}')

    def play(self, game_name):
        """
        玩耍
        :param game_name: 游戏名字
        """
        print(f'{self.name}正在玩{game_name}')
        
# 第二步:创建对象--->构造器语法--->类名(..., ...)
Stu1 = Student('黄小宇', 18)
Stu2 = Student('周大大', 21)

# Student.study(stu1, 'Python程序设计')
# 第三步:给对象发消息(调用对象的方法)
Stu1.eat('螺蛳粉')

Stu2.study('Python程序设计')

3、魔术方法

魔术方法(魔法方法)—> 有特殊用途和意义的方法
init —> 初始化方法,在调用构造器语法创建对象的时候会被自动调用
str —> 获得对象的字符串表示,在调用print函数输出对象时会被自动调用
repr —> 获得对象的字符串表示,把对象放到容器中调用print输出时会自动调用
—> representation
lt —> 在使用 < 运算符比较两个对象大小时会自动调用

如果一个变量的取值只有有限个选项,可以考虑使用枚举类型。
Python中没有定义枚举类型的语法,但是可以通过继承Enum类来实现枚举类型。
结论1:枚举类型是定义符号常量的最佳选择!!!
结论2:符号常量(有意义的名字)总是优于字面常量!!

4、继承和多态

继承:对已有的类进行扩展创建出新的类,这个过程就叫继承。
提供继承信息的类叫做父类(超类、基类),得到继承信息的类称为子类(派生类)。

继承是实现代码复用的一种手段,但是千万不要滥用继承。

继承是一种is-a关系。
a student is a person.
a teacher is a person.
a programmer is a person.

子类直接从父类继承公共的属性和行为,再添加自己特有的属性和行为,
所以子类一定是比父类更强大的,任何时候都可以用子类对象去替代父类对象。

Python中的继承允许多重继承,一个类可以有一个或多个父类。
如果不是必须使用多重继承的场景下,请尽量使用单一继承。

5、两个类之间有哪些关系

~ is-a关系:继承—>从一个类派生出另一个类
a student is a person
~ has-a关系:关联—>把一个类的对象作为另外一个类的对象的属性
a person has an identity card
——(普通)关联

​ —— 强关联:整体和部分的关联,聚合和合成
use-a关系:依赖—>一个类的对象作为另外一个类的方法的参数或返回值
​ a person use a vehicle(交通工具)

6、面向对象编程的四大支柱

1、抽象(abstraction):提取共性(定义类就是一个抽象过程,需要做数据抽象和行为抽象)
2、封装(encapsulation):把数据和操作数据的函数从逻辑上组成一个整体(对象)
—>隐藏实现细节,暴露简单的调用接口
3、继承(inheritance):扩展已有的类创建新类,实现对已有类的代码复用
4、多态(polymorphism):给不同的对象发出同样的消息,不同的对象执行了不同的行为。
—>方法重写(override):子类对父类已有的方法,重新给出自己的实现版本

​ 在重写方法的过程中,不同的子类可以对父类的同一个方法给出不同的实现版本,
那么该方法在运行时就会表现出多态性

7 经典例题

例题一:

现在有三类员工:
部门经理:固定月薪,15000
程序员:计时结算月薪,
销售员:底薪 + 提成,底薪1800,销售额 %5提成
写一个面向对象的编程实现工资的计算
from abc import abstractmethod


class Employee:
    def __init__(self, name):
        self.name = name

    @abstractmethod
    def get_salary(self):
        pass


class Manager(Employee):

    def get_salary(self):
        return 15000


class Programmer(Employee):

    def __init__(self, name):
        super().__init__(name)
        self.working_hour = 0

    def get_salary(self):
        return 200 * self.working_hour


class Salesman(Employee):

    def __init__(self, name):
        super().__init__(name)
        self.sales = 0

    def get_salary(self):
        return 1800 + 0.05 * self.sales


def main():
    emps = [Manager('刘备'), Programmer('诸葛亮'), Salesman('关羽')]

    for emp in emps:
        if type(emp) == Programmer:
            emp.working_hour = int(input(f'请输入{emp.name}本月工作时长'))
        elif type(emp) == Salesman:
            emp.sales = int(input(f'请输入{emp.name}本月销售额'))
        print(f'{emp.name}本月工资:{emp.get_salary()}元')


if __name__ == '__main__':
    main()

例题二:

# 创建一个时钟对象(可以显示时/分/秒),让它运转起来
import time


class Clock:

    # 数据抽象
    def __init__(self, hour=0, minute=0, second=0):
        self.hour = hour
        self.min = minute
        self.sec = second

    def show(self):
        """显示时间"""
        return f'{self.hour:0>2d}:{self.min:0>2d}:{self.sec:0>2d}'

    # 行为抽象
    def run(self):
        """走字"""
        self.sec += 1
        if self.sec == 60:
            self.sec = 0
            self.min += 1
            if self.min == 60:
                self.min = 0
                self.hour += 1
                if self.hour == 24:
                    self.hour = 0


if __name__ == '__main__':
    clock = Clock()
    while True:
        print(clock.show())
        time.sleep(1)
        clock.run()

五、总结

​ Python中的函数可以使用可变参数*args和关键字参数**kwargs来接收任意数量的参数,而且传入参数时可以带上参数名也可以没有参数名,可变参数会被处理成一个元组,而关键字参数会被处理成一个字典。Python中的函数也是对象,所以函数可以作为函数的参数和返回值,也就是说,在Python中我们可以使用高阶函数。如果我们要定义的函数非常简单,只有一行代码且不需要名字,可以将函数写成Lambda函数(匿名函数)的形式。

​ 面向对象编程是一种非常流行的编程范式,除此之外还有指令式编程函数式编程等编程范式。由于现实世界是由对象构成的,而对象是可以接收消息的实体,所以面向对象编程更符合人类正常的思维习惯。类是抽象的,对象是具体的,有了类就能创建对象,有了对象就可以接收消息,这就是面向对象编程的基础。定义类的过程是一个抽象的过程,找到对象公共的属性属于数据抽象,找到对象公共的方法属于行为抽象。

​ 这周的函数和面向对象编程是重点,也是难点。需要反复的去巩固练习,需要用时间去练习,以此来让我们能够熟练的掌握。



这篇关于学习Python第三周总结的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程