python面向对象编程(2)

类编写细节

1.class 语句

class语句细节

  • python的class语句是属于OOP的一种工具(即定义变量名的工具,将数据和逻辑暴露给客户端),而不是声明式的
  • class语句是对象的创建者,类似于对象工厂
  • class语句是一种隐含的赋值运算,即执行class语句时,会产生类对象并且将其引用存储到定义的类名称上
  • class语句与def一样,都是可执行语句,即python还没有执行到class语句时,类是不存在的
  • class是复合语句,所有种类语句都可以位于其主体内,如print, 赋值语句, if, def...

class语句如何得到命名空间

  • 首先,执行类语句的时候,会从头至尾执行其主体内的所有语句
  • 其次,是在执行过程中的赋值运算会在这个类作用域中创建变量名,从而成为对应的类对象属性
  • 与函数相比,可以把class语句看成一个本地作用域,在class语句下定义的变量就属于这个本地作用域
  • 与模块相比,定义的变量名是可以共享的并且成为当前类的对象属性

class语句一般形式

## 根据上述所言,className是类对象的一个引用
class className(superclass1,superclass2,...):          
    '''
        定义类属性,属于所有实例的共享数据,通过类语句下进行定义和创建
    '''
    class_attr = value 
    
    
    '''
        定义实例方法以及实例属性
    '''
    def method(self,data):      ## 定义实例方法
        self.attr = data        ## 设置实例属性,通过带有self的方法来分配属性信息

2.方法

实例方法对象调用等价于类方法函数调用

## python自动将实例方法的调用自动转成类方法函数,并传递实例对象作为第一个参数传递
class Person:
    def study(self,name):
        print("%s study method in for %s" % (name,self.__class__.__name__)

>>> p = Person()
>>> p.study("keithl")
keithl study method in for Person

>>> Person.study(p,"keithl")
keithl study method in for Person

## instance.method(arg1,arg2,...) == class.method(instance,arg1,arg2,...)

调用超类的构造函数__init__方法

class Person:
    def __init__(self):
        print("call person init ....")

class Student(Person):
    pass
        
>>> s = Student()               ## 创建子类时会调用父类构造函数,原因是子类没有定义自己的构造函数
call person init ....

## 为子类增加构造函数
class Student(Person):
    def __init__(self):
        print("call student init ....")

>>> s = Student()               ## 只输出子类的__init__方法,并没有调用父类方法,原因在于python是根据命名空间来执行调用方法
call student init ....

## 若要调用父类构造方法则必须显示进行调用
class Student(Person):
    """
        必须在子类构造函数中显式调用父类的构造函数,并传递子类的self引用
    """
    def __init__(self):
        print("call student init start....")
        Person.__init__(self)              
        print("call student init end....")

>>> s = Student()               
call student init start....
call person init ....
call student init end....

静态方法

  • 使用场景:
    • 目标:为所有类实例提供数据共享的类属性
    • 执行:通过类名称访问类属性
    • 优化:其一是使用OOP思想封装类属性而对外提供方法,其二是考虑扩展性,通过继承来定制
    • 落地:使用静态方法或者类方法,即不需要传递类对象self实例参数的方法
## person.py
class Person:
    num = 1
    """
        定义一个没有带参数的普通方法
    """
    def printNum():
        Person.num += 1
        print("the number is %s" % Person.num)
    
    printNum = staticmethod(printNum)                   ## 声明为静态方法
    
    """
        定义一个带参数的普通方法,此参数为类对象参数
    """
    def clsPrintNum(cls):
        Person.num += 1
        print("the number is %s" % Person.num)         

    clsPrintNum = classmethod(clsPrintNum)              ## 声明为类方法

>>> Person.printNum()
the number is 2

>>> Person.clsPrintNum()
the number is 3

## person.py 使用装饰器来声明静态或类方法
class Person:
    num = 1
    
    @staticmethod
    def printNum():
        Person.num += 1
        print("the number is %s" % Person.num)

    @classmethod
    def clsPrintNum(cls):
        Person.num += 1
        print("the number is %s" % Person.num)

静态方法、类方法与实例方法

  • 类中带有实例对象self的参数传递的方法称为实例方法
  • 类中带有类对象cls的参数传递的方法并通过函数classmethod或者装饰器@classmethod声明的方法称为类方法
  • 类中没有实例对象self和类对象cls参数传递的方法,且通过staticmethod或装饰器@staticmethod什么的方法称为静态方法
class Person:

    @staticmethod
    def static_method():
        print("static method ...")

    @classmethod
    def class_method(cls):
        print("class method ....")

    def instance_method(self):
        print("instance method ...")

    '''
        python3.x可以调用下面的函数,可以说是静态方法,但严格意义上是属于类的一个行为方法,但是python2.x无法该方法
    '''
    def fn():
        print("just a fn,if py3.x,it is static method")

## 总结:
1)在类中定义方法一定要规范化,明确是静态方法还是类方法抑或是实例方法
2)避免使用最后一种方式在类中定义方法

