本节重点
- 类属性与实例属性
- 类方法与静态方法
- 多态
- 单例
- slots、property关键字
- 异常
- 模块
一、类属性与实例属性
- 类属性属于在方法和类内部定义的属性
- 实例属性:在init放法中定义的属性
class Player(object):
# init方法中定义实例属性
type = "球员" # 类属性
def __init__(self,country,name,age):
# 对象属性,不能使用类名访问,必须是对象访问
self.country = country
self.name = name
self.age = age
类属性相关操作:
1、查看类属性的方法和属性
print(Player.__dict__)
'''
{'__module__': '__main__', 'type': '球员', '__init__': <function Player.__init__ at 0x000002335E9B7620>, '__dict__': <attribute '__dict__' of 'Player' objects>, '__weakref__': <attribute '__weakref__' of 'Player' objects>, '__doc__': None}
此方法可查:类属性的方法和属性和实例方法
'''
2、使用类名访问类属性
print(Player.type)
Player.type = "教练" # 修改
print(Player.type)
print(Player.__dict__)
'''
球员
教练
{'__module__': '__main__', 'type': '教练', '__init__': <function Player.__init__ at 0x000002335E9B7620>, '__dict__': <attribute '__dict__' of 'Player' objects>, '__weakref__': <attribute '__weakref__' of 'Player' objects>, '__doc__': None}
'''
实例属性相关操作:
p1 = Player()
print(p1.type) # 可以使用对象访问类属性
p1.type = "经理"
print(p1.type) # 别被骗了,这是之前说的动态增加实例属性,做不到修改类属性的功能
'''
教练
经理(实例属性值,而非类属性)
'''
print(p1.__dict__) # 看看属性就知道了,增加了一个type实例属性
'''
{'country': '法国', 'name': '内马尔', 'age': 27, 'type': '经理'}
'''
print(Player.__dict__) # 类属性没有变化
'''
{'__module__': '__main__', 'type': '教练', '__init__': <function Player.__init__ at 0x000002335E9B7620>, '__dict__': <attribute '__dict__' of 'Player' objects>, '__weakref__': <attribute '__weakref__' of 'Player' objects>, '__doc__': None}
'''
总结:
- 对象可以访问类属性,但是对象不可以修改类属性。
- 类属性的修改和访问都要由类完成,类不能访问对象属性。
二、类方法与静态方法
- 类方法,在方法名前加上@classmethod关键字,可以使用类名直接调用,不需要创建对象,所以方法不接受self参数,而是接受cls参数。
- 静态方法,与对象和类没有什么必要联系,只是一般出于使用到当前类的逻辑,和节省内存的目的,写在类里面。方法前添加@staticmethod关键字
# 类方法与静态方法
# 类方法的一般使用场景:修改类属性
class Player(object):
__type = "player"
def __init__(self,name,age):
self.name = name
self.age = age
# 定义对象方法
def show(self):
print(self.name,self.age)
# 定义类方法(修改、获取类属性)
@classmethod
def show_msg(cls):
print(cls)
print("class method")
@classmethod
def set_type(cls,type):
cls.__type = type
print(Player.__type)
@classmethod
def get_type(cls):
return cls.__type
# 定义一个静态方法
@staticmethod
def show_static():
print("static method")
调用类方法与静态方法
p1 = Player("neymar",27)
p1.show() # 对象调用实例方法
p1.show_msg() # 对象调用类方法
p1.show_static() # 对象调用静态方法
'''
neymar 27
<class '__main__.Player'>
class method
static method
'''
# 通过对象可以调用对象(实例)方法、类方法、静态方法
Player.show(p1) # 类名调用
Player.show_msg()
Player.show_static()
'''
neymar 27
<class '__main__.Player'>
class method
static method
'''
# 通过类名可以调用对象(实例)方法、类方法、静态方法
三、多态
python多态:关注的同一个方法,但是会出现不同的形式:具体来说就是多个类的同一方法。关注对象方法,不关心对象的类型。函数接受类作为参数,调用不同类的同一方法,表现出不同的行为,这就是多态。
class player(object):
def show(self):
print("player")
class coach(object):
def show(self):
print("coach")
class manager(object):
def show(self):
print("manager")
def show_identity(identity):
identity.show()
p = player()
c = coach()
m = manager()
show_identity(p)
show_identity(c)
show_identity(m)
'''
player
coach
manager
'''
四、单例
一种设计模式,这里仅做简单介绍。
定义:
不管创建多少次对象,都是同一个对象,指向同一个内存地址,节省内存。
示例:非单例的类创建多个对象,内存地址不同
p1 = Player("neymar",27)
p2 = Player("neymar",27)
print(p1,p2)
'''
<__main__.Player object at 0x000001FFCB0BBE10>
<__main__.Player object at 0x000001FFCB0BB860>
内存地址不同,是两个对象
'''
遵循单例的类,创建的多个对象指向同一个地址
class Player_danli(object):
__instance = None
def __new__(cls):
if cls.__instance == None:
cls.__instance = object.__new__(cls)
return cls.__instance
def __init__(self):
pass
p1 = Player_danli()
p2 = Player_danli()
print(p1,p2)
'''
<__main__.Player_danli object at 0x000001FFCB0336A0>
<__main__.Player_danli object at 0x000001FFCB0336A0>
内存地址一致,是同一个对象
'''
单例模式的应用场景:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置,回收站,任务管理器。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
五、slots、property关键字
1、slots
指明创建对象的时候不能增加其他属性。
class Student(object):
__slots__ = ("name","age") # 固定了该类只能有这两个属性
def __init__(self,name,age):
super().__init__() # 这种写法是默认执行父类的初始化函数
self.name = name
self.age = age
print("初始化完毕")
stu = Student("syp",18)
# stu.type = "学生" # 报错,不能再动态添加属性了
stu.name = "dsy" # 已经固定存在的属性可以修改
print(stu.name)
'''
初始化完毕
dsy
'''
2、property
将方法固定为属性值,get、set的简写。
# property关键字:将方法固定为属性值,get、set的简写
class Student(object):
def __new__(cls,*args):
print("new一个对象")
print(args) #必须返回父类的new方法(相当于创建对象)
return object.__new__(cls)
def __init__(self,name,age):
super().__init__()
self.name = name
self.age = age
self.__score = 100
print("初始化完毕")
@property # 将方法修改为对应的属性值,要求get必须在set上面
def get_score(self):
return self.__score
@get_score.setter # 配合property一起使用
def set_score(self, score):
self.__score = score
stu = Student("syp",18)
stu.set_score = 99
print(stu.get_score)
'''
new一个对象
('syp', 18)
初始化完毕
99
'''
六、异常
定义:
在控制台输出当前python解释器执行输出错误信息,遇到异常终止代码,抛出避免程序报错。
1、简单的异常捕获结构:
try:
num1 = input("请输入一个数")
num2 = input("请输入第二个数")
print(int(num1) / int(num2))
except ZeroDivisionError as e: # 捕获某种系统内置的异常类型,这里是除0异常
print(e)
else:
print("没有异常会执行else语句")
finally:
print("有没有异常都会执行")
'''
输入:1,0
输出:
division by zero
有没有异常都会执行
'''
2、自定义异常类
# 自定义异常类,多数继承自Exception
class customError(Exception):
def __init__(self,content,*args,**kwargs):
super().__init__(*args, **kwargs)
self.content = content # 抛出异常类的描述信息
def __str__(self):
return "我是自定义异常,异常数据为%s"%self.content
content = input("请输入数据")
if content != 'a': # 输入数据非a,就抛出异常
raise customError(content)
'''
not_a_Error
Traceback (most recent call last) in
8 content = input("请输入数据")
9 if content != 'a':
---> 10 raise not_a_Error(content)
not_a_Error: 我是自定义异常,异常数据为b
'''
七、模块
1、定义:
.py文件,内含管理代码:类、全局变量、函数等。在编写其他.py文件时,需要使用本文件内的类、函数时,讲本文件作为模块进行导入。
2、py内置的模块:
如time、sys、random等等。
3、更多框架与其他重要模块:
django、numpy、pandas、matplotlib、keras等等
4、导入模块
假定现在我们有两个.py文件,my_module1.py与run.py:
my_module1.py中的内容如下
num = 10
def sum_num(num):
return (num+1)num/2
print(sum_num(num))
class Class1(object):
def show(self):
print("实例方法")
def show():
print("show函数")
那么在run.py中可以这样写:
import my_module1
print(my_module1.num)
my_module1.sum_num()
'''
这种import+模块名导入,相当于所有代码复制过来
my_module1中的语句print(sum_num(num))也会被执行
'''
能不能不执行被导入模块内部的一些调试语句?试着将my_module1.py修改:
my_module1.py
num = 10
def sum_num(num):
return (num+1)num/2
class Class1(object):
def show(self):
print("实例方法")
def show():
print("show函数")
if __name__ == "__main__":# 当该模块作为主模块时执行
print(sum_num(num))
'''
当做为被导入模块时,__name__ != "__main__"
只有当作为导入模块时,该模块才作为主模块
'''
其他导入方式from
1、from 模块名 import 对应功能代码
run.py内容
# 仅导入类等,不需要使用模块名调用,直接使用
from my_module1 import Class1,show
c1 = Class1()
show()
2、from 模块名 import *(导入模块的所有功能)
run.py内容
# 仅导入类等,不需要使用模块名调用,直接使用
from my_module1 import *
c1 = Class1()
show()
注意:这种方式如果配合使用__ all __ ,可以限定导入的功能,只能导入在 __ all __ 列表中的功能*
现在my_module1.py为
__all__ = ["show","num"] # 指定功能
num = 10
def sum_num(num):
return (num+1)num/2
class Class1(object):
def show(self):
print("实例方法")
def show():
print("show函数")
if __name__ == "__main__":# 当该模块作为主模块时执行
print(sum_num(num))
run.py
from my_module1 import *
c1 = Class1() # 报错,不在限定代码范围内
show()
print(num)
5、给模块起别名
as 关键字后跟模块简写,之后可以用简写作为模块名、类名、函数名使用。
# 给模块起别名
import numpy as np
from module import show as show_msg
from module import Student as stu
总结:
1、自定义模块名不能和系统模块相同
2、导入功能代码不要在当前模块自定义
from module1 import show
def show():
print("AAAAAAA")
show()
'''
module1中的show会被主模块的show替换掉,被覆盖。
'''
3、尽量不要相互导入
4、违反以上规则需要修改模块的搜索顺序
import sys
print(sys.path) # 可查看模块搜索顺序
网友评论