python学习笔记 第七章 面向对象

第七章 面向对象

类和对象

#面向对象
	#基础概念:什么是类,什么是对象、实例,实例化
    	#类:具有相同方法和属性的一类事物
        #对象、实例:一个拥有具体属性值和动作的具体个体
        #实例化:从一个类得到一个具体对象的过程
	#三大特性
    	#继承 
        		#所有的查找名字(调用方法和属性),都是先找自己的,没有找父类
            	#如果自己和父类都有,希望自己和父类都调用,super()/指定类名直接调
        	#父类、基类、超类
            #派生类、子类
            #单继承
            #多继承
            	#查找顺序
                	#深度优先
                    #广度优先
                    class A:
                        def func():
                            print("a")
                    class B(A):
				       def func():
						  print("b")
                    class C(A):
					   def func():
						  print("c")
                    class D(B,C):
                         pass
                    
                    #python2的经典类来说会以深度优先,即调用D.func(),先找D->B>A->C
                    #python3默认是新式类,因此来说是广度优先,即调用D.func(),先找D->B->C->A
        #多态
        	#一个类表现出多种状态
            	#user类 用户类
            #鸭子类型
            
        #封装
        	#广义的封装:类中的成员
            #狭义的封装:私有成员
            	#__名字
                #只能在类的内部使用,既不能在类的外部调用,也不能在子类中使用
                #_类名__名字
    #类成员
    	#类变量
        #绑定方法
        #特殊成员
        	#类方法 classmethod   直接通过类可以调用方法,不需要创建对象
            #静态方法 staticmethod   不需要添加self参数
            #属性 property  可以将方法变成属性,调用的时候不用加括号
    #双下方法/魔术方法/内置方法
    	#__str__
        #__new__   构造方法
        #__init__  初始化方法
        #__dict__
        #__call__  源码中写这个方法很容易
        #__enter__ __exit__   with上下文管理
        #__getitem__
        #__setitem__
        #__delitem__
        #__add__
        #__iter__  #可迭代对象
    #组合
    	#一个类的对象作为另一个类对象的实例变量
    #相关内置函数
    	#isinstance
        #issubclass
        #type
        #super
    #新式类和经典类
    	#python2继承object就是新式类,其他默认是经典类
        #python3都是新式类,默认继承object
        
        #新式类
        	#继承object
            #支持super
            #多继承广度优先
            #mro方法 可以通过mro方法看继承的顺序
        #经典类
        	#python2中没有继承object方法的
            #没有super语法
            #多继承,深度优先
            #没有mro方法

7.1迭代器

自己不会写迭代器,只要会用就行

任务:请展示列表中的所有数据

  • while + 索引 + 计数器

  • 迭代器,帮助你对某种对象(可迭代对象)中的元素进行逐一获取

    • 先将列表转换成迭代器:v=iter([11,22,33]) ,再用.next()迭代取到值,当迭代完毕时还迭代会报StopIteration错

      v1=[11,22,33]
      #列表转换成迭代器
      v=iter(v1)  #生成一个迭代器的对象,注意v才是迭代器
      #v=v1.__iter__()
      print(type(v))  #<class 'list_iterator'>
      
      while True:
          try:
              val=v.__next__()  #里面有值就会迭代,逐一取到列表中的元素,当迭代到没有值会报错
              print(val)
          except Exception as e:
              break
      #对于字符串、列表、字典、元组、集合都可以进行逐一获取
      #上面这些类创建的对象也被称为序列
      

如何判断一个对象是否是迭代器,看其内部代码有没有next函数

for循环的内部

  v1=[11,222,3]
  
  #1.内部会将v1转换成迭代器 
  #2.内部反复执行 迭代器.__next__()
  #3.取完不报错
  for item in v1:
      print(item)

可迭代对象:简单来说,可以被for 循环,或者可以被'iter''()且需要返回一个迭代器

7.2生成器(函数的变异)

# 函数
def func():
    return 123


# 生成器函数(内部是否包含yield)
# 函数内部不会执行,返回一个生成器对象
def func1(arg):
    print("F1")
    yield 1
    print("F2")
    yield 2
    print("F3")
    yield 100

# 生成器可以被for 循环,一旦开始循环,函数 内部代码会开始执行
v1=func1(2000)  #由于有yield函数不会执行内部代码
for item in v1:
    print(item)  #只要遇到 yield函数就不会继续在执行,且将yield的值给item
    #第二次 循环会继续从上一个终止处开始执行,不会重新开始执行函数

