• 第七章 面向对象


    7.1 面向对象基础

    面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)

    优点和应用场景

    1. 业务功能较多时,通过面向对象归类
    2. 数据封装(创建字典存储数据)
    3. 游戏示例:创建一些角色,并根据角色需要再创建任务
    • 封装思想:将同一类的函数封装到同一个py文件中,以后方便使用
    • 面向对象:将同一类的函数封装到同一个class中,以后方便使用
    • 对象名:命名首字母大写

    Note1(1)

    • 函数式的应用场景 --> 各个函数之间是独立且无共用的数据

    1. 基础概念

    • :具有相同方法和属性的一类事物
    • 对象实例:一个拥有具体属性值和动作的具体个体
    • 实例化:从一个类得到一个具体对象的过程
    # 定义一个类,Account
    class Account:
      	# 方法, 哪个对象调用方法,其就是self
      	def login(self,name):
        		print(123)
            return 666
        def logout(self):
        		pass
    # 调用类中的方法 
    x = Account()                
    # 实例化(创建)Account类的对象,开辟一块内存
    val = x.login('henry')        # 使用对象调用class中的方法
    print(val)
    

    Note2(2)

    • 应用场景:用于很多函数,需要对函数进行归类和划分(封装)
    • self:哪个对象操作,self代表类的实例,而非类

    2. 对象的封装

    • 作用:存储一些值,将数据封装到对象,方便使用
    • 属性调用对象.属性名进行数据的调用
    • 广义封装:类中成员
    • 狭义封装:私有成员:_类名__名字:命名
    class File:
      def read(self):
        with open(self.path, mode='r', encoding='utf-8') as f:
          data = f.read()
      def write(self, content):
        with open(self.path, mode='a', encoding='utf-8') as f:
          data = f.write()
    
    obj = File()  					                        # 创建对象,并使用   
    obj.path = 'test.txt'                           # 往obj对象中写入一个私有对象
    obj.write(content)
    # 定义私有属性,私有属性在类外部无法直接进行访问
    obj2 = File('info.txt')
    obj2.write(content)
    
    class Person:
    # __init__初始化方法(构造方法),给对象内部做初始化
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.gender = gender
        def show(self):
          	temp = 'i am %s, age:%s, gender:%s ' % (self.name, self.age, self.gender)
          print(temp)
    # 类(),会执行__init__         
    obj = Person('henry', 19, 'male') 
    obj.show()
    
    obj2 = Person('echo', 19, 'female')
    obj2.show()
    

    Note3(3)

    1. 函数和数据的封装
      • 如果写代码时,函数较多,可以将函数归类,并放入同一类中。(函数的封装)
      • 函数如果有一个反复使用的公共值,则可以封装到类中(数据的封装)
    2. 面向对象三大特性:封装、继承、多态
    3. 执行类中的方法时,需要通过self间接调用被封装的内容

    2.1 查看对象的类

    # 类有一个名为 __init__() 的构造方法,该方法在类实例化时会自动调用,一般通过object类进行格式化
    # 类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
    
    # self.__class__:查看实例所在的类
    class Test:
        def prt(self):
            print(self)
            print(self.__class__)
    t = Test()
    t.prt()
    

    2.2 类的方法

    在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。self 的名字并不是规定死的,也可以使用 this,但是最好还是按照约定是用 self

    类的私有方法__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods

    2.3 示例

    # 循环让用户输入:用户名,密码,邮箱,输入完成后在打印
    class Person():
      def __init__(self, user, pwd, email):
        self.username = user
        self.password = pwd
        self.email = email
      def info(self):
        return  temp = 'i am %s, pwd:%s, email:%s ' % (self.username, self.password, self.email,)
    
    USER_LIST = []
    while 1:
      user = input('please input user name: ')
      pwd = input('please input user pwd: ')
      email = input('please input user email: ')
      p = Person(user, pwd, email)
      USER_LIST.append(p)
    
    for i in USER_LIST:
     	data = i.info()
      print(i)
    

    3. 继承

    场景:多个类中,如果有公共的方法可以放到基类中,增加代码的重用性。

    继承:可以对基类中的方法进行覆写

    3.1 继承的查找方法

    # 父类(基类)
    class Base:
      def f1(self):
        pass
      
    # 单继承,子类,Foo类继承Base类 (派生类)
    class Foo(Base):
      def f2(self):
        pass
    # 创建了一个子类对象
    obj = Foo()
    # 执行对象.方法时,优先在自己类中找,没有则找其父类
    obj.f2()    
    obj.f1()
    
    # 创建了一个父类对象
    obj = Base()
    obj.f1()
    obj.f2()   # 会报错
    

    继承关系中的查找方法

    1. self 指的是哪个对象
    2. 当类是经典类时,多继承情况下,会按照深度优先方式查找
    3. 当类是新式类时,多继承情况下,会按照广度优先方式查找

    3.2 经典类和新式类

    • 新式类:继承object,super,多继承(广度优先c3),具有__mro__方法
      • super(新式类支持,遵循mro顺序)
      • Python的每一个有父类的类都有一个与方法解析顺序相关的特殊属性:__mro__, 它是一个tuple, 装着方法解析时的对象查找顺序: 越靠前的优先级越高。
    • 经典类:py2不继承object,无super/mro , 深度优先
    • 从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
    class D(object):
        def bar(self):
            print 'D.bar'
            
    class C(D):
        def bar(self):
            print 'C.bar'
    
    class B(D):
    
        def bar(self):
            print 'B.bar'
    
    class A(B, C):
    
        def bar(self):
            print 'A.bar'
            
    a = A()
    # 执行bar方法时
    # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
    # 所以,查找顺序:A --> B --> C --> D
    # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
    a.bar()
    

    4. 多态(多种形态/类型)

    多态:一个类变现出来的多种状态—>多个类表现出相似的状态。

    Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,Python崇尚“鸭子类型”。list,tuple,python的多态是通过鸭子类型实现的

    # 多态,鸭子模型
    def func(arg):                   # 多种类型,很多事物
      v = arg[-1]		                 # 必须具有此方法,呱呱叫
      print(v)
    
    # 对于一个函数,python对参数类型不会限制,传入参数时可以是各种类型,在函数中如果有例如:arg.append方法,就会对传入类型进行限制。
    # 这就是鸭子模型,类似于上述的函数,我们认为只要能呱呱叫的就是鸭子,只要有append方法,就是我们想要的类型
    

    5. 类的专有方法

    • __init__ : 初始化,在生成对象时调用
    • __del__ : 析构函数,释放对象时使用
    • __repr__ : 打印,转换
    • __setitem__ : 按照索引赋值
    • __getitem__: 按照索引获取值
    • __len__: 获得长度
    • __cmp__: 比较运算
    • __call__: 函数调用
    • __add__: 加运算
    • __sub__: 减运算
    • __mul__: 乘运算
    • __truediv__: 除运算
    • __mod__: 求余运算
    • __pow__: 乘方

    6. 运算符重载

    Python同样支持运算符重载,我们可以对类的专有方法进行重载

    class Vector:
       def __init__(self, a, b):
          self.a = a
          self.b = b
     
       def __str__(self):
          return 'Vector (%d, %d)' % (self.a, self.b)
       
       def __add__(self,other):
          return Vector(self.a + other.a, self.b + other.b)
     
    v1 = Vector(2,10)
    v2 = Vector(5,-2)
    print (v1 + v2)
    

    7.2 类成员(6)

    • 实例化对象时,对在对象中存储类对象指针,指向其类

    1. 类变量(静态字段/属性)

    • 写在类的下一级,和方法同级
    • 访问:类.变量名/ 对象.变量名
    • 继承关系中,自己类中没有的变量可以去基类中找
    • 只能赋值、修改自己的变量

    对象成员实例变量(字段)

    Note:属于谁的只允许谁去取,python允许对象去其类中取变量

    2. 方法

    2.1 绑定/普通方法

    1. 定义:必须有self参数
    2. 执行:先创建对象,由 对象.方法 调用

    2.2 静态方法

    1. 定义:@staticmethod, 参数无限制
    2. 执行:类.静态方法名() / python对象也可以调用
    class Foo:
      	def __init__(self):
        	self.name = 123
        
        def func(self, a, b):
          	print(self.name, a, b)
    	# python内部装饰器
        @staticmethod
        def f():
          	print(1,2)
    
    Foo.f()
    obj = Foo()
    obj.func(1, 2)
    obj.f()
    

    2.3 类方法

    1. 定义:@classmethod, 必须有cls参数,当前类
    2. 执行:类.类方法() / python对象也可以调用
    class Foo:
      	def __init__(self):
        		self.name = 123
        
        def func(self, a, b):
          	print(self.name, a, b)
    # python内部装饰器
        @classmethod
        def f(cls, a, b):
          	print(a, b)
    
    Foo.f(1, 2)
    obj.f(1, 2)   # 不推荐
    

    3. 属性

    1. 定义:@property 只能有一个参数self
    2. 执行:对象.属性名( 无括号
    class Foo:
      	@property
      	def func(self):
            print(123)
            print(666)
           
    obj = Foo()
    ret = obj.func
    print(ret)
    
    # 示例:属性
    class Page:
    		def __init__(self, total_count, current_page, per_page = 10):
            self.total_count = total_count
            self.current_page = current_page
            self.per_page = per_page
        
        @proporty
        def start_index(self):
          	return(self.current_page -1 ) * self.per_page
        @property
        def end_index(self):
          	returno self.current_page * self.per_page_count
             
    USER_LIST = []
    for i in range(321):
      	USER_LIST.append('henry-%s' % (i,))
    
    # 请实现分页
    current_page = int(input('请输入要查看的页码:'))
    p = Page(321, current_page)
    data_list = USER_LIST[p.start_index:p.end_index]
    for i in data_list:
      	print(i)
    

    4. 成员修饰符

    • 公有:所有位置都能访问
    • 私有:__开头(只有自己才能访问)
    class Foo:
      	def __init__(self, name):
          	self.__name = name    
        def func(self):
          	print(self.name)        
    obj = Foo('alex')
    print(obj.__name)		# 会报错
    obj.func()          # 可以访问
    
    class Foo:
      	__x = 1 
        @staticmethod
        def func():
          	print(Foo.__x)
    obj = Foo()  
    print(Foo.__x)       # 会报错
    print(obj._Foo__x)   # 强制访问私有成员
    

    7.3 特殊方法

    • 以双下划线开头的 __foo 代表类的私有成员,以双下划线开头和结尾的 _foo_ 代表 Python 里特殊方法专用的标识,如 __init__()代表类的构造函数。

    • 特殊方法/魔术方法/内置方法/双下方法

    • 特殊成员(方法)__init__

    • type / isinstance / issubclass / super

    • 异常处理

    1. 类和对象的关系:对象是类的一个实例
    2. self:本质就是一个形式参数,对象调用方法时,python内部会将该对象传给这个参数
    3. 类/方法/对像都可以当作变量或嵌套到其他类中
    class School(object):
      	def __init__(self,title):
          self.title = title
        def rename(self):
          pass
       
    class Course(object):
      	def __init__(self, name, school_obj):
          self.name = name
          self.school = school_obj
        def reset_price(self):
          pass
          
    class Classes(object):
      	def __init__(self,cname, course_obj):
          self.cname = cname
          self.course = course_obj
        def sk(self):
          pass
    
    s1 = School('北京')
    c1 = Course('Python', s1)
    cl1 = Classes('全栈1期', c1)
    

    1. 嵌套

    • 函数:参数可以是任意类型
    • dict:函数、类和对像都可以作为字典的key, 即都是可hash的
    • 继承的查找关系
    # 示例1
    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.regisetr(obj)
    
    # 示例2
    class StarkConfig(object):
      def __init__(self, name, age):
        self.name = name
        self.age = aeg
        
    class AdminSite(object):
      def __init__(self):
        self.data_list = []
        self.sk = None
        
      def set_sk(self, arg=StarkConfig):
        self.sk =arg
         
    site = AdminSite()
    site.set_sk(StarkConfig)
    site.sk('henry', 19)
    
    # 示例3
    class StarkConfig(object):
      list_display = 'henry'
      
      def changelist(self):
        print(self.list_display)
        
    class UserConfig(StarkConfig):
      list_display = 'echo'
      
      
    class AdminSite(object):
      def __init__(self):
        self._register = {}
        
      def registry(self, key, arg=StarkConfig):
        self._register[key] = arg
      
      def run(self):
        for key, val in self._register.items():
          obj = val()
          obj.changelist()
        
    site = AdminSite()
    site.registry(1)
    site.registry(2, StackConfig)
    site.registry(3, UserConfig)     # 易错点 echo
    site.run()
    

    2. 特殊成员

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

    2.1 _init_(初始化方法)

    # 填充数据,一般称为初始化
    class Foo:
      """
      此类的作用
      """
      def __init__(self):
      """
      初始化方法
      """
        pass
    

    2.2 _new_(构造方法)

    Note

    1. new方法是静态方法,在使用__new__方法时,构造的对象值为 new 方法的返回值
    2. 创建的是一块内存和指针
    3. 返回一个对象
    #  __new__ 创建一个空对象
    # 通过 __init__ 初始化对像
    class Foo(object):
      def __new__(cls, *args, **kwargs):   # 在 __init__ 之前
        return 'henry'/ object.__new__(cls)
      
      obj = Foo()
      print(obj)
    

    2.3 _call_

    # 对象() 会执行类中的 __call__ 方法
    class Foo:
        def __init__(self):
            pass
        def __call__(self, *args, **kwargs):
            print('哈哈,你变成我了吧')
    
    Foo()()
    # 第三方模块。写一个网站,用户只要来访问,就自动找到第三个参数并执行
    make_server('ip', port, Foo())
    

    2.4 _getitem_ _setitem_ _delitem_

    obj = dict()
    obj['k1'] = 123
    class Foo(object):
      def __setitem__(self, key, values):
        print(key, value)
      def __getitem__(self, item):
        return item + 'uuu'
      def __delitem__(self, key):
       	print(key)
     
    obj1 = Foo()
    obj1['k1'] = 123  # 内部会自动调用__setitem__方法
    obj1['xxx']       # 内部会自动调用__getitem__方法
    del obj1['ttt']   # 内部会自动调用__delitem__方法
    

    2.5 _str_

    # 只有在打印时,会自动调用此方法,并将返回值显示出来
    # type 查看
    class Foo:
        def __str__(self):
            print('变样是不是不认识我了')
            return 'henry'
          
    obj = Foo()
    print(obj)
    

    2.6 _dict_

    作用: 查看对象中有哪些变量

    class Foo(object):
      def __init__(self, name, age, email):
        self.name = name
        self.age = age
        self.email = emial
    
    obj = Foo('henry', 19, '123@qq.com')
    val = obj.__dict__ 			   # 去对象中找到所有变量并将其转换为字典
    print(val) 
    

    2.7 _enter_(上下文管理

    作用:使用with语法时,需要

    class Foo(object):
    	def __enter__(self):
        	self.x = open('a.txt', mode='a', encoding='utf-8')
        	return self.x
      def __exit__(self, exe_type, exc_val, exc_tb):
        self.x.close()
      
    with Foo() as f:   					# 需要 __enter__ 和 __exit__ 方法
      f.write('henry')
      f.write('echo')
    

    2.8 _add_ 两个对像相加

    class Foo(object):
      def __init__(self, v):
        self.v = v
        
    	def __add__(self, other):
        return self.v + other.v
    
    obj1 = Foo()
    obj2 = Foo()
    val = obj1 + obj2    # obj1触发,把obj1传给self
    

    2.9 _iter_

    # 可迭代对象
    class Foo:
      	def __iter__(self):
        		return iter([1, 2, 3, 4])
      
    obj = Foo()
    # 示例2
    class Foo:
      	def __iter__(self):
            yield 1
            yield 2
            ...
     
    obj = Foo()
    

    2.10 _repr_

    • 当对象处于一个list中时,调用该方法
    class Studnet:
        def __init__(self, name):
            self.name = name
        # 面向用户
        def __str__(self):
            return self.name
        # 内部程序
        def __repr__(self):
            return '<{}>'.format(self.name)
    class Classes:
        def __init__(self):
            self.students = []
    s1 = Studnet('henry')
    s2 = Studnet('echo')
    # henry echo,优先调用str方法,
    print(s1,s2)
    c = Classes()
    c.students.append(s1)
    c.students.append(s2)
    # [<henry>, <echo>],调用__repr__方法
    print(c.students)
    # henry echo,调用__str__方法
    for i in c.students:
        print(i)
    

    2.11 其他

    # 类的
    cls.__dict__   	    # 打印出 cls 类的所有属性和方法,结果为一个字典  
    cls.__bases__      # 类的基类  
    cls.__doc__        # 类的docstring  
    cls.__name__       # 类的名字  
    cls.__module__     # 类所在模块,如果是主文件,就是__main__  
    # 对象的
    obj.__class__      # 类的类型<class '__main__.类名'>  
    obj.__module__     # 实例类型所在模块  
    obj.__dict__       # 对象的字典,存储所有实例成员信息  
    

    3. 内置函数

    3.1 type(对象)

    class Foo(object):
      pass
    
    obj = Foo()
    print('obj是Foo的对象,开心吧') if type(obj) == Foo else print('哪凉快呆哪去')
    

    3.2 issubclass(子类,基类)

    # 可以多级继承
    class Base(object):
        pass
    class Bar(Base):
        pass
    class Foo(Bar):
        pass
    print(issubclass(Foo, Base))
    

    3.3 isinstance(obj, Foo)

    # 判断某个对象是否时 某个类 或 基类 的实例(对象)
    class Base(object):
        pass
    class Foo(Base):
        pass
    obj = Foo()
    print(isinstance(obj, Foo))
    print(isinstance(obj, Base))
    

    4. super()

    # super().func(),根据 self所属类的继承关系进行查找,默认找到第一个就停止
    class Bar(object):
      def func(self):
          print('bar.func')
          return 123
    class Base(Bar):
     	 def func(self):
          super().func()
          print('bar.func')
          return 123
      
    class Foo(Base):
      def func(self):
        v = super().func()
        print('foo.func', v)
      
    obj = Foo()
    obj.func()
    

    7.4 接口类和抽象类(约束)&反射

    1. 扩展

    # 会打印 hello
    # 类里的成员会加载,代码会执行
    # 函数只有在调用时执行
    class Foo(object):
      print('hello')
      def func(self):
        pass
    
    # 类的嵌套
    class Foo(object):
        x = 1
        def func(self):
          	pass
    
        class Meta(object):
            y = 123
            print('hello')
            def show(self):
              	print(y.self)
    

    2. 可迭代对象

    • 表象:可被for循环的对象
    • 作用:组合搜索
    • 可迭代对象:在类中实现__iter__方法并返回迭代器/生成器
    # 可迭代对象示例1
    class Foo:
      	def __iter__(self):
        		return iter([1, 2, 3, 4])
      
    obj = Foo()
    # 示例2
    class Foo:
      	def __iter__(self):
            yield 1
            yield 2
            ...''
     
    obj = Foo()
    

    3. 抽象类/接口类(约束 源码)

    # python的约束,易错点
    # 约束子类中必须要有send方法,如果没有则会抛出:NotImplementedError
    class Interface(object):
      def send(self):
        raise NotImplementedError()
    
    class Foo(Interface):
      def send(self):
        pass
    
    class Base(Interface): 
      def func(arg):
        arg.send(arg)
    
    # 应用场景示例
    class BaseMassage(object):
      def send(self):
        raise NotImplementedError('子类中必须有send方法')
        
    class Msg(BaseMassage):
      def send(self):
        print('发送短信')
      
    class Email(BaseMassage):
      def send(self):
        print('发送邮件')
      
    class Wechat(BaseMassage):
    	def send(self):
        print('发送微信')
      
    class DingDing(BaseMassage):
    	def send(self):
    		pass
    
    obj = Email()
    obj.send()
    

    4. 反射

    反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

    反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

    • getattr('对象', 字符串):根据字符串的形式,去某个对象中获取其成员。
    • hasattr('对象', 字符串):根据字符串的形式,去某个对象中判断是否有该成员。
    • setattr('对象', '变量',值):根据字符串的形式,去某个对象中设置成员。
    • delatttr('对象', '变量'):根据字符串的形式,去某个对象中删除成员。
    # getattr示例
    class Foo(object):
      def __init__(self, name):
        self.name = name
        
    obj = Foo('alex')
    obj.name
    v1 = getattr(obj, 'name')
    # setattr示例
    obj.name = 'eric'
    setattr(obj, 'name', 'eric')
    
    • getattr:反射当前文件内容
    # 反射当前文件内容
    import sys
    getattr(sys.modules[__name__], 'ab')
    # 通过对象获取、示例变量、绑定方法
    # 通过类来获取类变量、类方法、静态方法
    # 通过模块名获取模块中的任意变量(普通变量、函数、类)
    # 通过本文件反射任意变量
    
    # 应用示例
    class Foo(object):
       def login(self):
          pass
        
       def regiseter(self):
          pass
      
    obj = Foo()
    func_name = input('please input method name: ')
    # 获取方法
    getattr(obj, func_name)()
    
    # setattr 示例
    class Foo(object):
      pass
    
    obj = Foo()
    setattr(obj, 'k1', 123)
    print(obj.k1)
    
    # delattr 示例
    class Foo(object):
      pass
    
    obj = Foo()
    obj.k1 = 999
    delattr(obj, 'k1')
    print(obj.k1)
    

    Note(2)

    • python中一切皆对象(py文件,包,类,对象),可以通过getattr获取
    • 通过字符串操作内部成员都可以通过反射的机制实现
    import x
    
    v = x.NUM
    # 等价于
    v = getattr(x, 'NUM')
    print(v)
    
    v = getattr(x, 'func')
    v()
    
    v = getattr(x, 'Foo')
    val = v()
    val.x
    

    示例:

    # 浏览器两类行为
    # way1: 输入地址+回车
    get....
    # way2: 表单(输入框+按键)
    post....
    
    # 浏览器都会有get,post,dispatch方法
    class View(object):
      def get(self):
        pass 
      def Post(self):
        pass
      def Dispatch(self):  # 请求第一步来这,在进行分发
        pass
    
    # 推荐使用性能较好
    class Foo(object):
      def post(self):
        pass
    
    # 方式1
    if hasattr(obj, 'get'):
      getattr(obj, 'get')
    # 方式2:推荐使用
    v = getattr(obj, 'get', None)
    print(v)
    

    5. setarrt和getatrr

    应用场景

    1. django中间件:
      • 注册中间件用的是字符串,django1.10之前(MIDDLEWAER_CLASSES),之后MIDDLEWAER
        • 基于反射实现,process_requests...(5个)
    2. flask 上下文管理:LocalProxy对象
    getattr(obj, 'args')()
    # 高级用法
    flask 上下文管理:LocalProxy对象
    

    7.5 单例&项目结构

    1. 单例模式

    1.1 单例

    场景数据库连接和数据库连接池(数据一致时)

    设计模式:23种设计模式

    class Foo(object):
      pass 
    # 每实例化一次,就创建一个新对象,内存地址 不一样
    obj1 = Foo()
    obj2 = Foo()
    
    # 单例(Singleton)模式,无论是实例化多少次,都用第一次创建的那个对象,内存地址一样
    class Singleton(object):
      instance = None
      def __new__(cls, *args, **kwargs):
        if not cls.instance:
        	cls.instance = object.__new__(cls)
        return cls.instance
     
    obj1 = Singleton()      # 内存地址一致
    obj2 = Singleton()
    

    1.2 标准

    # 需要加锁,多线程,并发
    
    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')   # 内存地址一致
    obj2 = FileHelper('x')
    

    2. 模块导入

    # 导入模块,只是保留模块内存
    # 思考角度:函数名不能重复、内存溢出
    from jd import n1
    
    # 多次导入,模块只会加载一次,即使模块中包含其他模块
    import 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)
    

    3. 项目开发规范

    1. binstart
    2. config:配置文件settings
    3. src:业务逻辑
    4. db:数据文件
    5. lib:扩展模块
    6. log:日志文件

    3.1 脚本

    import os
    import re
    import datetime
    
    import xlrd
    import requests
    

    3.2 单可执行文件

    # app(程序入口)/src(业务相关)/lib(公共的类库)/db(文件)/config(配置)
    app.py 越简单越好,少于10行
    

    3.3 多可执行文件

    # app(程序入口)/src(业务相关)/lib(公共的类库)/db(文件)/config(配置)
    # bin(多个可执行文件例如:student.py,teacher.py,admin.py)
    # log	(存储日志文件)
    # seetings(BASE_PATH,LOG_FILE_NAME...)
    path = sys.path.os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(path)
    

    项目目录结构

    7.6 MethodType和FunctionType

    from types import MethodType, FunctionType
    
    def fun():
        pass
    
    print(isinstance(func, FunctionType))  			 # True
    print(isinstance(list.append(), MethodType)) 	 # True
    
    
    class Foo:
        def fun(self):
            pass
    
    obj = Foo()
    obj.fun()					# 方法
    Foo.fun(123)				# 函数
    # 通过对象调用是方法,通过类调用时函数
    
  • 相关阅读:
    Win7系统中打开exe 无反应
    IE 浏览器主页劫持 如何修复
    win10 airpods显示已配对,但就是连不上怎么办?
    tp5 layui 渲染 时间戳转换为日期时间格式
    为什么要设置 繁琐的密码
    美食摄影 – 明确目的
    MsMpEng.exe进程停止删除或弹出设备,导致移动硬盘无法正常弹出,怎么办?
    单抗热门靶点 | VEGF | TNF-α | CD20 | HER2 | PD-1 | IL-6R | CD47
    EZH2 | Ezh2 | 组蛋白甲基化酶/组蛋白甲基转移酶
    宇宙微波背景辐射 | 著名实验
  • 原文地址:https://www.cnblogs.com/henryw/p/11681388.html
Copyright © 2020-2023  润新知