python笔记3(面向对象)

一、面向对象编程


面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。把大块函数通过切割成小函数来降低系统的复杂度

面向对象的程序设计把计算机程序视为一组对象的集合,计算机执行的就是一系列消息在各个对象之间传递

面向对象的数据思想是抽象出Class,根据Class创建Instance(实例)

一个Class既包含数据,又包含操作数据的方法

1、类和实例
  1. 定义类:

    class Student(object):

    (object)表示该类从哪个类继承,如果没有合适的继承类,就使用object类(所有类都会继承的类)

  2. 创建实例:

    类名+()实现:bart = Studen()

    通过一个特殊的__init__方法,在创建实例的时候就把一些必须的属性加上去

    def __init__(self,name,score):

    __init__的第一个参数必须是self,表示创建实例的本身,传入参数self时不需要传

  3. 数据封装

    在类的内部定义访问数据的函数

方法就是与实例绑定的函数,方法可以直接访问数据的实例

2、访问限制
  • 设为私有来限制访问

    class Student(object):
    	def __init__(self):
    		self.__name =name
    		self.__age = age
    
  • _name外部可以直接访问,但按约定,不直接进行访问

  • __name不能被访问的原因是python解释器对外把__name变量改为了_Student__name(不同版本的python改成不同的变量名)

Python本身没有任何机制不阻止你干坏事,一切靠自觉

3、继承和多态

class Dog(Animal):

子类获得父类的全部功能

当子类与父类同时存在相同的方法,子类会覆盖父类的方法

开闭原则:

  • 对扩展开发:允许增加新的子类
  • 对修改封闭
4、获取对象信息

