首页 > 技术文章 > 第七章 面向对象

xu1296634150 2020-04-05 16:30 原文

7.1 面向对象基本用法

7.1.1 面向对象基本格式

面向对象的封装作用:将同一类函数封装到一个类中,方便以后调用,函数如果有一个反复使用的公共值,则可以放到对象中。

1.1 .1基本格式:定义类
class 类名: #类名首字母需要大写
   def 方法名(self,name)#self是默认参数不用传参,而其他的需要传参,如name需要传参
      print(name)
  obj = 类名() #创建了一个类名的对象,实例化对象
  result = obj.方法名('alex')   #通过对象调用了方法
    print(result)
    
    
 class Foo:
    def func(self,name)
        print(name)
   obj = Foo()
   result = obj.name('alex')
    print(result)

应该场景:遇到很多函数,需要给函数进了归类和划分(封装思想)

例题:

class Db:  #Db是数据库
    def db_reda(self):
        pass
    def db_write(self):
        pass
    def db_deleta(self):
        pass
    def db_update(self):
        pass
class File:#file是文件
    def file_read(self):
        pass
    def file_write(self):
        pass
    def file_deleta(self):
        pass
    
1.1.2.对象的作用

存储一些值,以后方便调用

例题:

class File:
    def read(self):
        with open(self.xxxx, mode='r', encoding='utf-8') as f:
            data = f.read()
        return data

    def write(self,content):
        with open(self.xxxx, mode='a', encoding='utf-8') as f:
            f.write(content)

# # 实例化了一个File类的对象
obj1 = File()
# # 在对象中写了一个xxxxx = 'test.log'
obj1.xxxxx = "test.log"
# # 通过对象调用类中的read方法,read方法中的self就是obj。
##哪个对象调用了方法就是self
# # obj1.read()
obj1.write('alex')


# 实例化了一个File类的对象
obj2 = File()
# 在对象中写了一个xxxxx = 'test.log'
obj2.xxxxx = "info.txt"
# 通过对象调用类中的read方法,read方法中的self就是obj。
# obj2.read()
obj2.write('alex')
class Person:
    def show(self):
        temp = "我是%s,年龄:%s,性别:%s " %(self.name,self.age,self.gender,)
        print(temp)
        

p1 = Person()
p1.name = '李奇'
p1.age = 19
p1.gender = ''
p1.show()

p2 = Person()
p2.name = '利航'
p2.age = 19
p2.gender = ''
p2.show()
class Person:
    def __init__(self,n,a,g): # 初始化方法(构造方法),给对象的内部做初始化。
        self.name = n
        self.age = a
        self.gender = g

    def show(self):
        temp = "我是%s,年龄:%s,性别:%s " % (self.name, self.age, self.gender,)
        print(temp)

# 类() 实例化对象,自动执行此类中的 __init__方法。
p1 = Person('李兆琪',19,'')
p1.show()

p2 = Person('利奇航',19,'')
p2.show()

总结:将数据封装到对象,方便使用。

"""
如果写代码时,函数比较多比较乱。
1. 可以将函数归类并放到同一个类中。
2. 函数如果有一个反复使用的公共值,则可以放到对象中。
"""

class File:
    def __init__(self,path):
        self.file_path = path
        
    def read(self):
        print(self.file_path)
    
    def write(self,content):
        print(self.file_path)
    
    def delete(self):
        print(self.file_path)
    
    def update(self):
        print(self.file_path)
    
p1 = File('log.txt')
p1.read()

p2 = File('xxxxxx.txt')
p2.read()

例题:

# 1. 循环让用户输入:用户名/密码/邮箱。 输入完成后再进行数据打印。
# ########## 以前的写法
USER_LIST = []
while True:
    user = input('请输入用户名:')
    pwd = input('请输入密码:')
    email = input('请输入邮箱:')
    temp = {'username':user,'password':pwd,'email':email}
    USER_LIST.append(temp)
for item in USER_LIST:
    temp = "我的名字:%s,密码:%s,邮箱%s" %(item['username'],item['password'],item['email'],)
    print(temp)
    
# ########## 面向对象写法

class Person:
    def __init__(self,user,pwd,email):
        self.username = user
        self.password = pwd
        self.email = email
    
USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]
while True:
    user = input('请输入用户名:')
    pwd = input('请输入密码:')
    email = input('请输入邮箱:')
    p = Person(user,pwd,email)
    USER_LIST.append(p)

for item in USER_LIST:
    temp = "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,)
    print(temp)

# ########## 面向对象写法

