面向对象
面向对象(OOP, Object-Oriented Programing),是一种编程方式(函数式编程和面向对象编程)中的一种,可以降低代码冗余程度。python中的类是面向对象编程的一种工具,是除函数和模块之外的另一种封装逻辑和数据的方式。
类和实例的区别:
- python中类和实例是两种不同的对象
- 类是抽象的模板,实例是根据类创建出来的一个个具体的“对象”
- 类和实例都有独立的命名空间
面向对象的三大思想
- 继承
- 多态 基于对象接口而不是类型
- 封装
1. 类的定义与实例化
python中使用class关键字来定义一个类。
类名的命名规则:以大写字母开头
实例化一个类:实例名 = 类名(参数)
2. 类的成员
1. 属性
属性的方法方法:实例名.属性名
1.1 实例属性
由方法内部的self属性进行赋值运算产生,保存在对象(实例)中,执行只能通过对象访问。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15 | class Person:
    def __init__(self, name):
        # 1. 在类的内部定义属性
        self.name = name
tom = Person('Tom')
print(tom.name) # Tom
# 2. 在类的外部定义属性
tom.age = '18'
print(tom.age) # 18
Jerry = Person('Jerry')
print(Jerry.name) # Jerry
print(Jerry.age) # AttributeError: 'Person' object has no attribute 'age'
 | 
tom 和 Jerry两个对象属于两个不同的命名空间,给Tom添加的age属性在Jerry对象中并不能访问。
1.2 类属性
通过class语句内的赋值语句创建,保存在类中,执行时可以通过对象访问,也可以通过类访问
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13 | class Person:
    country = 'America'
    def __init__(self, name):
        self.name = name
Tom = Person('Tom')
# 通过实例访问类属性
print(Tom.country)  # America
# 通过类访问类属性
print(Person.country) # America
 | 
1.3 私有属性
在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,确保了外部代码不能随意修改对象内部的状态,但是可以间接访问。
|  | class Person:
    def __init__(self, name):
        self.__name = name
    def get_name(self):
        return self.__name
Tom = Person('Tom')
# 直接访问报错
# print(Tom.name)  # AttributeError: 'Person' object has no attribute 'name'
print(Tom.get_name()) # Tom
 | 
2. 方法
位于类中的函数称为方法。·
类方法调用的第二种方式:class.method(instance, args,...),事实上,instance.method(args...)还是会翻译成这种方式来调用
1. 构造方法
作用:
- 初始化实例属性
- 执行其他初始化任务
- 创建一个实例时自动运行
|  | class Bar:
    def __init__(self,name,age):
        self.n = name
        self.a = age
        print('创建对象时自动执行构造方法')
    def foo(self):
        print(self.n,self.a)
obj = Bar("Tom",10) # 创建对象时自动执行构造方法
obj.foo() # Tom 10
 | 
2. 普通方法
保存在类中,由对象调用
|  | class Bar:
    def __init__(self):
        pass
    def hello(self):
        print('hello world!')
obj = Bar()
obj.hello() # hello world!
 | 
3. 私有方法
|  | class Bar:
    def __init__(self):
        pass
    def __hello(self):
        print('hello world!')
    def foo(self):
        self.__hello()
obj = Bar()
obj.foo()
 | 
4. self参数
类在创建的过程中会在内存中开辟一个属于类的空间,当创建一个实例的时候也会创建属于实例的空间,当实例需要执行类中的方法,回去找类空间相应的方法,方法中的self参数,接收的就是实例本身。所以self代指调用方法的实例对象
实例时方法调用的主体,并且会自动传入给方法的self参数,把实例传入给第一个参数从而告诉方法应该处理哪一个实例。
|  | class Bar:
    def foo(self):
        print("self id:",id(self))
obj = Bar()
print("obj  id:",id(obj)) # obj  id: 2018867963888
obj.foo()        # self id: 2018867963888
# self 和 obj 是同一个东西
 | 
3. 继承
一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类(基类),新类称为子类(派生类)。子类还可以自定义自己的属性和方法。
3.1 继承
|  | class Animal:
    def run(self):
        print("Animal is running...")
