第三周学习总结

函数

  1. 函数的作用:世界级的编程大师Martin Fowler先生曾经说过:“代码有很多种坏味道,重复是最坏的一种!”我们可以将重复代码封装到一个称为“函数”的代码块中,在需要的地方,我们只需要“调用函数”就可以了。
  2. 定义函数:在Python中可以使用def关键字来定义函数,命名规则跟变量的命名规则是一致的,在函数名后面的圆括号中可以放置传递给函数的参数,函数执行完成后我们会通过return关键字来返回函数的执行结果,就是函数的因变量。
  3. 我们可以通过函数对代码进行重构。所谓重构,是在不影响代码执行结果的前提下对代码的结构进行调整。

函数的参数

参数的默认值:
  1. 果函数中没有return语句,那么函数默认返回代表空值的None。另外,在定义函数时,函数也可以没有自变量,但是函数名后面的圆括号是必须有的。Python中还允许函数的参数拥有默认值。
  2. 带默认值的参数必须放在不带默认值的参数之后,否则将产生SyntaxError错误,错误消息是:non-default argument follows default argument,翻译成中文的意思是“没有默认值的参数放在了带默认值的参数后面”。
可变参数
  1. 有的时候我们并不知道函数的调用者会向该函数传入多少个参数,这个时候可变参数就可以派上用场。
  2. *args —> 可变参数 —> 可以接收零个或任意多个位置参数 —> 将所有的位置参数打包成一个元组
  3. **kwargs —> 可以接收零个或任意多个关键字参数 —> 将所有的关键字参数打包成一个字典。

导入函数

  1. 使用函数的时候我们通过import关键字导入指定的模块再使用完全限定名的调用方式。
  2. 在导入模块时,还可以使用as关键字对模块进行别名,这样我们可以使用更为简短的完全限定名。
  3. 我们也可以使用from...import...语法从模块中直接导入需要使用的函数。

高阶函数

python中的函数是一等函数(一等公民):
  1. 函数可以作为函数的参数
  2. 函数可以作为函数的返回值
  3. 函数可以赋值给变量

如果把函数作为函数的参数或者返回值,这种玩法通常称之为高阶函数。
通常使用高阶函数可以实现对原有函数的解耦合操作。

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

函数可以自己调用自己吗?

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

函数的应用

例子1

设计一个生成指定长度验证码的函数

mport random
import string


def get_captcha_code(length: int = 4) -> str:
    """生成随机验证码

    :param length: 验证码的长度
    :return: 随机验证码字符串
    """
    selected_chars = random.choices(string.digits + string.ascii_letters, k=length)
    return ''.join(selected_chars)


for _ in range(10):
    print(get_captcha_code())
例子2

写实现对列表元素进行冒泡排序的函数,设计函数的时候,一定要注意函数的无副作用性(调用函数不影响调用者)

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, 78, 56, 64, 39, 80]
    print(bubble_sort(nums, ascending=False))
    # print(nums)
    words = ['apple', 'watermelon', 'hello', 'zoo', 'internationalization']
    print(bubble_sort(words, gt=lambda x, y: len(x) > len(y), ascending=False))

思维导图

在这里插入图片描述
在这里插入图片描述

面向对象编程入门

  1. 指令式编程 —> 面向过程(函数)编程 —> 程序比较简单的时候没有任何毛病

  2. 编程范式(程序设计的方法论):面向对象编程 / 函数式编程

  3. 对象:对象是可以接收消息的实体,面向对象编程就是通过给对象发消息达到解决问题的目标。

  4. 对象 = 数据 + 函数(方法)—> 对象将数据和操作数据的函数从逻辑上变成了一个整体。
    ~ 一切皆为对象
    ~ 对象都有属性和行为
    ~ 每个对象都是独一无二的
    ~ 对象一定属于某个类

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

面向对象编程:

  1. 定义类 —> class关键字加上类名来定义类, 类的命名使用驼峰命名法(每个单词首字母大写)
    数据抽象:找到和对象相关的静态特征(属性)—> 找名词
    行为抽象:找到和对象相关的动态特征(方法)—> 找动词
  2. 造对象
  3. 发消息

魔术方法(魔法方法)—> 有特殊用途和意义的方法

~ __init__ ---> 初始化方法,在调用构造器语法创建对象的时候会被自动调用
~ __str__ ---> 获得对象的字符串表示,在调用print函数输出对象时会被自动调用
~ __repr__ ---> 获得对象的字符串表示,把对象放到容器中调用print输出时会自动调用
    ---> representation
~ __lt__ ---> 在使用 < 运算符比较两个对象大小时会自动调用

静态方法和类方法

  1. 我们在类里面写的函数,通常称之为方法,它们基本上都是发给对象的消息。但是有的时候,我们的消息并不想发给对象,而是希望发给这个类(类本身也是一个对象),这个时候,我们可以使用静态方法或类方法。
    静态方法 - 发给类的消息 —> @staticmethod —> 装饰器
    类方法 - 发给类的消息 —> @classmethod —> 装饰器 —> 第一个参数(cls)是接收消息的类
  2. 二者的区别在于,类方法的第一个参数是类对象本身,而静态方法则没有这个参数。简单的总结一下,对象方法、类方法、静态方法都可以通过类名.方法名的方式来调用,区别在于方法的第一个参数到底是普通对象还是类对象,还是没有接受消息的对象。静态方法通常也可以直接写成一个独立的函数,因为它并没有跟特定的对象绑定。