class Person:
    def __init__(self,user,pwd,email):
        self.username = user
        self.password = pwd
        self.email = email
        
    def info(self):
        return "我的名字:%s,密码:%s,邮箱%s" %(item.username,item.password,item.email,)
    
USER_LIST = [对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]
while True:
    user = input('请输入用户名:')
    pwd = input('请输入密码:')
    email = input('请输入邮箱:')
    p = Person(user,pwd,email)
    USER_LIST.append(p)

for item in USER_LIST:
    msg = item.info()
    print(msg)
1.1.3.游戏开发
class Police:
    def __init__(self,name) 
        self.name = name 
         self.hp = 10000
    
    def tax(self):
        msg = "%s收了个税。" %(self.name,)
        print(msg)
    
    def fight(self):
        msg = "%s去战了个斗。" %(self.name,)

lsq = Police('李邵奇') 
zzh = Police('渣渣会')
tyg = Police('堂有光')


class Bandit:
    def __init__(self,nickname) 
        self.nickname = nickname 
        self.hp = 1000
    
    def murder(self,name):
        msg = "%s去谋杀了%s" %(self.nickname, name,)
        
        
lcj = Bandit('二蛋')
lp = Bandit('二狗')
zsd = Bandit('狗蛋')

# 1. 二狗去谋杀渣渣会,二狗生命值-100; 渣渣会生命值减5000
lp.murder(zzh.name)
lp.hp = lp.hp - 100
zzh.hp = zzh.hp - 5000
# ... 
class Police:
    def __init__(self,name) 
        self.name = name 
         self.hp = 10000
    
    def dao(self,other):
        msg = "%s个了%s一刀。" %(self.name,other.nickname)
        self.hp = self.hp - 10
        other.hp = other.hp - 50
        print(msg)
    
    def qiang(self):
        msg = "%s去战了个斗。" %(self.name,)
        
    def quan(self,other):
        msg = "%s个了%s一全。" %(self.name,other.nickname)
        self.hp = self.hp - 2
        other.hp = other.hp - 10
        print(msg)
        
        
class Bandit:
    def __init__(self,nickname) 
        self.nickname = nickname 
        self.hp = 1000
    
    def qiang(self,other):#other代指警察
        
        msg = "%s个了%s一全。" %(self.nickname,other.name)
        self.hp -= 20
        other.hp -= 500
    
    
lcj = Bandit('二蛋')


lsq = Police('李奇')
lsq.dao(lcj)  #lcj是对象
lsq.quan(lcj)
lcj.qiang(lsq)
1.1.4 继承(可以一直往上继承)

继承关系中的查找方法的顺序:执行对象.方法时,优先在自己的类中找,如果没有就是父类中找。

注意:创建了一个父类的对象,父类不能继承子类的

# 父类(基类)
class Base:
    def f1(self):
        pass
# 子类(派生类)
class Foo(Base):
    def f2(self):
        pass

# 创建了一个子类的对象
obj = Foo()
# 执行对象.方法时,优先在自己的类中找,如果没有就是父类中找。
obj.f2()
obj.f1()

# 创建了一个父类的对象,父类不能继承子类的
obj = Base()
obj.f1()
obj.f2()#--->错

问题:什么时候才能用到继承?多个类中如果有公共的方法,可以放到基类中避免重复编写。

class Base:
    def f1(self):
        pass
    
class Foo(Base):
    def f2(self):
        pass
    
class Bar(Base):
    def f3(self):
        pass

obj1 = Foo()

obj2 = Bar()

继承关系中的查找方法的顺序:

# 示例一
class Base:
    def f1(self):
        print('base.f1')
        
class Foo(Base):
    def f2(self):
        print('foo.f2')
        
obj = Foo()
obj.f1()#base.f1  self是obj
obj.f2()#foo.f2   self是obj

# 示例二
class Base:
    def f1(self): #self是obj
        print('base.f1')
        
class Foo(Base):
    def f2(self):
        self.f1()
        print('foo.f2')
        
obj = Foo()
obj.f2()#base.f1   foo.f2

# 示例三
class Base:
    def f1(self):
        print('base.f1')
        
class Foo(Base):
    def f2(self):
        self.f1() #obj.f1
        print('foo.f2')
    def f1(self):
        print('foo.f1')
        
obj = Foo()
obj.f2() # foo.f1   foo.f2

# 示例四
class Base:
    def f1(self):
        self.f2()
        print('base.f1')
    def f2(self):
        print('base.f2')
class Foo(Base):
    def f2(self):
        print('foo.f2')
        
obj = Foo()
obj.f1()# foo.f2  base.f1


# 示例五
class TCPServer:
    pass
class ThreadingMixIn:
    pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): 
    pass

