python面向对象编程(2)

类编写细节

1.class 语句python

class语句细节python3.x

  • 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.方法优化

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

## 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__方法spa

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....复制代码

静态方法code

  • 使用场景:
    • 目标:为全部类实例提供数据共享的类属性
    • 执行:经过类名称访问类属性
    • 优化:其一是使用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)复制代码

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

  • 类中带有实例对象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抑或其余语言来扩展
    • 必须导入才能使用

喜欢能够关注我我的公众号,持续更新工程师技术平常

相关文章
相关标签/搜索