• Python面向对象编程(二)


     

    面向对象进阶篇:

    初级篇中我们介绍了面向对象基本知识:

      1.面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用
      2.介绍了类中的对象、方法和属性及类中内置的方法
      3.类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中)
      4.对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
      5.面向对象三大特性:封装、继承和多态

    本篇将详细介绍Python 类的成员、成员修饰符、类的特殊成员。

    一、类的成员:

    类的成员可以分为三大类:字段、方法和属性.

    注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。

    一、字段

    字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同.

    • 普通字段属于对象
    • 静态字段属于
    复制代码
     1 class Province:
     2 
     3     # 静态字段
     4     country = '中国'
     5 
     6     def __init__(self, name):
     7 
     8         # 普通字段
     9         self.name = name
    10 
    11 
    12 # 直接访问普通字段
    13 obj = Province('河北省')
    14 print obj.name
    15 
    16 # 直接访问静态字段
    17 Province.country
    复制代码

    由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。

    • 静态字段在内存中只保存一份
    • 普通字段在每个对象中都要保存一份

    应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段

    二、方法

    方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。

      1.>普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
      2.>静态方法:由类调用;无默认参数.   
      3.>类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;

    复制代码
     1 #方法的定义和使用
     2 
     3 class Foo:
     4 
     5     def __init__(self, name):      #构造方法
     6         self.name = name       #普通字段
     7 
     8     def ord_func(self):
     9         """ 定义普通方法,至少有一个self参数 """
    10 
    11         # print self.name
    12         print '普通方法'
    13 
    14     @staticmethod          #定义静态方法关键字
    15     def static_func():
    16         """ 定义静态方法 ,无默认参数"""
    17 
    18         print '静态方法'
    19 
    20     @classmethod          #定义类方法关键字.
    21     def class_func(cls):
    22         """ 定义类方法,至少有一个cls参数 """
    23 
    24         print '类方法'
    25 
    26 # 调用普通方法
    27 f = Foo('Kity')
    28 f.ord_func()
    29 
    30 
    31 # 调用静态方法
    32 Foo.static_func()
    33 
    34 # 调用类方法
    35 Foo.class_func()

    ###静态方法和类方法的好处是节省内存空间,不用每次调用都开辟内存空间.
    复制代码

    相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。

    不同点:方法调用者不同、调用方法时自动传入的参数不同。

    三、属性  

    如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。

    对于属性,有以下三个知识点:

    • 属性的基本使用
    • 属性的两种定义方式

    1、属性的基本使用

    • 装饰器 即:在方法上应用装饰器
    • 静态字段 即:在类中定义值为property对象的静态字段

    属性的定义和调用要注意一下几点:

    • 定义时,在普通方法的基础上添加 @property 装饰器;
    • 定义时,属性仅有一个self参数
    • 调用时,无需括号
                 方法:foo_obj.func()
                 属性:foo_obj.prop

    注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象

            属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

    实例:对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据(即:limit m,n),这个分页的功能包括:

    • 根据用户请求的当前页和总数据条数计算出 m 和 n
    • 根据m 和 n 去数据库中请求数据 
    1 # ############### 定义 ###############
     2 class Pager:
     3     
     4     def __init__(self, current_page):
     5         # 用户当前请求的页码(第一页、第二页...)
     6         self.current_page = current_page
     7         # 每页默认显示10条数据
     8         self.per_items = 10 
     9 
    10 
    11     @property
    12     def start(self):
    13         val = (self.current_page - 1) * self.per_items
    14         return val
    15 
    16     @property
    17     def end(self):
    18         val = self.current_page * self.per_items
    19         return val
    20 
    21 # ############### 调用 ###############
    22 
    23 p = Pager(1)
    24 p.start 就是起始值,即:m
    25 p.end   就是结束值,即:n
    
    实例

    装饰器方式:在类的普通方法上应用@property装饰器

      我们知道Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )

    经典类,具有一种@property装饰器

    复制代码
     1 #没有用修饰符的经典类
     2 class Goods:
     3     def BBB(self):
     4         return "Saneri"
     5 obj = Goods()
     6 result = obj.BBB()
     7 print result
     8 
     9 #定义了修饰符的经典类
    10 class Goods:            #定义经典类Goods
    11     @property            #修饰符
    12     def AAA(self):
    13         return "Saneri"
    14 obj = Goods()             #定义obj对象.
    15 result = obj.AAA       #自动执行 @property 修饰的 AAA 方法,并获取方法的返回值
    16 print result

    #加了修饰符的函数在执行时调用时无需括号,这应该就是两者最直观的区别.
    复制代码

    新式类,具有三种@property装饰器:

    复制代码
     1 # ############### 定义 ###############
     2 class Goods(object):    #新式类定义
     3 
     4     @property
     5     def price(self):
     6         print '@property'
     7 
     8     @price.setter
     9     def price(self, value):
    10         print '@price.setter'
    11 
    12     @price.deleter
    13     def price(self):
    14         print '@price.deleter'
    15 
    16 # ############### 调用 ###############
    17 obj = Goods()
    18 
    19 obj.price          # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
    20 
    21 obj.price = 123    # 自动执行 @price.setter 修饰的 price 方法,并将  123 赋值给方法的参数
    22 
    23 del obj.price      # 自动执行 @price.deleter 修饰的 price 方法
    复制代码

    注:经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
          新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法

    由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

    1 class Goods(object):
     2 
     3     def __init__(self):
     4         # 原价
     5         self.original_price = 100
     6         # 折扣
     7         self.discount = 0.8
     8 
     9     @property
    10     def price(self):
    11         # 实际价格 = 原价 * 折扣
    12         new_price = self.original_price * self.discount
    13         return new_price
    14 
    15     @price.setter
    16     def price(self, value):
    17         self.original_price = value
    18 
    19     @price.deltter
    20     def price(self, value):
    21         del self.original_price
    22 
    23 obj = Goods()
    24 obj.price         # 获取商品价格
    25 obj.price = 200   # 修改商品原价
    26 del obj.price     # 删除商品原价
    
    实例

     其他相关

    一、isinstance(obj, cls)

    检查obj是否是类 cls 的对象 ,如果是则返回True.

    复制代码
    a = 10
    b = [1,2,3,4,5]
    print isinstance(a,int)          #检查a是否是int值,如果是则返回True
    print isinstance(b,list)         #检查b是否是个列表,如果是返回True,不是则返回False.
    
    ###########################
    True
    True

    检查类对象:
    class A:
    pass

    class B(A):
    pass

    P = B() #实例化一个P对象
    print isinstance(P,B) #检查P是否是B的对象
    print isinstance(P,A) #检查P是否是A的对象

    True
    True

    复制代码

    二、issubclass(sub, super)

    检查sub类是否是 super 类的派生类.

    复制代码
    class A:
        pass
    
    class B(A):
        pass
    
    print issubclass(B,A)    #检查B是否是A的子类,如果是则返回True
    print issubclass(A,B)    #检查A是否是B的子类,如果不是则返回False
    
    -------------------------------
    True
    False
    复制代码

    断言:

    # assert 条件      测试的时候用的比较多.比如有的软件只能在windows用.
     
    assert 1 == 1    #如果条件满足,则执行程序,不满足报错.
     
    assert 1 == 2

     反射:

    python中的反射功能是由以下四个内置函数提供.

    getattr():   #获得对象的属性和方法

    hasattr():  #检查实例是否有这个属性

    setattr():    #给对象重新赋值

    delattr():  #删除对象成员

    实现反射功能的演化:

    根据访问URL做if条件判断.

    ##home.py文件内容#############
    def index():
        return "result home.index"
    
    def dev():
        return "result home.dev"
    def Say():
        return "result home.Say"
    
    def A():
    
        return "result home.A"
    def B():
        return "result home.B"
    
    -----------------------------------------------------------------
    import home
    #####################原始方法
    print "OldBoy ..."
    url = raw_input("Plz input URL:")
    if url == "home/index":
        ret = home.index()
        print ret
    elif url == "home/dev":
        ret = home.dev()
        print ret
    elif url == "home/Say":
        ret = home.Say()
        print ret
    
    else:
        print "404"
    
    原始访问URL方法
    原始访问URL的方法

    使用getattr方法实现:

    def index():
        return "result home.index"
    
    def dev():
        return "result home.dev"
    def Say():
        return "result home.Say"
    
    def A():
    
        return "result home.A"
    def B():
        return "result home.B"
    
    home.py
    复制代码
     1 import home
     2 url = raw_input("Plz input URL:")
     3 #假如 url == 'home/dev'
     4 con,action = url.split('/')
     5 #con == home
     6 #action == dev
     7 
     8 #action = 字符串
     9 #去某个容器(模块)中,找函数,字符串函数名,如果有,则返回
    10 
    11 func = getattr(home,action)    #home相当于*.py的模块名,action为函数名.
    12 #func = def dev():
    13 #    :return "result home.dev"
    14 
    15 ret = func()
    16 print ret
    复制代码

     使用wsg实现web访问:

    复制代码
    from wsgiref.simple_server import make_server
    
    
    def RunServer(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        url = environ['PATH_INFO']
        temp = url.split('/')[1]        #对url进行split,获取第一个元素. http://localhost:8001/index
                                        #index
        import home            #home模块为home.py文件.
    
        is_exist = hasattr(home, temp)      #去home模块检查,是否含有指定的函数.
        if is_exist:                    #如果函数存在指定函数
            func = getattr(home, temp)      #获取函数
            ret = func()              #执行函数,并获取返回值
            return ret                #将函数返回值响应给请求着.
        else:
            return '404 not found'
    
    if __name__ == '__main__':
        httpd = make_server('', 8001, RunServer)
        print "Serving HTTP on port 8000..."
        httpd.serve_forever()

    #访问方式:
    #执行脚本,浏览器端输入http://localhost:8001/index 方式访问.
    复制代码
    反射操作类和对象中的成员:
    复制代码
    class Foo:
        static_name = 'NBA'
        def __init__(self):
            self.name = 'nb'
    
        def show(self):
            print "hello show !!!"
        @staticmethod           #静态方法
        def static_show():
            print "hello static_show ..."
        @classmethod             #类方法
        def class_show(cls):
            print "hello class_show ..."
    
    print Foo.__dict__
    print Foo.__dict__.keys()       #查看类中的成员
    print hasattr(Foo,'static_show')        #查看Foo 中是否存在static_show
    obj = Foo()
    
    print obj.__dict__
    print hasattr(obj,'name')   #类去找的时候只在自己的成员里面去找.
    
    print hasattr(obj,'show')   #对象去找的时候,先在自己内存中去找,然后再去创建这个对象的类里面去找。因为他有一个类对象指针
    复制代码

     动态模块导入:

    复制代码
    #动态导入模块
    # import home     import导入的你不知道其为什么数据类型. 这里导入的home不知道数据类型.
    # __import__("home")  __import__导入的为一个字符串,"home"在这里就是字符串.
    
    # module = __import__("home")  类似于 import home as module
    
    
    controller,action = raw_input("Plz input url:").split('/')  #根据‘/’进行分割,输入第一个参数为controller,第二个为action.
    print controller
    print action
    
    module = __import__(controller)
    func = getattr(module,action)
    ret = func()
    print ret
    
    -----------------------------------------------------------执行
    Plz input url:home/dev
    home
    dev
    result home.dev
    复制代码

    摘自:http://www.cnblogs.com/wupeiqi/p/4766801.html

  • 相关阅读:
    Codeforces E-Anton and Tree
    树的重心和直径-POJ1655
    Cisco packet tracer 实现两台计算机互ping
    codeforce 679A Bear and Prime 100 (交互题)
    codejam 2019 round 1C Robot Programming Strategy (构造)
    luogu P1086 花生采摘 (优先队列+模拟)
    ZOJ 4110 Strings in the Pocket (马拉车+回文串)
    HDOJ 6508 Problem I. Spell Boost (01背包/DP)
    L2-011 玩转二叉树 (25 分) (树)
    L2-004 这是二叉搜索树吗? (25 分) (树)
  • 原文地址:https://www.cnblogs.com/onesea/p/15459247.html
Copyright © 2020-2023  润新知