# 示例六
class BaseServer:
    def serve_forever(self, poll_interval=0.5):
        self._handle_request_noblock()
    def _handle_request_noblock(self):
        self.process_request(request, client_address)
        
    def process_request(self, request, client_address):
        pass
    
class TCPServer(BaseServer):
    pass

class ThreadingMixIn:
    def process_request(self, request, client_address):
        pass
    
class ThreadingTCPServer(ThreadingMixIn, TCPServer): 
    pass

obj = ThreadingTCPServer()
obj.serve_forever()

注意事项:

  1. self 到底是谁?需要先清楚self到底是谁

  2. self 是哪个类创建的,就从此类开始找,自己没有就找父类。

  3. 多级层的,从左到右查找

1.1.5 多态(多种形态/多种类型)鸭子模型
# Python
def func(arg):
    v = arg[-1] # arg.append(9)
    print(v)

# java
def func(str arg):
    v = arg[-1]
    print(v)

面试题:什么是鸭子模型。

对于一个函数而言,Python对于参数的类型不会限制,那么传入参数时就可以是各种类型,在函数中如果有例如:arg.send方法,那么就是对于传入类型的一个限制(类型必须有send方法)。
这就是鸭子模型,类似于上述的函数我们认为只要能呱呱叫的就是鸭子(只有有send方法,就是我们要想的类型)
1.1.6总结

面向对象的三大特性:封装/继承/多态

1 封装 同一类的相同方法封装;公共的

class File:
    def read(self):
        pass
    def write(self):
        pass
class Person:
    def __init__(sef,name,age):
        self.name = name
        self.age = age
p = Person('alex',19)

2 继承

class Base:
    pass
class Foo(Base):
    pass

3 多态

def func(arg): # 多种类型,很多事物
     arg.send() # 必须具有send方法,呱呱叫

7.1.2 格式和关键词

三个关键词:类 / 对象/ 方法

class 类:
    def __init__(self,x):
        self.x = x 
        
    def 方法(self,name):
        print(self.x, name)
        
# 实例化一个类的对象
v1 = 类(666)
v2.方法('alex')

7.1.3 什么时候用面向对象?

- 函数(业务功能)比较多,可以使用面向对象来进行归类。
- 想要做数据封装(创建字典存储数据时,面向对象)。
- 游戏示例:创建一些角色并且根据角色需要再创建人物

7.2面向对象的类成员

7.2.1 成员--类

7.2.1.1类变量(静态字段)
  • 定义:写在类的下一级和方法同一级。

  • 访问:

类.类变量名称
对象.类变量名称
class Foo:
    city = '北京'--》city是类变量
    def __init__(self,name)
       self.name = name
    def func(self):
        pass
 obj1 = Foo('alex')
 print(Foo.city) #北京
 print(obj2.city ) #北京

面试题

class Base:
    x = 1
    
obj = Base()


print(obj.x) #1 先去对象中找,没有再去类中找。
obj.y = 123  # 在对象中添加了一个y=123的变量。
print(obj.y) #123
obj.x = 123
print(obj.x) #123
print(Base.x) #1
class Parent:
    x = 1
    
class Child1(Parent):
    pass

class Child2(Parent):
    pass

print(Parent.x,Child1.x,Child2.x) # 1 1 1
Child1.x = 2
print(Parent.x,Child1.x,Child2.x) # 1 2 1
Child2.x = 3
print(Parent.x,Child1.x,Child2.x) # 1 2 3

总结:找变量优先找自己,自己没有找父 类 或 基类;修改或赋值只能在自己的内部设置。

7.2.1.2 方法(绑定方法/普通方法)
  1. 定义:至少有一个self参数

  2. 执行:先创建对象,由对象.方法()。

  3. 想要封装数据并且调用可以用绑定方法

class Foo:
    def func(self,a,b):
        print(a,b)
        
obj = Foo()
obj.func(1,2)
# ###########################
class Foo:
    def __init__(self):
        self.name = 123

    def func(self, a, b):
        print(self.name, a, b)

obj = Foo()
obj.func(1, 2)
7.2.1.3 静态方法
  1. 定义:

    1. @staticmethod装饰器

    2. 参数无限制

  2. 执行:

    1. 类.静态方法名 ()

    2. 对象.静态方法() (不推荐)

class Foo:
    def __init__(self):
        self.name = 123

    def func(self, a, b):
        print(self.name, a, b)

    @staticmethod
    def f1():
        print(123)

obj = Foo()
obj.func(1, 2)

