<Python> python从入门到实践(5) --代码复用

函数、类与代码复用

代码复用的思想

  1. 把代码当成资源进行抽象。
    • 代码资源化:程序代码是一种用来表达计算的"资源"
    • 代码抽象化:使用函数等方法对代码赋予更高级别的定义
    • 代码复用:同一份代码在需要时可以被重复使用
  2. 函数对象是代码复用的主要形式,对象化的抽象程度更高
  3. 模块化设计、分而治之:模块内部紧耦合(交流多、不可独立);模块之间松耦合(交流少、可独立)

函数

函数的定义

  • 函数实例:
def do_something():
    """这是函数注释"""
    print("Hello World!")
    
do_something()

def进行函数定义,接下来是函数名,括号内是参数表,随后是:下一行进行函数体,三对引号是文档注释。像c_like语言一样调用函数

  • 使用参数的函数:

    def do_something(name):
        """这是注释"""
        print("Hello "+name.title()+"!")
        
    do_something()
    

    这里参数没必要指出类型

传递实参:函数传递实参的方式很多,可使用位置实参,这要求实参顺序与形参顺序对应,也可使用关键字实参,其中每个实参都由变量名和值组成;此外,还可以使用列表和字典

  • 位置实参:调用函数时,python会将每一个实参都关联到函数定义的一个形参,最简单的关联方式是基于实参的顺序,这种关联方式被称为位置实参

    #定义函数
    def describe_pet(animal_type, pet_name):
        """显示宠物信息"""
        print("\nI have a "+animal_type+"  and its name is " + pet_name.title()+".")
    #调用函数, 实参按照一定顺序赋值给形参  
    describe_pet('hamster', 'harry')
    describe_pet('dog','pearl')
    
  • 关键字实参:传递给函数的名称-值对,直接在是惨重将名称和值关联,无所谓顺序

    #调用函数,按照关键字传递实参
    describe_pet(animal_type='hamster', pet_name='harry')
    describe_pet(animal_type='dog',pet_name='pearl')
    
  • 默认值:在定义函数时,添加默认值,当没有合适的实参传入时,将会使用默认值版本(写法同c++),要求也与c++相同,要求带有默认值的形参放在最后
    通过给某个形参赋值空初始值 '',可以实现可选参数的功能

返回值:值得注意,python没有必要定义函数时说明有无返回值和返回值类型。返回简单值、字典都可以;返回一个值、多个值、零个值都可以。返回多个值的时候会以元组的方式返回。

 ~~~ python
 def get_formatted_name(first_name,last_name):
     full_name= first_name + ' ' + last_name
     return full_name.title()
 
 
 def get_formatted_name_dic(first_name,last_name):
     person = {
         'first': first_name,
         'last': last_name
     }
     return person
 
 
 
 musician = get_formatted_name('zhao','siqi')
 print(musician)
 ~~~
  • 传递列表
def greet_users(names):
    """to greet"""
    for name in names:
        msg = 'Hello, ' + name.title() + '!'
        print(msg)
        
usernames['A', 'B', 'C']
grret_users(usernames)
  • 在函数中修改列表:列表传递给函数后,函数就可以对其进行修改,在函数中对列表的修改是永久性的
  • 禁止函数修改列表:将列表的副本传递给函数,比如function_name(list_name[:])

传递未定数量的实参:

有时不知道函数需要接受多少实参,于是使用可变形参*<名称>**<名称>其中前者创建了一个内容可变的空元组,后者创建了内容可变的空字典

def make_pizza(*topping):
    print(toppings)
    

make_pizza('Chicken')
make_pizza("mushroom", "Chicken", "beef")


这里的*topping创建了一个空元组,并将收到的所有值都封装到元组中

  • 同时使用位置形参和任意数量形参:位置形参应该位于任意数量形参之前

  • 同时使用关键字形参和任意数量形参:一般使用关键字形参和任意数量形参时都使用了空字典

    def build_profile(first, last, **user_info):
    	profile={
            'first_name': first,
            'last_name': last
        }
        for key, value in user_info:
            profile[key] = value
        return profile
    
    
    user_profile = build_profile('albert','einstein', location = 'German', field = 'physics')
    print(user_profile)
    

将函数储存在模块中