总结:函数中如果存在yield(不管yield会不会被运行),那么函数就是一个生成器函数,调用生成器函数会返回一个生成器 ,生成器只有被for 循环的时候,生成器内部的代码才会执行,每次 循环都会获取yield的值返回。

应用:

def func():
    count=1
    while True:
        yield count
        count+=1
        # if count==10000:
        #	return   这样就可以生成确定范围的值,而不需要使用range

val=func()  #生成器
for item in val:
    print(item)  #边使用边生成

生成器示例:

def func():
    """
    分批去读取文件中的内容,将文件中的内容返回给调用者
    :return: 
    """
    cursor=0
    while  True:
        f=open("aaa.txt",mode="r",encoding="utf-8")  #通过网络连接数据
        f.seek(cursor)
        #代指 redis[0:10]
        data_list=[]
        for i in range(10):  #每次传入10个数据
            line=f.readline()
            if not line:   #没有值的时候
                break
            data_list.append(f.readline())
        #if not data:
        #    break
        for row in data_list:
            yield row    #一次一次进行yield
        cursor=f.tell()
        f.close()  # 关闭与redis的链接
        #这样可以取10次数据就关闭连接
        
for item in func():
    print(item)

生成器读取数据示例扩展

#pip下载redis模块
import redis

conn=redis.Redis(host="192.168.11.11")

#scan_iter,是一个生成器函数
result=conn.scan_iter(count=1000)
for item in result:
    print(item)
"""

def scan_iter(self,match=None,count=None):
	cursor="0"
	while cursor !=0:
		#每次去获取100个
		#cursor取完之后的游标位置
		#data本次取出来的100条数据
		cursor,data=self.scan(cursor=cursor,match=match,count=count)
		for item  in data:
			yield item	
"""

conn.close()

特殊的可迭代对象

def func():
    yield 1

v=func()
print(v,type(v))  #查看v的类型,在此处v是生成器 
print(dir(v))  #查看v中有哪些方法
#for i in dir(v):
#    print(i)

result=v.__iter__()
print(result)
class Foo():
    pass

#创建一个对象
obj=Foo()

#不能被循环,不是可迭代对象
for item in obj:
    print(item)
#特殊的迭代器
#定义一个类,具有__iter__方法
class Foo():
    def __iter__(self):
        # return  iter([11,22,33])
        yield 1
        yield 2
        yield 3

#创建一个对象
obj = Foo()
# 可以被for循环
for item in obj:
    print(item)   #循环打印出1,2,3

补充:yield from

def base():
    yield 88
    yield 99
    
def func():
    yield 1
    yield 2
    yield from base()
    yield 3
    
result=func()
for i in result:
    print(i)   #当运行func函数中的yield from,程序会跳转到base()函数中先执行
#检测此文件是否是主文件(当前执行的文件)
print(__name__)  #__main__  
#表示当前的py文件是主文件

#根据这个可以判断是否是主文件执行
if __name__ == "__main__":
    pass
def func():
    print(123)
    n=yield "aaa"
	print("->",n)
    yield "bbb"
 
g=func()
print(g)
n=next(g)
print(n)
print("_"*10)
#next(g)   #g.send(None)
g.send("message")   #可以传入一个参数,在这里传入的参数为n

7.3 类

应用场景:在遇到有很多的函数,需要对函数进行划分和归类

#函数
def func():
    pass

#类
class Account:
   	#类里面的函数一般称为方法
    def login(self):
        print("登录")
        
    def logout(self):
        print("注销")
        
#调用类中的方法
x=Account()  #创建一个该类的对象
x.login()  #通过对象使用类中的方法
#其实我们之前使用到的数据的转换也使用到 创建类的对象的方法
#不过由于python为了日常使用简单,也创建一些更加快捷的创建此类的方法
v=int()
v=str()
v=list()
#...

7.3.1 self的使用

self 实际上就是一个形式参数,python内部会将这个对象传送这个参数

#self的使用
class Person:
    def  show(self):
        print(self.name)
        
p1=Person()
p1.name="apple"
p1.show()

p2=Person()
p2.name="pear"
p2.show()
#self在执行的时候,可以分辨出相同的类创建出的不同的对象
class Person:
    def show(self):
        temp="我是%s,年龄%s,性别%s" %(self.name,self.age,self.gender)
        print(temp)
        
        
