python 函数、类

1、面向对象(oop)

面向过程:面向处理,更多的是注重计算每一个步骤

面向对象:认为万事万物皆对象,程序是由多个对象协作共同完成的,能更好的直接代码复用和设计复用

问题->面向对象分析(OOA)->发现对象->类->用类实例化对象->对象协作完成功能
2、类和对象
  • 类:具有相同特征和行为的对象的集合

  • 对象:具有某些功能和特征的具体事物的抽象,是类的实例

  • 类定义必须使用关键字class,类名一般用大驼峰命名规则:每个单词首字母大写,其他小写

    • class MyDog(object): #python3默认继承自object,可以class Mydog:

      ​ 函数体

3、类
class MyDOg(object):
	num = 100    
	#类属性   可以通过类名访问,也可以被对象访问.如果成员属性名和类属性名冲突,优先访问成员属性,成员属性屏蔽类属性.
	
	def __init__(self,name,age,sex)   #构造函数,一般用于完成对象数据成员设置初值或进行其他必要的		self.name = name	 #初始化工作,不会创建对象,如未提供,python会提供一个默认的构造函数   
		#成员属性,描述对象的静态特征,其实就是一个变量,作用域属于类。python中成员属性可以在构造函数中添加。成员属性属于对象,每个对象的成员属性的值都不同。
		self.__age =age # 私有变量  外界不能直接对象.__age调用了,只能通过调用对象的公用方法来访问。
		self.__sex =sex  #私有变量 

	def bark(self):
		print('汪汪')      #成员公有方法,作用域在类内,成员方法的第一个参数必须是self,代表调用当前对象,只有对象可以调用
	def eat(self):
		print('吃骨头')    #成员公有方法  
    
    #定义一个公开方法,间接访问私有变量    外界通过对象.get_age()
    def get_age(self):
    	return self.__age   
    
    #定义一个公开方法,间接设置私有变量   外界通过对象.set_age()
    def set_age(self,age):
    	self.__age =age
    
    
#对于私有属性的访问,使用公开方法间接访问的方法太麻烦,python提供了一种便捷语法,属性装饰器,通过属性装饰器,可以很方便的对私有属性访问,属性装饰器可以把方法属性化
    @property              #外界使用 对象.sex
    def sex(self):
    	return self.__sex
     
    @sex.setter   		#外界使用  对象.sex =sex
    def sex(self,sex)
    	self.sex = sex
    	
    	
    	
   #定义一个成员私有方法(双下划线)   
   	def __sleep(self):     
   		print('这是我的地盘')
   	 #外界通过,对象.__sleep()会报错,该方法为私有方法,只能在当前类中被成员公有方法调用。外界通过公有方法获取
   	
   	#定义一个类方法
   	@classmethod
   	def c1(cls):
   		rerurn('我是类方法')
   	
   #定义一个静态方法
   @staticmethod
   def show():
   		return time.time()
  
    
	
	def __del__(self):   #析构函数,用来释放对象占用的资源,如果未提供,python将会提供一个默认的析构函数进行必要的清理工作。
	def __str__(self):
		return self.name
	def __repr__(self):
		return self.__str__()

#将对象转化为字符串,凡是涉及对象向字符串转化的都会调用(`print,str`),返回值是字符串.
#__repr__作用同__str__,不过是给解释器看的
	
		
		
dog = MyDog('泰迪')  #对象的创建,对象的实例化 ,定义了一个 类 类型的变量
print(dog.__dict__)  #__dict__属性可以查看实例属性
print(dog.__class__) #查看对象的类名

#属性获取
print(dog.name)   #成员属性的调用:对象。成员属性
print(dog.get_age())   #获取私有属性age的值go
dog.set_age(10)        #设置私有属性的值
print(dog.sex)         #用了@property方法后获取属性值
dog.sex = sex			#用了@sex.setter方法后修改属性值


dog.bark()  #成员方法的调用
dog.eat().bark() #成员方法的连贯调用

  • 属性私有化:如果想让类的内部属性不被外界直接访问,可以在这个属性的前面加两个下划线 ,在Python中,如果一个属性的前面出现两个下划线,就表示这个属性只能在当前类中的方法中访问,不能通过对象直接访问,这个变量就被称为私有变量
