Python快速入门之基础(二)

本文深入介绍了Python的基础知识,包括函数的定义、调用、高阶和匿名函数;模块的导入和使用;面向对象的概念,如类、实例、多态;以及错误和异常处理的技巧,如try-except-finally和调试方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇来聊聊python的函数和对象

一、函数

Python内置了很多有用的函数,我们可以直接调用。

  • Python中函数也是一个对象,可以赋值,可以拷贝,可以像普通变量那样使用.

  • 函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数!

  • python函数是一个对象,那么他也就有属性,函数对象有一个__name__属性,可以拿到函数名字

定义函数

def function_name(args):
      function_body;

调用函数

调用函数的方式function_name(formal_args):

>>> def power(x):  
... return x*x;  
...   
>>> power(4)  
16  
>>>

高阶函数

能够接收函数作为参数的函数称之为高阶函数

map()
map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
    >>> def f(x):
    ...     return x * x
    ...
    >>> map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    [1, 4, 9, 16, 25, 36, 49, 64, 81]
reduce()
reduce把一个函数作用在一个序列[x1, x2, x3…]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,效果如下:
    reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

    # 例如求和计算
    >>> def add(x, y):
    ...     return x + y
    ...
    >>> reduce(add, [1, 3, 5, 7, 9])
    25
filter()
和map()类似,filter()也接收一个函数和一个序列。和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
    def is_odd(n):
        return n % 2 == 1

    filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])
    # 结果: [1, 5, 9, 15]

匿名函数

关键字lambda表示匿名函数,冒号前面的x表示函数参数。它没有名字,只有参数和表达式:
lambda args: expression

>>> d = lambda x: x*x;  
>>> d(2)  
4

如果想定义一个什么事也不做的空函数,可以用pass语句:

def nop():
    pass

二、模块

有时候我们把很多函数移到一个python文件中,作为工具类使用,这时候我们要怎么去使用这些外部函数呢?使用import导入即可。

比如你写一个myutils.py的工具类

def addition(x1,x2):
    return x1+x2

这时候你要使用myutils里面的addition方法,便如下引入:

from myutils import addition

这样我们即从myutils里引入了addition方法,你直接使用即可。当然你也可以这样:

import myutils

print myutils.addition(1,2)

不过这样就有点繁琐了,我们通过上面的方法直接引入,直接使用更方便。

如果你有一系列的公共Python文件需要放在一个另一个文件夹下,这时候我们又怎么引入呢?

首先,我们把文件放入到一个新的文件夹下,结构如下:

/demo
  -/common
      -myutils.py
      -test.py
  -home.py

这时候我们要在home.py文件中使用common包下的myutils.py内的addition方法怎么操作?

首先我们要在common包下创建__init__.py文件,文件内容可以不写。

这样我们就创建了一个common的包,然后我们在home.py中如下引入:

from common.myutils import addition

这样我们就可以使用addition方法了。

这就是Pyhont的模块引入。感兴趣的同学可以自行搜索深入学习。


三、面向对象

类和实例

用class关键字定义类:

class ClassName(object):
    ...

在python中,__init__()可以被当成构造器,如下所示:

class ClassName(object):
    def __init__(self, args):
        pass

我们可以在构造方法中传入创建对象所需要的参数。

self是必须的,这是类方法都必须有的,外部调用时候不用传入。

不过不像其他语言中的构造器,它并不创建实例——它仅仅是你的对象创建后执行的第一个方法。它的目的是执行一些该对象的必要的初始化工作。因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。

Python对象有如下一些特性:

  • 可以自由地给一个实例变量绑定属性
    对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同

  • 和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数和关键字参数。

  • 如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。
    (双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量)

  • 有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。

获取对象信息

type(): 获取对象类型
isinstance():  判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上
dir():  获得一个对象的所有属性和方法,返回一个包含字符串的list
getattr():  getattr(obj, 'y') # 获取属性'y'  'y'可以是类的属性也可以是类的方法
setattr():  setattr(obj, 'y', 19) # 设置一个属性'y'
hasattr():  hasattr(obj, 'x') # 有属性'x'吗?

如果试图获取不存在的属性,会抛出AttributeError的错误
可以传入一个default参数,如果属性不存在,就返回默认值:

>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404

多态

和java的多态差不多,子类继承父类,重写父类的方法,实现多态。

