python基础之函数和面向对象详解

目录
  • 函数
  • 函数参数
    • 变量作用域
    • 内嵌函数和闭包
    • lambda 表达式
  • 面向对象
    • 三大特性
    • 类、类对象 和 实例对象
    • 类属性 和 对象属性
    • 私有
  • 魔法方法
    • 基本的魔法方法
    • 算术运算符
  • 属性访问
    • 描述符
  • 迭代器和生成器
    • 迭代器
    • 生成器
  • 总结

函数

python中『一切皆对象』, 函数也不例外.

在之前所学的C++Java中, 可以发现函数的返回值要么为空, 要么是某种数据类型, 但是在python中, 返回值可以是任何对象, 包括函数.

函数参数

函数的参数种类比较多, 主要有:

1.位置参数 (positional argument): 就是最常见的x, y等

2默认参数 (default argument): 给定一个默认值, 用户也可以传入实参来调整.

def func(x, y=3):
    print(x+y)

func(1)  # 4
func(1, 666)  # 667

3.可变参数 (variable argument): 不限制输入参数的个数, 传入后自动保存为元组类型.

1.*args 是可变参数,args 接收的是一个 tuple

def printinfo(arg1, *args):
    print(arg1)
    print(args, type(args))

printinfo(10)  # 仅一个参数, 没有属于args的.
# 10
# () <class 'tuple'>
printinfo(70, 60, 50)  # 除arg1位置匹配的, 其他都传入给可变参数
# 70
# (60, 50) <class 'tuple'>

4.关键字参数 (keyword argument): 不限制关键字的个数和命名, 传入后自动保存为字典的形式.

1.**kw 是关键字参数,kw 接收的是一个 dict

def printinfo(arg1, *args):
    print(arg1)
    print(args, type(args))

printinfo(10)  # 仅一个参数, 没有属于args的.
# 10
# () <class 'tuple'>
printinfo(70, 60, 50)  # 除arg1位置匹配的, 其他都传入给可变参数
# 70
# (60, 50) <class 'tuple'>

5.命名关键字参数 (name keyword argument)

1.命名关键字参数是为了限制调用者可以传入的『参数名』,也可以提供默认值.

2.与关键字参数不同的是, 关键字参数的名字和值都是任意的, 后续再进行匹配使用, 而命名关键字则只能接受给定的关键字作为参数.定义命名关键字参数

3.不要忘了写分隔符 *, 否则定义的是位置参数, 命名关键字参数调用函数时必须给定参数名.

def person(name, *, age, height=1.90):
    print(f'{name}今年{age}岁, 身高{height:.2f}m')

person('张三', age=18, height=1.80)  # 张三今年18岁, 身高1.80m
person('李四', age=18)  # 李四今年18岁, 身高1.90m
person('王五')  # TypeError, 需要传入给定关键字

6.参数组合

Python中定义函数时, 以上这5种参数都可以使用, d但最多可以使用4种, 并且要注意顺序:

1.位置参数、默认参数、可变参数和关键字参数.

2.位置参数、默认参数、命名关键字参数和关键字参数.

变量作用域

在python程序中, 处于不同位置的变量, 有不同的作用域.

  • 定义在函数内部的变量拥有局部作用域, 该变量称为局部变量.
  • 定义在函数外部的变量拥有全局作用域, 该变量称为全局变量.
  • 局部变量只能在其被声明的函数内部访问, 而全局变量可以在整个程序范围内访问.

需要注意的是:

  • 当局部变量试图访问全局变量时, 一定要在函数内声明global.
  • 当局部变量与全局变量命名冲突时, 程序会优先选择局部变量.

内嵌函数和闭包

内嵌函数就是在外层函数内定义内层函数.

def outer():
    print('outer函数在这被调用')

    def inner():
        print('inner函数在这被调用')

    inner()  # 该函数只能在outer函数内部被调用

outer()
# outer函数在这被调用
# inner函数在这被调用

闭包是一个比较重要的语法结构, 结构上与内嵌函数类似, 区别在于返回值, 闭包的外层函数返回值是一个函数.

如果在一个内部函数里对外层非全局作用域的变量进行引用, 那么内部函数就被认为是闭包.

通过闭包可以访问外层非全局作用域的变量, 这个作用域称为闭包作用域.

def funX(x):
    def funY(y):
        print('使用funY(y)')
        return x * y

    return funY

