python基础-09-面向对象、装饰器

面向对象

面向对象

  1. 类概念
  2. 类的定义
  3. 类的实例化
  4. 类和实例的属性
  5. 类的私有变量
  6. 数据封装
  7. 继承
  8. 多态
  9. 多继承
  10. 类的特殊方法
  11. 装饰器
  12. 类的装饰器

1.面向对象(Object Oriented,OO)概念

面向对象,是我们编程的一种思维。
早期的计算机编程是基于面向过程的方法,例如实现算术运算1+1+2 = 4,通过设计一个算法就可以解决当时的问题。
通过面向对象的方法,更利于用人理解的方式,对复杂系统进行分析、设计与编程。
同时也提高了系统的可维护性,可扩展性,可重用性。
(就是使编程的思维,更接近与人的思维和认知)

面向对象编程的关键,就是类的定义。
类是对现实生活中一类具有共同特征的事物的抽象。

2.类的定义

基本形式:
    class ClassName(object):
        Statement

1.class定义类的关键字
2.ClassName类名,类名的每个单词的首字母大写(驼峰规则)。
3.object是父类名,object是一切类的基类。在python3中如果继承类是基类可以省略不写。
'''
class Animal(object):
    pass
'''

'''
重点:学会定义类,了解属性和方法,类的初始化和实例化。
定义类时,这种方法可以使类对象实例按某种特定的模式生产出来。
'''
#类方法:

后面的参数中第一个参数我们约定俗成的为self参数名,
self代表的是在类实例化后这个实例对象本身。

'''
class Animal: 
    #构造方法,实例化对象,必须调用__init__
    #在初始化的时候,默认往构造方法,传入一个值
    #self是实例化对象本身
    def  __init__(self): 
        print("正在实例化一个对象")
    def test(self):#实例化对象调用方法,必须加上self
        print("aaa")
    def test1(self,b):#第一个参数默认是self参数,不需要传值
        print("方法;test1,self=%s"%(type(self)))
    def test2():#未加self参数,只能通过  Animal.test2()直接调用,实例化对象无法调用
        print("方法;test2")
运行结果:
>>> Animal().test1(1111)
正在实例化一个对象
方法;test1,self=<class '__main__.Animal'>
'''
'''
class Animal:   #当我们没有写__init__(),默认调用我们父类的__init__
    def test(self):
        print("aaa")
'''




初始化函数除了有self这个参数表示实例对象本身之外,
其他的参数的定义也遵循函数的必备参数和默认参数一样的原则,
必备参数就是在实例化是一定要传入的参数,
默认参数就是在定义时可以给这个参数一个初始值。没有函数名的函数

3.类的实例化

 基本形式:实例对象名 = 类名(参数)

    在实例化的过程中,self代表的就是这个实例对象自己。

    实例化时会把类名后面接的参数传进去赋值给实例,
    这样传进去的参数就成为了这个实例对象的属性。

    实例化的过程遵循函数调用的原则。
    在实例化时也必须个数和顺序与定义时相同(使用关键字参数可以改变传参的顺序)。
    当初始化函数定义时使用了默认参数时,在实例化时默认参数可以不传参这时
    这个实例对象就会使用默认的属性,如果传了参数进去则会改变这参数值,
    使实例化对象的属性就为你传进来的这个参数。

    isinstance(实例名,类名)
    判断一个实例是不是这个类的实例。

4.类和实例的属性

     类属性
            .类属性是可以直接通过“类名.属性名”来访问和修改。
            .类属性是这个类的所有实例对象所共有的属性,
            任意一个实例对象都可以访问并修改这个属性(私有隐藏除外)。
            .对类属性的修改,遵循基本数据类型的特性:列表可以直接修改,字符串不可以,
            所以当类属性是一个列表时,通过任意一个实例对象对其进行修改。
            但字符串类型的类属性不能通过实例对象对其进行修改。
            当实例对不可变对象进行修改之后,会查找实例的类属性,不会查找类的属性,同时类的属性不会边

        实例属性
            .在属性前面加了self标识的属性为实例的属性。
            .在定义的时候用的self加属性名字的形式,在查看实例的属性时
            就是通过实例的名称+‘.’+属性名来访问实例属性。
