OO:面向对象
- OOA:面向对象的分析
- OOD:面向对象的设计
- OOI:xxx的实现
- OOP:xxx的编程面向对象的实现过程
- OOA->OOD->OOI:
#dict前后各有两个下划线
对象所有成员检查
A.__dict__
class A():
name = "xiaoxiong"
age = 18
print(A._dict_)=>{'__module__': '__main__', 'name': 'dana', 'age': 18, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
B=A()
print(B._dict_)=>{}
print(B.name)=>xiaoxiong
使用类访问绑定类的方法时, 如果类方法中需要访问当前类的成员,可以通过 __class__成员名来访问
class Teacher():
name = "dana"
age = 19
def say(self):
self.name = "yaona"
self.age = 17
print("My name is {0}".format(self.name))
# 调用类的成员变量需要用 __class__
print("My age is {0}".format(__class__.age))
def sayAgain():
print(__class__.name)
print(__class__.age )
print("Hello, nice to see you again")
t = Teacher()
t.say()=>My name is yaona My age is 19
# 调用绑定类函数使用类名
t.sayAgain()=>报错
Teacher.sayAgain()=>dana 19 Hello, nice to see you again
[python中下划线使用]
_xxx:表示内部使用,不能被from M imoprt *导入
xxx_:表示避免和关键字冲突,如Tkinter.Toplevel(master, class_='ClassName')
__xxx:更彻底的private.用到了name mangling技术,会自动加上类名前缀.不能被子类和类外访问.
__xxx__:魔术方法或用户控制的命名空间.
私有
私有成员是最高级别的封装,只能在当前类或对象中访问
在成员前面添加两个两个下划线即可
Python的私有不是真私有,是一种成为name mangling的改名策略
__age = 18
受保护的封装 protected
- 受保护的封装是将对象成员进行一定级别的封装,然后,在类中或者子类中都
可以进行访问,但是在外部不可以
- 封装方法: 在成员名称前添加一个下划线即可
_age = 18
继承
子类和父类定义同一个名称变量,则优先使用子类本身
扩充父类函数
class Person():
name="NoName"
def work(self):
print("make some money")
#父类写在括号内
class Teacher(Person):
name="xiaoxiong"
def work(self):
# 扩充父类的功能只需要调用父类相应的函数,首先名字相同
# 扩充父类的两种方法,第一种是通过父类名调用
# 第二种super代表得到父类
Person.work(self)//super().work()//super(Teacher.self).work()
self.make_test()
t=Teacher()
#子类和父类定义同一个名称变量,则优先使用子类本身
print(t.name)=>xiaoxiong
t.work()
构造函数
__init__就是构造函数
每次实例化的时候,第一个被自动的调用
class Dog():
def __init__(self):
print("I am init in dog")
xiaoming=Dog()=>i am init in dog
继承中的构造函数
class Animel():
def __init__(self):
print("Animel")
class PaxingAni(Animel):
def __init__(self):
print(" Paxing Dongwu")
class Dog(PaxingAni):
def __init__(self):
print("I am init in dog")
# 实例话的时候,自动调用了Dog的构造函数
# 因为找到了构造函数,则不在查找父类的构造函数
kaka = Dog()=>I am init in dog
# 猫没有写构造函数
class Cat(PaxingAni):
pass
# 此时应该自动调用构造函数,因为Cat没有构造函数,所以查找父类构造函数
# 在PaxingAni中查找到了构造函数,则停止向上查找
c = Cat()=>Paxing Dongwu
多继承
子类可以直接拥有父类的属性和方法,私有属性和方法除外
class Bird():
def __init__(self, name):
self.name = name
def fly(self):
print("I am flying.....")
class SuperMan(Person, Bird, Fish):
def __init__(self, name):
self.name = name
s=SuperMan("xiaoxiong")
s.fly()=>i am flying
issubclass()
判断参数 class 是否是类型参数 classinfo 的子类。
所有参数都是object的子类
class A():
pass
class B(A):
pass
class C():
pass
print( issubclass(B, A))=>True
print( issubclass(C, A))=>False
print( issubclass(B, object))=>True
isinstance()
检测一个对象是否是一个类的实例
class A():
pass
a = A()
print(isinstance(a, A))=>True
print(isinstance(A, A))=>Flase
- hasattr:检测一个对象是否有成员xxx
class A():
name="xiaoxiong"
pass
a = A()
print(hasattr(a, "name"))=>True
- getattr: get attribute
- setattr: set attribute
- delattr: delete attribute
- dir: 获取对象的成员列表
类的常用魔术方法
- 魔术方法就是不需要人为调用的方法,基本是在特定的时刻自动触发
- 魔术方法的统一的特征,方法名被前后各两个下滑线包裹
- 操作类
__init__
: 构造函数__new__
: 对象实例化方法,此函数较特殊,一般不需要使用__call__
: 对象当函数使用的时候触发__str__
: 当对象被当做字符串使用的时候调用__repr__
: 返回字符串,跟__str__
具体区别请百度
- 描述符相关
__set__
__get__
__delete__
- 属性操作相关
__getattr__
: 访问一个不存在的属性时触发__setattr__
: 对成员属性进行设置的时候触发- 参数:
- self用来获取当前对象
- 被设置的属性名称,以字符串形式出现
- 需要对属性名称设置的值
- 作用:进行属性设置的时候进行验证或者修改
- 注意: 在该方法中不能对属性直接进行赋值操作,否则死循环
- 参看案例
- 参数:
- 运算分类相关魔术方法
__gt__
: 进行大于判断的时候触发的函数- 参数:
- self
- 第二个参数是第二个对象
- 返回值可以是任意值,推荐返回布尔值
- 案例
- 参数:
class A():
name = "xiaoxiong"
age = 18
#必须初始化name
def __init__(self, name=0 ):
print("哈哈,我被调用了")
def __call__(self):
print("我被调用了again")
def __str__(self):
return "这是个例子"
def __getattr__(self, name):
print("没找到呀没找到")
print(name)
def __setattr__(self, name, value):
print("设置属性: {0}".format(name))
# 下面语句会导致问题,死循环
# self.name = value
# 此种情况,为了避免死循环,规定统一调用父类魔法函数
super().__setattr__(name, value)
a = A()=>哈哈,我被调用了
a()=>我被调用了again
print(a)=>这是个例子
print(a.name)=>xiaoxiong
#输出None的原因是没有return语句,默认return None
print(a.addr) =>没找到呀没找到 addr None
print(a.__dict__)=>{}
a.age=18 =>设置属性:age
print(a.__dict__)=>{'age':18}
class Student():
def __init__(self, name=0):
self.name = name
def __gt__(self, obj):
print("哈哈, {0} 会比 {1} 大吗?".format(self.name, obj.name))
return self.name > obj.name
stu1 = Student("one")
stu2 = Student("two")
print(stu1 > stu2)=>哈哈, one 会比 two 大吗? False
类和对象的三种方法
实例方法
- 需要实例化对象才能使用的方法,使用过程中可能需要截止对象的其他对象的方法完成
静态方法
- 不需要实例化,通过类直接访问
类方法
- 不需要实例化
# 三种方法的案例
class Person:
# 实例方法
def eat(self):
print(self)
print("Eating.....")
#类方法
# 类方法的第一个参数,一般命名为cls,区别于self
@classmethod
def play(cls):
print(cls)
print("Playing.....")
# 静态方法
# 不需要用第一个参数表示自身或者类
@staticmethod
def say():
print("Saying....")
yueyue = Person()
# 实例方法
yueyue.eat()=><__main__.Person object at 0x0000021678FDB240> Eating.....
# 类方法
Person.play()=><class '__main__.Person'> Playing.....
yueyue.play()=><class '__main__.Person'> Playing.....
#静态方法
Person.say()=>Sayying.......
yueyue.say()=>Sayying.......
属性的三种用法
1, 赋值
2. 读取
3. 删除 del
类属性 property
class A():
def __init__(self):
self.name = "haha"
self.age =18
# 此功能,是对类变量进行读取操作的时候应该执行的函数功能
def get(self):
print("我被读取了")
return self.name
# 模拟的是对变量进行写操作的时候执行的功能
def fset(self, name):
print("我被写入了,但是还可以做好多事情")
self.name = "王子:" + name
# fdel模拟的是删除变量的时候进行的操作
def f2del(self):
pass
# property的四个参数顺序是固定的
# 第一个参数代表读取的时候需要调用的函数
# 第二个参数代表写入的时候需要调用的函数
# 第三个是删除
name2 = property(get, fset, f2del, "这是一个property的例子")
a = A()
print(a.name)=>haha
a.name2="xiaoxiong"=>我被写入了,但是还可以做好多事情
print(a.name2)=>我被读取了 王子:xiaoxiong
del a.name2
print(a.name2)=>我被读取了 王子:xiaoxiong
抽象类
抽象方法: 没有具体实现内容的方法成为抽象方法
- 抽象方法的主要意义是规范了子类的行为和接口
- 抽象类的使用需要借助abc模块
抽象类:包含抽象方法的类叫抽象类,通常成为ABC类
抽象类可以包含抽象方法,也可以包含具体方法- 抽象类中可以有方法也可以有属性
- 抽象类不允许直接实例化
- 必须继承才可以使用,且继承的子类必须实现所有继承来的抽象方法
- 假定子类没有是现实所有继承的抽象方法,则子类也不能实例化
- 抽象类的主要作用是设定类的标准,以便于开发的时候具有统一的规范
import abc
#声明一个类并且指定当前类的元类
class Human(metaclass=abc.ABCMeta):
# 定义一个抽象的方法
@abc.abstractmethod
def smoking(self):
pass
# 定义类抽象方法
@abc.abstractclassmethod
def drink():
pass
# 定义静态抽象方法
@abc.abstractstaticmethod
def play():
pass
def sleep(self):
print("Sleeping.......")
组装一个类
类其实是一个类定义和各种方法的自由组合
- 可以定义类和函数,然后自己通过类直接赋值
- 可以借助于MethodType实现
- 借助于type实现
- 利用元类实现- MetaClass
- 元类是类
- 备用来创造别的类
from types import MethodType
class A():
pass
def say(self):
print("Saying... ...")
a = A()
a.say = MethodType(say, A)
a.say()=>say......
利用type造一个类
先定义类应该具有的成员函数
def say(self):
print("Saying.....")
def talk(self):
print("Talking .....")
#用type来创建一个类
A = type("AName", (object, ), {"class_say":say, "class_talk":talk})
# 然后可以像正常访问一样使用类
a = A()
a.class_say()=>Say......
a.class_talk()=>Talk......
# 元类演示
# 元类写法是固定的,必须继承自type
# 元类一般命名以MetaClass结尾
class TulingMetaClass(type):
# 注意以下写法
def __new__(cls, name, bases, attrs):
#自己的业务处理
print("哈哈,我是元类呀")
attrs['id'] = '000000'
attrs['addr'] = "北京海淀区公主坟西翠路12号"
return type.__new__(cls, name, bases, attrs)
# 元类定义完就可以使用,使用注意写法
class Teacher(object, metaclass=TulingMetaClass):
pass
t = Teacher()=>哈哈,我是元类呀
t.id