i = funX(8)
print(type(i))  # <class 'function'>
print(i(5))  # 40

注意到上述代码中, 内部函数FunY中使用了外部非全局作用域的变量x.

同样是, 函数内嵌套的函数作用域也需要特别注意, 若我们需要修改闭包内的变量, 需要使用nonlocal关键字.

num = 999

def outer():
    num = 10

    def inner():
        nonlocal num  # nonlocal关键字声明
        num = 100
        print(f'inner中num = {num}')

    inner()
    print(f'outer中num = {num}')

outer()
# inner中num = 100
# outer中num = 100
print(f'全局中num = {num}')
# 全局中num = 999

lambda 表达式

lambda需要注意的是:

  • 匿名函数没有return, 表达式本身就是返回值.
  • 匿名函数拥有『自己的命名空间』, 不能访问参数列表之外或全局变量.

匿名函数主要适用于函数式编程(函数不会影响函数之外的内容)的一些高阶函数中. 例如map映射和filter过滤, 当然也可以在自己自定义函数中使用.

odd = lambda x: x % 2 == 1
templist = filter(odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])
print(list(templist))  # [1, 3, 5, 7, 9]

m1 = map(lambda x: x ** 2, [1, 2, 3, 4, 5])
print(list(m1))  # [1, 4, 9, 16, 25]

面向对象

三大特性

面向对象就必须了解三大特性:

  • 封装: 把客观事物封装成抽象的类, 让数据和方法给信任的类或对象操作, 而隐藏部分信息.
  • 继承: 子类自动共享父类的属性和方法.
    • 一般认为一个类是自身的子类;
    • 可以使用issubclass(B, A)查看B是否是A的子类.
    • python也支持多继承, 但会使得类的整体层次复杂, 所以并不建议使用.
  • 多态: 同一个方法的调用, 会由于不同对象而得到不同的结果.
    • 必要条件是继承方法的重写.

类、类对象 和 实例对象

  • 类: 就是指对类的定义
  • 类对象: 是在创建类的时候, 在内存开辟的一个空间, 一个类只有一个类对象.
  • 实例对象: 通过实例化类创建的对象, 可以有多个.

类属性 和 对象属性

  • 类属性: 类定义内, 类方法外定义的变量称为类属性, 类属性属于类对象, 可以被多个实例化对象所共享, 就像我们都有一个家, 名字叫中国一样.
  • 对象属性: 对象属性和具体创建的对象实例直接相关, 并且相互之间不共享属性, 就像我的老婆只是我的一样.
class A():
    a = 0  #类属性
    def __init__(self, xx):
        A.a = xx  #使用类属性可以通过 (类名.类属性)调用。

有一些操作属性的方法:

  • 使用hasattr(object, name)来判断对象是否包含对应的属性或方法.
  • 使用getattr(object, name)来获取属性或方法.
  • 使用setattr(object, name, value)来修改属性值, 或创建新的属性和值.
  • 使用delattr(object, name)来删除属性.
class A(object):
    name = '张三'
    def set(self, a, b):
        x = a
        a = b
        b = x
        print(a, b)

a = A()
print(hasattr(a, 'name'))  # 判断是否有name属性 True
print(hasattr(a, 'set'))  # 判断是否有set方法 True
x = getattr(a, 'name')  # 获取属性值
print(x)  # 张三
c = getattr(a, 'set')  # 获取方法
c(a='1', b='2')  # 2 1

私有

私有属性和方法仅需在定义命名的时候加上两个下划线"__"即可.

相对于公有属性和公有方法来说, 私有属性和私有方法更加的安全. 从定义上来说, 将需要安全保护的属性和方法封装为私有, 可以阻止外部直接调用, 而必须使用实例化对象方法类方法进行调用, 从而提高安全性.

但在python中的私有是『伪私有』, 即可以使用类名, 通过 object._className__attrName 访问私有属性,用 object._className__func() 访问私有方法.

class JustCounter:
    __secretCount = 0  # 私有变量
    publicCount = 0  # 公开变量

    def count(self):
        self.__secretCount += 1
        self.publicCount += 1
        print(self.__secretCount)

counter = JustCounter()
counter.count()  # 1
print(counter.publicCount)  # 1
# 特殊方法依旧可以访问
print(counter._JustCounter__secretCount)  # 1
# 直接访问则会报错.
print(counter.__secretCount)

实例直接使用就可以增加属性了, 这点需要注意一下.