Foo.f1()  #静态方法可以不需要创建对象,直接调用类
obj.f1() # 不推荐
7.2.1.4类方法
  1. 定义:

    1. @classmethod装饰器

    2. 至少有cls参数,当前类。

  2. 执行:

    1. 类.类方法()

    2. 对象.类方法() (不推荐)

class Foo:
    def __init__(self):
        self.name = 123

    def func(self, a, b):
        print(self.name, a, b)

    @staticmethod
    def f1():
        print(123)

    @classmethod
    def f2(cls,a,b): #cls是当前的类就是Foo
        print('cls是当前类',cls)
        print(a,b)

obj = Foo()
obj.func(1, 2)

Foo.f1()
Foo.f2(1,2)
obj.f2(1,2) #不推荐

面试题:

# 问题: @classmethod和@staticmethod的区别?
"""
一个是类方法一个静态方法。 
定义:
    类方法:用@classmethod做装饰器且至少有一个cls参数。
    静态方法:用staticmethod做装饰器且参数无限制。
调用:
    类.方法直接调用。
    对象.方法也可以调用。 
"""
7.2.1.5 属性
  1. 定义:

    1. @property装饰器

    2. 只有一个self参数

  2. 执行:

    1. 对象.方法 不用加括号。

class Foo:

    @property
    def func(self): #只能有self参数不能有其他参数
        print(123)
        return 666

obj = Foo()
result = obj.func
print(result)
# 属性的应用

class Page:
    def __init__(self, total_count, current_page, per_page_count=10):
        self.total_count = total_count
        self.per_page_count = per_page_count
        self.current_page = current_page
    @property
    def start_index(self):
        return (self.current_page - 1) * self.per_page_count
    @property
    def end_index(self):
        return self.current_page * self.per_page_count


USER_LIST = []
for i in range(321):
    USER_LIST.append('alex-%s' % (i,))

# 请实现分页展示:
current_page = int(input('请输入要查看的页码:'))
p = Page(321, current_page)
data_list = USER_LIST[p.start_index:p.end_index]#起始和结束位置
for item in data_list:
    print(item)

7.2.2 成员 --实例(对象)

实例变量(字段)
class Foo:
    def __init__(self.name):
        self.name = name
     def info(self):
        pass
    obj1 = Foo('alex')
    obj2 = Foo('eric')

7.2.3 成员修饰符

  1. 公有,所有地方都能访问到。

  2. 私有(有双下划线),只有自己可以访问到,下一级也不能访问

class Foo:
    def __init__(self, name):
        self.__name = name #私用变量
        self.name = name #公共变量  外部可以访问

    def func(self):
        print(self.__name)


obj = Foo('alex')
# print(obj.__name) #外部访问不到
obj.func() #alex  内部可以访问
class Foo:
    __x = 1

    @staticmethod
    def func():
        print(Foo.__x)


# print(Foo.__x)
Foo.func() #1 NONE
class Foo:

    def __fun(self):
        print('msg')

    def show(self):
        self.__fun()

obj = Foo()
# obj.__fun()
obj.show()
class Base:
    def __f1(self):
        print('Bsae.f1')
 class Foo(Base):
    def func(self):
        self.__f1()
  obj = Foo()
  obj.func() #报错,下一级也无法访问私有的
class Foo:
    def __init__(self,name):
        self.__x = name
obj = Foo('alex')
print(obj._Foo__x)  #alex  强制访问私有实例变量

练习题:

class Foo:
    def __init__(self,num):
        self.num = num
        
        
cls_list = []
for i in range(10):
    cls_list.append(Foo)
    
for i in range(len(cls_list)):
    obj = cls_list[i](i) #对象
    print(obj.num) # 0-9
class Foo:
    def __init__(self,num):
        self.num = num
        
B = Foo
obj = B('alex')
class Foo:
    def f1(self):
        print('f1')
    
    def f2(self):
        print('f2')

obj = Foo()

v = [ obj.f1,obj.f2 ]
for item in v:
    item()
class Account:
    
    def login(self):
        pass
    
    def register(self):
        pass
    
    def run(self):
        info = {'1':self.register, '2':self.login }
        choice = input('请选择:')
        method = info.get(choice)
        method()
class Foo:
    pass

class Foo(object):
    pass

# 在python3中这俩的写法是一样,因为所有的类默认都会继承object类,全部都是新式类。


# 如果在python2中这样定义,则称其为:经典类
class Foo:
    pass 
# 如果在python2中这样定义,则称其为:新式类
class Foo(object):
    pass 

class Base(object):
    pass
class Bar(Base):
    pass

7.2.4 嵌套

  1. 函数:参数可以是任意类型。

  2. 字典:对象和类都可以做字典的key和value

  3. 继承的查找关系

