第七章.面向对象

7.1面向对象三大特性

  • 封装

  • 继承

  • 多态

7.1.1封装(基本格式)

  • 封装的两种方式 :

    将数据封装到方法 / 将方法封装到类

class 类名:
   def 方法名(self,要传入参数一,要传入参数二):
  print(name)
       return 123
   
   def 方法名(self,要传入参数一,要传入参数二):
  print(name)
       return 123
   
   def 方法名(self,要传入参数一,要传入参数二):
  print(name)
       rturn 123
       
obj = 类名()       #创建该类的对象
result = obj.方法名(要传入参数一,要传入参数二)   #通过对象调用方法
print(result)
  • 应用场景

    遇到很多函数,需要给函数进行归类和划分时

  • 什么是封装思想

    将同一类函数封装到同一py文件,方便以后调用

  • 广义的封装 :类中的成员

  • 狭义的封装 :私有成员

  • __名字

  • 只能在类的内部使用,既不能在类的外部调用,也不能在子类中使用

  • _类名__名字

7.1.2 继承

class Base:         #父类(基类)
    def f1(self):
        pass

class Foo(base):   #子类(派生类)
    def f2(self):
        pass

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

obj = Base()    # 创建了一个父类的对象
obj.f1()
  • 什么时候用到继承?

    多个类中如果有公共的方法,可以放到基类中避免重复编写。

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

    • 注意self到底是谁

    • 注意self是哪个类创建的,就从此类开始找,自己没有就找 父类(基类 或 超类)。

    • 深度优先 广度优先

    #例一:
    class Base:
       def f1(self):
           print('base.txt')
           
    class Foo(Base):
       def f2(self):
           print('Foo.txt')
     
    obj = Foo()
    obj.f1()     #base.txt
    obj.f2()     #Foo.txt
    #例二:
    class Base:
       def f1(self):
           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()
           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
    v#例六:
    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()
    • 补充

#例一:
class StarkConfig(object):
   pass

class AdminSite(object):
   def __init__(self):
       self.data_list = []
       
   def register(self,arg):
       self.data_list.append(arg)
       
site = AdminSite()
obj = StarkConfig()
site.register(obj)     #[<__main__.StarkConfig object at 0x00000000025393C8>] 为列表里面是一个StarkConfig类
#例二:
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 = []
site.set_sk(StarkConfig)    #site.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._register = {}
site.registry(1,StackConfig)     #{1:StackConfig}
site.registry(2,StackConfig)     #{1:StackConfig,2:StackConfig}
site.registry(3,StackConfig)     #{1:StackConfig,2:StackConfig,3:StackConfig}
site.registry(4,Foo)             #{1:StackConfig,2:StackConfig,3:StackConfig,4:Foo}
site.registry(5,Base)            #{1:StackConfig,2:StackConfig,3:StackConfig,4:Foo,5:Base}

for k,v in site._register.items():
   print(k,v() )    # 1   StackConfig地址
                    # 2   StackConfig地址
                    # 3   StackConfig地址
                    # 4   Foo地址
                    # 5   Base地址
#例四;
class StackConfig(object):
   pass

class UserConfig(StackConfig):
   pass

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()
           print(key,obj)
           
site = AdminSite()            #site._register={}
site.registry(1)              #{1:StackConfig}
site.registry(2,StackConfig)  #{1:StackConfig,2:StackConfig}
site.registry(3,UserConfig)   #{1:StackConfig,2:StackConfig,3:StackConfig}
site.run()
class StackConfig(object):
   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()
           print(key,obj.list_display)