class B:
    def func(self):
        print('调用func方法')

b = B()
print(b.__dict__)  # 查看属性 {}
b.name = '张三'
b.age = 18
print(b.__dict__)  # 查看属性{'name': '张三', 'age': 18}

b1 = B()
print(b1.__dict__)  # 查看属性 {}

魔法方法

基本的魔法方法

魔法方法基本上是被下划线包围的一些特殊方法. 相比于普通的方法, 它能够在适当的时候自动调用. 第一个参数一般是cls『类方法』或者self『实例方法』.

  • __init__(self[, ...]) 构造器, 当一个实例被创建的时候调用的初始化方法.
  • __new__(cls[, ...]) 在一个对象实例化的时候所调用的第一个方法, 在调用__init__初始化前, 先调用__new__.
    • 需要注意的是, __new__的返回值必须为当前类的实例, 否则将不会调用__init__初始化.
    • 主要是在继承一些不可变的class(比如int, str, tuple)时, 提供一个自定义该类实例化过程的途径.
  • __del__(self) 析构器, 当一个对象将要被系统回收之时调用的方法.
  • __str__(self): 当你打印一个对象、使用%s格式化或使用str强转数据类型的时候,触发__str__.
  • __repr__(self)__str__(self)的备胎, 情况类似, 不过自定义时往往更加准确, 主要用于调试.

算术运算符

普通的计算在对象中是无法进行的, 需要自定义计算方式.

__add__(self, other)定义加法的行为: +

__sub__(self, other)定义减法的行为: -

__mul__(self, other)定义乘法的行为: *

__truediv__(self, other)定义真除法的行为: /

__floordiv__(self, other)定义整数除法的行为: //

__mod__(self, other) 定义取模算法的行为: %

__divmod__(self, other)定义当被 divmod() 调用时的行为

divmod(a, b)把除数和余数运算结果结合起来,返回一个包含商和余数的元组(a // b, a % b)

__pow__(self, other[, module])定义当被 power() 调用或 ** 运算时的行为

__lshift__(self, other)定义按位左移位的行为: <<

__rshift__(self, other)定义按位右移位的行为: >>

__and__(self, other)定义按位与操作的行为: &

__xor__(self, other)定义按位异或操作的行为: ^

__or__(self, other)定义按位或操作的行为: |

还有对应的反运算符, 在之前加上r即可, 例如__rsub__. 对应增量赋值运算符, 在之前加上i即可, 例如__isub__.

属性访问

__getattr__(self, name): 定义当用户试图获取一个不存在的属性时的行为.

__getattribute__(self, name): 定义当该类的属性被访问时的行为(先调用该方法, 查看是否存在该属性, 若不存在, 接着去调用__getattr__).

__setattr__(self, name, value): 定义当一个属性被设置时的行为.

__delattr__(self, name): 定义当一个属性被删除时的行为.

描述符

描述符就是将某种特殊类型的类的实例指派给另一个类的属性.

__get__(self, instance, owner): 用于访问属性, 它返回属性的值.

__set__(self, instance, value): 将在属性分配操作中调用, 不返回任何内容.

__del__(self, instance): 控制删除操作, 不返回任何内容.

迭代器和生成器

迭代器

迭代是Python最强大的功能之一, 是访问集合元素的一种方式.

  • 迭代器是一个可以记住遍历的位置的对象.
  • 迭代器对象从集合的第一个元素开始访问, 直到所有的元素被访问完结束.
  • 迭代器只能往前不会后退.
  • 字符串, 列表或元组对象都可用于创建迭代器.

迭代器有两个基本的方法: iter() 和 next():

  • iter(object) 函数用来生成迭代器.
  • next(iterator[, default]) 返回迭代器的下一个项目. 在元素为空时返回默认值, 若没有则会触发 StopIteration 异常. 在元组推导式和next中使用过, 不过是下面的『生成器』.

把一个类作为一个迭代器使用需要在类中实现两个魔法方法 __iter__() 与 __next__() .

  • __iter__(self)定义当迭代容器中的元素的行为, 返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成.
  • __next__() 返回下一个迭代器对象. 
    • StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
class Fibs:
    def __init__(self, n=10):
        self.a = 0
        self.b = 1
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > self.n:
            raise StopIteration
        return self.a

fibs = Fibs(100)
for each in fibs:
    print(each, end=' ')

# 1 1 2 3 5 8 13 21 34 55 89

生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator)。

  • 跟普通函数不同的是, 生成器是一个返回迭代器的函数, 只能用于迭代操作, 更简单点理解生成器就是一个迭代器.
  • 在调用生成器运行的过程中, 每次遇到 yield 时函数会暂停并保存当前所有的运行信息, 返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行.
  • 调用一个生成器函数, 返回的是一个迭代器对象.