7.2.4.1 函数:参数可以是任意类型。
class School(object):
    def __init__(self,title,addr):
        self.title = title
        self.address = addr
        
class ClassRoom(object):
    
    def __init__(self,name,school_object):
        self.name = name
        self.school = school_object
        
s1 = School('北京','沙河')
s2 = School('上海','浦东')
s3 = School('深圳','南山')

c1 = ClassRoom('全栈21期',s1)
c1.name
c1.school.title
c1.school.address
# ############################################
v = [11,22,33,{'name':'山海','addr':'浦东'}]

v[0]
v[3]['name']
#学校、老师互相关联
class School(object):
    def __init__(self,name,address):
        self.name = name
        self.address = address
        self.teacher_list = []
     def append_teacher(self,teacher):
        self.teacher_list.append(teacher)
 
    
class Teacher(object):
    def __init__(self,name,comment,school):
        self.name = name
        self.comment = comment
        self.school = school
     def check_address(self):
        print('%s在%s办公'%(self.name,self.school.address))
 #创建三个校区       
beijing = School('老男孩北京校区','沙河')
shanghai = School('老男孩上海校区','章江')
shenzhen = School('老男孩深圳校区','南山')
#创建两个老师
t1 = Teacher('太白','还行',beijing)
t2= Teacher('alex','屌丝',shanghai)

t1.check_address() #太白在沙河办公 查看老师归属哪个学校
t2.check_address() #alex在章江办公
7.2.4.2字典:对象和类都可以做字典的key和value
class StackConfig(object):
    list_display = '李邵奇'
    
    def changelist_view(self):
        print(self.list_display)
        
class UserConfig(StackConfig):
    list_display = '利奇航'

class AdminSite(object):
    def __init__(self):
        self._register = {}

    def registry(self,key,arg=StackConfig):
        self._register[key] = arg

    def run(self):
        for key,value in self._register.items():
            obj = value()
            obj.changelist_view()#李邵奇 李邵奇 利航
site = AdminSite()
site.registry(1)
site.registry(2,StackConfig)
site.registry(3,UserConfig)
site.run()
7.2.4.3 继承的查找关系
class StarkConfig(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

class AdminSite(object):
    def __init__(self):
        self.data_list = []
        self.sk = None

    def set_sk(self,arg):
        self.sk = arg
        
        
site = AdminSite() # data_list = []  sk = StarkConfig
site.set_sk(StarkConfig) #sk = StarkConfig
site.sk('alex',19)
class StackConfig(object):
    pass

class Foo(object):
    pass

class Base(object):
    pass

class AdminSite(object):
    def __init__(self):
        self._register = {}

    def registry(self,key,arg):
        self._register[key] = arg

site = AdminSite()
site.registry(1,StackConfig)
site.registry(2,StackConfig)
site.registry(3,StackConfig)
site.registry(4,Foo)
site.registry(5,Base)

for k,v in site._register.items():
    print(k,v() )

7.3 特殊成员

7.3.1 '_ init _' 初始化方法
class Foo:
    """
    类是干啥的。。。。
    
    """
    def __init__(self,a1):
        """
        初始化方法
        :param a1: 
        """
        self.a1 = a1
        
obj = Foo('alex')
7.3.2 _ new _创建空对象,构造方法
class Foo(object):
    def __init__(self):
        """
        用于给对象中赋值,初始化方法
        """
        self.x = 123
    def __new__(cls, *args, **kwargs):
        """
        用于创建空对象,构造方法
        :param args: 
        :param kwargs: 
        :return: 
        """
        return object.__new__(cls)#返回什么obj就等于什么

obj = Foo()  #先执行new,在执行对象的初始化
7.3.3 __cal__
class Foo(object):
    def __call__(self, *args, **kwargs):
        print('执行call方法')

# obj = Foo()
# obj()#执行call方法
Foo()()-->先执行new方法在执行init方法在执行call方法,#输出执行call方法
 
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from wsgiref.simple_server import make_server

def func(environ,start_response):
    start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
    return ['你好'.encode("utf-8")  ]

class Foo(object):

    def __call__(self, environ,start_response):
        start_response("200 OK", [('Content-Type', 'text/html; charset=utf-8')])
        return ['你<h1 style="color:red;">不好</h1>'.encode("utf-8")]


# 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。
server = make_server('127.0.0.1', 8000, Foo())
server.serve_forever()
7.3.4 __getitem__ __setitem__ __delitem__
class Foo(object):

    def __setitem__(self, key, value):
        pass

    def __getitem__(self, item):
        return item + 'uuu'

    def __delitem__(self, key):
        pass


obj1 = Foo()
obj1['k1'] = 123  # 内部会自动调用 __setitem__方法
val = obj1['xxx']  #取值 内部会自动调用 __getitem__方法
print(val)#xxxuuu
del obj1['ttt']  #删除 内部会自动调用 __delitem__ 方法
7.3.5 __str__
class Foo(object):
    def __str__(self):
        """
        只有在打印对象时,会自动化调用此方法,并将其返回值在页面显示出来
        :return: 
        """
        return 'asdfasudfasdfsad'

obj = Foo()
print(obj)
class User(object):
    def __init__(self,name,email):
        self.name = name
        self.email = email
    def __str__(self):
        return "%s %s" %(self.name,self.email,)
user_list = [User('二狗','2g@qq.com'),User('二蛋','2d@qq.com'),User('狗蛋','xx@qq.com')]
for item in user_list:
    print(item)
7.3.6 __dict__
class Foo(object):
    def __init__(self,name,age,email):
        self.name = name
        self.age = age
        self.email = email

obj = Foo('alex',19,'xxxx@qq.com')
print(obj)
print(obj.name)
print(obj.age)
print(obj.email)
val = obj.__dict__ # 去对象中找到所有变量并将其转换为字典
print(val){'name':'alex','age':19,'email':'xxxx@qq.com'}
7.3.7 上下文管理【面试题】
class Foo(object):
    def __enter__(self):
        self.x = open('a.txt',mode='a',encoding='utf-8')
        return self.x
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.x.close()

with Foo() as ff:
    ff.write('alex')
    ff.write('alex')
    ff.write('alex')
    ff.write('alex')
'内部执行')
#     ctx.do_something()