p1=Person()
p1.name="apple"
p1.age=18
p1.gender="男"
p1.show()

#同理创建一个p2也会自动用self判断出创建的对象是那个,使用其中的变量

7.3.2 类中的初始化方法(构造方法)

#__init__() 创建实例化对象的时候,会自动执行此类中的这个方法
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("apple",18,"男")
p1.show()

p2=Person("pear",20,"男")
p2.show()
#类实例化对象之后,自动会执行此类中的__init__方法

7.3.3类成员和对象成员

类成员里面包括类变量(静态字段/属性)、方法(绑定方法/普通方法)、静态方法、类方法、属性

对象成员中只有实例变量(字段/属性),对象成员根据类成员创建,创建时先执行__init__()方法

class Foo:
    city="北京"

    def __init__(self,name):
        self.name=name

    def  func(self):
        pass

obj1=Foo("apple")
obj2=Foo("pear")
#在python中可以取到obj1.city,obj2.city,Foo.city   python比较灵活 
#但是对于java等其他语言来说只能取到Foo.city。对象成员不能取到类中的变量,只能取到类中的方法。
  • 类变量

上述例子中的city就是一个类变量

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

访问:类.类变量名称/对象.类变量名称(当对象里面有city,则对象会先使用对象里面的city)

面试题:

class Base:
    x=1

obj=Base()
print(obj.x)
obj.y=123   #在对象中添加一个y=123的变量
obj.x=123   #在对象中添加一个x=123的变量  不能修改类中的变量
Base.x=666  #直接找到类变量,修改类变量的值
#继承中的类变量
class Base():
    x=1

class Foo(Base):
    pass

print(Base.x)
print(Foo.x)  #Foo里面没有x,但是由于Foo继承Base,可以到父级Base去找
Base.x=666
print(Base.x)
print(Foo.x)
Foo.x=999   #只修改Foo里面的值,不能修改父级的值
print(Base.x)
print(Foo.x)
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   #在对象成员中创建x变量
print(Parent.x,Child1.x,Child2.x)  #1 2 1
Child2.x=3
print(Parent.x,Child1.x,Child2.x)   #1 2 3

小结:

如果想获取值,优先在自己这里找,找不到再到类中或者父级去找

修改值的时候,只能在自己的内部设置修改

class Parent():
    x=1

class Child(Parent):
    pass

obj=Child()
print(obj.x)  #1
obj.x=2
print(Child.x)  #1

7.3.4方法(绑定方法)

  • 定义:至少有一个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.3.5静态方法

  • 定义
    • @staticmethod装饰器
    • 参数无限制
  • 执行
    • 类.静态方法名(在其他语言不能用对象.静态方法执行,虽然python可以,但是不推荐)

不用到封装的数据的时候,可以写成静态方法

class Foo():
    def __init__(self):
        self.name=123
    
    @staticmethod
    def func(): 
        print(123)
      
Foo.func()  #静态方法可以不用self参数,且能直接通过类来调用,不用创建对象

7.3.6类方法

  • 定义:
    • 至少有一个cls参数,cls是当前类
    • @classmethod装饰器
  • 执行:
    • 类.类方法
    • 对象.类方法(不推荐)
class Foo():
    @classmethod
    def func(cls,a,b):
        print("cls是当前类",cls)
        print(a,b)

Foo.func(1,2)

面试题:

#问题:@classmethod 和@staticmethod 的区别
"""
定义:
@classmethod是类方法,用@classmethod作装饰器,且至少有一个是cls参数
@staticmethod是静态方法,用@staticmethod作装饰器,没有参数限制
执行:
类.方法直接调用
对象.方法也可以直接调用
"""

7.3.7属性

定义:

  • @property装饰器
  • 只有一个self参数

执行:

  • 对象.方法(不带括号)
class Foo():
    @property
    def func(self):
        print(123)
        return 666

obj=Foo()
result=obj.func  #由于加了@property,func由方法变成属性,不需要加括号
print(result)
#加@property前提是没有其他参数,只能有self
USER_LIST=[]
for i in range(321):
    USER_LIST.append("apple-%s"%(i,))