将函数存储在被称为模块的独立文件,再将模块导入(import)到主程序(注:模块也是.py文件)

  • 导入整个模块:

    import<module name>
    随后的调用函数:

    modele_name.function_name(...)

  • 导入某个函数

    from <module_name> import<fuction_name1>, <function_name2>

  • 使用as指定别名

    from <module_name> import<fuction_name1> as new_name

  • 使用as给模块指定别名

    import<modele_name> as <new_name>

  • 导入模块的所有函数

    from module_name import*

    调用函数时不必加模块名.

局部变量和全局变量:

(这里局部变量会在离开作用域时自动释放)

  • 基本数据模型,无论是否重名,局部变量与全局变量不同:

    即发生了作用域和可视性的覆盖

  • 可以通过global关键字声明全局变量
    经过实验,global声明的变量可以在局部作用域内使用、修改,且会修改原始的全局变量。并且在函数内使用global关键字可以创建原来并不存在的全局变量

    def func():
        global num
        num = 9
        return num
    t = func()
    m = num
    
    print(str(t))
    print(str(m))
    print(str(num))
    # 输出
    # 9
    # 9
    # 9
    
  • 对于组合数据类型,如果局部变量未创建,那么就会使用全局变量

lambda函数:

lambda函数是一种匿名函数,使用Lambda保留字定义,不指定函数名,函数名即为赋值的变量(类似于创建了一个函数指针,将指针赋给了某变量,随后该变量可当作函数名正常使用),一般仅仅定义简单的,能够用一行表示的代码,常常用于大型函数的函数对象使用

# 基本形式
<变量名> = Lambda <参数表> : <返回值>
# 例子
add = Lambda x, y : x+y

函数编写时的注意细节:

  1. 命名只使用小写字母和下划线
  2. 包含带有对功能简易说明的注释
  3. 给形参指定默认值时等号两侧不要加空格
  4. 所有import都要放在(除了)注释外的最前面
  5. 定义函数的代码块后加两行空行与其他部分分开

函数递归

  1. 关键特征:
    • 链条:计算过程中存在递归链条
    • 基例:存在一个或多个不需要再次递归的基例
  2. 核心编写方法在于分支语句对参数进行判断,分别处理基例和链条

类和对象

根据约定,在python中,首字母大写的名称指的是类(即是命名规则,也是使用提示)

创建和使用类:

class Dog():
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
        
    def sit(self):
        print(self.name.title() + "is sitting")
        
  • 类中的函数称为方法,与普通函数的唯一区别在于调用的方式,通过对象.方法名(参数表)的方式调用
  • __init__()是一种特殊的函数(构造函数),创建实例时自动调用
  • 形参self必不可少,且必须位于其他形参最前面,但是调用时不必传递实参,因为它自动指向实例本身的引用

使用类

# 已经定义好Dog类

#创建实例
my_dog = Dog("A", 3)

#访问属性
print("My dog's name is "+my_dog.name.title())
#调用方法
my_dog.sit()

给属性指定默认值:在构造函数(__init__)指定这种初始值,此时不必在形参表中写出

修改属性的值:

  • 通过访问成员直接修改属性的值
  • 定义成员函数修改属性的值

继承

  • 子类的构造函数

    class Dog():
        #略
        
    class My_dog(Dog):
        def __init__(self, name, age, weight):
            super().__init__(name, age)
            self.weight = weight
    

    通过super()获取父类的引用,随后借助父类的构造函数完成构造

  • 重写父类的方法:在子类中定义一个与父类中同名的方法,此时会直接调用子类的同名方法

  • 将实例用作属性:使用代码模拟实物时,类中的属性和方法可能会越来越长,此时将类的一部分作为一个独立的类提取出来,将大型类拆分成多个协同工作的小类

导入类:与导入函数的操作基本相同

Python标准库:

Python标准库是一组模块,安装的python都含有它

例题:使用collections的一个类——OrderedDict,这是一个有序字典,在保存键值对关系的同时保留顺序

from collections import OrderedDict

favorite_languages = OrderedDict()

favorite_languages['Jen'] = 'python'
favorite_languages['Sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'python'

for name.language in favotite_languages.items():
    print(name.title() + "like " + language + ".")
    

类编码风格

  1. 类名实施驼峰命名法,将每个单词的首字母大写,不适用下划线,实例名和模块名使用小写,并在单词之间加下划线。
  2. 每个类在定义后使用文档注释描述类功能
  3. 在需要同时导入标准库和编写的自定义模板时,先import标准库,空行,再import自定义库
posted @ 2020-08-08 23:45  Faura_Sol  阅读(265)  评论(0)    收藏  举报
Live2D