class Foo(object):
    def do_something(self):
        print('内部执行')

class Context:
    def __enter__(self):
        print('进入')
        return Foo()

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('推出')

with Context() as ctx:
    print('内部执行')
    ctx.do_something()
7.3.8两个对象相加
val = 5 + 8
print(val)

val = "alex" + "sb"
print(val)

class Foo(object):
    def __add__(self, other):
        return 123
    
obj1 = Foo()
obj2 = Foo()
val  = obj1 + obj2
print(val) #123

特殊成员:就是为了能够快速实现执行某些方法而生。

 

7.4 内置函数补充

7.4.1 type,查看类型

判断一个实例对象是否是一个类的实例对象

class Foo:
    pass

obj = Foo()

if type(obj) == Foo:
    print('obj是Foo类的对象')
7.4.2 issubclass 判断某个类是否是某个类的子类

子类在前,父类在后

class Base:
    pass

class Base1(Base):
    pass

class Foo(Base1):
    pass

class Bar:
    pass

print(issubclass(Bar,Base)) #False
print(issubclass(Foo,Base)) #True
7.4.3 isinstance
class Base(object):
    pass

class Foo(Base):
    pass

obj = Foo()

print(isinstance(obj,Foo)) True # 判断obj是否是Foo类或其基类的实例(对象)
print(isinstance(obj,Base)) #True 判断obj是否是Foo类或其基类的实例(对象)
7.4.4.super

根据self对象所属类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了)

class Base(object):
    def func(self):
        print('base.func')
        return 123


class Foo(Base):
    def func(self):
        v1 = super().func()#返回值给v1
        print('foo.func',v1)

obj = Foo()
obj.func() #base.func  foo.func 123
# super().func() 去父类中找func方法并执行
class Bar(object):
    def func(self):
        print('bar.func')
        return 123

class Base(Bar):
    pass

class Foo(Base):
    def func(self):
        v1 = super().func()
        print('foo.func',v1)

obj = Foo()
obj.func() base.func  foo.func 123
# super().func() 根据类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了)
class Base(object): # Base -> object
    def func(self):
        super().func()
        print('base.func')

class Bar(object):
    def func(self):
        print('bar.func')

class Foo(Base,Bar): # Foo -> Base -> Bar
    pass

obj = Foo()
obj.func() # bar.func  base.func

# super().func() 根据self对象所属类的继承关系,按照顺序挨个找func方法并执行(找到第一个就不在找了)

7.5 异常处理

7.5.1 基本格式
try:
    pass
except Exception as e:
    pass
try:
    v = []
    v[11111] # IndexError
except ValueError as e:
    pass
except IndexError as e:
    pass
except Exception as e:
    print(e) # e是Exception类的对象,对象中有一个错误信息。
try:
    int('asdf')
except Exception as e:
    print(e) # e是Exception类的对象,中有一个错误信息。
finally:
    print('最后无论对错都会执行')
  #  finally:最后无论对错都会执行