#请实现分页展示
class page():
    #total_page表示总的数据个数,current_page表示当前要查看的页码,per_page表示每页展示的数据个数
    def __init__(self,total_page,current_page,per_page=10):
        self.total_page=total_page
        self.current_page=current_page
        self.per_page=per_page

    #@property
    def start_page(self):
        return (self.current_page-1)*self.per_page
    
    #@property
    def end_page(self):
        return (self.current_page)*self.per_page

current_page=int(input("请输入查看的页码:"))
obj=page(321,current_page)
for i in USER_LIST[obj.start_page():obj.end_page()]:  #由于加了@property,不需要再加括号
    print(i)

7.3.8成员修饰符

  • 公有:所有地方都能访问到
  • 私有:只有自己可以访问到
#实例变量
class Foo():
    def __init__(self,name,age):
        self.name=name  #公有的
        self.__age=age  #私有的

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

    def show(self):   #私有的只有在内部才能访问到,外部无法访问
        print(self.__age)

obj=Foo("apple",18)
print(obj.name)
obj.func()

#print(obj.__age)  
#外部无法访问到obj.__age
obj.show()
#只有内部能够访问
class Foo():
    __x=1

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

#print(Foo.__x)
#类变量为私有的时候,外部也不能进行访问
Foo.func()
#但是内部仍然可以访问
#私有的方法
class Foo():

    def __func(self):
        print("msg")

    def show(self):
        self.__func()

obj=Foo()
#obj.__func()  
#func方法是私有的,外部不能访问
obj.show()
#通过内部可以使用到__func方法

私有的东西,外部不能访问,有继承关系的儿子也不能访问

class Foo():
    
    def __func(self):
        print("msg")


class Base(Foo):

    def func(self):
        self.__func()  #不能访问到

obj=Base()
obj.func()
#访问私有成员---强制访问
#对象成员._类名__私有变量
class Foo:
    def __init__(self,name):
        self.__x=name

obj=Foo("apple")
#print(obj.__x)  #报错'Foo' object has no attribute '__x'
print(obj._Foo__x)   #python的漏洞,导致可以访问到私有成员,强制访问私有变量

7.3.9抽象类和接口类

#抽象类/接口类
#就是给子类一个规范,让子类必须按照抽象类的规范来实现方法
"""
class Foo():
    def func(self):
        raise NotImplementedError

class Son(Foo):
    # def func(self):  #由于Son继承Foo类,func方法如果不实现就会报错
    #     pass

s=Son()
s.func()
"""

7.4 封装

封装的思想:

  • 将同一类的函数封装到同一个py文件中,而面向对象中就是将一类的函数封装到一个类,方便日后使用
  • 如果有一个需要反复使用的公共值,也可以放到对象中
class File:
    def read(self):
        pass
    def  wirte(self):
        pass
class Person:
    def __init__(self,name,age):
        self.name=name
        self.age=age
        
p=Person("appel",18)

狭义的封装:私有成员

class A:
    def __init__(self):
        self.__func()
    
    def __func(self):
        print("A")

class B(A):
    def __func(self):
        print("B")

B()  #A   实例化对象B以后打印A        
class A:
    def __init__(self):
        self.func()
    
    def func(self):
        print("A")

class B(A):
    def func(self):
        print("B")

B()  #A   实例化对象B以后打印B  

1586916208816

7.5 继承

class Base:
    pass

class Foo(base):
    pass
class Foo():
	pass

class Foo(object):
    pass

#在python3中这两种写法是一样的,所有的类默认会继承object类

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

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

#写类一定要继承object,所以在python2中一定要直接或者间接继承(父类继承object)object

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

#父类(基类)
class Base:
    def f1(self):
        pass
    
#子类
class Foo(Base):
    def f2(self):
        pass
    
    def f1(self):
        pass
    
#创建一个子类的对象
obj=Foo()
#执行方法的时候,会优先到自己的类中找,找不到才会到父类中找
obj.f2()
obj.f1()  #父类不能执行到子类中的方法

继承关系中查找的示例

#示例一
class Base:
    def f1(self):
        print("base.f1")
        
class Foo(base):
    def f2(self):
        print("foo.f2")
   
obj=Foo()
obj.f1()
obj.f2()
#示例二
class Base:
    def f1(self):
        print("base.f1")
        
class Foo(base):
    def f2(self):
        self.f1()
        print("foo.f2")
   
obj=Foo()
obj.f2()
#示例三
class Base:
    def f1(self):
        print("base.f1")
    