site = AdminSite()            #site._register = {}
site.registry(1)              #{1:StackConfig}
site.registry(2,StackConfig)  #{1:StackConfig,2:StackConfig}
site.registry(3,UserConfig)   #{1:StackConfig,2:StackConfig,3:UserConfig}
site.run()     #1   '李邵奇'
 #2   '李邵奇'
              #2   '利奇航'
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._register = {}
site.registry(1)             #{1:StackConfig}
site.registry(2,StackConfig) #{1:StackConfig,2:StackConfig}
site.registry(3,UserConfig)  #{1:StackConfig,2:StackConfig,3:UserConfig}
site.run()     #1   '李邵奇'
 #2   '李邵奇'
              #2   '利奇航'

7.1.3 多态

  • 一个类表现出来的多种状态 --> 多个类表现出相似的状态

(多种形态/多种类型) 鸭子模型

#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方法,就是我们想要的类型)

 

7.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)
           
obj1 = File()   #实例化一个File类对象
obj1.xxxx = 'text.txt'   #在对象中写了一个 xxxx = 'text.txt'
obj1.read()     #通过对象调用类中的read方法,read方法中的self就是obj1  
obj1.write('alex')

obj2 = File()   #实例化一个File类对象
obj2.xxxx = 'info.txt'   #在对象中写了一个 xxxx = 'text.txt'
obj2.read()     #通过对象调用类中的read方法,read方法中的self就是obj1  
obj2.write('alex')
class Person:
   def show(self):
       temp = '我是%s,年龄:%s,性别:%s' %(self.name,self.age,self.gender,)
       print(temp)
       
p1 = Person()         #实例化一个Person类对象
p1.name = '张三'
p1.age = '17'
p1.gender = '男'       #传入三个参数
p1.show()             #调用类中的show方法

p2 = Person()         #实例化一个Person类对象
p2.name = '李四'
p2.age = '19'
p2.gender = '男'       #传入三个参数
p2.show()             #调用类中的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)
       
p1 = Person('张三','17','男')  # 类() 实例化对象,自动执行此类中的 __init__方法。
p1.show()

p2 = Person('李四','19','19')
p2.show(

总结

  • 如果写代码时,函数比较多比较乱,可以将函数归类并放到同一类中

  • 函数如果有反复使用的公共值,就可以放到对象中.

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,content)   #删
  print(self.file_path)
       
   def update(self)          #更新
  print(self.file_path)
       
p1 = File('log.txt')
p1.read()

p2 = File('xxxxxx.txt')
p2.read()
#例题:循环让用户输入:用户名/密码/邮箱,输入完成后进行数据打印