单下划线:_age    #受保护的,可以访问的,约定俗称,不要使用它
双下划线:__age   #私有的
两边都有双下划线: __age__  #系统内置变量
  • 属性装饰器:对于私有属性的访问,使用公开方法间接访问的方法太麻烦,python提供了一种便捷语法,属性装饰器,通过属性装饰器,可以很方便的对私有属性进访问,属性装饰器可以把方法属性化。

    描述器:描述器在监视特定属性的时候很有用,其只在新式类中起作用,种类至少实现了3个特殊的方法__get__, __set__, __delete__中的一个。
    如果一个对象同时定义了 get() 和 set(),它叫做资料描述器(data descriptor)。仅定义了 get() 的描述器叫非资料描述器
    描述器在属性访问时被自动调用。
    调用优先级:
    资料描述器 -> 实例字典 -> 非资料描述器
    
  • 成员私有方法(属于对象)

    • 如果以对一个方法的名字前面加双下划线__,声明该方法为私有方法,只能在当前类中被成员公有方法调用,在外界不能通过对象调用,这就是私有方法。
  • 类方法

    • 使用了装饰器@classmethod,第一个参数是当前类对象,该参数一般约定为cls,通过它来传递类的属性和方法(不能传实例的属性和方法)
    • 调用:实例和类都可以调用
  • 静态方法

    • 使用装饰器@staticmethod。参数没有self和cls,函数体也没有类和对象的属性和方法,就是一个独立的、单纯的函数放在类里了,仅仅托管于某个类的命名空间。
    • 调用:实例对象和类对象都可以调用
    • 其实,我们可以在类外面写一个同样的函数来做这些事,但是这样做就打乱了逻辑关系,也会导致以后代码维护困难
  • 实例成员的动态绑定(了解)

    • 实例的属性和方法都可以动态绑定,也就是在程序运行期间可以给程序增加功能。
    • 给实例动态添加的属性只属于这个实例,其他对象没有该属性
    • 使用__slot__限制属性的动态绑定
    • 给类绑定成员方法,所有对象都可以使用
4、类的三大特性
  • 封装

    • 隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读取和修改的访问级别。
    • 类本身就是一种封装,通过类将数据(属性)和行为(方法)相结合,提供外部接口,以特定的权限来使用类的成员。成员私有化是实现封装的手段。
  • 继承

    • 所谓继承就是使现有的类无需编码就可以拥有基类的方法和属性

    • 被继承的类称为父类,基类,超类,继承的类称之为子类,派生类。

    • 继承的优点:可以简化代码,减少冗余度

      ​ 提高了代码的可维护性,扩展性

      ​ 提高了代码的安全性

    • 单继承:就是只继承一个父类,子类会继承父类所有的属性和方法

      • 继承自父类的私有成员在子类中无法直接使用,要用原父类的方法调用。因为私有方法,它现在已经不在父类中了,在子类

      • 子类方法和父类方法重名,通过子类对象调用的是子类方法(重写覆盖)

        构造函数的继承
        class Mydog(Animal)
        	def __init__(self,name,age,gender)
        		父类名.__init__(self,name,age)
        		self.gender = gender
        		#或者
        		super(Mydog,self).__init__(name,age)  #实参列表不要带self
        		self.gender =gender
        		#或者
        		super().__init__(name,age)
        		self.gender =gender
        
    • 多继承:继承自多个父类,如果两个父类中有同名方法,调用的前面父类的方法,前面父类的方法会遮蔽后面的

      • class MyDog(Animal,Pet):
  • 多态

    • 多态指的是根据对象或类的不同而表现出不同的行为,
    • 不同的子类对象调用相同的父类方法,产生了不同的执行结果
    • 多态好处:
      • ​ 提高了方法调用的灵活性
  • 鸭子类型: 鸭子类型就是不关系对象的类型,只关心对象的行为

    • 如果一只鸟 走起来像鸭子,叫起来也像鸭子,那么这只鸟就可以被称为鸭子
    • 鸭子类型是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。
    • 比如如果一个对象实现了__getitem__方法,那python的解释器就会把它当做一个collection,就可以在这个对象上使用切片,获取子项等方法;如果一个对象实现了__iter__next方法,python就会认为它是一个iterator,就可以在这个对象上通过循环来获取各个子项。