class Cat(Animal):
    pass
Tom = Cat()
Tom.run() # Animal is running...
 | 
3.2 扩展
在父类的方法上添加新的功能。
|  | class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def pay(self, base):
        print("应发工资:%s" % money)
class Manager(Person):
    def pay(self, base, commission):
        Person.pay(self, base+commission)
 | 
3.3 重写
|  | class Animal:
    def run(self):
        print("Animal is running...")
class Cat(Animal):
    def run(self):
        print('Cat is running...')
Tom = Cat()
Tom.run() # Cat is running...
 | 
3.4 组合
一个类A中,使用另一个类B的实例对象作为类A的属性。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16 | class Date():
    '''date'''
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
class Person:
    def __init__(self, name, date):
        self.name = name
        self.birthday = date
    def show_birthday(self):
        print("%s:%s-%s-%s" %(self.name, self.birthday.year, self.birthday.month, self.birthday.day))
Jerry = Person('Jerry',Date('1999','2','14'))
Jerry.show_birthday() # Jerry:1999-2-14
 | 
3.5 super()
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15 | class A:
    def func(self):
        print("This is A")
class B(A):
    def func(self):
        super().func()
        # A.func(self) # 另一种的写法
        print("This is B")
b = B()
b.func()  
# 输出结果
# This is A
# This is B
 | 
super安装MRO顺序来寻找当前类的下一个类
python2新式类:super(子类名,self).函数名()
3.6 抽象类
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16 | from abc import ABCMeta, abstractclassmethod
class Super(metaclass=ABCMeta):
    def __init__(self):
        pass
    @abstractclassmethod
    def action(self):
        pass
class Sub(Super):
    def action(self):
        print("hello")
x = Sub()
x.action() # hello
 | 
action函数必须在子类中定义,否则会报错
TypeError: Can't instantiate abstract class Sub with abstract methods action
3.7 多继承
- 从左到右
- 从下到上
- 广度优先
例1:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19 | class F:
    def bar(self):
        print('F.bar')
class F1(F):
    def boo(self):
        print('F1.bar')
class F2:
    def bar(self):
        print('F2.bar')
class S(F1,F2):            #从下往上找
    pass
obj = S()
obj.bar()
#############
F.bar
 | 
例2:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15 | class F1:
    def bar(self):
        print('F1.bar')
class F2:
    def bar(self):
        print('F2.bar')
class S(F2,F1):         #从左往右找
    pass
obj = S()
obj.bar()
###########
F2.bar
 | 
例3:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | class Base:
    def bar(self):
        print('Base.bar')
class F(Base):
    def foo(self):
        print('F.bar')
class F1(F):
    def foo(self):
        print('F1.bar')
class F2(Base):
    def bar(self):
        print('F2.bar')
class S(F1,F2):
    pass
obj = S()
obj.bar()   #有共同的父类,最后在父类中找
############
F2.bar
 | 
3.7   经典类和新式类
python2.x:默认是经典类,搜索算法为DFLR(Depth First,Left to Right),深度优先。继承object后是新式类
python3.x:没有经典类,都是新式类,隐式继承object类,搜索算法为 MRO(method resolution order),广度优点。
4. 多态和多态性
Python3.7之多态与多态性 - 彩虹然 - 博客园 (cnblogs.com) 
多态:多态是指运算的意义取决于运算的对象。(也就是说,代码不应该关心它处理的对象是什么,而应该关注这个对象做什么)。多态可以用来隐藏接口差异性。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | class Animals:
    def talk(self):
        pass
class Cat(Animals):
    def talk(self):
        print("Meow...")
class Dog(Animals):
    def talk(self):
        print("Woof!...")
class Person(Animals):
    def talk(self):
        print("Ying...")
def func(animal):
    # 不用关心是什么动物,只要是个动物就应该叫。
    animal.talk()
xiaoming = Person()
xiaohei = Cat()
xiaohuang = Dog()
for i in [xiaoming, xiaohei, xiaohuang]:
    func(i)
 | 