class Animal(object):
    def run(self):
        print('Animal is running...')

class Dog(Animal):
    def run(self):
        print('Dog is running...')

class Cat(Animal):
    def run(self):
        print('Cat is running...')

定义一个方法

def run_twice(animal):
    animal.run()
    animal.run()

然后:

>>> run_twice(Dog())
Dog is running...
Dog is running...

>>> run_twice(Cat())
Cat is running...
Cat is running...

静态语言 vs 动态语言

对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了:

class Timer(object):
    def run(self):
        print('Start...')

这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

Python的“file-like object“就是一种鸭子类型。对真正的文件对象,它有一个read()方法,返回其内容。但是,许多对象,只要有read()方法,都被视为“file-like object“。许多函数接收的参数就是“file-like object“,你不一定要传入真正的文件对象,完全可以传入任何实现了read()方法的对象。

实际上可以有另外一种解释:  
run_twice方法中,animal只是一个普通变量
的名字,形参换成anything再来看呢?答案显然是可以的。

四、错误和异常处理

捕捉异常

所以高级语言通常都内置了一套try…except…finally…的错误处理机制,Python也不例外。

# 不含finally
try:
    pass
except Exception as e:
    raise e


# 含有finally 
try:
    pass
except Exception as e:
    raise e
finally:
    pass

一般我们使用如上两种情况即可,当然,你可能也知道异常是有不同的种类的,常见的有参数异常,空指针异常等等,感兴趣的同学可以自行去搜索,我这里就简单粗暴全部给把所有异常都给捕获了。

调试

在python的开发中,我们肯定经常碰到各种错误和异常,这时候我们怎么去排查问题呢?

一是使用print

二是使用python的logging模块

使用print就不用多说了,这里我们着重来说下使用logging模块吧,直接上代码:

import logging

# 配置输出等级为debug和输出格式
logging.basicConfig(level=logging.DEBUG, format='[%(asctime)s][%(thread)d][%(filename)s][line: %(lineno)d][%(levelname)s] ## %(message)s')

logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')

这样我们便可以在控制台上看到我们的信息。

[2018-08-17 11:33:57,345][140104970061632][testlog.py][line: 5][DEBUG] ## debug
[2018-08-17 11:33:57,345][140104970061632][testlog.py][line: 6][INFO] ## info
[2018-08-17 11:33:57,345][140104970061632][testlog.py][line: 7][WARNING] ## warning
[2018-08-17 11:33:57,345][140104970061632][testlog.py][line: 8][ERROR] ## error
[2018-08-17 11:33:57,345][140104970061632][testlog.py][line: 9][CRITICAL] ## critical

logging的参数解释:

debug : 打印全部的日志,详细的信息,通常只出现在诊断问题上

info : 打印info,warning,error,critical级别的日志,确认一切按预期运行

warning : 打印warning,error,critical级别的日志,一个迹象表明,一些意想不到的事情发生了,或表明一些问题在不久的将来(例如。磁盘空间低”),这个软件还能按预期工作

error : 打印error,critical级别的日志,更严重的问题,软件没能执行一些功能

critical : 打印critical级别,一个严重的错误,这表明程序本身可能无法继续运行

仅仅输出到控制台是不够的,我们肯定是需要把日志输出到文件中的的,下面我们来自定义一个logger工具类提供给其他模块使用:

import logging   

# 创建一个logger   
logger = logging.getLogger('mylogger')   
logger.setLevel(logging.DEBUG)   # 设置log信息的输出级别

# 创建一个handler,用于写入日志文件   
fh = logging.FileHandler('test.log')   
fh.setLevel(logging.DEBUG)   

# 再创建一个handler,用于输出到控制台   
ch = logging.StreamHandler()   
ch.setLevel(logging.DEBUG)   

# 定义handler的输出格式   
formatter = logging.Formatter('[%(asctime)s][%(thread)d][%(filename)s][line: %(lineno)d][%(levelname)s] ## %(message)s')  
fh.setFormatter(formatter)   
ch.setFormatter(formatter)   

# 给logger添加handler   
logger.addHandler(fh)   
logger.addHandler(ch)   

# 记录一条日志   
logger.info('foorbar')  

这样便可以输出到当前目录的test.log文件中

我们可以把这样的一个自定义logger放到公共模块中,就可以提供给其他模块用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值