5、魔术方法
  • 魔术方法就是一个类的特殊方法,和普通方法唯一的不同时,普通方法需要调用!而魔术方法由系统自动调用。

  • 常用魔术方法

    1.__init__

    初始化魔术方法
    触发时机:初始化对象时触发(不是实例化触发,但是和实例化在一个操作中)
    p1 = Person()
    p1对象   实例化对象p1   p1 实例
    参数:至少有一个self,接收对象
    返回值:无
    作用:初始化对象的成员
    

    2.__new__

    实例化魔术方法  类方法
    触发时机: 在实例化对象时触发
    参数:至少一个cls 接收当前类
    返回值:必须返回一个对象实例
    作用:实例化对象
    注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。
    没事别碰这个魔术方法,先触发__new__才会触发__init__ 
    class Dog:
        def __new__(cls, *args, **kwargs):
            print('new方法在执行')
           // return super().__new__(cls,*args, **kwargs)   #必须通过父类的__new__创建对象
            return object.__new__(cls,*args, **kwargs)
            
        def __init__(self,name,age):
            self.name = name
            self.__age = age
            print('init方法在执行')
    

    3.__del__

    析构魔术方法
    触发时机:当对象没有用(没有任何变量引用)的时候被触发
    参数:一个self 
    返回值:无
    作用:在销毁对象时回收资源
    注意:del不一定会触发当前方法,只有当前对象没有任何变量引用时才会触发
    

    4.__call__

    调用对象的魔术方法
    触发时机:将对象当作函数调用时触发,方式: 对象()
    参数:至少一个self接收对象,其余根据调用时参数决定
    返回值:根据情况而定
    作用:可以将复杂的步骤进行合并操作,减少调用的步骤,方便使用
    注意:无
    

    5.__len__

    触发时机:使用len(对象) 的时候触发
    参数:一个参数self
    返回值:必须是一个整型
    作用:可以设置为检测对象成员个数,但是也可以进行其他任意操作
    注意:返回值必须必须是整数,否则语法报错,另外该要求是格式要求。
    

    6.__str__

    触发时机:使用print(对象)或者str(对象)的时候触发
    参数:一个self接收对象
    返回值:必须是字符串类型
    作用:print(对象时)进行操作,得到字符串,通常用于快捷操作
    注意:无
    

    7.__repr__

    触发时机:在使用repr(对象)的时候触发
    参数:一个self接收对象
    返回值:必须是字符串
    作用:将对象转使用repr化为字符串时使用,也可以用于快捷操作
    

    8.__bool__

    触发时机: 使用bool(对象)的时候触发
    参数:一个self接收对象
    返回值:必须是布尔值
    作用:根据实际情况决定,可以作为快捷方式使用
    注意:仅适合于返回布尔值的操作
    

    9.__format__

    触发时机:使用字符串.format(对象)时候触发
    参数:一个self接收对象,一个参数接收format的{}中的格式,例如:>5
    返回值:必须是字符串
    作用:设置对象可以作为format的参数,并且自定义对象格式化的规则
    注意:无
    

    10.__eq__

    比较运算符重载:__eq__,__ge__,__le__,__gt__,__ne__
    
6、常用内建函数
  • issubclass(sub,sup)

    如果sub是sup的子类,返回True,否则返回False。sub和sup必须是类

  • isinstance(obj,class)

    如果obj是class的对象或子类对象,返回Ture,否则返回False,属性必须是公有的才能判断。

    isinstance与type区别
    	isinstance考虑继承关系,isinstance(对象或子类,父类) True
    	type不考虑继承关系      type(子类对象或子类) = 父类  False				  	
    
  • hasattr(object,name)

判断对象是否具有指定属性(name),有则返回True,否则返回False

  • getattr(object,name[,default])

获取object对象的属性值

  • setattr(object,name)

    设置对象的属性值,属性必须存在

  • callable(object)

    判断一个对象是否可调用

  • dir(obj/class)

    显示类或对象属性、方法等详细信息

  • super(obj,self)

调用父类(超类)的一个方法