# #################### 特殊情况 #########################
def func():
    try:
        # v = 1
        # return 123
        int('asdf')
    except Exception as e:
        print(e) # e是Exception类的对象,中有一个错误信息。
        return 123
    finally:
        print('最后')

func() 
#在python中有try中finally即使遇到return,它也是先执行完在return
7.5.2 主动触发异常
try:
    int('123')
    raise Exception('阿萨大大是阿斯蒂') # 代码中主动抛出异常
except Exception as e:
    print(e)  #阿萨大大是阿斯蒂
def func():
    result = True
    try:
        with open('x.log',mode='r',encoding='utf-8') as f:
            data = f.read()
        if 'alex' not in data:
            raise Exception()
    except Exception as e:
        result = False
    return result
7.5.3 自定义异常
class MyException(Exception):
    pass

try:
    raise MyException('asdf')
except MyException as e:
    print(e)
class MyException(Exception):
    def __init__(self,message):
        super().__init__()
        self.message = message

try:
    raise MyException('asdf')
except MyException as e:
    print(e.message)

7.6 可迭代对象

表象:可以被for循环的对象就可以称为是可迭代对象: "x" [11,2] {}...

class Foo:
    pass

obj = Foo()
class Foo:
    def __iter__(self):
        return iter([1,2,3,4])#转换成迭代器

obj = Foo()


class Foo:
    def __iter__(self):
        yield 1
        yield 2
        yield 3

obj = Foo()
for item in obj:
    print(obj) #1 2 3

记住:只要能被for循环就是去看他内部的iter方法。

7.7 约束

# 约束字类中必须写send方法,如果不写,则调用时候就报抛出 NotImplementedError 
class Interface(object):
    def send(self):
        raise NotImplementedError()
        
class Message(Interface):
    def send(self):
        print('发送短信')z
        
class Email(Interface):
    def send(self):
        print('发送邮件')
class Message(object):
    
    def msg(self):
        print('发短信')

    def email(self):
        print('邮件')
        
    def wechat(self):
        print('微信')

obj = Message()
obj.msg()
obj.email()
obj.wechat()
class BaseMessage(object):
    def send(self,a1):
        raise NotImplementedError('子类中必须有send方法')
        
class Msg(BaseMessage):('子类中必须有send方法')
    def send(self):
        pass

class Email(BaseMessage):
    def send(self):
        pass

class Wechat(BaseMessage):
    def send(self):
        pass

class DingDing(BaseMessage):
    def send(self):
        print('钉钉')
    
obj = Email()
obj.send()

7.8 反射

根据字符串的形式去某个对象中操作他的成员。

7.8.1getattr(对象,"字符串")

根据字符串的形式去某个对象中 获取 对象的成员.

class Foo(object):
    def __init__(self,name):
        self.name = name
    def login(self):
        pass
obj = Foo('alex')
func_name = input('请输入方法名:') #login
getattr(obj,func_name) #执行login方法

# 获取变量
v1 = obj.name
v1 = getattr(obj,'name')

obj.name = 'eric'
setattr(obj,'name','eric')  #重新赋值
# 获取方法
method_name = getattr(obj,'login')
method_name()
7.8.2 hasattr(对象,'字符串')

根据字符串的形式去某个对象中判断是否有该成员。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from wsgiref.simple_server import make_server

class View(object):
    def login(self):
        return '登陆'

    def logout(self):
        return '等处'

    def index(self):
        return '首页'


def func(environ,start_response):
    start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
    #
    obj = View()
    # 获取用户输入的URL
    method_name = environ.get('PATH_INFO').strip('/')
    if not hasattr(obj,method_name):
        return ["sdf".encode("utf-8"),]
    response = getattr(obj,method_name)()
    return [response.encode("utf-8")  ]

# 作用:写一个网站,用户只要来方法,就自动找到第三个参数并执行。
server = make_server('192.168.12.87', 8000, func)
server.serve_forever()
7.8.3 setattr(对象,'变量','值')

根据字符串的形式去某个对象中设置成员。

class Foo:
    pass


obj = Foo()
obj.k1 = 999
setattr(obj,'k1',123) # obj.k1 = 123

print(obj.k1) #123
7.8.4 delattr(对象,'变量')

根据字符粗的形式去某个对象中删除成员。

class Foo:
    pass

obj = Foo()
obj.k1 = 999
delattr(obj,'k1')
print(obj.k1)
# 反射
    # hasattr(重要)
    # getattr(重要)
    # setattr
    # delattr
# ab = 'test'