继承和多态

  1. 如果一个变量的取值只有有限个选项,可以考虑使用枚举类型。
    Python中没有定义枚举类型的语法,但是可以通过继承Enum类来实现枚举类型。
    结论1:枚举类型是定义符号常量的最佳选择!!!
    结论2:符号常量(有意义的名字)总是优于字面常量!!!
  2. 继承:对已有的类进行扩展创建出新的类,这个过程就叫继承。
    提供继承信息的类叫做父类(超类、基类),得到继承信息的类称为子类(派生类)。
    注意:继承是实现代码复用的一种手段,但是千万不要滥用继承。
  3. 子类直接从父类继承公共的属性和行为,再添加自己特有的属性和行为,所以子类一定是比父类更强大的,任何时候都可以用子类对象去替代父类对象。
    注意:Python中的继承允许多重继承,一个类可以有一个或多个父类。如果不是必须使用多重继承的场景下,请尽量使用单一继承。
两个类之间有哪些可能的关系???
  1. ~ is-a关系:继承 —> 从一个类派生出另一个类。
    a student is a person.
    a teacher is a person.
  2. ~ has-a关系:关联 —> 把一个类的对象作为另外一个类的对象的属性。
    a person has an identity card.
    a car has an engine.
    • (普通)关联
    • 强关联:整体和部分的关联,聚合和合成
  3. ~ use-a关系:依赖 —> 一个类的对象作为另外一个类的方法的参数或返回值。
    a person use a vehicle.

面向对象编程的四大支柱:

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

思维导图

在这里插入图片描述

应用

例子1

工资(月薪)结算系统
三类员工:
~ 部门经理:固定月薪,15000元
~ 程序员:计时结算月薪,每小时200元
~ 销售员:底薪+提成,底薪1800元,销售额5%提成

录入员工信息,自动结算月薪

from abc import abstractmethod


class Employee:

    def __init__(self, no, name):
        self.no = no
        self.name = name

    @abstractmethod
    def get_salary(self):
        pass


class Manager(Employee):

    def get_salary(self):
        return 15000


class Programmer(Employee):

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

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


class Salesman(Employee):

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

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


def main():
    emps = [
        Manager(1122, '刘备'), Programmer(2233, '诸葛亮'),
        Salesman(3344, '关羽'), Salesman(4455, '张飞'),
        Programmer(5566, '庞统'), Salesman(6677, '马超')
    ]
    for emp in emps:
        if type(emp) == Programmer:
            emp.working_hour = int(input(f'请输入{emp.name}本月工作时长: '))
        elif type(emp) == Salesman:
            emp.sales = float(input(f'请输入{emp.name}本月销售额: '))
        print(f'{emp.name}本月工资: {emp.get_salary()}元')


if __name__ == '__main__':
    main()
例子2
扑克游戏,四个玩家参与,先洗牌,再把牌发到四个玩家的手上。
牌(Card)
  • 属性:花色(suite)、点数(face)
  • 行为:显示
扑克(Poker)
  • 属性:保存牌的列表
  • 行为:洗牌(shuffle)、发牌(deal)
玩家
  • 属性:名字(昵称)、保存玩家手牌的列表
  • 行为:摸牌(get)、整理(arrange)
import random


class Card:
    """牌"""

    def __init__(self, suite, face):
        """
        初始化方法
        :param suite:花色
        :param face: 点数
        """
        self.suite = suite
        self.face = face

    def __str__(self):
        return self.show()

    def __repr__(self):
        return self.show()

    def __lt__(self, other):
        # if self.suite == other.suite:
            return  self.face < other.face
        # return ord(self.suite)<ord(other.suite)

    def show(self):
        suites = {'S': '♠', 'H': '♥', 'C': '♣','D':'♦'}
        faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
        return f'{suites[self.suite]}{faces[self.face]}'


class Poker:
    """扑克"""

    def __init__(self):
        self.cards = [Card(suite, face)
                      for suite in 'SHCD'
                      for face in range(1, 14)]
        self.counter = 0

    def shuffles(self):
        """洗牌"""
        self.counter = 0
        random.shuffle(self.cards)

    def deal(self):
        """发牌"""
        card = self.cards[self.counter]
        self.counter += 1
        return card

    def has_more(self):
        """是否还有牌"""
        return  self.counter<len(self.cards)


class Player:

    def __init__(self, nickname):
        self.nickname = nickname
        self.cards = []

    def get_one_card(self,card):
        """摸牌"""
        self.cards.append(card)
        return self.cards

    def arrange(self):
        """礼牌"""
        self.cards.sort()

    def show(self):
        print(self.nickname,end=':')
        for card in self.cards:
            print(card,end=' ')
        print()

def main():
    poker = Poker()
    poker.shuffles()
    nicknames = ['东邪','西毒','北乔峰','南慕容']
    players = [Player(nickname) for nickname in nicknames ]
    for _ in range(13):
        for player in players:
            card = poker.deal()
            player.get_one_card(card)
    for player in players:
        player.arrange()
        player.show()

if __name__ == '__main__':
    main()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小杨奋斗吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值