7.装饰器
  • 装饰器就是用于拓展原来函数功能的一种函数,在不改变源代码的情况下,动态的添加功能,经常用在插入日志、性能测试。
    写代码要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
    •  封闭:已实现的功能代码块   
    •  开放:对扩展开发
    
  • #无参装饰器
      def decorator(func):
      	print('我被调用了')
      	@wraps(func)         #加不加都可以,减少装饰器带来的一些副作用,如函数名等属性变化
          def wrapper(*args,**kwargs):    
              print('任务开始')
              r=func(*args,**kwargs)
              print('任务完成')
          return  wrapper
    
      @decorator
      def f1():
          print(123)
      f1()     
      f1()
      #同一个函数如f1执行两次,装饰器中print('我被调用了')只会执行一次,在函数调用第一次执行。
    
      @decorator
      def f2(a,b):
          print(a,b)    
      f2(1,2)
      f2(1,2)
  • #有参装饰器
    def decorator(number): 
      	print(number)
          def decorator1(func): 
              def wrapper(*args, **kwargs):
                  print('--------->开始')
                  r=func(*args, **kwargs)
                  print('--------->结束')
                  return r
              return wrapper
          return decorator1
    
      #比无参装饰器多套了一层
    @decorator(10)
    def show():
          rerurn '调用show函数'
          
    
    a=show()
    print(a)
    
      # 如果装饰的函数有返回值,装饰器的内层函数也要有返回值,从而保证装饰后的函数与原函数保持一致性
    
  • #多个装饰器
    def decorator1(func):
        print('我是装饰器1')
    
        def wrapper(*args, **kwargs):
            func(*args, **kwargs)  # func =  house
            print('铺地板')
    
        return wrapper
    
    
    def decorator2(func):  # func = 第一层wrapper
        print('我是装饰器2')
    
        def wrapper(*args, **kwargs):
            func(*args, **kwargs)
            print('买衣柜')
    
        return wrapper
    
    
    @decorator2
    @decorator1
    def house():
        print('------》毛坯房')
    
    
    house()
    # 多层装饰器:谁离原函数最近先执行哪个装饰器,将第一层装饰器的返回结果传给第二层装饰器。
    最后:原函数得到的地址是第二层函数的返回值wrapper
    
    # 执行结果
    我是装饰器1
    我是装饰器2
    ------》毛坯房
    铺地板
    买衣柜
    
    
  

##### 8.设计模式

- 单例设计模式的实现
  
- 基于`__new__`方法实现
  
  ```python
  class Singleton:
  
      def __new__(cls, *args, **kwargs):
          if not hasattr(cls,"_instance"):
          	cls.instance = object.__new__(cls)
          return cls._instance	
  • 基于装饰器

    def singleton(cls):
    	_instance = {}  #创建一个字典,一会字典中键就是类,值就是对象
    	
    	def _singleton(*args,**kwargs):
    		if cls not in _instance:
    			_instance[cls] = cls(*args,**kwargs)  #类创建对象,赋值给字典_instance,字典键cls唯一,所以一个类只有一个键
    		return _instance[cls]
    	return _singleton
    		
    @singleton
    class A:
    	def __init__(self,name):
    		self.name = name 
    
    a1 = A(2)
    a2 =A(3)
  • 基于python模块

    python模块就是天然的单例模式,因为模式在第一次导入时,会生成.pyc文件。当第二次导入时,就会直接加载.pyc文件,而不会再次执行模块代码,因此我们只需把相关的函数和数据定义在一个天然模块中,就可以获得一个单例对象了。
    
    新建一个a.py文件
    class Singleton:
    	pass
    singleton =Singleton()
    
    #使用
    from a.py import singleton
    
  • 基于__metaclass__ 它是在类创建过程中

  • 设计模式共23种,主要分三个类型 :创建型、结构型和行为型

    • 创建型

      Singleton 单例模式

      Abstract Factory 抽象工厂

      Factory Method 工厂方法

      Prototype 原型模式

    • 行为型

      iterator 迭代器模式

      Observer 观察者模式

      Visitor 访问者模式

      Mediator 中介者模式

    • 结构型

      composite 组合模式

      decrator 装饰模式

      Bridge 桥模式

      Flyweight 享元模式

9 、函数重载
  • python不需要函数重载,函数重载是为了解决两个问题
    两个函数仅仅是参数类型 和 参数个数多少。
    python参数可以是任意类型的,参数个数可以设置为缺省。
posted @ 2019-12-28 09:49  千亿  阅读(114)  评论(0编辑  收藏  举报