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

面向对象

  • 类概念
  • 类的定义
  • 类的实例化
  • 类和实例的属性
  • 类的私有变量
  • 数据封装
  • 继承
  • 多态
  • 多继承
  • 类的特殊方法
  • 装饰器
  • 类的装饰器
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个,类的内置装饰器

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容

  • 定义类并创建实例 在Python中,类通过 class 关键字定义。以 Person 为例,定义一个Person类...
    绩重KF阅读 3,914评论 0 13
  • @(python)[笔记] 目录 前言 在python中,一切皆对象面向对象的程序设计的核心就是对象;面向对象的程...
    CaiGuangyin阅读 581评论 0 5
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,493评论 18 399
  • 闲时听音乐,听到一句念白:“平生不会相思,才会相思,便害相思。先前我怎么没看明白。”兀自心疼好久,这句词出自元时徐...
    安寂染阅读 1,300评论 17 26
  • 非典型游记 几点映象 随口说说 ladyboy 明艳活泼 如果把城市拟人,曼谷的第一映像应该是ladyboy,蓬...
    帝江啊阅读 145评论 0 1