今天的主要内容是面向对象汇总
1.type(obj) obj是一个对象,那么type它就得到它的类型。 type(对象)的结果是对象实例化之前对应的类,type(类)结果是type。
代码块
class Student:
pass
s=Student()
print(type(s)) #<class '__main__.Student'>
print(type(Student)) #<class 'type'>
类名+()就是一个实例化
new()创造了一个对象的空间,一些简单的初始化
2. type是所有类的元类,object是所有类的父类
类也是被创建出来的,type创建类, type(类名) =type
代码块
from abc import ABCMeta
class A(metaclass=ABCMeta):
pass
a=A()
print(type(a))
print(type(A)) #ABCMeta创建了这个A类,那么ABCMeta就是A的元类
# 如果没有指明ABCMeta,那么 type就是这个类的 元类
# type(类)的结果就是创建这个类的元类,大多数情况下就是type,除非你指定metaclass
代码块
class Saler:
def __init__(self,name,sex,ident):
self.name = name
self.sex = sex
self.ident = ident
def sale(self):
print('%s卖东西'%self.name)
def add_goods(self):
pass
alex = Saler('alex',None,'looser')
print(type(alex)) #Saler
print(type(Saler)) #type
3 什么时候使用面向对象?
python当中一切皆对象 基础数据类型 都是对象
类型和自定义类的关系 类型和类是一个东西
代码量大,功能比较复杂,角色多的时候,比如(qq 好友 陌生人 群 组
复杂的电商程序
公司/学校的人事管理/功能的系统
4 面向对象的好处
我的代码的清晰度更高了
可读性 无论是开发者 还是调用者 都能明确的分辨出每个角色拥有的方法和属性
增强了代码可扩展性
增加复用性
更加规范
5 类是什么时候被加载的,以及类名是什么时候生效的?
类从一创建就被加载,但是类中的函数只用调用才执行。
代码块
class Person:
ROLE='student'
# print(Person.ROLE) name 'Person' is not defined
print(ROLE)
def func(self):
print('我是一个函数')
return 'bye'
p=Person()
print(Person.func) #<function Person.func at 0x037C94B0>
print(p.func()) #我是一个函数 bye
思考5.1:为什么print(Person.ROLE)会报错?
因为这个时候class类还没有加载完成,只有加载完成才会有Person,此时还不存在,所以报错。
思考5.2:为什么Person.func和a.func两个内存地址不一样?
a.func指向class.func的地址,所以不一样。6 对象与组合
对象
对象:类实例化对象的过程,就是构造new,初始化init
对象可以通过指针找到类的空间中的内容,指向类
对象本身存储了一些只属于对象的属性
组合
组合:一个类实例化对象作为另外一个类对象的属性就是组合
7 单继承(单继承子类调用父类方法)
代码块
class Foo:
def __init__(self):
self.func()
def func(self):
print('Foo.func')
class Son(Foo):
def func(self):
print('我是儿子')
s = Son() #先执行父类的__init__(),再执行self.func()
子类有,父类没有,调用子类的
子类没有,父类有,调用父类的
子类有,父类也有,调用子类的
子类有,父类有,想调用父类,怎么办:
super().父类方法(参数)参数里面不用传self
父类名.父类方法(self,其它参数)
8 多继承的继承顺序
代码块
class A:
def func(self):
print('A')
class B(A):
def func(self):
super().func()
print('B')
class C(A):
def func(self):
super().func()
print('C')
class D(B,C):
def func(self):
super().func()
print('D')
d = D()
d.func() #ACBD 广度优先
b= B()
b.func() # AB
print(D.mro()) #[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
#类的继承顺序是DBCA
新式类(度优先 - C3算法)和经典类
代码块
mro方法查看继承顺序
py3 默认继承object 所以py3都是新式类
super().func() 遵循mro算法,在类的内部不用传子类名和self
py2 需要主动继承object,默认不继承
super(子类名,self).func() 必须传子类名和self
经典类 : 深度优先
py2 不继承object,默认都是经典类,也可以手动继承object,没有mro
9 多态(一种类型的多种形态 多个子类去继承父类,那么每一个子类都是这个父类的一种形态)
10封装
广义的封装 : 把方法和属性都封装在一个类里,定义一个规范来描述一类事物.
狭义的封装 : 私有化 只能在类的内部访问
__静态变量,私有方法 ,私有的对象属性,私有的类方法,私有的静态方法
在内存中存储 类名_名字
为什么在类的内部可以使用双下划线访问 : 在类的内部使用,你就知道你在哪个类中
在子类中可以访问访问父类的私有变量么?不行
私有 : 不能在类的外部使用也不能被继承
11 property的使用(把方法伪装成属性)
property装饰器函数,内置函数,帮助你将类中的方法伪装成属性,特性
调用方法的时候不需要主动加括号
让程序的逻辑性更合理
代码块
class A:
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self, new_name):
self.__name = new_name
@name.deleter
def name(self):
del self.__name
a = A('alex')
a.name = 123
print(a.name)
# del a.name # 语法
# #
# print(a.name)
@方法名.setter
(self,变量,新的值)
装饰器,修改被property装饰的属性的时候会调用被这个装饰器装饰的方法,除了self之外还有一个参数,被修改的值
@方法名.deleter
装饰器,当要删除被property装饰的属性的时候会调用被这个装饰器装饰的方法
12类方法classmethod(通过类调用,不通过对象)
代码块
class Goods:
__discount = 0.8
def __init__(self,price):
self.__price = price
@property
def cost(self):
return self.__price * Goods.__discount
@classmethod
def change_discount(cls,num):
cls.__discount = num
Goods.change_discount(10) #不用通过对象,通过类名就可以直接调用
a=Goods(5)
print(a.cost) #50
13静态方法
如果一个类里面的方法 既不需要用到self中的资源,也不用cls中的资源.
相当于一个普通的函数
但是你由于某种原因,还要把这个方法放在类中,这个时候,就将这个方法变成一个静态方法
某种原因:
你完全想用面向对象编程 ,所有的函数都必须写到类里
某个功能确确实实是这个类的方法,但是确确实实没有用到和这个类有关系的资源
14反射
反射 - 从某个指定的命名空间中,用字符串数据类型的变量名来获取变量的值
类名反射: 静态属性 类方法 静态方法
对象反射 :对象属性 方法
模块 : 模块中的方法
代码块
import sys
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
self.school='北京大学'
def study(self):
print('%s%s在%s上大学'%(self.name,self.age,self.school))
res=sys.modules['__main__']
s2=getattr(res,'Student')('alex',18) #实例化
s2.study()
getattr(s2,'study')()
# s2.study()与getattr(s2,'study')()是同一个
print(s2.study==getattr(s2,'study')) #是同一个东西
15 双下方法(内置方法/魔术方法/双下方法)
代码块
__名字__不是被直接调用的
间接调用 : 内置函数/面向对象中特殊语法/python提供的语法糖
__str__ : str(obj),要求必须实现了__str__,要求这个方法的返回值必须是字符串str类型
print %sstr
__call__ : 相当于 对象() 用类写装饰器
__len__ : len(obj),要求obj必须实现了__len__,要求这个方法的返回值必须是数字int类型
__new__ : 在实例化的过程中,最先执行的方法,在执行init之前,用来创造一个对象,构造方法
__init__ : 在实例化的过程中,在new执行之后,自动触发的一个初始化方法,每个对象都会自动执行这个方法,没有就去父类中找__init__
16语法糖
代码块
x=5
y =6
print(x.__add__(y)) #11
print(x+y)# 语法糖 11
代码块
class MyType:
def __init__(self,s):
self.s = s
def __add__(self, other):# __sub__ __mul__ __div__
return self.s.count('*') + other.s.count('*')
obj1 = MyType('asjkfhk***17264****')
obj2 = MyType('asjkfhk***17***')
print(obj1.__add__(obj2) ) #13
print(obj1 + obj2) #语法糖
17 str和repr区别
name='wangsiyu'
print(name) #wangsiyu 一个没有引号
print(repr(name)) #'wangsiyu' 一个有引号
代码块
__str__: str(obj)
要求必须实现了__str__,要求这个方法的返回值必须是字符串str类型
print %s str
__repr__: 是__str__的备胎.如果有__str__方法,那么# print %s str都先去执行__str__方法,并且使用__str__的返回值
如果没有__str__,那么print %s str都会执行repr
repr(obj),%r
代码块
class A:
def __init__(self,name):
self.name = name
def __str__(self):
return '**%s**'%self.name
def __repr__(self):
return self.name
class B(A):
def __init__(self,name):
self.name = name
def __repr__(self):
return '***'
b = B('alex') #实例化一个B类
print(str(b),repr(b)) #**alex** ***
print('%s | %r'%(b,b)) #**alex** | ***
print('---%r---'%('abc')) #r代表repr
print('---%s---'%('abc')) #s代表str
在子类中使用__str__,先找子类的__str__,没有的话要向上找,只要父类不是object,就执行父类的__str__
但是如果除了object之外的父类都没有__str__方法,就执行子类的__repr__方法,
如果子类也没有,还要向上继续找父类中的__repr__方法.一直找不到 再执行object类中的__str__方法
18内置方法
代码块
abs()
dict()把一个数据转为字典
help()
min()取出列表最小
bool()有就是True,没有就是False
dir()打印当前所有变量
hex()将一个数字转为16进制
sorted()排序
ascii()
oct()转为8进制
bin()转为2进制
eval()把字符串转为数字计算
ord()返回ACSII表位置
chr() 和ord()正好相反
map() reduce() filter()
callable() 是否可以被调用
tuple()转为元祖
别跑,点个赞再走
网友评论