def libs(n):
    a = 0
    b = 1
    while True:
        a, b = b, a + b
        if a > n:
            return
        yield a

for each in libs(100):
    print(each, end=' ')

# 1 1 2 3 5 8 13 21 34 55 89

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Python面向对象之内置函数相关知识总结

    Python内置函数 1. classmethod.staticmethod.property . 上述三个内置函数在文章(Python进阶--面向对象之成员)的方法和属性中已经详细介绍使用,可以返回浏览,具体地址: 2. callable,是否可在后面加括号执行. 函数 def func(): pass print( callable(func) ) # True 类 class Foo(object): pass print( callable(Foo) ) # True 类中具有__cal

  • Python函数式编程之面向过程面向对象及函数式简析

    目录 Python 函数式编程 同一案例的不同写法,展示函数式编程 面向过程的写法 面向对象的写法 接下来进入正题,函数式编程的落地实现 Python 函数式编程的特点 纯函数 Python 函数式编程 Python 不是纯粹的函数式语言,但你可以使用 Python 进行函数式编程 典型的听君一席话,如听一席话,说白了就是 Python 具备函数式编程的特性, so,可以借用函数式语言的设计模式和编程技术,把代码写成函数式编程的样子 一般此时我会吹嘘一下,函数式代码比较简洁和优雅~ 好了,已经吹

  • Python面向对象程序设计构造函数和析构函数用法分析

    本文实例讲述了Python面向对象程序设计构造函数和析构函数用法.分享给大家供大家参考,具体如下: 构造函数和析构函数 1.构造方法的使用 很多类都倾向于将对象创建为有初始化状态.因此类可以定义一个名为init()的特殊方法(构造方法)来实例化一个对象. 构造方法也叫做构造器,是指当实例化一个对象(创建一个对象)的时候,第一个被自动调用的方法. 演示1:构造方法被调用的契机 class Person(): #构造方法 def __init__(self): print("构造函数被执行了&quo

  • Python面向对象程序设计OOP深入分析【构造函数,组合类,工具类等】

    本文深入分析了Python面向对象程序设计OOP.分享给大家供大家参考,具体如下: 下面是一个关于OOP的实例,模块文件为person.py # File person.py(start) class Person: def __init__(self, name, job=None, pay=0): self.name = name self.job = job self.pay = pay def last_name(self): return self.name.split()[-1] d

  • python基础之函数和面向对象详解

    目录 函数 函数参数 变量作用域 内嵌函数和闭包 lambda 表达式 面向对象 三大特性 类.类对象 和 实例对象 类属性 和 对象属性 私有 魔法方法 基本的魔法方法 算术运算符 属性访问 描述符 迭代器和生成器 迭代器 生成器 总结 函数 python中『一切皆对象』, 函数也不例外. 在之前所学的C++或Java中, 可以发现函数的返回值要么为空, 要么是某种数据类型, 但是在python中, 返回值可以是任何对象, 包括函数. 函数参数 函数的参数种类比较多, 主要有: 1.位置参数

  • Python基础之函数用法实例详解

    本文以实例形式较为详细的讲述了Python函数的用法,对于初学Python的朋友有不错的借鉴价值.分享给大家供大家参考之用.具体分析如下: 通常来说,Python的函数是由一个新的语句编写,即def,def是可执行的语句--函数并不存在,直到Python运行了def后才存在. 函数是通过赋值传递的,参数通过赋值传递给函数 def语句将创建一个函数对象并将其赋值给一个变量名,def语句的一般格式如下: def <name>(arg1,arg2,arg3,--,argN): <stateme

  • Python学习之面向函数转面向对象详解

    还记得前文函数章节的‘函数的定义与使用’章节么?今天我们就来针对 类 进行一个综合练习,利用所学的面向对象编程.类 的知识将我们之前做的面向函数编写的学生信息库重构为面向对象的方式. 所谓重构就是对代码设计和结构进行重新修改和开发,上一次我们都是通过函数来开发的,其实他们都是为了一个大目标开发出来的.就是学生目标管理,所以目标都相同,可以放在一个类中开发. 我们今天有两个目的,第一就是将之前面向函数开发的学生信息库功能转变为面向对象开发的学生信息库功能:第二就是要实现批量的增删改查及模糊查找的功

  • Python基础知识之变量的详解

    一.定义 在python中,变量名只有在第一次出现的时候,才是定义变量.当再次出现时,不是定义变量,而是直接调用之前定义的变量. 二.命名方法 2.1小驼峰命名法 第一个单词以小写字母开始,后续单词的首字母大写 firstName , lastName 2.2大驼峰命名法 每一个单词的首字母都采用大写字母 FirstName , LastName 2.3下划线命名法 每个单词之间用下划线连接起来 first_name , last_name 三.命名规则 3.1标识符 开发人员自定义的一些符号和

  • Python基础教程之pytest参数化详解

    目录 前言 源代码分析 装饰测试类 装饰测试函数 单个数据 一组数据 组合数据 标记用例 嵌套字典 增加测试结果可读性 总结 前言 上篇博文介绍过,pytest是目前比较成熟功能齐全的测试框架,使用率肯定也不断攀升.在实际 工作中,许多测试用例都是类似的重复,一个个写最后代码会显得很冗余.这里,我们来了解一下 @pytest.mark.parametrize装饰器,可以很好的解决上述问题. 源代码分析 def parametrize(self,argnames, argvalues, indir

  • 对Python实现累加函数的方法详解

    这个需求比较奇怪,要求实现Sum和MagaSum函数,实现以下功能 Sum(1) =>1 Sum(1,2,3) =>6 MegaSum(1)() =>1 MegaSum(1)(2)(3)() =>6 实际上Sum就是Python自建的sum函数,它支持变参,变参怎么实现,自然是*args,所以很容易写出雏形: Sum def Sum(*args): count = 0 for i in args: count+=i return count 第二个函数就有点皮了,它要求有参数的时候

  • Python文件操作函数用法实例详解

    这篇文章主要介绍了Python文件操作函数用法实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 字符编码 二进制和字符之间的转换过程 --> 字符编码 ascii,gbk,shit,fuck 每个国家都有自己的编码方式 美国电脑内存中的编码方式为ascii ; 中国电脑内存中的编码方式为gbk , 美国电脑无法识别中国电脑写的程序 , 中国电脑无法识别美国电脑写的程序 现在硬盘中躺着 ascii/gbk/shit/fuck 编码的文件,

  • Python threading Local()函数用法案例详解

    目录 前言 local() 函数是什么? local()函数如何用? 1. 不做标记,不做隔离 2.使用local()函数加以控制 3. 模拟实现local()的功能,创建一个箱子 4. 简化代码操作,进一步模拟实现local()函数 总结 前言 当多线程访问同一个公共资源时,如果涉及到修改该公共资源的操作就可能会出现由于数据不同步导致的线程安全问题.一般情况下我们可以通过给公共资源加互斥锁的方式来处理该问题. 当然,除非必须将多线程使用的资源设置为公共资源的情况.如果一个资源不需要在多个线程之

  • python模块shutil函数应用示例详解教程

    目录 本文大纲 知识串讲 1)模块导入 2)复制文件 3)复制文件夹 4)移动文件或文件夹 5)删除文件夹(慎用) 6)创建和解压压缩包 本文大纲 os模块是Python标准库中一个重要的模块,里面提供了对目录和文件的一般常用操作.而Python另外一个标准库--shutil库,它作为os模块的补充,提供了复制.移动.删除.压缩.解压等操作,这些 os 模块中一般是没有提供的.但是需要注意的是:shutil 模块对压缩包的处理是调用 ZipFile 和 TarFile这两个模块来进行的. 知识串

  • Python基础必备之语法结构详解

    目录 Python 语句 续行 隐式续行的方式 显式续行的方式 每行多语句 注释 空白字符 空格作为缩进 Python 语句 语句是 Python 解释器解析和处理的基本指令单元.通常解释器按顺序一个接一个的执行语句. 在 REPL 会话中,语句在输入时执行,直到解释器终止.当执行脚本文件时,解释器从文件中读取语句并执行直到遇到文件结尾. 通常每个语句占用一行,语句的结尾由标记行尾的换行符分隔. print('真・三國無双') 真・三國無双 x = ['劉備', '関羽','張飛'] print

随机推荐