(1)type():查看对象类型,返回对应的class类型

  • 基本类型都可以用type()判断

    例:type(123)type('str')

    • 判断基本数据类型可以直接写intchar

      ``type(123) == int`

  • 一个变量指向函数或者类,也可以用type()判断

    例:type(abs)type(a)

    • 判断一个对象是否是函数(可以使用type模块中定义的常量)

      import types
      def fn():
      	pass
      print(type(fn) == types.FunctionsType)
      print(type(abs) == types.BuiltFunctionType)
      

(2)isinstance():判断一个对象是否是该类型本身或者位于该类型的父继承链上

  • 判断继承

    如果继承关系为:

    object->Animal->Dog

    a = Animal()
    d = Dog()
    isinstance(d,Dog)
    isinstance(d,Animal)
    
  • type()一样判断基本类型

    isinstance('a',str)

  • 判断一个变量是否是某些类型中的一种

    isinstance([1,2,3],(list,tuple))

优先使用instance

(3)dir():获取对象的所有属性和方法,返回一个包含字符串的list

  • 直接操作对象的状态,获得对象的方法

    • 获取属性:getattr()getattr(obj,'x')

      可以传入default参数,如果参数不存在,返回默认值

      getattr(obi,'x',404) #不存在返回404

    • 设置属性:setattr()setattr(obj,'y',19)

    • 查看属性:hasattr()hasattr(obj,'y')

二、实例属性和类属性


  • 实例属性:

    实例属性属于各个实例所有,互不干扰

  • 类属性:

    类本身绑定属性,在class中直接定义属性,类属性属于类所有,所有实例共享一个属性

不要对实例属性和类属性使用相同的名字,实例属性会将类属性屏蔽掉

三、面向对象高级编程


1、使用__slots__方法
  • 给实例绑定方法

    def set_age(self,age): #定义一个函数作为实例方法
    	self.age = age
    from types import Methodtype
    s.set_age = MethodType(set_age,s) #给实例绑定一个方法
    
  • 给class绑定方法

    def set_score(self,score):
    	self.score = score
    Student.set_score = set_score
    
  • **__slots__:**限制该实例的能添加的属性

    class Student(object):
    	__slots__ = ('name','age') #用tuple定义允许绑定的属性名称
    

    __slots__定义的属性仅对当前类的实例起作用,对继承的子类不起作用

    想在子类中运用,就需在子类中也定义__slots__,子类允许定义的属性就是自身的__slots__加上父类的__slots__

2、使用@property
  • 定义读写属性:定义gettersetter方法

    class Student(object):
    	
    	@property		#getter方法
    	def birth(self):
    		return self._birth
    	
    	@birth.setter    #setter方法
    	def birth(self,value):
    		self._birth = value
    
  • 定义只读属性:只定义setter方法

    class Student(object):
    	
    	@property
    	def age(self):
    		return 2015-self._birth
    
3、多重继承
  • MixIn

    多重继承:一个子类同时继承多个父类(class Bat(Mammal,Flyable)

    MixIn:(mix+in:混入)给一个类增加多个功能(继承多个父类)

    优先通过多重继承来组合多个Mixln的功能

4、定制类
  • __str__:返回字符串

    定义__str__方法:

    def __str__(self):
    	return 'Student object (name:%s)' % self.name
    

    直接显示变量调用的不是__str__(),而是__repr__()

    • __str__()返回用户看到的字符串Student object (name:micle)
    • __repr__()返回开发者看到的字符串<__main__.Student object at 0x109afb310>
    • 解决办法:__repr__ = __str__
  • __iter__:循环类

    iter:循环

    类想被for...in循环,就必须实现一个__iter__()方法,改方法返回一个迭代对象

    class Fib(object):
    	def __init__(self):
    		self.a,self.b = 0,1
    	def __iter__(self):
    		return self   #实例本身是迭代对象,故返回自己
    
  • __getitem__:类按下标访问元素

    item:

    按照下标取出元素:__getitem__()

    class Fib(object):
    	def __getitem__(self,n):
    		a,b=1,1
    		for x in range(n):
    			a,b = b,a+b
    		return a
    

    对Fib切片会报错,原因是__getitem__()传入的可能是一个int,也可能是一个切片对象slice

    所以需要对传入的参数做判断if isinstance(n,slice)

  • __getattr__:避免调用类的方法或属性不存在报错

    attr:属性

    def __getattr__(self,attr)
    	if attr == 'age':
    		return 99   		#返回score的值
    		#return lambda: 25	#也可以返回函数
    

    只有在没有找到属性的情况下,才调用__getattr__

    __getattr__()默认返回时None

    要让class只响应特定的几个属性,就需要抛出AttributeError(把一个类的所有属性和方法调用全部动态化处理了)

  • __call__:对实例进行调用

    class Student(object):
    	def __init__(self,name):
    		self.name = name
    		
    	def __call__(self):
    		print('.....')
    

    __call__() 还可以定义参数:def __call__(self,age)

    判断一个对象能否被调用:

    能被调用的对象就是一个Callable对象:callable(Student())

    Python的官方文档

5、使用枚举类Enum()
  • 使用Enum()

    from enum import Enum

    for name,member in Month__members__.item():
    	print(name,'=>',',',member.value)
    

    value属性则是自动赋值给成员的int常量,默认从1开始

    from enum import Enum,unique
    @nuique
    class Weekday(Enum)
    

    @unique装饰器可以保证没有重复值

  • 访问枚举类型

    • 可以用成员名引用枚举常量(Weekday.Tue
    • 也可以直接根据value的值获得枚举常量(Weekday(1)
6、使用元类metaclass
  • type()

    • 查看一个类型或变量的类型

      Hello是一个class,它的类型就是`type``

      h = Hello()h是一个实例,它的类型就是classHello

    • 动态创建新的类型

      Hello = type('Hello',(object,),dict(hello=fn)) #创建Hello class

      要创建一个class对象,type()函数依次传入3个参数:

      • 1、class的名称 #Hello
      • 2、继承的父类集合,继承多重继承,注意tuple的单元素写法 3 #(object,)
      • 3、class的方法与函数绑定 #decit(hello=fn)
  • metaclass:控制类的创建行为

    • 1、先定义metaclass

      class ListMetaclass(type):

      metaclass的类名以Metaclass结尾

      metaclass是类的模板,所以必须从type类型派生

    • 2、再创建class

      class MyList(list,metaclass=ListMetaclass:

      定义类时,需要传入关键字metaclass

    • 3、最后创建实例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值