3.命名空间与作用域

  • 命名空间:用于记录变量的轨迹,key是变量名称,value是变量值,作用就是根据变量名称搜索变量
    • 使用无点号运算的变量名称(X),将根据LEGB(local/enclosing/global/builtin)作用域查找法则来搜索变量
    • 使用点号的属性名称(object.x)使用的是对象命名空间来搜索变量(对象:类的实例对象和类对象)
    • 有些作用域会对对象的命名空间进行初始化(模块和类)

无点号运算的变量名称

  • 赋值语句:在当前作用域创建或更改变量X,除非声明为全局变量
X = "global X"
def enclosing_fn():
    ## global X             
    X = "enclosing fn"      ## 创建当前enclosing_fn的本地变量X如果没有声明为全局变量的话
  • 引用:根据LEGB作用域法则来搜索变量
X = "global X"
def enclosing_fn():
    X = "enclosing fn"      ## 如果注释此行,将打印全局的变量X
    print(X)
    def local_x()
        x = "local x"       ## 如果仅注释此行,将会打印嵌套的变量X
        print(x)
    local_x()

点号的属性变量名称

  • 赋值语句:在对应的对象命名空间中创建或修改属性名称X,即object.X = value
>>> p = Person()

## 在对象实例的命名空间创建或更改属性名称name
p.name = "keithl"       ## 并无进行变量名称的搜索

## 在类的命名空间中创建或更改属性名称name
Person.name = "keithl"  ## 并无进行变量名称的搜索
  • 引用
    • 基于类的对象引用:会在对象内搜索属性名称X,若没有找到则根据继承搜索来查找
    • 基于模块对象的引用:先导入模块,再从模块中读取X
>>> p = Person()
>>> p.name          ## 从对象命名空间开始按照继承树来搜索
>>> Person.name     ## 从类的命名空间开始按照继承树来搜索

命名空间字典

  • 模块的命名空间是以字典的形式实现的,并且可以由属性__dict__来显示
  • 类和对象可以看成一个带有链接的字典,属性点号就是字典索引运算,属性继承就是搜索链接的字典
    • 实例与类通过__class__属性链接
    • 类与超类通过__bases__属性链接,可以通过递归往上遍历超类
  • 都可以通过__dict__查看模块、类或者对象的属性信息

类与模块的关系总结

    • 调用类会创建新的对象
    • 由class来创建类对象
    • 通过调用来使用
    • 属于模块的一部分
  • 模块

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

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,517评论 6 13
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,296评论 18 399
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,103评论 18 139
  • 心跳 距离 呼吸 阴影 眼神 吻
    水摇绢阅读 198评论 1 1
  • 离别是一个伤感的词,说到离别,心里总会涌起一股忧伤的情绪,即使离别是因为更好的开始。自古离别诗词数不胜数,却也没读...
    夜莺方方阅读 322评论 0 0