面向对象
面向对象 vs 面向过程
面向对象着重谁去做
面向过程着重做什么
类和对象
类:描述具有相同属性或者方法的集合
对象/实例: 具体的摸个事务,实实在在的一个实例
实例化:创建一个对象的实例
属性:对象的描述信息 -变量
方法:对象的方法 -函数
面向对象的三大特征
1.封装
2.继承
3.多态
类的命名:驼峰式命名 HunanAtm
python2 vs python3
python2 经典类和新式类
python3 只有新式类
新式类显式继承object
反之为经典类
• 经典类
• 所有的类都是classobj类型,而类的实例都是instance类型。
• 类与实例只有通过__class__属性进行关联
• 新式类(c3算法)
• 类实例的类型是这个实例所创建自的类(通常是和类实例的__class__相同)
c3算法
首先将自身类加入本序列,然后对继承序列的元素依次判断
若某个元素不在其它序列,或者它是所有继承序列的第一个,那么把这个元素提取到本序列
class A:
def test(self):
print("from A")
class B(A):
def test(self):
print("from B")
class C(A):
def test(self):
print("from C")
class D(B):
def test(self):
print("from D")
class E(C):
def test(self):
print("from E")
class F(D, E):
def test(self):
print("from F")
f = F()
f.test()
# 经典类: F --> D --> B --> A -->E -->C
# 新式类: F --> D --> B --> E --> C --> A
类空间和实例空间
类创建的时候会生成类空间
实例化对象就会生成实例空间,不同实例之间,空间都是独立的
实例查找属性方法的时候,先会去实例空间查找,找不到就去类空间查找
类空间找不到,就去父类空间找
实例可以访问到类以及父类空间
类访问不到实例空间
实例可以访问类空间属性,但是改变不了类空间属性
__init__方法
实例对象的构造方法(初始化方法)
实例化对象的时候 自动调用__init__方法
__new__方法
创建实例的方法,一般情况下不需要重写
小结
__new__是创建实例的方法
__init__是对创建好的实例进行初始化工作的方法
__new__方法必须要传入一个参数(cls),代表当前类
__new__必须返回一个实例化对象
__init__的self就表示__new__返回的实例,__init__对这个实例进行初始化工作
子类没有定义__new__,就会去找父类的__new__
新式类才有__new__
如果实例化对象和本身class不一致,__init__就不执行
单例模式
无论实例化多少次,都返回同一个对象实例 重写__new__
class Danli:
instance = None
def __new__(cls, *args, **kwargs):
if cls.instance is None:
# cls.instance = super().__new__(cls)
cls.instance = object.__new__(cls) #
return cls.instance
# 创建多个对象
dan1 = Danli()
print(dan1)
dan2 = Danli()
print(dan2)
dan1.area = "hunan"
print(dan1.area)
# del dan1.area
# print(dan1.area)
# print(Danli.instance)
# Danli.model = 1
# Danli.model = 2
# print(Danli.model)
#删除实例属性 del
self详解
self 就代表实例本身
self不必写成self 它就是形参名字,一般约定俗称写成self
class Person():
name = "sc"
def info(this):
print(f'i am {this.name}')
print(this)
print(this.__class__)
p = Person()
p.info()
self可以不写
class Person():
name = "sc"
def info(this):
print(f'i am {this.name}')
print(this)
print(this.__class__)
def info2():
print("this is info2")
p = Person()
# p.info2() #==>Person.info2(p)
Person.info2()
类的继承
…
#python实现链表的反转
class Node(object):
def __init__(self, value=None, next=None):
self.value = value
self.next = next
@staticmethod #静态方法
def reverse(head):
cur_node = head # 当前节点
new_link = None # 表示反转后的链表
while cur_node != None:
tmp = cur_node.next # cur_node后续节点传递给中间变量
cur_node.next = new_link # cur_node指向new_link
new_link = cur_node # 反转链表更新,cur_node为新的头结点
cur_node = tmp # 原链表节点后移一位
return new_link
link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9)))))))))
# print(link.value)
# print(link.next.value)
# print(link.next.next.value)
# print(link.next.next.next.value)
root = Node.reverse(link)
while root:
print(root.value)
root = root.next
多态
python里不支持多态, python处处是多态
接口
def pay(obj): #python里崇尚鸭子类型,不管obj数据什么类型,只管obj有没有pay方法
obj.pay()
pay(zhi)
pay(wei)
python中不支持多态
语法上的多态 不需要额外实现多态的代码
按照多态的严格语法 不属于多态(父类作为参数,传递子类对象)
python里处处是多态 python是一个动态类型语言,崇尚鸭子类型,本身就实现了多态
不关心对象是什么类型,到底是不是鸭子,只关心行为
属性
属性: 对象描述信息
静态属性 – 类属性
普通属性 – 实例属性
方法
实例方法
静态方法
类方法
python中的下划线
_max 保护属性
__min 私有属性,类内部访问,子类都不能访问,对象也不能访问的
python的私有是一种伪私有,是在类的内部对双下划綫的变量名做了一层转换
__min -> _类名__max
常见的私有属性
__name__ 类名
__class__ 对象所属的类
__modoule__ 所在模块
__doc__ 文档
魔术方法
魔术方法不需要手动调用,在一定的场景下自动执行,有特殊含义的方法
## 构造方法
__new__
__init__
## 析构方法
__del__
## 调用方法
__call__ 实例化之后将对象当做函数调用
只有可调用对象callable才有的方法
## 其他
__str__:用户
__repr__:程序员
__getitem__
__setitem__
__delitem__
python自省
• getattr(obj, ‘name’):
获取成员 • 根据字符串去获取obj对象里的对应的方法的内存地址
• hasattr(obj, ‘name’):
检查是否含有成员 • 判断一个对象obj里是否有对应的name_str字符串的方法
• setattr(obj, ‘age’, 18): 设置成员
• delattr(obj, ‘name’): 删除成员
脚本传参的方式
1.sys.argv
2.getopt
import getopt
import sys
opts, args = getopt.getopt(sys.argv[1:], 'h:i:', ['help', 'input='])
print(opts)
print(args)
3.argparse
4.fire
元类
元类:创建类的类称为元类
type是最上层的元类
-> 表示期望传入的数据类型,非强制
使用type函数创建对象
name:str 期望name传入一个str类型
->None 期望函数有一个None返回值
def init(self, name:str) ->None:
self.name = name
def eat(self):
print("i am eating....")
#第一个参数 类名
#第二个参数元组类型 显示是继承关系
#第三个参数是字典 设置属性和方法
Animal = type("Animal", (object,), {"species":'animals','__init__':init, 'eat':eat})
a1 = Animal("sc")
a1.eat()
print(a1.species)
元类一般用于拦截类的创建
自定义元类
class MyMate(type):
def __new__(cls, name, bases, attrs):
if "foo" not in attrs:
raise TypeError("必须设置foo属性")
attrs["test"] = "mymate"
return type.__new__(cls, name, bases, attrs)
class A(metaclass=MyMate):
#pass
foo = "foo!"
a = A()
print(a.test)
python面向对象有两种关系
1、继承关系 object是所有类的父类,是最顶层的类
2、创建关系 实例与类的关系 type是最顶层的类
抽象基类
抽象基类 定义了接口规范,子类必须实现抽象基类父类里的抽象方法
抽象基类不能实例化