'''
class Aniaml:
    eye=2  #共有的属性
    def __init__(self,name,food):
        print("正在实例化")
        self.name=name #实例化属性
        self.food=food
    def getName(self):
        print(self.name)
运行:
>>> dog=Aniaml("大黄","骨头")
实例化属性调用:
>>> dog.name  #调用实例属性
'大黄'
类属性调用:
>>>Aniaml.eye
>>> dog.eye 
      '''

        一些说明:
            .一般,方法第一个参数被命名为self,,这仅仅是一个约定,
            self没有特殊含义,程序员遵循这个约定。
            .查看类中的属性和实例属性可以调用__dict__方法返回属性组成的字典。
            .Python中属性的获取是按照从下到上的顺序来查找属性
            .Python中的类和实例是两个完全独立的对象
            .Python中的属性设置是针对对象本身进行的

5.类的私有属性和方法

        在Python中,通过单下划线”_”来实现模块级别的私有化,
       一般约定以单下划线”_”开头的变量、函数为模块私有的,
       也就是说”from moduleName import *”将不会引入以单下划线”_”开头的变量、函数
       '''
       import random #显示所有的方法,属性
       from random import *  #只显示
       '''

        对于Python中的类属性,可以通过双下划线”__”来实现一定程度的私有化。
        _”和” __”的使用 更多的是一种规范/约定,并没有真正达到限制的目的:

        “_”:以单下划线开头只能允许其本身与子类进行访问,(起到一个保护的作用)
        “__”:双下划线的表示的是私有类型的变量。这类属性在运行时属性名会加上单下划线和类名。
        “__foo__”:以双下划线开头和结尾的(__foo__)代表python里特殊方法专用的标识,如 __init__()
        '''
       class Aniaml:
    eye=2
    _age=3
    __leg=4
    def __init__(self,name,food):
        self.name=name
        self.food=food
    def getName(self):
        print(self.name)
  >>> dog._age   #单_会隐藏属性名称
  >>> dog._Aniaml__leg  #双_会隐藏属性名称,双_会修改属性的名称
       '''

6.数据封装

    在类里面数据属性和行为函数的形式封装起来,
    访问时直接调用,不需知道类里面具体的实现方法。 比如,list.append
    封装:
    def test2():
           print("方法;test2")

7.继承

用法:
    .在定义类时,可以从已有的类继承,
    被继承的类称为基类(父类),新定义的类称为派生类(子类)。

    .在类中找不到调用的属性时就搜索基类,
     如果基类是从别的类派生而来,这个规则会递归的应用上去。
     反过来不行。

    .如果派生类中的属性与基类属性重名,那么派生类的属性会覆盖掉基类的属性。
     包括初始化函数。

    .派生类在初始化函数中需要继承和修改初始化过程,
     使用’类名+__init__(arg)’来实现继承和私有特性,也可以使用super()函数。

    issubclass(类名1,类名2)
    判断类1是否继承了类2

作用:
    面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。
    继承完全可以理解成类之间的类型和子类型关系。

    子类在重写父类方法之后,如果要继承父类方法中的功能,要先调用父类的方法  class.fun(self)
'''
class Aniaml:
    eye=2
    _age=3
    __leg=4
    def __init__(self,name,food):
        self.name=name
        self.food=food
    def getName(self):
        print(self.name)

class People(Aniaml):#继承
    __leg=2
    def __init__(self,name,food,sex):
        self.name=name
        self.food=food
        self.sex=sex
    def getSex(self):
        print(self.sex)
'''

8.多态

当派生类重写了基类的方法时就实现了多态性。(子类重写父类方法)
class Aniaml:
    eye=2
    _age=3
    __leg=4
    def __init__(self,name,food):
        self.name=name
        self.food=food
    def getName(self):
        print(self.name)

