简述Python中的实例方法,类方法,静态方法
1. 实例方法:
与具体的实例相关,会传入一个必须的参数self。self代表被实例化的对象本身。实例方法中能够访问在构造函数__init__()中方初始化的成员变量。
2. 类方法:
与类本身相关的方法。会传入一个必须的参数cls。cls表示当前类,无法通过cls访问构造函数__init__()中创建的成员变量。但是可以在类方法中修改类属性。类方法声明时,需要使用装饰器classmethod进行修饰
3.静态方法:
静态方法,与对象以及类均无关系,不需要传递额外的参数。静态方法需要使用装饰器@staticmethod进行修饰。
# 实例方法
class Person:
country = "china" # 类属性 / 需要与self.xxx类数据成员进行区别
def __init__(self, name, age, occupation):
"""
属性定义
:param name: public
:param age: protected
:param occupation: private
"""
self.name = name
self._age = age
self.__occupation = occupation
def eat(self):
"""
实例方法,因为第一个参数是self(具体的实例),参数是实例
:return:
"""
print("{} is eating.".format(self.name))
@classmethod
def greet(cls):
"""
类方法,需要添加装饰器,且第一个参数必须是cls(class,类),参数是类
:return:
"""
cls.country = "Russion" # 可以在类方法中修改类属性country
print("Hello Everyone, I am from {}".format(cls.country))
# print("Name is {}".format(cls.name)) # 通过cls也无法访问类中的数据成员
@staticmethod
def static_test():
"""
静态方法不需要传递self或者cls参数,他的操作跟当前的类或者对象没有关系
:return:
"""
print("This is a static method")
if __name__ == "__main__":
p1 = Person("Sam", 31, "Doctor")
p1.eat() # 实例方法
# Person.eat() # 报错,无法调用
Person.greet() # 类方法,只能通过类调用
p1.greet() # 也可以调用
# 通过类和对象均可调用静态方法
Person.static_test()
p1.static_test()
4. python中的继承:
python中实现继承法的方式如下所示:
继承的public,protected类型的数据成员在子类中可以直接访问,private成员无法直接进行访问,续通过调用父类的方式进行获取。
# encoding: utf-8
class Person:
"""
define class person
"""
def __init__(self, name, age, occupation):
self.name = name
self._age = age
self.__occupation = occupation
def get_occupation(self) -> str:
return self.__occupation
def get_person_info(self):
print("My name is {}, I am {} years old and I am a {}".format(self.name, self._age, self.__occupation))
@staticmethod
def _get_passwd(self) -> str:
return "123"
class Student(Person):
def __init__(self, name, age):
super(Student, self).__init__(name, age, "Student") # 调用父类的构造函数
def print_name(self):
print("My name is {}".format(self.name)) # 继承的public成员
def print_age(self):
print("My age is {}".format(self._age)) # 继承的protected成员
def print_occupation(self):
print("My work is {}".format(super(Student, self).get_occupation())) # 父类的private在子类中无法直接访问
if __name__ == "__main__":
s = Student("Sam", 22)
s.print_name()
s.print_age()
s.print_occupation()
5. __new__(cls, *args, **kwargs)
__new__()是用来控制类实例化对象的创建流程,这个方法在对象还没创建之前就会执行,__init__()方法是在创建对象完成执行的。
# encoding: utf-8
class Person:
def __new__(cls, *args, **kwargs):
"""
__new__()方法执行完毕后,一定要返回父类Object的__new__方法调用,且只能传递参数cls
:param args:
:param kwargs:
"""
print("Call the new method!")
# 打印参数
print(args)
print(kwargs)
return super().__new__(cls) # 这里必须要返回对象,如果不反悔,则实例化的对象始终为None
def __init__(self, name):
self.name = name
print("Name is {}".format(name))
if __name__ == "__main__":
p = Person("Elly")
执行结果:
若存在继承的情况:
# encoding: utf-8
class Person:
def __new__(cls, *args, **kwargs):
"""
__new__()方法执行完毕后,一定要返回父类Object的__new__方法调用,且只能传递参数cls
:param args:
:param kwargs:
"""
print("Call the new method!")
# 打印参数
print(args)
print(kwargs)
return super().__new__(cls) # 这里必须要返回对象,如果不反悔,则实例化的对象始终为None
def __init__(self, name):
self.name = name
print("Name is {}".format(name))
class Student(Person):
def __new__(cls, *args, **kwargs):
print("Call the new method student")
return super().__new__(cls, name=args[0]) # 父类不是object,可以将参数传递给父类的__new__()方法
def __init__(self, name):
self.name = name
if __name__ == "__main__":
# p = Person("Elly")
s = Student("Sam")
执行结果:
6. Python中的单例设计模式
某个类在程序运行期间只能有一个对象被创建:
# 单例设计
class User:
__instance = None # 定义私有的类属性
def __new__(cls, *args, **kwargs):
"""
在__new__方法中,判断类属性__instance是否为None,如果为None,调用super().__new__()进行创建,赋值给类属性__instance
如果__instance已经不为None,则直接返回__instance,这样保证了不管在程序运行中实例化了多少次对象,只会返回最初实例化的那
个对象,实现对象的全局唯一。
:param args:
:param kwargs:
"""
if cls.__instance is None:
cls.__instance = super().__new__(cls)
return cls.__instance
def __init__(self):
pass
@classmethod
def get_user(cls):
return User()
if __name__ == "__main__":
user1 = User.get_user()
user2 = User.get_user()
print(id(user1))
print(id(user2))
可以看到实例化两次后返回的是同一个对象:
设计线程安全的单例模式:在上述的单例模式中,如果一个线程在实例化对象的过程中,判断到类属性__instance为None,则会去super().__new__()创建一个新的对象,如果此时实例化过程未结束,类属性__instance依然为空,另一个线程又去实例化对象,则后面线程创建的对象会将前面线程创建的对象覆盖。
7. 异常处理:
具体语法格式
if __name__ == "__main__":
a = 3
b = 0
c = 0
try: # 捕获异常的区域
c = a / b
except Exception: # 捕获的异常的具体类型,Exception表示捕获所有异常
print("Exception appeared!")
else:
print("Result is {}".format(c)) # 没有捕获到异常
finally:
print("End the routine") # 不管有没有异常都会执行的代码区域
可以写多个except捕获多种类型的异常:
if __name__ == "__main__":
a = 3
b = 5
c = 0
try: # 捕获异常的区域
c = a / b
print(d) # 未定义变量
except ZeroDivisionError: # 捕获的异常的具体类型,Exception表示捕获所有异常
print("Can not divide zero!")
except NameError:
print("variable is not defined!")
else:
print("The result is {}".format(c)) # 没有捕获到异常
finally:
print("End the routine") # 不管有没有异常都会执行的代码区域
也可以通过下面的方式打印异常信息:
except NameError as error:
print("variable is not defined!")
print(error.args)
8. 抛出异常:
def greet(name, age):
"""
:param name:
:param age:
:return:
"""
if not isinstance(name, str):
raise TypeError("name must be a string.") # 抛出异常
if not isinstance(age, int):
raise TypeError("age must be int") # 抛出异常
print("I am {} and {} years old".format(name, age))
if __name__ == "__main__":
try:
greet("Tom", "1")
except TypeError as error:
print(error.args)
9. 自定义异常
自定义异常需要继承自Exception类
def greet(name, age):
"""
:param name:
:param age:
:return:
"""
if not isinstance(name, str):
raise ArgumentError("name must be a string.") # 抛出异常
if not isinstance(age, int):
raise ArgumentError("age must be int") # 抛出异常
print("I am {} and {} years old".format(name, age))
class ArgumentError(Exception):
def __init__(self, *args, **kwargs):
tmp_args = args + ("参数错误", )
super(ArgumentError, self).__init__(*tmp_args)
if __name__ == "__main__":
try:
greet("Tom", "1")
except ArgumentError as error:
print(error.args)
python常见异常:
异常名称 | 异常说明 |
AttributeError | 属性错误,访问一个对象的不存在的属性的时候,抛出这个异常 |
ImportError | 导入包错误 |
IndexError | 下标错误,一般有列表越界等 |
KeyError | key错误,一般访问字典的key不存在的时候 |
NameError | 变量名不存在 |
NotImplementedError | 某个方法没有实现的错误 |
StopIteration | 迭代器已经到最后了 |
IndentationError | 缩进错误 |
TabError | 包含了tab和空格错误 |
TypeError | 类型错误,有时候传递了一个错误类型的值给其他函数 |
UnicodeEncodeError | Unicode编码错误,一般是unicode->str错误 |
UnicodeDecodeError | Unicode解码错误,一般是str->unicode错误 |
ValueError | 值错误,比如传一个12a给int()函数转换 |
ZeroDivisionError | 除0错误 |
IOError | 打开一个不存在的文件(在Python3中使用FileNotFoundError) |
FileNotFoundError | 文件没有找到的错误 |
9. python模块导入
在大型项目中,将所有的代码都放到一个文件中不利于代码维护。python中通过模块和包将不同文件中相关的代码整合到一个文件中。
python中的包:包本质上是一个文件夹,将相关的模块组合到一起。如果一个文件夹想被python识别为一个包,则必须在这个文件夹中创建一个__init__.py的文件。此时这个文件夹就能被python识别为一个包。在一个包中的模块,通过import可以相互导入。
在python中导入包,在使用import的时候,是按照特定的路径去查询相应的包是否存在,可以通过sys模块来查询路径的列表,在import相应的包的时候,python是按照如下的路径列表去查找代码中的包或者模块是否存在:
import sys
print(sys.path)
python会按照上述的路径列表进行查找相应的包。
包中的模块在执行import导入模块的时候,可以采用两种方式,相对路径导入和绝对路径导入
from ..modulename import 相对路径上级目录
form .modulename import 相对路径当前目录
__all__变量:可以控制from modulename import * 的行为,如果__all__ = [ ]列表中指定了相应的变量,函数,或者类,import * 的时候只会导入__all__变量中的内容。
在__init__.py中导入的模块,才可以通过包名直接导入,否则不会导入成功,可以在__init__.py中通过__all__ = [ ] 控制import *的导入行为。