# import demo
# print(getattr(demo,'a'))
# print(getattr(demo,'a'))
import demo
import sys
# print(demo)
# print(sys.modules)
# print(sys.modules['demo'])
# print(demo is sys.modules['demo']) #True
# print(getattr(sys.modules['demo'],'a')) #取demo.py文件里a的值
# print(getattr(sys.modules[__name__],'ab'))#取demo.py文件里ab的值,__name__反射当前文件中的内容,不管是导入的还是就是当前的都用。(
#print(geattr(sys.moudles['__main__'],'ab')) #当前文件取ab的值  __main__当前文件
# '__main__': <module '__main__' from 'D:/code/day24/1.内容回顾.py'>
    # setattr
    # delattr

# 反射
    # 通过 对象 来获取 实例变量、绑定方法
    # 通过 类   来获取  类变量、类方法、静态方法
    # 通过 模块名 来获取 模块中的任意变量(普通变量 函数  类)
    # 通过 本文件 来获取 本文件中的任意变量
        # getattr(sys.modules[__name__],'变量名')

例题:

class Cloud(object):

    def upload(self):
        pass
    
    def download(self):
        pass
    
    def run(self):
        # up|C:/xxx/xxx.zip
        # down|xxxx.py
        value = input('请用户输入要干什么?')
        action = value.split('|')[0]
        # 最low的形式
        if action == 'up':
            self.upload()
        elif action == 'down':
            self.download()
        else:
            print('输入错误')
        
        # 构造字典 (*)
        method_dict = {'up':self.upload, 'down':self.download}
        method = method_dict.get(action)
        method()
         
        # 反射(*)
         method = getattr(self,action) # action必须是upload 和download  # self.upload (self,action)表示去找self.up或者self.download
        method()
        
        
 class Foo(object):
    def get(self):
        pass

obj = Foo()
# if hasattr(obj,'post'): 
#     getattr(obj,'post')

v1 = getattr(obj,'get',None) # 推荐
print(v1)

 

7.9 python一切皆对象

  1. py文件

  2. 对象

python一切皆对象,所以以后想要通过字符串的形式操作其内部成员都可以通过反射的机制实现。

7.10 模块:importlib

根据字符串的形式导入模块。

模块 = importlib.import_module('utils.redis')
内部会执行 form utils import redis

getattr(redis,'func') #用字符串的形式去对象(模块)中找她的成员
函数:
import importlib
path = 'utils.redis.func'
module_path,func_name = path.rsplit('.',maxsplit =1)
#从右边开始往左分割两个字符串,一个路径,一个函数名
module_object = importlib.import_module(module_path)
getattr(module_object,func_name)()

类:
import importlib
middleware_classer = ['utils.redis.Redis','utils.mysql.Mysql']
for path in middleware_classer:
    module_path,class_name = path.rsplit('.',maxsplit =1)
#从右边开始往左分割两个字符串,一个路径,一个类名
    module_object = importlib.import_module(module_path)
    cls = getattr(module_object,class_name)#找到类
    obj = cls() #实例化对象
    obj.connect()
    

7.11 栈和队列

class Stack(object):#后进后出
    pass

class Queue(object): #队列 先进先出
    pass

# 补充
    # 栈 Stack
        #后进先出是栈  lifo
    # 队列 Queue
        # 先进先出是队列 fifo

7.13 单例模式

无论实例化多少次,永远用的都是第一次实例化出的对象。

 什么是单例模式
# 单例的应用场景
# __new__方法 :(指针)创建实例的  并且在init之前工作
class Foo:
    pass

# 多例,每实例化一次就创建一个新的对象。
obj1 = Foo() # 实例,对象
obj2 = Foo() # 实例,对象
# 单例,无论实例化多少次,都用第一次创建的那个对象。
obj1 = Foo()
obj2 = Foo()

单例模式标准 内存地址一样

无论实例化多少次对象用的都是第一次实例化创建的对象(第一次创建的内存地址)

应该场景:连接池,数据库的链接

class Singleton(object):
    instance = None
    def __new__(cls, *args, **kwargs):
        #cls = Singleton
        if not cls.instance:#判断是否存在
            cls.instance = object.__new__(cls)
        return cls.instance

obj1 = Singleton()
obj2 = Singleton()
#obj1和obj2的内存地址一样
# 不是最终,加锁。

文件的连接池

class FileHelper(object):
    instance = None
    def __init__(self, path):
        self.file_object = open(path,mode='r',encoding='utf-8')

    def __new__(cls, *args, **kwargs):
        if not cls.instance:
            cls.instance = object.__new__(cls)
        return cls.instance

obj1 = FileHelper('x')  #x是文件
obj2 = FileHelper('x')
obj1.file_object.reda(1)
obj2.file_object.read(2)

 

推荐阅读