python学习心得之: 方法,参数,装饰器

2021/9/5 22:08:35

本文主要是介绍python学习心得之: 方法,参数,装饰器,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一,方法的定义

方法是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
方法能提高应用的模块性,和代码的重复利用率。
Python提供了许多内建方法,比如print()。
你也可以自己创建方法,这被叫做用户自定义方法。

二,方法的参数

  1,网上关于参数的分类可谓五花八门, 这里我们做个归类,方法的参数只有两种

  • 位置参数, 按照输入参数的顺序, 依次赋值给方法定义时的参数名
  • 关键字参数, 按照 key=value 的形式, 赋值给方法定义时的参数名, 不依赖顺序

   下面我们来详解

def test(a, b=1, c=2, *args, **kwargs):
    print(a)
    print(b)
    print(c)
    print(args)
    print(kwargs)

   当使用以下方式来调用test方法时

test(1,2,3,4,5,6)

   输出

1
2
3
(4, 5, 6)
{‘y’: 7}

   在这里, 六个参数都变成了位置参数, 按照你输入的顺序,依次赋值给定义的参数,区别在于
    a,b,c三个参数为显式定义, 可以直接打印参数名
    args为可变参数, a,b,c后面没有显式定义的参数名的参数, 以元组的形式赋值给args, 本质上就是个位置参数

    当使用以下方式调用test方法时

test(c=1,a=2,b=3,d=4,e=5)

输出

2
3
1
()
{‘d’: 4, ‘e’: 5}

   在这里, a,b,c,d,e都变成了关键字参数
   输出时,没有按照输入的顺序赋值,而是按照key赋值
   其中显式定义的a,b,c都拿都到了自己的值,
    kwargs为可变参数, a,b,c后面显式定义的参数, 以字典的形式赋值给kwargs,本质上就是个关键字参数
   在上述代码中, a与bc的却别在于, bc被赋予了默认值, 又称默认参数,所以调用方法时可以不输入bc,但必须输入a
   a可以是位置参数(下图1,2),也可以是关键字参数(3,4,5)

# 正确
test(1)             # 1
test(1, b=1, c=1)   # 2
test(a=1)           # 3
test(a=1, b=1)      # 4
test(b=1,c=1,a=2)   # 5

# 报错
test(b=2)           # 6
test(b=2, c=1)      # 7

    从调用的角度来看, *args可以理解为位置参数, **kwargs可以理解为关键字参数

    在没有不定参数*args与 **kwargs的情况下, 位置参数和关键字参数更多是由调用时决定的, 只要保证默认参数在后即可
    调用时,隐式调用就是位置参数,显示调用就是关键字参数, 二者可以互相转换
    ps: 这里使用隐式和显示可能不太准确, 但我想不到更好的词, 能理解即可

    请注意: 上面提到了默认参数, 默认参数的值必须为不可变对象,下面会说明

    在有不定参数*args与 **kwargs的时候, 位置参数和关键字参数就不能随意转换



2, 参数顺序

    先说结论, 位置参数一定要在关键字参数前面
    因此定义方法时, 建议的参数顺序

def test(a, b, c=100, *args, d=1, e=2, f, **kwargs):
   print(a)
   print(b)
   print(c)
   print(args)
   print(d)
   print(e)
   print(f)
   print(kwargs)


test(1, 2, 3, 4, 5, d=10, e = 7, l=11, f=8, h=10)

执行结果如下

1
2
3
(4, 5)
10
7
8
{‘l’: 11, ‘h’: 10}

    *args之前(含) 为位置参数, 依次赋值, 不能乱序
    *args之后为关键字参数, 无所谓顺序

    上图中参数c在定义时被赋予了默认值100, 但是打印出的结果为3, 被位置参数所取代, 所以在有*args时,位置参数不建议设置默认值, 几乎不会生效(注:不是一定)

    当不需要参数*args, 但又想区分位置参数与关键字参数,可以使用*区分