#法一:
USER_LIST = []
while True:
   user = input('请输入用户名:')
   psw = input('请输入密码:')
   email = input('请输入邮箱:')
   temp = {'username':user,'password':psw,'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,psw,email):
       self.username = user
       self.password = psw
       self.email = email
       
USER_LIST = []    #添加之后变为[对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]    
while True:
   user = input('请输入用户名:')
   psw = input('请输入密码:')
   email = input('请输入邮箱:')
   p = Person(user,psw,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 = psw
       self.email = email
   
   def info(self):    #因为有__init__(self,user,pwd,email),所以可以直接用
       return '用户名:%s,密码:%s,邮箱:%s' %(item.username,item.password,item.email)

USER_LIST = []    #添加之后变为[对象(用户/密码/邮箱),对象(用户/密码/邮箱),对象(用户/密码/邮箱)]  
while True:
   user = input('请输入用户名:')
   psw = input('请输入密码:')
   email = input('请输入邮箱:')
   p = Person(user,psw,email)
   USER_LIST.append(p)

for item in USER_LIST:
   temp = '用户名:%s,密码:%s,邮箱:%s' %(item['username'],item['password'],item['email'])
   print(temp)

 

7.3 游戏开发

class Police:          #创建一个警察类
   def __init__(self,name):
       self.name = name
       self.hp = 1000
   
   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('二蛋')    #已经调用类
print(lcj.nickname)
lp = Bandit('二狗')
zsd = Bandit('狗蛋')
   

#1.二狗谋杀李四,二狗生命值-50,李四生命值-100
lp.murder(zzh.name)
lp.hp = lp.lp - 50
zzh.hp = zzh.hp -100

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):
       msg = "%s个了%s一全。" %(self.nickname,other.name)
       self.hp -= 20
       other.hp -= 500
 
lcj = Bandit('二蛋')

lsq = Police('李邵奇')
lsq.dao(lcj)
lsq.quan(lcj)
lcj.qiang(lsq)

 

7.4成员

  • 对象

    • 实例变量

    • 类变量

    • 绑定方法

    • 类方法

    • 静态方法

    • 属性

  • 新式类和经典类

    #py2 继承object就是新式类
    #     默认是经典类
    # py3 都是新式类,默认继承object

    # 新式类
       # 继承object
       # 支持super
       # 多继承 广度优先C3算法
       # mro方法
    # 经典类
       # py2中不继承object
       # 没有super语法
       # 多继承 深度优先
       # 没有mro方法

7.4.1实例变量

7.4.2 类成员

7.4.2.1类变量

  • 定义:写在类的下一级和方法同级

    可通过两种方式调用: Foo.city---->obj1.city

    obj2.city

    访问:

      类.类变量名称
    对象.类变量名称
  • 面试题

    class Base:
       x = 777
       
    obj = Base()
    print(obj.x)   #先去对象中找,没有再去内中找
                #777
    obj.y = 123    #在对象中创建了一个 y=123 的变量
    print(obj.x) #777
    print(Base.x)#777
    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.4.2.2类方法

  • 定义

    • @classmethod装饰器

    • 至少有cls参数,当前类

  • 执行

    • 类.类方法()

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

    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):
    print('cls是当前类',cls)
    print(a,b)

    obj = Foo()
    obj.func(1, 2)  # 123 1 2
    Foo.f1()        # 123

    Foo.f2(1,2)     # cls是当前类 <class '__main__.Foo'>
                   # 1 2
  • 问题@classmethod和@staticmethod的区别?

    一个类方法,一个静态方法
    定义 :
       类方法 : 用classmethod做装饰器且至少一个cls参数
       静态方法:用staticmethod做装饰器且参数无限制
    调用:
       类:方法直接调用
    对象:方法也可调用

7.4.2.3绑定方法 ( 方法 / 普通方法 )

  • 定义 : 至少有一个self参数

  • 执行 : 先创建对象,由对象执行方法

    #法一:(不推荐)
    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.4.2.4 静态方法

  • 定义 :

    • @staticmethod装饰器

    • 参数无限制

  • 执行

    • 类.静态方法名()

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

    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.4.2.5 属性

  • 定义:

    • @property装饰器

    • 只有一个self参数

  • 执行 : 对象.方法不用加括号。

    class Foo:
       
       @property
       def func(self):
           print(123)
           return 777
       
    obj = Foo()
    result = obj.func
    print(result)       #123
                       #777
    #属性的应用
    class Page:
       def __init__(self,total_count,current_page, per_page_count=10)
    self.total_count = total_count          #数据总数量
    self.current_page = current_page        #选择页码数
    self.per_page_count = per_page_count    #每页展示数量
           
    @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(377):
       USER_LIST.append('alex-%s' %(i,))
       
    # 请实现分页展示:
    current_page = int(input('请输入要查看的页码数:'))
    p = page(377,current_page)
    data_list = USER_LIST[p.start_index:p.end_index]
    for item in data_list:
    print(item)  