6. 装饰器
6.1 @property
把方法变成属性。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | class Bar:
    def __init__(self):
        pass
    # 属性
    @property
    def foo(self):
        return 1
    @foo.setter
    def foo(self,val):
        print(val,"setter")
    @foo.deleter
    def foo(self):
        print("delete")
obj = Bar()
obj.foo=123  #执行赋值语句将执行@foo.setter下对应的方法
del obj.foo #执行@foo.deleter下对应的方法
############
setter
delete
 | 
例1:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 | class Page:
    def __init__(self,page):
        try:
            p = int(page)
        except Exception as e:
            p = 1
        self.page = p
    @property
    def start(self):
        val = (self.page-1) * 10
        return val
    @property
    def end(self):
        val = self.page * 10
        return val
li = []
for i in range(1000):
    li.append(i)
while True:
    p = input("请输入页码:")
    if p == "q":
        break
    obj = Page(p)
    print(li[obj.start:obj.end])
 | 
例2:属性的另一种表示方法
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17 | class Bar:
    def f1(self):
        return 1
    def f2(self,val):
        print('f2:',val)
    def f3(self):
        print("f3:del")
    per = property(fget=f1,fset=f2,fdel=f3,doc="注释")
obj = Bar()
print(obj.per)
obj.per = 123
del obj.per
###########
f2: 123
f3:del
 | 
6.2 @staticmethod
静态方法,不需要创建对象,不会隐式传递self。实例对象和类对象都可以调用。当方法和实例无相关性时使用。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14 | import time
class Person:
    country = 'China'
    def __init__(self,name,age):
        self.name = name
        self.age = age
    @staticmethod
    def show_time():
        print(time.strftime("%Y-%m-%d %H:%M:%S" ))
Person.show_time() # 2020-02-15 19:17:53
Tom = Person('Tom', 18)
Tom.show_time() # 2020-02-15 19:17:53
 | 
6.3 @classmethod
第一个参数必须是当前类对象,该参数名一般约定为cls,通过它来传递类的属性和方法。实例对象和类对象都可以调用。在实例化之前修改类属性的时候使用。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15 | import time
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    @classmethod
    def today(cls):
        struct_time = time.localtime()
        date = cls(struct_time.tm_year, struct_time.tm_mon, struct_time.tm_mday) # 自己类的实例化
        return date
today = Date.today()
print(today.year,today.month,today.day) # 2020 2 15
 | 
7. 反射
用字符串数据类型的名字,来操作这个名字对应的函数,示例变量,绑定方法等。
反射的使用场景:
- 反射对象的实例变量、绑定方法
- 反射类中的静态变量、绑定方法、其他方法
- 反射模块中的所有变量
7.1 反射对象的实例变量、绑定方法
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18 | class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def foo(self):
        return 'hello world!'
zhangsan = Person('张三', 18)
# 1.反射对象的实例变量
print(getattr(zhangsan, 'name'))
# 2.反射对象的绑定方法
print(getattr(zhangsan, 'foo')())
# 输出结果
# 张三
# hello world!
 | 
7.2 反射类中的静态变量
|  | class Person:
    country = 'China'
    def __init__(self):
        pass
    def foo(self):
        pass
print(getattr(Person, 'country'))
# 输出结果
# China
 | 
7.3 反射模块中的变量
1.反射模块中的变量
|  | import module
getattr(module,'func')
getattr(module,'Bar')
 | 
2.反射脚本(本文件)中的变量
|  | import sys
getattr(sys.modules['__main__'],func)
 | 
7.4 hasattr、setattr和delattr
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16 | class Person:
    country = 'China'
    def __init__(self):
        pass
    def foo(self):
        pass
Bob = Person()
# hasattr 判断是否有某个成员
print(hasattr(Bob, 'name')) # False
# setattr 设置属性
setattr(Bob, 'name', 'Bob')
print(hasattr(Bob, 'name')) # True
# delattr 删除属性
delattr(Bob, 'name')
print(hasattr(Bob, 'name')) # False
 | 