def test(a, b, c=100, *, d=1, e=2, f, **kwargs):
    print(a)
    print(b)
    print(c)
    print(d)
    print(e)
    print(f)
    print(kwargs)

结果如下

1
2
3
10
7
8
{‘l’: 11, ‘h’: 10}

   *在这里只是一个分隔符, 不暂用参数位置,不可被调用和继承

    ps: 这里的参数顺序是我个人经验总结的经验最佳顺序, 但是在python版本中, 默认参数在*args之后似乎会报错, 可尝试调整.但参数顺序的原则是, 在不报错的情况下, 输入的每一个参数在方法中都能够被取到

3, 默认参数

    在定义方法时, 以key=value的形式定义的参数,就是默认参数, 这个value称为默认值
    在调用方法时,如果不输入这个key,或者位置参数覆盖不到这个key, 方法中取到的就是默认值

    但是,需要注意的是, 默认参数的值必须是不可变对象
    来看下面的例子:

def test(a=[]):
    a.append(1)
    print(a)

test()
test()
test()
test()

    运行结果:

[1]
[1, 1]
[1, 1, 1]
[1, 1, 1, 1]

    这是由于python在对变量赋值时,赋予的并不是值本身, 而是该值的引用,形参a每次被调用时, 访问的都是同一个内存地址

三, 装饰器

    一个不恰当的比喻,如果将方法比作一张照片,装饰器就是照片外面的相框, 一束光想要穿过照片, 就要先穿过相框前面,然后穿过照片,最后穿过相框的背面,在相框与照片之前的间隙中,可以插入我们想要的处理.
    举个例子: 我要执行一个方法,并计算方法执行的时间

import time
import datetime
def test():
       start_time = datetime.datetime.now()
       '''
       you code here
       '''
       end_time = datetime.datetime.now()
       print('方法执行时间:'+str(end_time-start_time))
test()

# 输出
# 方法执行时间:0:00:00.000006

    方法本身没有问题, 但写成方法的目的就是为了精简代码,提高重用率, 每一个方法中都去定义start_time与end_time也过于繁琐了

1,修饰方法的方法–装饰器

    直接上代码

import time
import datetime

def count_time(func):
    def inner(*args, **kwargs):
       start_time = datetime.datetime.now()
       res = func(*args, **kwargs)
       end_time = datetime.datetime.now()
       print('方法执行时间:'+str(end_time-start_time))
       return res
    return inner

@ count_time
def test(s=1):
    time.sleep(5)
    return s

re = test(3)
print(re)

# 执行结果
# 方法执行时间:0:00:05.000924
# 3

2,装饰器的参数

import time
import datetime

def count_time(text):
    def wraper(func):
        def inner(*args, **kwargs):
            print(text)
            start_time = datetime.datetime.now()
            res = func(*args, **kwargs)
            end_time = datetime.datetime.now()
            print('方法执行时间:'+str(end_time-start_time))
            return res
        return inner
    return wraper

@ count_time('hello')
def test(s=1):
    time.sleep(5)
    return s

re = test(3)
print(re)

# 运行结果
# hello
# 方法执行时间:0:00:05.000002
# 3

3,类方法装饰器–调用self参数

import time
import datetime


class Test:

    def __init__(self, text):
        self.text = text

    def count_time(text):
        def wraper(func):
            def inner(self, *args, **kwargs):
                print(text)
                print(self.text)
                start_time = datetime.datetime.now()
                res = func(self, *args, **kwargs)
                end_time = datetime.datetime.now()
                print('方法执行时间:'+str(end_time-start_time))
                return res
            return inner
        return wraper

    @count_time('hello')
    def a(self):
        time.sleep(5)



a = Test(text='welcome')
a.a()

# 运行结果
# hello
# welcome
# 方法执行时间:0:00:05.000297

这种写法的好处,是可以在装饰器中调用类的参数
需要注意的是,在类装饰器里, 装饰器一定要写在被装饰的方法之前

如有错误,还请指正



这篇关于python学习心得之: 方法,参数,装饰器的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程