7.5成员修饰符

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

  • 私有,只有自己可以访问到.

    #例一:
    class Foo:
       def __init__(self,name):
           self.__name = name
       
       def func(self):
           print(self.__name)

    obj = Foo('alex')
    obj.func()          #'alex'
    #print(obj.__name)   #不能找到,会报错
    class Foo:
    __x = 1

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

    # print(Foo.__x)   #不能找到,会报错
    Foo.func()     #1
    class Foo:
    def __fun(self):
    print('msg')

       def show(self):
    self.__fun()

    obj = Foo()
    # obj.__fun()   #不能找到,会报错
    obj.show()       #'msg'
  • 补充

    class Foo:
       def __init__(self,num):
           self.num = num
           
    cls_list = []
    for i in range(10):
    cls_list.append(Foo)    #列表里面有10个类
    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()      #'f1'   'f2'
    class Foo:
    def f1(self):
    print('f1')
    def f2(self):
    print('f2')
    def f3(self):
    v = [self.f1 , self.f2 ]
    for item in v:
    item()
    obj = Foo()
    obj.f3()       #'f1'   'f2'
    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
    • 赠送

    # 强制访问私有成员
    class Foo:
       def __init__(self,name):
           self.__x = name

    obj = Foo('alex')
    print(obj._Foo__x) # 强制访问私有实例变
    • 嵌套

    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 Foo:
         def __init__(self,name):
             self.name = name
             
      def run(self):
             pass
         
      obj1 = Foo('alex')
      obj2 = Foo('eric')

 

7.6 特殊成员

  • 就是为了能够快速实现执行某些方法而生。

7.6.1. _ _ init _ _

初始化方法,用于给对象中赋值

class Foo:
   def __init__(self,a1):   #初始化方法
       self.a1 = a1
       
obj = Foo('alex')  

7.6.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 = Foo()

7.6.3._ _ call _ _

class Foo(object):
   def __call__(self, *args, **kwargs):
       print('执行call方法')

# obj = Foo()
# obj()
Foo()()    #执行call方法
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.6.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)
del obj1['ttt']  # 内部会自动调用 __delitem__ 方法
    __getitem__(self,key):返回键对应的值。
   __setitem__(self,key,value):设置给定键的值
   __delitem__(self,key):删除给定键对应的元素。

7.6.5._ _ str _ _

只有在打印对象时,会自动调用此方法,并将其返回值在页面显示出来

class Foo(object):
   def __str__(self):
       """
      只有在打印对象时,会自动调用此方法,并将其返回值在页面显示出来
      :return:
      """
       return 'asdfasudfasdfsad'

obj = Foo()
print(obj)    #'asdfasudfasdfsad'   不是字符串
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)       #'二狗 2g@qq.com'
                     #'二蛋 2d@qq.com'
                     #'狗蛋 xx@qq.com'

7.6.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)           #Foo类地址
print(obj.name)      #'alex'
print(obj.age)       #19
print(obj.email)     #'xxxx@qq.com'
val = obj.__dict__ # 去对象中找到所有变量并将其转换为字典
print(val)           #{'name': 'alex', 'age': 19, 'email': 'xxxx@qq.com'}

7.6.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')
# class Context:
#     def __enter__(self):
#         print('进入')
#         return self
#
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print('推出')
#
#     def do_something(self):
#         print('外部执行')
#
# with Context() as ctx:
#     print('内部执行')         #进入
#内部执行
                               #外部执行
#     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.6.8._ _ add_ _

两个对象相加

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)

7.7 异常处理

7.7.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('最后无论对错都会执行')
   
# #################### 特殊情况 #########################
def func():
   try:
       # v = 1
       # return 123
       int('asdf')
   except Exception as e:
       print(e) # e是Exception类的对象,中有一个错误信息。
       return 123
   finally:
       print('最后')

func()

7.7.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.7.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)
class Base(object):
   def send(self):
       raise NotImplementedError('子类中必须实现send方法')

class Foo(Base):    # 约束字类中必须写send方法,如果不写,则调用时候就报抛出 NotImplementedError
   def send(self):
       print('234')

obj = Foo()
obj.send()
#例一:
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):
   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.1 getattr(对象,"字符串")

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

    class Foo(object):
       def __init__(self,name):
           self.name = name
    def login(self):
           print(123)
           
    obj = Foo("alex")

    #获取变量(v1和v2等价)
    v1 = getattr(obj,'name')
    v2 = obj.name
    print(v1,v2)

    #获取方法
    method_name = getattr(obj,'login')
    method_name()