7.5  反射的例子
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #!/usr/bin/env python
# -*- coding: utf-8  -*-
while True:
    inp = input("请输入要访问的URL:")
    if inp == "q":
        break
    class Bar:
        def f1(self):
            return "首页"
        def f2(self):
            return "新闻"
        def f3(self):
            return "博客"
    obj = Bar()
    if hasattr(obj,inp):
        f = getattr(obj,inp)
        print(f())
    else:
        print("404")
 | 
8. 元类
9. 重装运算符
9.1__new__
是一个构造方法,用来创建一个对象需要的空间。
使用场景:创建单例模式(一个类只会创建一次self的空间)
|  | class Bar:
    __instance = None
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = super().__new__(cls)
        return cls.__instance
 | 
9.1  __call__方法
|  | class Bar:
    def __init__(self):
        print("init")
    def __call__(self):
        print("call")
obj = Bar()
obj() #对象加括号自动执行__call__方法
 | 
9.2 str 与 int
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17 | class Bar:
    def __init__(self):
        pass
    def __int__(self):
        return 111
    def __str__(self):
        return "str"
obj = Bar()
print(obj,type(obj))
r = int(obj)   #int 加对象,自动执行对象的int方法,并将返回值赋值给int对象
print(r)
r = str(obj)
print(r)    #str 加对象,自动执行对象的str方法,并将返回值赋值给str对象
------------
str <class '__main__.Bar'>
str
 | 
9.3 例:__str_
|  | class Bar:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):
        return "%s:%s" %(self.name,self.age)
obj = Bar("Tom",18)
print(obj)
-----------
Tom:18
 | 
9.4 del 析构方法:对象销毁的时候执行
|  | class Bar:
    def __init__(self):
        pass
    def  __del__(self):
        print("析构方法")
obj = Bar()
 | 
9.5 dict 将字段中的成员以字段的形式返回
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13 | class Bar:
    """注释"""
    def __init__(self,name,age):
        self.name = name
        self.age = age
obj = Bar('Tom',18)
#将字段中的成员以字段的形式返回
print(Bar.__dict__)
print(obj.__dict__)
---------
{'__module__': '__main__', '__init__': <function Bar.__init__ at 0x0000013DAD733AE8>, '__weakref__': <attribute '__weakref__' of 'Bar' objects>, '__doc__': '注释', '__dict__': <attribute '__dict__' of 'Bar' objects>}
{'name': 'Tom', 'age': 18}
 | 
9.6 getitem 、 setitem  和 delitem
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17 | class Bar:
    """注释"""
    def __init__(self):
        pass
    def __getitem__(self,item):
        return item + 10
    def __setitem__(self,k,v):
        print(k,v) 
    def __delitem__(self,val):
        print('delete:',val)
obj = Bar()
print(obj[2])
obj['name']='Tom'
del obj['del']
----------------
name Tom
delete: del
 | 
9.7  iter
如果类中有__iter__方法,其对象就是一个可迭代对象;
对象名.iter()的返回值是迭代器
|  | class Bar:
    def __iter__(self):
        return iter([11,22,33])
obj = Bar()
for i in obj:
    print(i)
  #for循环执行obj对象的类中的__iter__方法,并获取其迭代器;循环上一步中返回的对象
 | 
10. 单例模式
应用场景:数据库连接池
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20 | class Bar:
    __v = None
    @classmethod
    def get_instance(cls):
        if cls.__v:
            return cls.__v
        else:
            cls.__v = Bar()
            return cls.__v
# 不用再使用Bar()创建实例
obj1 = Bar.get_instance()
print(obj1)
obj2 = Bar.get_instance()
print(obj2)
obj3 = Bar.get_instance()
print(obj3)
###########
<__main__.Bar object at 0x0000026D865B4A20>
<__main__.Bar object at 0x0000026D865B4A20>
<__main__.Bar object at 0x0000026D865B4A20>
 | 
线程安全单例模式
|  | class Bar:
    from threading import Lock
    __instance = None
    lock = Lock()
    def __new__(cls, *args, **kwargs):
        with cls.lock:
            if not cls.__instance:
                cls.__instance = super().__new__(cls)
        return cls.__instance
 |