关于类与对象操作的BIFs
- type() 返回对象类型
- id(),查看对象id
- dir(),查看对象下变量及函数
- issubclass(),isinstance(), super(),类,实例,调父类
- hasattr(),getattr(),setattr(),delattr()类属性操作
- globals(),locals(),全局与局部的名称空间
- import(),reload(),模块的导入与重载
面向对象编程OOP
1.比较编程方式
面向过程:根据业务逻辑从上到下写垒代码
函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可,函数是对面向过程的一次封装
面向对象:对函数进行分类和封装,让开发“更快更好更强…”,面向对象是更高一层的封装
2.OOP的核心思想:
类:从近似的对象中抽象出类
对象:然后再从类出实例化出对象
类的创建与实例化
创建类
- class关键字
- 指定继承
- 定义类的成员
数据成员
类变量
实例变量
方法成员
类方法
实例方法
实例化类
class Student():
#类变量
student_total=0
student_list=[]
student_graduated=0
pass_score=1000
#魔法函数创建实例变量
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
self.__score=0
Student.student_total+=1
Student.student_list.append(name)
#实例方法
def exam(self,score):
if score<60:
return 'sorry, You have failed this time,better luck next time'
else:
self.__score+=score
str1='Good!, Your score is now'+str(self.__score)
if self.__score>=Student.pass_score:
Student.student_graduated+=1
return str1
def check(self,):
if self.score<Student.pass_score:
return 'You have',Student.pass_score-self.score,' scores to archive!'
else:
return 'You have graduated from julyedu.com'
#类方法
@classmethod
def get_student_graduated(cls,):
return Student.student_graduated
@classmethod
def get_student_list(cls,):
return Student.student_list
#普通方法
@staticmethod
def static1():
return 'it can be called by both the instance and the class'
xiaohong=Student('xiaohong',23,'female')
xm=Student('xiaoming',22,'male')
xm.exam(99)
类的内部结构
- 数据成员:[用于处理类及实例对象的相关数据]
类变量:在类中且在函数体外,实例之间共享
实例变量:定义在方法中,作用于当前实例的类 - 方法成员(在类中定义的函数叫方法) :
类方法:定义时需要使用@classmethod装饰器,第一个参数为cls。
实例方法:绑定到实例的方法,第一个参数为self,只有实例能调用实例方法。 - 静态方法[普通方法]
定义的时候使用@staticmethod装饰器。
静态方法没有参数限制,不需要实例参数self和类参数cls
静态法可以通过类名访问,也可以通过实例访问。
OOP三大特性总结
- 继承
创建一个类时可以从新开始,也可以从已经有的类继承下来,继承的类叫做subclass。
super()用于子调用父类的方法
#继承时在括号中加父类名字
>>class list1(list):
>> name='this is list1 class'
>> #__name如果使用前双划,属性将被隐藏
>>issubclass(list1,list) #判断list1是不是list的子类
True
>>class person():
>> def speak(self,):
>> return 'people can speak language!'
>> def work(self,):
>> print('people should have work to do!')
>>class fireMan(person):
>> def work(self,):
>> print('A great work that can save people!')
>> def speak2(self,):
>> print(super().speak(),'FireMan needs to speak loudly!')
>>fireman1=fireMan()
>>fireman1.work()#多态,子类方法覆盖父类方法
>>fireman1.speak2()#super方法调用父类
A great work that can save people!
people can speak language! FireMan needs to speak loudly!
- 多态
因为类具有继承关系,子类可以向上转型被看做是父类的类型,比如
无论是战士还是快递员,都是人类。
有了继承关系,子类可以继承父类的所有方法和属性,当然也可以重
载父类的成员函数及属性。
例如,当子类(直升机)和父类(飞机)都存在相同的fly()方法时,子
类的fly()覆盖了父类的fly(),在运行时就总是会调用子类的fly()。 - 封装
封装就是将抽象的数据(变量)和行为(函数)打包,形成一个逻辑上的整体(即类);
封装可以增强安全性(数据)并简化编程(函数),用户只能通过类对外接口的访问权限来使用类的成员。
访问控制
Python没有像其它语言有访问控制的关键字,例如private、protected等等。Python通过命名约定来实现的访问控制,例如在之前Student类的基础上,对其进行数据的保护。便其数据不能再被通过类名.或对象.的形式被调用。
对模块级的控制,通过在标识符前加单下划线_实现。
对类内部的属性及方法,通过在在标识符前加双下划线__来实现的私有化
类中两个双下划线包裹的属性或方法为特殊
魔法方法Magic Method
- 魔术方法:
魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被Python 所调用,你可以定义自己想要的行为,这些会自动发生。 - 当调用 x = SomeClass() 的时候, __init__ 并不是第一个被调用的方法。还有一个叫做__new__ 的方法,两个共同构成了“构造函数”。
__new__是用来创建类并返回这个类的实例, 而__init__只是将传入的参数来初始化该实例。
在对象生命周期调用结束时,__del__ 方法会被调用,可以将__del__理解为“构析函数”。 - 它们经常是两个下划线包围来命名的
案例
#构造和初始化魔术
>>class myclass():
>> def __init__(self,):
>> print('被__init__')
>> def __del__(self,):
>> print('我被__del__了,再见')
>>c1=myclass()
被__init__
>>del c1
我被__del__了,再见
比较魔术 | 作用 |
---|---|
__cmp__(self, other) | 是最基本的用于比较的魔术方法。实现了所有的比较符号 |
__eq__(self, other) | 定义了等号的行为, == 。 |
__ne__(self, other) | 定义了不等号的行为, != 。 |
__lt__(self, other) | 定义了小于号的行为, < 。 |
__gt__(self, other) | 定义了大于等于号的行为, >= 。 |
数值处理魔法 | |
__pos__(self) | 实现正号的特性(比如 +some_object) |
__neg__(self) | 实现负号的特性(比如 -some_object) |
__abs__(self) | 实现内置 abs() 函数的特性。 |
__invert__(self) | 实现 ~ 符号的特性。 |
__add__(self, other) | 实现加法。 |
__sub__(self, other) | 实现减法。 |
__mul__(self, other) | 实现乘法。 |
__floordiv__(self, other) | 实现 // 符号实现的整数除法。 |
__div__(self, other) | 实现 / 符号实现的除法。 |
__truediv__(self, other) | 实现真除法。 |
__iadd__(self, other) | 实现赋值加法+= |
容器魔法 | |
__len__(self) | 定义当被 len() 调用时的行为(返回容器中元素的个数) |
__getitem__(self, key) | 定义获取容器中指定元素的行为,相当于 self[key] |
__setitem__(self, key, value) | 定义设置容器中指定元素的行为,相当于 self[key] = value |
__delitem__(self, key) | 定义删除容器中指定元素的行为,相当于 del self[key] |
__iter__(self) | 定义当迭代容器中的元素的行为 |
__reversed__(self) | 定义当被 reversed() 调用时的行为 |
__contains__(self, item) | 定义当使用成员测试运算符(in 或 not in)时的行为 |
反射 | 通过魔术方法控制使用 isinstance() 和 issubclass() 内置方法的反射行为。 |
__instancecheck__(self, instance) | 检查一个实例是不是你定义的类的实例 |
__subclasscheck__(self, subclass) | 检查一个类是不是你定义的类的子类 |
调用 | |
__call__(self, [args...]) | 允许一个类的实例像函数一样被调用,即x() 与 x.__call__() 是相同的. __call__ 参数可变。这意味着你可以定义 __call__ 为其他你想要的函数,无论有多少个参数 |
案例
#比较魔术
class myclass():
def __init__(self,num):
self.num=num
print('被__init__')
def __eq__(self,other):
if type(other)==int:
return True if self.num>other else False
else:
print('can\'t compare with other datatype except int',)
>>c1=myclass(3)
被__init__
>>c1=='china'
cant compare with other datatype except int
#数值处理魔法
>>class myclass():
def __init__(self,num):
self.num=num
print('被__init__')
def __pos__(self):
self.num=10086
>>c1=myclass(-3)
被__init__
>>+c1
>>c1.num
10086
#类表现魔法
class myClass():
__doc__='this is myClass docuemtnt'# 表示类的描述信息,重写代表自定义描述
__name__='moduel name is V'#模块是对象,并且所有的模块都有一个内置属性 __name__。
#一个模块的 __name__ 的值取决于如何应用模块。
#如果 import 一个模块,那么模块__name__ 的值通常为模块文件名,不带路径或者文件扩展名。
#但是也可以像一个标准的程序样直接运行模块.
#在这种情况下, __name__ 的值将是一个特别缺省"__main__"。上述类中加上__name__ == '__main__'的判断语句
#可以直接在终端环境下执行python dirfile.py /tmp进行测试,不必非得在交互式环境下导入模块进行测试。
#容器魔法
class FunctionalList():
def __init__(self, values=None):#初始化
if values is None:
self.values = []
else:
self.values = values
def __len__(self):
return len(self.values)+10#故意多加10个
def __getitem__(self, key):
if type(key)==slice:#如果传入的key是一个slice类,则这是一个切片访问
start=key.start
stop=key.stop+1
if key.stop==None:
stop=-1
if key.start==None:
start=0
return self.values[start:stop]
else:
return str(self.values[key])*2#故意多输出2次
def __setitem__(self, key, value):
self.values[key] = str(value)+'haha'#故意都给转成str,再加haha字样
def __delitem__(self, key):
pass
#del self.values[key]#就是故意不去删
def __iter__(self):
#用于迭代器,之所以列表、字典、元组等可以进行for循环,是因为类型内部定义了 __iter__
# pass
return iter(self.values)
def __reversed__(self):
return reversed(self.values)
def append(self, value):#非魔术方法
self.values.append(value)
>>l1=list(range(10))
>>o1=FunctionalList(l1)
>>len(o1)#调用的是__len__
20
>>o1[0:9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
#调用
>>class callableInstance():
def __init__(self, x, y):
self.x, self.y = x, y
def __call__(self,):
self.x, self.y = self.y, self.x
#调用时交换对象
>>c1=callableInstance(1,5)# 执行 __init__,赋值x,y
>>print(c1.x,c1.y)
1 5
>>c1()# 执行 __call__,交换变量变换
>>print(c1.x,c1.y)
5 1
模块module
- 模块定义:一个.py文件,包含了对象定义与语句
- 模块作用:用来从逻辑上组织代码
- 模块使用:
- 搜索路径(标准模块,自定义与第三方模块)路径(记得import sys)
搜索路径设置(修改sys.path(sys.path.append()),设置环境变量) - 导入方法
import test #作为模块空间导入
from ** import * #指定模块下具体的类,对象导入,并入当前空间
from *** import *** #将模块下所有对象导入,并入当前空间
包package
- 包定义:
含有init.py文件夹被称为包, init.py文件用于标识当前文件夹是一个包。
(该文件可以为空,但必须有)
包用于组织模块,通常把功能相近的模块进行再次封装成为包。 - 包的目录结构:
模块
子包
(子包下的子包) - 包的安装(pip,conda)
- 不同的导入方式(假设包名为test)
import test#导入init.py这个moduel。
from test import *#导入init.py这个moduel下所有对象导入到当前空间。
from test.test_level1.test_level2 import test_level2#导入的层次目录下的模块。
还是模块
网友评论