7.8.2 hasattr(对象,'字符串')

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

    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)

7.8.4 delattr(对象,'变量')

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

    class Foo:
       pass

    obj = Foo()
    obj.k1 = 999
    delattr(obj,'k1')
    print(obj.k1)

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

    • py文件

    • 对象

7.9 栈和队列

  • 栈(Stack) lifo

    后进先出

    class Stack(object):
       def __init__(self):
           self.data_list = []
         
       def push(self,val):
           self.data_list.append(val)    #变量从前到后依次加入到列表中(最后放入的在最后)
           print(self.data_list)
       
       def pop(self):
           v = self.data_list.pop()
           print(self.data_list)
           return(v)
     
    obj = Stack()
    obj.push('alex')      #['alex']
    obj.push('eric')      #['alex','eric']

    a = obj.pop()         #['alex']   删除是从前向后删
    print(a)              #'eric'
  • 队列(Queue) fifo

    先进先出

    class Queue(object):
       def __init__(self):
           self.data_list = []
         
       def push(self,val):
           self.data_list.insert(0,val)    #变量从前到后依次加入到列表中(最后放入的在最后)
           print(self.data_list)
       
       def pop(self):
           v = self.data_list.pop()
           print(self.data_list)
           return(v)
     
    obj = Queue()
    obj.push('alex')      #['alex']
    obj.push('eric')      #['eric', 'alex']

    a = obj.pop()         #['eric']   删除是从前向后删
    print(a)              #'alex'

7.10 循环中删除元素

  • 注 : 在删除时如果从前向后删除会报错

    class User(object):
       def __init__(self, name, age):
           self.name = name
           self.age = age

    info = [User('武沛齐', 19), User('李杰', 73), User('景女神', 16)]
    name = input('请输入要删除的用户姓名:')
    # 请补充代码将指定用户对象再info列表中删除。
    for item in info:
       if name == item.name:
           info.remove(item)
    print(info)

7.11单例模式

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

class Foo:
   pass     # 多例(自己取的),每实例化一次就创建一个新的对象。
obj1 = Foo() # 实例,对象
obj2 = Foo() # 实例,对象
  • 单例模式

    class Singleton(object):
       instance = None
       def __new__(cls, *args, **kwargs):
      if not cls.instance:
               cls.instance = object.__new__(cls)
               return cls.instance
    obj1 = Singleton()
    print(obj1)      #<__main__.Singleton object at 0x0000000002628400>
    obj2 = Singleton()
    print(obj2)      #None
    # 不是最终,加锁

    #通过__new__方法,将类的实例在创建的时候绑定到类属性_inst上。如果cls._inst为None,说明类还未实例化,实例化并将实例绑定到cls._inst,以后每次实例化的时候都返回第一次实例化创建的实例。注意从Singleton派生子类的时候,不要重载__new__。
  • 文件的连接池

    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')
    print(obj1)      #<__main__.Singleton object at 0x0000000002628400>
    obj2 = Filehelper('x')
    print(obj2)      #None

7.12模块导入

  • 多次导入重现加载

    import jd # 第一次加载:会加载一遍jd中所有的内容。
    import jd # 由已经加载过,就不再加载。
    print(456)
  • 实现再次加载

    import importlib
    import jd
    importlib.reload(jd)
    print(456)
  • 通过模块导入的特性实现单例模式

    # jd.py
    class Foo(object):
    pass
    obj = Foo()
    # app.py
    import jd # 加载jd.py,加载最后会实例化一个Foo对象并赋值给obj
    print(jd.obj)