class People(Aniaml):
    __leg=2
    def __init__(self,name,food,sex):
        self.name=name
        self.food=food
        self.sex=sex
    def getSex(self):
        print(self.sex)
    def speak(self):
        print("adsfsfd")

class Chinese(People):#中国人 
    def speak(self):#中国文说你好
        print("你好"

class America(People):#美国人
    def speak(self):#美国人说Hello
        print("Hello")

class Thai(People):#泰国人
    def speak(self):#泰国人说萨瓦迪卡
        print("萨瓦迪卡")

xiaomi=Chinese("小明","米饭","男")
jack=America("jack","面包","男")
lala=Thai("lala","香蕉","未知")

9.多继承

#当继承的类有同种方法的时候,只会继承前面一个的方法。调用父类方法super()
class Base:
    def play(self):
        print("This is base")

class A(Base):
    def play(self):
        print(type(self))
        print("This is a")
class B(Base):
    def play(self):
        print("This is b")
class C(A,B):
    def play(self):
        #A.play(self) #第一种调用父类的方法
        super().play()#第二种调用父类的方法,同super(C,self).play()
        #super(C,self).play()
        print("This is c")
运行效果:
<class '__main__.C'>
This is a
This is c
#对象的扩展使用
#C().__class__.mro()  查看对象的排序
#C(B,A)   C->B->A->Base->object 针对C继承对象排序
#C(A,B)   C->A->B->Base->object 针对C继承对象排序
class C(B,A):
    def play(self):
        #super(A,self).play()  #调用base
        super(B,self).play()  #调用a
>>> C().__class__.mro()  #C->B->A->Base->object 针对C继承对象排序
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.Base'>, <class 'object'>]

10.类的特殊方法

千万不要把自己往死胡同里面逼,否则你会走火入魔
'''
class Rectangle:
    '''测试'''
    aaa=1
    def __init__(self,length,width):
        if isinstance(length,(int,float)) and isinstance(width,(int,float)):
            self.length=length
            self.width=width
        else:
            print("请输入int or float")
    def area(self):
        return self.length*self.width
    def __str__(self):
        return "这个长方形的面积%s"%self.area()
    def __repr__(self):
        return "长:%s 宽:%s"%(self.length,self.width)
    def __call__(self):
        print("这是一个Rectangle类,你要干嘛")
    def __add__(self,other):
        return self.area()+other.area()
    def __sub__(self,other):
        return self.area()-other.area()
r=Rectangle(2,3)
r1=Rectangle(2,3)
r2=Rectangle(2,3)

'''

#类属性:
__dict__     # 类的属性(包含一个字典,由类的数据属性组成)


>>> r.__dict__
{'length': 2, 'width': 3}
>>> r.aaa=33
>>> r.__dict__  
#注意,共有属性,当不修改时,默认引用Rectangle
#修改之后,才会出现再实例里面
{'length': 2, 'width': 3, 'aaa': 33}

__doc__     # 类的文档字符串
>>> r.__doc__
'测试'

#类方法:(魔法方法) ,方法也是对象
    __init__    # 初始化
    __repr__    # 直接返回这个对象  repr() 函数就是调用对象的这个方法
    >>> r
    长:2 宽:3

    __str__     # print(obj) 如果类里面定义了__repr__,没有定义__str__ print(obj)也会返回__repr__的内容,或者说__repr__的优先级更高
    >>> print(r) #重写print方法了
    这个长方形的面积6
    "%s"%"ssss"  对应  __str__
    "%r"%"rrrr"  对应 __repr__

    __call__    # Obj() 使实例可被调用
    >>> r()
    这是一个Rectangle类,你要干嘛

#运算符方法
    __add__(self,other)     #x+y
    >>> r1+r2
    12

    __sub__(self,other)     #x-y 
    __mul__(self,other)     #x*y  
    __mod__(self,other)     #x%y
    __iadd__(self,other)    #x+=y
    __isub__(self,other)    #x-=y 
    __radd__(self,other)    #y+x
    __rsub__(self,other)    #y-x 
    __imul__(self,other)    #x*=y 
    __imod__(self,other)    #x%=y 

#和类有关的几个函数  
    delattr()        # 删除对象属性
    getattr()        # 得到某个属性值
    setattr()        # 给对象添加某个属性值
    hasattr()          # 判断对象object是否包含名为name的特性
    isinstance()      # 检查对象是否是类的对象,返回True或False
    issubclass()      # 检查一个类是否是另一个类的子类。返回True或False    

11.装饰器

装饰器(deco):
    装饰函数的参数是被装饰的函数对象,返回原函数对象装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象
    概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

def  f1(func):
    print("f1 running")
    def f2(y):
        print("f2 running")
        return func(y)+1
    return f2
@f1
def  gun2(m):
    print("gun running")
    return m*m
#运行结果
f1 running
>>> gun2(5)
f2 running
gun running
26
运行流程
1.@f1->f1(gun2)->f2
2.f2,等待调用
3.gun2(2)->当参数5传入->f2(5)
4.f2(5),开始运行->print("f2 running")->fun(y):func=gun2 y=5
5.gun2(5) 开始运行->print("gun running")->25
6.25+1=26

#测试时间的装饰器
import time  #不要纠结

def run_time(func):
    def new_fun():
        t0 = time.time()
        print('star time: %s'%(time.strftime('%x',time.localtime())) )
        func()
        print('end time: %s'%(time.strftime('%x',time.localtime())) )
        print('run time: %s'%(time.time() - t0))

    return new_fun



@run_time
def test():
    for i in range(1,10):
        for j in range(1,i+1):
            print('%dx%d=%2s'%(j,i,i*j),end = ' ')
        print ()

12.类装饰器

'''
class Rectangle:
    '''测试'''
    aaa=1
    def __init__(self,length,width):
        if isinstance(length,(int,float)) and isinstance(width,(int,float)):
            self.length=length
            self.width=width
        else:
            print("请输入int or float")
    @property #可以把方法当属性使用
    def area(self):
        return self.length*self.width
    @staticmethod #把方法变成静态方法
    def func():
        print("可以调用")
    @classmethod  #把实例化对象转换成类
    def show(self):
        print(self)
        print("show fun")

>>> Rectangle(2,3).area
6
'''

@property 
    装饰过的函数返回的不再是一个函数,而是一个property对象
    装饰过后的方法不再是可调用的对象,可以看做数据属性直接访问。


@staticmethod #(静态方法)
    把没有参数的函数装饰过后变成可被实例调用的函数,      
    函数定义时是没有参数的,可以不接收参数

@classmethod (类方法)
    把装饰过的方法变成一个classmethod类对象,既能能被类调用又能被实例调用。
    注意参数是cls代表这个类本身。而是用实例的方法只能被实例调用。     

一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。
而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。
这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁
'''
#类装饰器

'''
class Test_Class():
    def __init__(self,func):
        self.func=func
    def __call__(self):
        print("类")
        return self.func
@Test_Class
def fun_test():
    print("这只是一个测试")
运行:
>>> fun_test()
类
<function fun_test at 0x033081E0>
>>> fun_test()()
类
这只是一个测试
#python自带的3个,类的内置装饰器
  • 发表于 2017-11-14 09:53
  • 阅读 ( 1663 )
  • 分类:python

0 条评论

请先 登录 后评论
不写代码的码农
doublechina

IT

31 篇文章

作家榜 »

  1. 威猛的小站长 124 文章
  2. Jonny 65 文章
  3. 江南烟雨 36 文章
  4. - Nightmare 33 文章
  5. doublechina 31 文章
  6. HJ社区-肖峰 29 文章
  7. 伪摄影 22 文章
  8. Alan 14 文章