使用Python写过面向对象的代码的同学,可能对 init 方法已经非常熟悉了,init 方法通常用在初始化一个类实例的时候。例如:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return '<Person: %s(%s)>' % (self.name, self.age)
if __name__ == '__main__':
niwa = Person('Niwa', 24)
print(niwa)
执行结果
<Person: Niwa(24)>
这样便是init最普通的用法了。但init其实不是实例化一个类的时候第一个被调用 的方法。当使用 Persion(name, age) 这样的表达式来实例化一个类时,最先被调用的方法 其实是new方法。
new方法接受的参数虽然也是和init一样,但init是在类实例创建之后调用,而new方法正是创建这个类实例的方法。
class Person(object):
"""Silly Person"""
def __new__(cls, name, age):
print('__new__ called')
return super().__new__(cls)
def __init__(self, name, age):
print('__init__ called.')
self.name = name
self.age = age
def __str__(self):
return '<Person: %s(%s)>' % (self.name, self.age)
if __name__ == '__main__':
niwa = Person('Niwa', 24)
print(niwa)
执行结果
__new__ called
__init__ called.
<Person: Niwa(24)>
我们比较两个方法的参数,可以发现__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__new__方法返回的值就是一个实例化对象(ps:如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法)。我们可以这么理解它们之间的关系,__new__是开辟疆域的大将军,而__init__是在这片疆域上辛勤劳作的小老百姓,只有__new__执行完后,开辟好疆域后,__init__才能工作,结合到代码,也就是__new__的返回值正是__init__中self。
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
print('self:', self)
# 定义一个build方法,返回一个person实例对象,这个方法等价于Person()。
@classmethod
def build(cls):
# cls()等于Person()
p = cls("Tom", 18)
print('cls:', cls)
return p
if __name__ == '__main__':
person = Person.build()
print(person, person.name, person.age)
执行结果
self: <__main__.Person object at 0x000002474096B3C8>
cls: <class '__main__.Person'>
<__main__.Person object at 0x000002474096B3C8> Tom 18
总结
有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt函数,必须用语句**#include
<math.h>**引入math.h这个头文件,否则是无法正常进行调用的。
- 那么在Python中,如果要引用一些其他的函数,该怎么处理呢?
- 在Python中有一个概念叫做模块(module),这个和C语言中的头文件以及Java中的包很类似,比如在Python中要调用sqrt函数,必须用import关键字引入math这个模块,下面就来了解一下Python中的模块。
- 包: 当我们写了几个相近的py文件后, 想要集成起来给别人使用. 这时候就需要用到我们的包了.
- 包就是为了多个py文件打包起来访问的东西. 只要在包里面放一个init.py文件, 在init.py文件import包里面的模块(py文件), 就可以实现"import 包名", 实现对多个模块的调用.
说的通俗点:模块就好比是工具包,要想使用这个工具包中的工具(就好比函数),就需要导入这个模块
模块定义好后,我们可以使用 import 语句来引入模块,语法如下:
import module1[, module2[,... moduleN]]
比如要引用模块 math,就可以在文件最开始的地方用import math来引入。在调用 math 模块中的函数时,必须这样引用:
模块名.函数名
当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。
搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块 support.py,需要把命令放在脚本的顶端:
一个模块只会被导入一次,不管你执行了多少次import。这样可以防止导入模块被一遍又一遍地执行。
Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中。语法如下:
from modname import name1[, name2[, ... nameN]]
例如,要导入模块 fib 的 fibonacci 函数,使用如下语句:
from fib import fibonacci
这个声明不会把整个 fib 模块导入到当前的命名空间中,它只会将 fib 里的 fibonacci 单个引入到执行这个声明的模块的全局符号表。
把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:
from modname import *
这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
例如我们想一次性引入 math 模块中所有的东西,语句如下:
from math import *
当你导入一个模块,Python解析器对模块位置的搜索顺序是:
常见异常类型
捕捉异常可以使用try/except语句。
try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。
如果你不想在异常发生时结束你的程序,只需在try里捕获它。
语法:
以下为简单的try…except…else的语法:
try:
<语句> #运行别的代码
except <名字>:
<语句> #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句> #如果引发了'name'异常,获得附加的数据
else:
<语句> #如果没有异常发生
try的工作原理,当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。
def get_score():
while True:
str_score = input("请输入成绩:")
try:
int_score = int(str_score)
except ValueError:
continue
if 1<=int_score<=100:
return int_score
print(get_score())
执行结果
请输入成绩:a
请输入成绩:101
请输入成绩:11
11
当程序出现错误,python会自动引发异常,也可以通过raise显示地引发异常。一旦执行了raise语句,raise后面的语句将不能执行。
try:
s = None
if s is None:
print("s 是空对象")
raise NameError # 如果引发NameError异常,后面的代码将不能执行
print(len(s)) # 这句不会执行,但是后面的except还是会走到
except TypeError:
print("空对象没有长度")
s = None
if s is None:
raise NameError
print('is here?') # 如果不使用try......except这种形式,那么直接抛出异常,不会执行到这里
执行结果
s 是空对象
Traceback (most recent call last):
File "E:/PyCharm_study_test/project/Learn_py/raise.py", line 5, in <module>
raise NameError # 如果引发NameError异常,后面的代码将不能执行
NameError