7.13 日志(模块:logging)

  • 用于便捷记录日志且线程安全的模块,程序员用其进行统计,用来做故障排除以及记录错误,完成代码的优化

  • 日志是一种可以追踪某些软件运行时所发生事件的方法。软件开发人员可以向他们的代码中调用日志记录相关的方法来表明发生了某些事情。一个事件可以用一个可包含可选变量数据的消息来描述。此外,事件也有重要性的概念,这个重要性也可以被称为严重性级别(level)。

  • 日志的等级

    • NOTSET = 0 不设置

    • DEBUG = 10 调试

    • INFO = 20 正常信息

    • WARNING = 30 警告

    • ERROR = 40 错误

    • CRITICAL = 50 严重错误

      只有大于或等于当前日志等级的操作才会被记录

       

  • logging模块提供的日志记录函数所使用的日志器设置的日志格式默认是BASIC_FORMAT,其值为:

    "%(levelname)s:%(name)s:%(message)s"
  • 日志字段信息与日志格式

    • 事件发生时间

    • 事件发生位置

    • 事件的严重程度--日志级别

    • 事件内容

  • logging.basicConfig

    • 使用方便

    • 不能实现 编码问题;不能同时向文件和屏幕上输出

    • logging.debug,logging.warning

    import logging

    logging.basicConfig(
       filename='log.log',    #filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
       format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
       datefmt='%Y-%m-%d %H:%M:%S %p',   #asctime:当前时间   levelname :
       level=logging.ERROR
    )

    logging.debug('debug')
    logging.info('info')
    logging.warning('warning')
    logging.error('error')
    logging.critical('critical')
    logging.log(10,'log')
  • logger对象

    • 比较复杂

    • 操作格式为:

      • 创建一个logger对象

      • 创建一个文件操作符

      • 创建一个屏幕操作符

      • 创建一个格式(用于记录时间)

         

      • 给logger对象绑定 文件操作符

      • 给logger对象绑定 屏幕操作符

      • 给文件操作符 设定格式

      • 给屏幕操作符 设定格式

         

      • 用logger对象进行操作

import logging

logger = logging.getLogger()      #创建一个logger对象
fh = logging.FileHandler('log.log')    #创建一个文件操作符
sh = logging.StreamHandler()       #创建一个屏幕操作符

logger.addHandler(fh)        #给logger对象绑定 文件操作符
logger.addHandler(sh)       #给logger对象绑定 屏幕操作符
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')    #创建一个格式(用于记录时间)
fh.setFormatter(formatter)   #给文件操作符 设定格式
sh.setFormatter(formatter)   #给屏幕操作符 设定格式
logger.warning('message')    #用logger对象进行操作

  • 日志处理 + 日志分割

    import time
    import logging
    from logging import handlers
    # file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',)
    file_handler = handlers.TimedRotatingFileHandler(filename='x3.log', when='s',
    interval=5, encoding='utf-8')
    logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    handlers=[file_handler,],
    level=logging.ERROR
    )
    for i in range(1,100000):
    time.sleep(1)
    logging.error(str(i))
  • 注意事项

    # 在应用日志时,如果想要保留异常的堆栈信息。
    import logging
    import requests
    logging.basicConfig(
    filename='wf.log',
    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S %p',
    level=logging.ERROR
    )
    try:
    requests.get('http://www.xxx.com')
    except Exception as e:
    msg = str(e) # 调用e.__str__方法
    logging.error(msg,exc_info=True)

7.14项目结构

  • 项目名

    • bin 存放start,主程序

      • import os
        import sys
        base_path = os.path.dirname(os.path.dirname(__file__))
        sys.path.append(base_path)

        #等价于
        import os
        import sys
        base_path = os.path.dirname(os.path.dirname(os.path.abspath('文件路径')))
        sys.path.append(base_path)  
    • db 存放数据文件,

    • lib 存放扩展模块

    • log 存放日志文件

    • conf 配置一般放置可修改的内容 settings

    • src 业务逻辑

  • 脚本

  • 单可执行文件

  • 多可执行文件

posted @ 2019-04-29 17:33  Primrose  阅读(170)  评论(0编辑  收藏  举报