class Foo(base):
    def f1(self):
        print("foo.f1")
        
    def f2(self):
        self.f1()
        print("foo.f2")
   
obj=Foo()
obj.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()

先判断self到底是谁,是由那个类创建的,就由此类开始找,自己没有就找父类

7.6 多态

class func(arg):  #多种类型,很多事物
    arg.send()  #必须具有send方法,呱呱叫 
#python
def func(arg):
    v=arg[-1]
    print(v)
    
#java
def func(str arg):
    v=arg[-1]
    print(v)

什么是鸭子模型:

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

面向对象作业:

import sys

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


class Account:
    def __init__(self):
        #用户列表,数据格式:[user对象,user对象,user对象]
        self.user_list=[]

    def login(self):
        """
        用户登录
        :return:
        """
        while True:
            username=input("请输入用户名:(n/N退出)")
            if username.upper()=="N":
                break
            password=input("请输入密码:")
            flag=False
            for row in self.user_list:
                #row是一个对象
                if row.name==username and row.pwd==password:
                    flag=True
                    print("登录成功!")
                    sys.exit(0)
            if not flag:
                print("用户名或密码错误!")

    def register(self):
        """
        用户注册,每注册一个用户就创建一个user对象,然后添加到self.user_list中,表示注册成功
        :return:
        """
        while True:
            user=input("请输入用户名:(n/N退出)")
            if user.upper()=="N":
                break
            pwd=input("请输入密码:")
            user_object=User(user,pwd)
            self.user_list.append(user_object)


    def  run(self):
        """
        程序入口
        :return:
        """
        while True:
            print("1.注册;2.登录")
            choice=input("请选择:(n/N退出)")
            if choice.upper=="N":
                break

            if choice=="1":
                self.register()
            elif choice=="2":
                self.login()
            else:
                print("输入错误!")

if __name__=="__main__":
    #开辟一块内存给obj,内存中存储user_list=[]
    obj=Account()
    obj.run()

7.7补充

7.7.1类和对象能放列表

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

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.name)  
#打印0-9

B=Foo
obj=B("apple")  #同样也是创建Foo对象

类和对象都是可以哈希的,所以也能放到字典中做字典的key/value

7.7.2方法能放到列表中

class Foo:
    def f1(self):
        print("f1")

    def f2(self):
        print("f2")

    def f3(self):
        v=[self.f1,self.f2]
        for i in v:
            i()

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

7.7.3对象的嵌套

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("广州","天河")
c1=ClassRoom("python",s1)
print(c1.name)   #python
print(c1.School.address)  #天河
print(c1.School.title)    #广州
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()  #site.date_list=[]  site.sk=None
site.set_sk(StarkConfig)
site.sk("apple",18)  #sk是StarkConfig类
class StackConfig(object):
    def  __init__(self):
        pass

class Foo(object):
    pass

