Python基础学习笔记(21)二分查找 os.walk() 面向对象基础

Python基础学习(21)二分查找 os.walk() 面向对象基础

一、今日大纲

  • 递归算法的扩展:二分查找
  • os 模块的扩展:walk 方法
  • 面向对象基础

二、递归算法的扩展

之前在介绍递归函数的时候已经介绍过,递归算法本质上是分治法的应用,其核心意义就在于把一个复杂的问题不断分解成一个个小问题,从而达到解决问题的方法。利用递归函数实现二分法必然是递归算法的一项重要应用:

# 由于递归次数很多,所以效率其实挺低的
def b_search(lis, element, left=None, right=None):
    if left == None and right == None:
        left = 0
        right = len(lis) - 1
        # print(right)
    mid = (right + left) // 2
    if lis[mid] == element:
        return mid
    elif left >= right:
        return 0
    return b_search(lis, element, left, mid - 1) + b_search(lis, element, mid + 1, right)


# l = [1,2,3,4,5,321312,421,2133,16,7]
# print(b_search(l,2133))

利用递归二分法查找是了解递归的一个重要过程,但其效率实在是不高,所以更多的是将其作为一个了解学习的过程。

三、os 模块的扩展:walk 方法

之前学习递归函数的时候我们尝试过利用递归方法查看一个目录下面的所有内容以及计算目录空间占用情况,但在实际应用中,用 os 模块中的 walk 方法遍历目录显然是更好的方法,下面进行基本的介绍:

import os
g = os.walk('D:\Python\Python_Project')

for i in g:
    print(i)
    
# 迭代器每次迭代返回一个元组,中间包含三个内容:字符串形式的目录路径、目录下的子目录组成的列表、目录下的文件组成的列表
('D:\\Python\\Python_Project\\week02 作业\\blog\\lib\\__pycache__', [], ['common.cpython-36.pyc'])
('D:\\Python\\Python_Project\\week02 作业\\blog\\log', [], ['access.log'])
('D:\\Python\\Python_Project\\week02 作业\\blog\\user', [], ['marui.txt', '母猪的产后护理', '要求.md', '要求.txt'])
('D:\\Python\\Python_Project\\week03 作业', ['calculator'], [])
('D:\\Python\\Python_Project\\week03 作业\\calculator', [], [])
...

四、面向对象楔子

假如我们要利用 Python 编写一个游戏程序,程序的名字叫做:人狗大战(Legend of Dogs & Humans)。人类具有名字、血条、性别、职业、等级、武器、攻击力等基本属性;狗具有名字、品种、血条、技能等基本属性。我们可以通过字典定义分别定义一个人类角色和一个狗角色:

alex = {
    'name': 'alex',
    'gender': 'unknown',
    'job': '搓澡工',
    'level': 0,
    'hp': 250,
    'weapon': '搓澡巾',
    'ad': 1,
}

xiaobai = {
    'name': '小白',
    'kind': '泰迪',
    'hp': 500,
    'ad': 249
}

可是如果这个游戏有好多人玩,我们只能一个一个定义角色吗;又如何保证所有玩家初始化的时候都有相同的属性;人和狗的技能又要怎么实现?可以尝试写一个人类和狗的还有技能的函数,然后每次新建一个角色,都通过函数调用套这个人和狗的模子:

def Person(name, gender, job, hp, weapon, ad, level=0):  # 人
    dic = {
        'name': name,
        'gender': gender,
        'job': job,
        'level': level,
        'hp': hp,
        'weapon': weapon,
        'ad': ad,
    }
    return dic

def Dog(name, kind, hp, ad):  # 狗
    dic = {
        'name': name,
        'kind': kind,
        'hp': hp,
        'ad': ad
    }
    return dic

# 人类技能:搓澡
def Rub(person, dog):
    dog['hp'] -= person['ad']
    print("%s rubbed %s, %s lose %sHP."%(person['name'], dog['name'], dog['name'], person['ad']))

# 狗技能:舔
def Lick(dog, person):
    person['hp'] -= dog['ad']
    print("%s licked %s, %s lose %sHP."%(dog['name'], person['name'], person['name'], dog['ad']))
    
    
alex = Person('alex', 'unknown', '搓澡工', 250, '搓澡巾', 1)
wusir = Person('wusir', 'male', '法师', 500, '打狗棒', 1000)
xiaojin = Dog('xiaojin', 'keji', 10000, 499)
xiaobai = Dog('xiaobai', 'taidi', 5000, 249)

Rub(alex, xiaobai)  # alex rubbed xiaobai, xiaobai lose 1HP.
Lick(xiaobai, alex)  # xiaobai licked alex, alex lose 249HP.

这样好像整个功能都已经大概实现了,但是这时除了一个意外:

Rub(xiaobai, alex)  # xiaobai rubbed alex, alex lose 249HP.

狗使用了人的已经,这一定不是这个游戏允许发生的,那么我们该如何解决这个问题呢?可以尝试将人和狗的技能封装在各自的 Person 和 Dog 函数中,这样就只有人类能使用rub()且只有狗能使用lick()了。

# Lick函数应该不是一个公用的函数,是一个有归属的技能,这时我们可以再次对Dog和Person下手
def Dog(name, kind, hp, ad):
    def Lick(dog, person):
        person['hp'] -= dog['ad']
        print("%s licked %s, %s lose %sHP." % (dog['name'], person['name'], person['name'], dog['ad']))

    dic = {
        'name': name,
        'kind': kind,
        'hp': hp,
        'ad': ad,
        'ability': Lick
    }
    return dic

def Person(name, gender, job, hp, weapon, ad, level=0):  # 人模子
    def Rub(person, dog):
        dog['hp'] -= person['ad']
        print("%s rubbed %s, %s lose %sHP." % (person['name'], dog['name'], dog['name'], person['ad']))

    dic = {
        'name': name,
        'gender': gender,
        'job': job,
        'level': level,
        'hp': hp,
        'weapon': weapon,
        'ad': ad,
        'ability': Rub
    }
    return dic


alex = Person('alex', 'unknown', '搓澡工', 250, '搓澡巾', 1)
wusir = Person('wusir', 'male', '法师', 500, '打狗棒', 1000)
xiaojin = Dog('xiaojin', 'keji', 10000, 499)
xiaobai = Dog('xiaobai', 'taidi', 5000, 249)


# 现在我们打印以下xiaobai和alex,发现这样是可以的
print(xiaobai)
print(alex)
# {'name': 'xiaobai', 'kind': 'taidi', 'hp': 4999, 'ad': 249, 'ability': <function Dog.<locals>.Lick at 0x0000023DC6560730>}
# {'name': 'alex', 'gender': 'unknown', 'job': '搓澡工', 'level': 0, 'hp': 1, 'weapon': '搓澡巾', 'ad': 1, 'ability': <function Person.<locals>.Rub at 0x0000023DC61C1F28>}

而根据闭包知识,我们可以知道 Person 和 Dog 中的字典是一个闭包,这样我们可以减少一个技能方法参数:

# 我们根据闭包知识,还可以对Person和Dog进行下面的修改,减少一个技能的参数
def Dog(name, kind, hp, ad):
    def Lick(person):
        person['hp'] -= dic['ad']
        print("%s licked %s, %s lose %sHP." % (dic['name'], person['name'], person['name'], dic['ad']))

    dic = {
        'name': name,
        'kind': kind,
        'hp': hp,
        'ad': ad,
        'ability': Lick
    }
    return dic

def Person(name, gender, job, hp, weapon, ad, level=0):  # 人模子
    def Rub(dog):
        dog['hp'] -= dic['ad']
        print("%s rubbed %s, %s lose %sHP." % (dic['name'], dog['name'], dog['name'], dic['ad']))

    dic = {
        'name': name,
        'gender': gender,
        'job': job,
        'level': level,
        'hp': hp,
        'weapon': weapon,
        'ad': ad,
        'ability': Rub
    }
    return dic


alex = Person('alex', 'unknown', '搓澡工', 250, '搓澡巾', 1)
wusir = Person('wusir', 'male', '法师', 500, '打狗棒', 1000)
xiaojin = Dog('xiaojin', 'keji', 10000, 499)
xiaobai = Dog('xiaobai', 'taidi', 5000, 249)

但是这时出了个比较要命的问题,调用技能的方式发生了改变:

xiaobai['ability'](alex)  # xiaobai licked alex, alex lose 249HP.

我们发现利用函数的知识无论怎么样优化这个程序的编写,好像也无法达到完美的效果,这时我们就要引入一种全新的概念:面向对象开发。

其实上面所写的函数已经是面向对象开发的基本思路了,即两个对象/类之间的不断交互影响。在一些复杂的、拥有开放式结局的程序,就可以使用面向对象开发,如购物、游戏程序等。

