zoukankan      html  css  js  c++  java
  • 面向对象(二)

    类的成员

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

    一、字段

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

    • 普通字段属于对象,在内存中为每个对象保存一份
    • 静态字段属于类,在内存中只保存一份

    一般情况下,自己访问自己字段,普通字段只能使用对象访问,静态字段使用类访问(最好不要用对象访问静态字段),静态字段在代码加载时创建。

    #!/usr/bin/env python
    # coding=utf-8
    
    
    class Province(object):
    
        # 静态字段,保存在类中
        country = '中国'
    
        def __init__(self, province):
            # 普通字段,保存在对象中
            self.name = 'province'
        # 普通方法,由对象去调用执行(方法属于类)
        def show(self):
            return self.name
    
        # 静态方法,由类调用执行,对象是封装数据的,用不到对象封装数据,使用静态方法
        @staticmethod
        def f1():
            return '....'
    
    test = Province('henan')
    print(Province.country)
    print(test.country)
    print(test.show())
    
    print(Province.f1())
    View Code

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

    二、方法

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

    • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self
    • 类方法:由调用; 至少一个cls参数;执行类方法时,自动将调用该方法的复制给cls
    • 静态方法:由调用;无默认参数;
    #!/usr/bin/env python
    # coding=utf-8
    
    # 面向对象中类成员
    # 字段: 静态字段, 普通字段
    # 方法:  普通方法 静态方法, 类方法
    #      所有方法属于类
    #      普通方法:至少一个self,对象执行
    #      静态方法:任意参数, 类执行(对象执行,基本不要用)
    #      类方法: 至少一个cls,类执行(对象执行,基本不要用)
    # 属性: 看pager.py  (@property)
    #       具有方法的写作形式,具有字段的访问形式
    
    class Province(object):
    
        # 静态字段,保存在类中
        country = '中国'
    
        def __init__(self, province):
            # 普通字段,保存在对象中
            self.name = 'province'
        # 普通方法,由对象去调用执行(方法属于类)
        def show(self):
            return self.name
    
        # 静态方法,由类调用执行,对象是封装数据的,用不到对象封装数据,使用静态方法
        # 可以有参数,可以没有
        @staticmethod
        def f1():
            return '....'
    
        # 类方法
        # 必须有一个参数cls, cls是类名  加()创建对象
        @classmethod
        def f2(cls):
            print(cls.country)
            print(cls)
    
    test = Province('henan')
    print(Province.country)
    print(test.country)
    print(test.show())
    
    
    print(Province.f1())
    
    Province.f2()
    View Code 

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

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

    三、属性

    属性定义有两种方式

    1. 装饰器 在方法上应用装饰器
      #!/usr/bin/env python
      # coding=utf-8
      
      class Pager(object):
      
          def __init__(self, page):
              self.all_count = page
      
          # 获取
          @property
          def all_pager(self):
              a1, a2 = divmod(self.all_count, 10)
              if a2 == 0:
                  return a1
              else:
                  return a1 + 1
          # 设置
          @all_pager.setter
          def all_pager(self, value):
              print(value)
      
          # 删除
          @all_pager.deleter
          def all_pager(self):
              print('del all_pager')
      
      
      p = Pager(101)
      ret = p.all_pager  # 自动去执行Pager里面的@property下的all_pager方法,下同
      print(ret)
      
      p.all_pager = 111
      
      del p.all_pager
      View Code
    1. 静态字段 在类中定义为property对象的静态字段
       1 #!/usr/bin/env python
       2 # coding=utf-8
       3 class Pager:
       4     def __init__ (self, all_count):
       5         self.all_count = all_count
       6     def f1(self):
       7         return 123
       8     def f2(self, value):
       9         pass
      10     def f3(self):
      11         pass
      12     foo = property(fget=f1, fset=f2, fdel=f3)
      13 p = Pager(101)
      14 ret = p.foo # 执行fget
      15 print(ret)
      16 p.foo = 'hexm'  # 执行fset
      17 del p.foo   # 执行fdel
      View Code

    类成员修饰符

    对于每一个类的成员而言都有两种形式:

    • 公有成员,在任何地方都能访问
    • 私有成员,只有在类的内部才能方法
     1 class Foo(object):
     2     __cc = '123'    # 公有静态字段
     3 
     4     def __init__(self, name):
     5         # 私有的,只能在类内部访问
     6         self.__name = name    # 私有字段
     7 
     8     def f1(self):
     9         print(self.__name)
    10 
    11     def f2(self):
    12         print(Foo.__cc)
    13 
    14 obj = Foo('hexm')
    15 obj.f1()
    16 # print(obj.__name)  # 错误
    17 print(obj._Foo__name)  # 最好不要用这种方式访问私有字段
    18 
    19 obj.f2()
    20 print(Foo.f1__cc)
    21 
    22 # 继承Foo也不能访问私有的
    23 class Bar(Foo):
    24     def f2(self):
    25         print(self.__name)
    26 
    27 obj = Bar('hexm')
    28 obj.f1()
    29 obj.f2()  # 错误
    View Code

    类的特殊成员

    上面介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:

    1. __doc__

      表示类的描述信息

    1 class Foo:
    2     """ 描述类信息 """
    3 
    4     def func(self):
    5         pass
    6 
    7 print Foo.__doc__
    View Code

    2. __module__ 和  __class__ 

      __module__ 表示当前操作的对象在那个模块

      __class__     表示当前操作的对象的类是什么

    1 #!/usr/bin/env python
    2 # -*- coding:utf-8 -*-
    3 
    4 class C(object):
    5 
    6     def __init__(self):
    7         self.name = 'hexm'
    lib/a.py
    1 from lib.aa import C
    2 
    3 obj = C()
    4 print obj.__module__  # 输出 lib.aa,即:输出模块
    5 print obj.__class__      # 输出 lib.aa.C,即:输出类
    index.py

    3. __init__

      构造方法,通过类创建对象时,自动触发执行。

    4. __del__

      析构方法,当对象在内存中被释放时,自动触发执行。

    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

    5.__call__

    对象后面加括号,触发执行

     1 class Foo(object):
     2     def __init__(self):
     3         # 构造方法,创建对象自动执行
     4         print('init')
     5     def __del__(self):
     6         # 析构方法
     7         pass
     8     def __call__(self):
     9         print('call')
    10 p = Foo()
    11 ret = p.__class__
    12 print(ret)
    13 p()  # 对象后面加括号,执行__call__方法
    14 Foo()()  # 先执行构造方法再执行call
    View Code

    6.__dict__

    类或对象里面所有成员

     1 class Foo:
     2     def __init__(self, name, age):
     3         self.name = name
     4         self.age = age
     5     def __call__(self):
     6         return 123
     7 test1 = Foo('hexm', 18)
     8 test2 = Foo('zhuxj', 17)
     9 # 对象里面封装的字段
    10 ret = test1.__dict__
    11 print(ret)
    12 # 类里面所有成员
    13 print(Foo.__dict__)
    View Code

    7.__str__

    在类中定义了__str__方法,在打印对象时,默认输出该方法的返回值

     1 #!/usr/bin/env python
     2 # coding=utf-8
     3 class Foo:
     4     def __init__(self, name, age):
     5         self.name = name
     6         self.age = age
     7     def __str__(self):
     8         #  print 对象时,自动执行该方法
     9         return '%s---%s' % (self.name, self.age)
    10 test1 = Foo('hexm', 18)
    11 test2 = Foo('zhuxj', 17)
    12 print(test1)
    13 print(test2)
    14 ret1 = str(test1)
    15 ret2 = str(test2)
    16 print(ret1)
    17 print(ret2)
    View Code

    8.__getitem__、__setitem__、__delitem__

    用于索引操作,如字典。以上分别表示获取、设置、删除数据

     1 #!/usr/bin/env python
     2 # coding=utf-8
     3 class Foo:
     4     def __init__(self, name, age):
     5         self.name = name
     6         self.age = age
     7     def __str__(self):
     8         #  print 对象时,自动执行该方法
     9         return '%s---%s' % (self.name, self.age)
    10     def __getitem__(self, item):
    11         if type(item) == slice:
    12             print(item.start)
    13             print(item.stop)
    14             print(item.step)
    15         elif type(item) == str:
    16             print(item)
    17     def __setitem__(self, key, value):
    18      #   print(type(key), type(value))
    19         if type(key) == slice:
    20             print(key,value)
    21     def __delitem__(self, key):
    22         print(type(key))
    23 test1 = Foo('hexm', 18)
    24 test1['sb']   # 执行__getitem__  字符串类型
    25 test1[1:3:1]    # 执行__getitem__   slice类型
    26 test1['k1'] = 'hexm'  # 执行 __setitem__
    27 test1[1:4] = [1, 2, 3, 4]
    28 del test1['k1']  # 执行 __delitem__
    29 del test1[1:4]
    View Code

    9.__iter__

    用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了__iter__

    1 #!/usr/bin/env python
    2 # coding=utf-8
    3 class Foo:
    4     def __iter__(self):
    5         return iter([1, 2, 3, 4])
    6 test = Foo()
    7 #  把对象放到for循环中,会自动执行__iter__方法, 返回的值得可迭代对象
    8 for item in test:
    9     print(item)
    View Code

    10. __add__, __del__

    在类中定义__add__, __del__时,执行两个对象相加,执行__add__,两个对象相减,执行__del__

    1 def __add__(self, lover):
    2     xxx
    View Code

    11. issbuclass, isinstance

     1 #!/usr/bin/env python
     2 # coding=utf-8
     3 class Foo:
     4     def __iter__(self):
     5         return iter([1, 2, 3, 4])
     6 
     7 class Fo(Foo):
     8     pass
     9 test = Foo()
    10 # 对象是否属于某个类
    11 ret = isinstance(test, Foo)
    12 print(ret)
    13 ret = isinstance(test, Fo)
    14 print(ret)
    15 # 一个类是否是另一个类的子类
    16 ret = issubclass(Fo, Foo)
    17 print(ret)
    View Code

    12.__enter__

    python使用with-as语法,就会调用__enter__函数,然后把函数的return值传给as后指定的变量。然后执行with-as下的语句,无论出现了什么异常,都会在离开时执行__exit__

    为了让一个对象兼容with语句,需要实现__enter__()__exit__()方法。

     1 from socket import socket, AF_INET, SOCK_STREAM
     2 class LazyConnection:
     3     def __init__(self, address, family=AF_INET, type=SOCK_STREAM):
     4         self.address = address
     5         self.family = family
     6         self.type = type
     7         self.connections = []
     8     def __enter__(self):
     9         sock = socket(self.family, self.type)
    10         sock.connect(self.address)
    11         self.connections.append(sock)
    12         return sock
    13     def __exit__(self, exc_ty, exc_val, tb):
    14         self.connections.pop().close()
    15 # Example use
    16 from functools import partial
    17 conn = LazyConnection(('www.python.org', 80))
    18 with conn as s1:
    19     pass
    20     with conn as s2:
    21         pass
    22         # s1 and s2 are independent sockets
    View Code

    创建大量对象时节省内存方法

    如果程序要创建(上百万)大量对象,导致占用很大内存。可以给类添加__slots__属性来极大减少实例所占的内存。使用slots后不能给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。

    比如:

    #!/usr/bin/env python
    # coding=utf-8
    
    class Date(objct):
        __slot__ = ['year', 'month', 'day']
        def __init__(self, year, month, day):
            self.year = year
            self.month = month
            self.day = day

     

     

  • 相关阅读:
    Luogu P4071 [SDOI2016]排列计数
    CF 961E Tufurama
    Luogu P2057 [SHOI2007]善意的投票
    Luogu P2756 飞行员配对方案问题
    POJ2151
    POJ 3349&&3274&&2151&&1840&&2002&&2503
    POJ 2388&&2299
    EZ 2018 03 30 NOIP2018 模拟赛(六)
    POJ 1459&&3436
    BZOJ 1001: [BeiJing2006]狼抓兔子
  • 原文地址:https://www.cnblogs.com/xiaoming279/p/6102514.html
Copyright © 2011-2022 走看看