class Base(object):
    pass

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

    def registry(self,key,arg,):
        self._resgister[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._resgister.items():
    print(k,v())   #1 <__main__.StackConfig object at 0x000001F073BDD7F0> ...
class StackConfig(object):
    list_display="apple"

    def changelist_view(self):
        print(self.list_display)

class UserConfig(StackConfig):
    list_display="pear"

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

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

    def run(self):
        for  item in self._register.values():
            obj=item()
            print(obj)
            print(obj.list_display)
            obj.changelist_view()


site=AdminSite()
site.registry(1)
site.registry(2,StackConfig)
site.registry(3,UserConfig)
site.run()

7.7.4特殊成员

为了能够快速执行某些方法而生

7.7.4.1初始化方法__init__
class Foo():
    """
    类是干啥的注释
    """
    def __init__(self,a1):
        """
        初始化方法
        :param a1:
        """
        self.a1=a1    
7.7.4.2构造方法new

用于创建一个空的对象/创建实例,并在init之前工作

class Foo(object):

    def __init__(self):
        print("给对象中进行赋值")
        self.x=123

    def __new__(cls, *args, **kwargs):
        print("创建对象")
        return object.__new__(cls)  #调用object创建对象的方法
        #return 123

obj=Foo()    #先创建对象,再给对象进行赋值
7.7.4.3call
class Foo(object):
    def __call__(self,*args,**kwargs):
        print("执行call方法")

#obj=Foo()
#obj()    #对象加()就去执行类中的__call__()方法
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")]

#作用:写一个网站,只要用户来访问,就 自动找到第三个参数并执行
server=make_server("127.0.0.1",8000,func)
server.serve_forever()
#127.0.0.1 - - [16/Feb/2020 17:05:21] "GET / HTTP/1.1" 200 6
#用户发来请求

采用call方法

from wsgiref.simple_server import make_server
class Foo(object):
    def __call__(self,environ,start_response):
        start_response("200 OK", [('Content-Type', 'text/html;charset=utf-8')])
        return ["你<h1 style="">不好</h1>".encode("utf-8")]

server=make_server("127.0.0.1",8000,Foo())  #现在第三个对象是Foo类创建的对象,执行时会执行__call__()方法
server.serve_forever()
7.7.4.4 getitem setitem delitem
obj=dict()
obj["k1"]=123

class Foo(object):
    def __setitem__(self, key, value):
        """
        支持上述字典的方法
        :param key:
        :param value:
        :return:
        """
        print(key,value)

    def __getitem__(self, item):
        return item+"你好"
    
    def __delitem__(self, key):
        pass

obj1=Foo()
obj1["k1"]=123  #内部自动调用__setitem__()方法,k1传给key,123传给value
obj1["k1"]      #内部自动调用__getitem__()方法,k1传给item
del obj1["ttt"] #内部自动调用__delitem__()方法,k1传给key
#只是支持这种语法,但是里面的功能现在还不需要了解
7.7.4.5 str

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

所以print打印出来的东西最好不要相信,最好用type显示其类型

v="sdafqw"
print(v)   #sdafqw

class Foo(object):
    def __str__(self):
        return "dfaggasgd"

obj=Foo()
print(obj)  #dfaggasgd
#同样也是打印出字符串,但是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("狗蛋","gd.@qq.com")]
print(user_list[0])  #狗蛋 gd.@qq.com
7.7.4.6 dict
class User(object):
    def __init__(self,name,age,email):
        self.name=name
        self.age=age
        self.email=email

obj=User("apple","19","xxx@qq.com")  #存储三个变量
print(obj,obj.name,obj.age,obj.email)  #<__main__.User object at 0x000001D6650260B8> apple 19 xxx@qq.com
val=obj.__dict__  #去对象中找到全部变量将其转换为字典
print(val)  #{'name': 'apple', 'age': '19', 'email': 'xxx@qq.com'}
7.7.4.7上下文管理enter+exit
class Foo(object):
    def __enter__(self):
        print("__enter__")
        self.x=open("aaa.txt", mode="a", encoding="utf-8")
        return self.x

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("__exit__")
        self.x.close()

with Foo() as f:  #__enter__返回值返回给f
    print(123)  #__enter__ 123 __exit__  先执行__enter__,在执行缩进里面的代码,在执行__exit__
    f.write("666")
class Foo(object):
    def __enter__(self):
        print("进入")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("退出")

    def do_something(self):
        print("内部执行2")

with Foo() as f:  #return返回的是类,所以f现在也是Foo类
    print("内部执行1")
    f.do_something()  #同样执行类中的 do_something方法 
7.7.4.8对象相加、减、乘、除
val="apple"+"pear"
print(val)

class Foo(object):
    def __add__(self, other):
        return 123

obj1=Foo()
obj2=Foo()
cal=obj1+obj2  #Foo类具有 __add__()方法,可以实现两个对象相加的操作,并return对应的值给cal
print(cal)  #123

7.7.5内置函数的补充

  • type 判断类型

  • 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
    #只要有继承关系都可以判断出来
    
  • isinstance

    class Base():
        pass
    
    class Foo(Base):
        pass
    
    obj=Foo()
    
    #isinstance判断obj是不是Foo类或者其基类的实例
    print(isinstance(obj,Foo))  #True
    print(isinstance(obj,Base)) #True
    
    if type(obj)==Foo:   #判断obj是否是Foo类的实例
        print("obj是Foo类的对象")
    

7.7.6 super

  • super()表示其父类,可以优先执行父类的方法,父类找到则停止,父类没有则到其父类的父类中去找

    class Bar():
        def func(self):
            print("bar.func")
            return 123
    
    class Base(Bar):
        pass
    
    class Foo(Base):
        def func(self):
            v1=super().func()  #super()代指按照继承关系,能够找到其父类或者祖宗
            print(v1,"foo.func")
    
    obj=Foo()
    obj.func()
    #bar.func
    #123 foo.func
    
    #super()是根据self对象所属类的继承关系,按顺序挨个找func方法并执行(找到第一个就不在找了)
    class 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
    
class A:
    def func(self):
        print("a")
class B(A):
    def func(self):
        print("b")
        super().func()   #根据mro方法找到其下一个类
class C(A):
    def func(self):
        print("c")
        super().func()
class D(B,C):
    def func(self):
        print("d")
        super().func()
obj=D()
obj.func()   #d b c a 
#super都会根据mro的顺序,找到自己对应的下一个类

7.7.7面向对象作业

#1.类内的代码会执行,方法里面的代码不会执行
class Foo(object):
    print("666")
    def func(self):
        pass

v=Foo()  #666
#类内可以嵌套类
class Foo(object):
    print("你")
    def func(self):
        pass
    class Base(object):
        print("好")
        def fun(self):
            pass

v=Foo()
#你
#好
#2.看代码写结果
class Foo(object):

    def __init__(self,age):
        self.age=age

    def display(self):
        print(self.age)

data_list=[Foo(8),Foo(9)]
for item in data_list:
    print(item.age,item.display())
# 8
# 8 None
# 9
# 9 None
#3.看代码写结果
class Base(object):
    def __init__(self,a1):
        self.a1=a1

    def f2(self,arg):
        print(self.a1,arg)

class Foo(Base):
    def f2(self,arg):
        print(666)

obj_list=[Base(1),Foo(2),Foo(3)]
for item in obj_list:
    item.f2(6)

#1 6
#666
#666
#4.看代码写结果
class StackConfig(object):
    def __init__(self,num):
        self.num=num

    def changelist(self,request):
        print(self.num,request)

    def run(self):
        self.changelist(999)

class RoleConfig(StackConfig):
    def changelist(self,request):
        print(666,self.num)

config_obj_list=[StackConfig(1),StackConfig(2),RoleConfig(3)]
config_obj_list[1].run()  #2 999
config_obj_list[2].run()  #666 3
#5.看代码写结果
class StackConfig(object):
    def __init__(self,num):
        self.num=num

    def  changelist(self,request):
        print(self.num,request)

    def run(self):
        self.changelist(999)

class RoleConfig(StackConfig):
    def changelist(self,request):
        print(333,self.num)

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

    def register(self,k,v):
        self._registry[k]=v

site=AdminSite()
site.register("aaa",StackConfig(555))
site.register("bbb",StackConfig(666))
site.register("ccc",RoleConfig(999))
print(len(site._registry))
for k,v in site._registry.items():
    v.changelist(888)

#3
#555 888
#666 888
#333 999
#6.看代码写结果
class F3(object):
    def f1(self):
        ret=super().f1()  #super会根据类创建对象的优先级找下去
        print(ret)
        return 12s3

class  F2(object):
    def f1(self):
        print("666")
 
class F1(F3,F2):   #优先级:F1->F3->F2
    pass

obj=F1()
obj.f1()
#666
#None
#7.看代码写结果
class Base(object):
    def __init__(self,name):
        self.name=name

class Foo(Base):
    def __init__(self,name):
        super().__init__(name)
        self.name="你大爷"

obj1=Foo("apple")
print(obj1.name)
#你大爷
obj2=Base("apple")
print(obj2.name)
#apple
#8.看代码写结果
class StackConfig(object):
    def __init__(self,num):
        self.num=num

    def run(self):
        self()

    def __call__(self, *args, **kwargs):
        print(self.num)

class RoleConfig(StackConfig):
    def __call__(self, *args, **kwargs):
        print(666)

    def __getitem__(self, item):
        return self.num[item]

v1=RoleConfig("apple")
v2=StackConfig("pear")

print(v1[1])
#p

7.8约束

常出现在源码中,某个类继承父类,父类中的一个方法中有raise NotImplementedError() 抛出异常

意味着继承父类的约束类中必须写send方法,如果不写,则调用的时候就会输出报错 NotImplementedError

#约束
class Interface(object):
    def send(self):
        #raise Exception()  #抛出异常
        raise NotImplementedError()  #一旦继承Interface,python在调用send方法时候发现没有会报错,但是其他语言中只要类中没有send方法就会报错
        
class  Foo(Interface):
    def send(self):
        print(123)

class Base(Interface):
    def send(self):
        print("继承约束以后一定要写上继承类中的方法")

7.9反射

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

  • getattr(对象,“字符串”) 根据字符串的形式去对象中获取对象的成员
  • hasattr(对象,“字符串”) 根据字符串的形式去对象中判断是否有该成员
  • setattr(对象,“变量”,“值”) 根据变量的形式去对象中设置对象的值
  • delattr(对象,“变量”) 根据变量的形式去对象中删除成员
#反射:根据字符串的形式去某个对象中操作他的成员
class Foo(object):
    def __init__(self,name):
        self.name=name

obj=Foo("pear")
v1=getattr(obj,"name")  #等价于v1=obj.name
print(v1)  #pear

setattr(obj,"name","apple")  #等价于obj.name="apple"
print(obj.name)  #apple
class Foo(object):
    def login(self):
        print("登录")

obj=Foo()
method_name=getattr(obj,"login")
method_name()  #等价于obj.login()

func_name=input("请输入方法名:")  #login
getattr(obj,func_name)()

注意:python一切皆对象(广义)

故反射不仅仅是对类中的对象进行操作,实际上也可以对包中的py文件,py文件中的类等一级级的找到对象进行操作

绑定方法要创建对象,根据对象再进行获取,不然绑定方法中的self不能传到

以后想要通过字符串的形式操作其内部成员都可以通过反射的机制实现

补充:

#from utils  import redis
#用字符串的形式导入模块
import importlib
redis=importlib.import_module("utils.redis") #import_module会根据字符串导入模块

#redis.func()
#用字符串的形式去对象(模块)中找到他的成员
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_classes=[
    "utils.redis.Redis",
    "utils.mysql.MYSQL",
]

for path in middleware_classes:
    module_path,class_name=path.rsplit(".",maxsplit=1)
    module_object=importlib.import_module(module_path)
    cls=getattr(module_object,class_name)  #获取到redis中的Redis类
    obj=cls()
    obj.connect()  #找到对象中的方法执行
#反射示例
class Cloud(object):
    def upload(self):
        pass

    def download(self):
        pass

    def run(self):
        #用户只能输入
        # up|C:/xxx/xxx.zip
        # down|xxx.py
        value=input("请输入用户要干什么?")
        action=value.split("|")[0]
        #方法一 :if判断

        # 方法二:构造与函数名对应的字典
        # method_dict={"up":self.upload,"down":self.download}
        # method=method_dict.get(action)
        # method()

        #方法三:反射
        flag=hasattr(self,action)
        print(flag)
        method=getattr(self,action) #用户只能输入upload或者download
        method()
        #method=getattr(self,action,None) #推荐,性能要比hasattr要好
        #method()

obj=Cloud()
obj.run()

实际应用见python-day23作业8

7.10单例模式

class Foo():
    pass

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

class Foo(object):

    def __new__(cls, *args, **kwargs):
        global instance
        if instance:
            return instance  #当对象已经创建就直接返回第一次创建的对象
        instance=object.__new__(cls)  #第一次才会创建对象
        return instance

obj1=Foo()
obj2=Foo()
print(obj1,obj2)  #不管实例化多少次,用的都是第一次创建的对象
#简化
class Foo(object):
    instance = None

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

obj1=Foo()
obj2=Foo()
print(obj1,obj2)

单例模式标准

class Singleton(object):
    instance=None
    def __new__(cls, *args, **kwargs):  #cls代指当前的类
        if not cls.instance:
            cls.instance=object.__new__(cls)
        return cls.instance
#不是最终,需要加锁,为了支持多线程
#模块导入构造单例模式
"""
#jd.py
class Foo():
	pass

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

补充:

class A:
    @staticmethod
    def func():
        print(123)

#方法一:
#getattr(A,"func1",None)()  #TypeError: 'NoneType' object is not callable

#方法二:
if hasattr(A,"func"):
    getattr(A,"func")()


import jd
import sys
print(jd)
print(sys.modules["jd"])  #sys.modules是一个字典,里面包括导入的所有文件名
print(jd is sys.modules["jd"])  #True
print(getattr(sys.modules["jd"],"n1"))  #666

a=888
#想要取当前文件的一个变量也可以这样
print(getattr(sys.modules["__main__"],"a"))  #888
#如果当前文件不是执行的文件
print(getattr(sys.modules[__name__],"a")) #888
posted @ 2020-11-02 17:48  wrrr  阅读(48)  评论(0编辑  收藏  举报