五、面向对象基础

  1. 定义类

    在Python等高级编程语言中,类就是我们刚才所讨论的“模子”(C语言不含面向对象开发),每个类包括一系列属性以及一系列方法等,我们就这刚才的“人狗大战”问题,定义人的类。

    class Person:  # 类名
        def __init__(self):
            # 这个方法必须叫这个名字,不能改变
            # 所有的基本属性都可以写在这里
            # print('-' * 20)
            self.name = 'alex'  # 对象的属性/实例变量
            self.gender = 'unknow'
            self.job = 'rubber'
            self.level = 0
            self.hp = 250
            self.ad = 1
            self.weapon = 'cuozaojin'
            # print(self, self.__dict__)
            # print('*' * 20)
        # print('in person')
    
    # 无需调用,class内部会从上而下在自动执行(不含方法内部)
    # in person
    
  2. 通过类获取对象(实例化)

    在我们调用类的时候会自动调用__init__方法,__init__方法内部的self会作为返回值从调用类处返回,这样我们就实现了通过类获取对象的过程,这个过程也被称为实例化。

    alex = Person()  # 对象名 alex=Person()是通过类获取一个对象的过程,也称为实例化
    
    # 因为调用类的过程会自动调用__init__方法,所以在上面Person类的定义下,会自动返回这些“值。
    # --------------------
    # <__main__.Person object at 0x0000016A0E973588> {'name': 'alex', 'gender': 'unknow', 'job': 'rubber', 'level': 0, 'hp': 250, 'ad': 1, 'weapon': 'cuozaojin'}
    # ********************
    
  3. 读取对象的属性和方法

    object_name.__dict__可以返回对象的所有属性和方法:

    print(alex, alex.__dict__)
    
    # <__main__.Person object at 0x0000016A0E973588> {'name': 'alex', 'gender': 'unknow', 'job': 'rubber', 'level': 0, 'hp': 250, 'ad': 1, 'weapon': 'cuozaojin'}
    
  4. 类和对象的关系

    • 类 class :是一个大范围、是一个模子,它约束了一种事物有哪些属性,但是它不能约束具体的值。
    • 对象(实例) object :是一个具体的内容,它是类的产物,它遵循类的约束,同时又给属性赋予上了具体的值。
  5. 属性的读取和修改

    假如我们现在要读取对象alex的血量数据,我们利用alex.__dict__['hp']读取,但是这样的方法很明显比较笨拙,所以 Python 给我们提供这样的方法:

    # 称为属性的查看
    print(alex.gender)  # print(alex.__dict__['name'])
    
    # 也可以通过这种方法实现属性的修改
    alex.gender = 'male'
    print(alex.gender)  # male
    
    # 也可以通过这种方法新增属性
    alex.money = 100000
    print(alex.money)  # 100000
    
    # 也可以通过这种方法删除属性
    del alex.money
    
  6. 实例化所经历的步骤

    • 调用之后首先开辟一块内存空间
    • 调用__init__把空间的内存地址作为self函数传递到函数内部
    • 所有的一个个对象所需要的属性都要和self关联起来
    • 执行完__init__中的逻辑之后,self变量会自动返回到调用处
  7. 在类中定义和调用方法

    我们刚刚解决了“人狗大战”两类角色的属性问题,但是还没有解决技能问题,我们可以取之前定义的类,对它进行这样的修改:

    class Person:
        def __init__(self, name, gender, job, hp, weapon, ad):
            self.name = name
            self.gender = gender
            self.job = job
            self.level = 0
            self.hp = hp
            self.ad = ad
            self.weapon = weapon
    
        def rub(self, dog):
            dog.hp -= self.ad
            print(f'{self.name} rubbed {dog.name}, {dog.name} lose {self.ad}HP.')
            
    class Dog:
        def __init__(self, name, kind, hp, ad):
            self.name = name
            self.kind = kind
            self.hp = hp
            self.ad = ad
        def lick(self, person):
            person.hp -= self.ad
            print(f'{self.name} licked {person.name}, {person.name} lose {self.ad}.')
            
    
    xiaobai = Dog('xiaobai', 'taidi', 5000, 249)
    alex = Person('alex', 'unknown', 'rubber', 250, 'cuozaojin', 1)
    alex.rub(xiaobai)  # alex rubbed xiaobai, xiaobai lose 1HP.
    xiaobai.lick(alex)  # xiaobai.lick(alex)
    

    这样就基本解决了“人狗大战”角色属性和技能的问题了。

  8. 练习

    # 定义一个圆形类,半径是这个圆形的属性,实例化一个半径为5的圆形,一个半径为10的圆形
    # 实现方法:计算圆的面积和周长
    # 定义一个用户类,用户名和密码是这个类的属性,实例化两个用户,分别由不同的用户名和代码
    from math import pi
    class Circle:
        def __init__(self, radius):
            self.radius = radius
    
        def perimeter(self):
            return 2 * pi * self.radius
        def area(self):
            return self.radius ** 3 * pi
    circle1 = Circle(5)
    circle2 = Circle(10)
    print(circle1.perimeter())
    print(circle1.area())
    
    
    
    class User:
        def __init__(self, username, password):
            self.username = username
            self.password = password
    
    user1 = User('taibai', 'taibai123')
    user2 = User('alex', 'alex123')
    
posted @ 2020-07-19 21:58  Raigor  阅读(128)  评论(0)    收藏  举报