面向对象的进阶(一)

面向对象进阶(一)

一、类的成员

  类的成员分为三类 : 变量、方法、属性。

二、变量

  变量分为:

    1) 实例变量  (字段)

      a) 公有实例变量(公有字段)

      b)    私有实例变量(私有字段)

    2) 类变量   (静态字段)

      a)公有变量 (公有静态字段)

      b)私有类变量  (私有静态字段)

分析下面示例,并了解实例变量和类变量:

# ######示例一(类变量和实例变量)
  class Foo:
      country = "中华人民共和国"  # 类变量(静态字段)
    
      def __init__(self, name):
          self.name = name  # 实例变量(字段)
        
      def func(self):
          pass
  obj1 = Foo("juan")
  obj2 = Foo("sylar")
  print(obj1.name)  # juan
  print(Foo.country)  # 或print(obj1.name)  结果为:中华人民共和国

上述示例一得如下准则:

    实例变量(字段)访问时,使用对象访问,即obj1.name

    类变量(静态字段)访问时,使用类访问,即Foo.country(实在不方便时,才使用对象访问)

# 易错点--通过类的某个对象改变类变量的值,该类的其他对象不会受影响,通过类改变类变量,该类的所有对象都会跟着改变
    obj1.country = "美国"
    print(obj1.country)  # 美国
    print(obj2.country)  # 中国

    Foo.country = "美国"
    print(obj1.country)  # 美国
    print(obj2.country)  # 美国

问题一:什么时候使用类变量?

    当所有对象中有共同的字段,且要改都改,要删都删时,可以将实例变量(字段)提取到类变量(静态变量)。

# ######示例二(私有实例变量(私有字段))
    class Foo:
        def __init__(self,name):
            # 规则:公有实例变量前加两个下划线(变量成员修饰符)就是私有实例变量
            self.__name = name    # 私有实例变量(私有字段)
            self.age = 123

        def func(self):
            print(self.__name)

    obj = Foo('alex')
    print(obj.age)  # age是公有实例变量  可以访问  结果为:123
    # obj.__name  # name是私有实例变量  无法直接访问
    obj.func()  # 找一个内部人:func, 让func帮你执行私有 __name  结果为:alex
# ######示例三(私有类变量(私有静态变量))
    class Foo:
        # 规则:公有类变量前加两个下划线(变量成员修饰符)就是私有类变量
        __country = "中国"   # 私有类变量(私有静态变量)

        def func(self):
            # 内部调用
            print(self.__country)
            print(Foo.__country)  # 推荐使用类来使用静态变量

    # print(Foo.country)  # 报错  外部无法使用私有类变量
    obj = Foo()
    obj.func()
    # 结果为:
    # 中国
    # 中国
# ######示例四(验证该类的子类也不能访问该类的私有变量)
    class Base(object):
        __secret = "受贿"

    class Foo(Base):
        def func(self):
            print(self.__secret)
            print(Foo.__secret)
        
    obj = Foo()
    obj.func()  
    # 报错  AttributeError: 'Foo' object has no attribute '_Foo__secret'

三、方法

  方法分为:

    1)实例方法

      a)公有实例方法

      b)私有实例方法

    2)静态方法

      a)公有静态方法

      b)私有静态方法

    3)类方法

      a)公有类方法

      b)私有类方法

  分析下面示例,并了解实例方法、静态方法、类方法:

# ######示例一(实例方法)
    class Foo(object):
        def __init__(self, name):
            self.name = name
        # 实例方法
        def func(self):
            print(self.name) # 使用了对象中封装的值

    obj = Foo('alex')
    obj.func()
# ######示例二(静态方法 @staticmethod  参数可有可无)
    class Foo(object):
        def __init__(self, name):
            self.name = name
        # 静态方法,如果方法无需使用对象中封装的值,那么就可以使用静态方法
        @staticmethod
        def display(a1,a2):
            return a1 + a2

    print(Foo.display(1,3))  # 4

静态方法总结:

    1)定义时:方法上方写@staticmethod、方法参数可有可无;

    2)执行时:推荐用 类.方法名(),也可以用对象.方法名(),但是不推荐;

    3)什么时候写静态方法:无需调用对象中封装的值时;

# ######示例三(类方法 @classmethod  参数只有cls)
    class Foo(object):
        # 类方法,自动传递cls,cls就是这个类
        @classmethod
        def show(cls, x1, x2):
            print(cls, x1, x2)

    # 执行类方法
    Foo.show(1, 8)  # <class '__main__.Foo'> 1 8

类方法总结:

    1)定义时:方法上方写@classmethod、方法至少有一个cls参数;

    2)执行时:类名.方法名()   注意:默认会将当前类传到参数中,也可用 对象名.方法名() 但不推荐;

    3)什么时候写类方法:如果在方法中会使用到当前类,那么就可以使用类方法;

  面试题:静态方法/类方法和实例方法的区别?

         定义时:

      静态方法/类方法:方法上方分别要加@staticmethod/@classmethod;

                实例方法:方法上方不用加东西;

         调用时:

                静态方法/类方法:通过 类名.方法名() 调用;

                实例方法:通过 对象名.方法名() 调用;

         应用场景:

                静态方法:在方法内部不会用到对象封装的数据时;

      类方法:在方法内部不会用到对象封装的数据,且会用到当前类时;

                实例方法:在方法内部需要用到对象封装的数据时;

  同变量类似,方法也有私有方法,规则分别是在公有方法名前加两个下划线(方法成员修饰符),如下:

# ######示例四(私有实例方法、私有静态方法、私有类方法)
    class Foo(object):
        def __init__(self, name):
            self.name = name

        def __fun1(self):
            print("私有实例方法",self.name)

        @staticmethod
        def __display():
            print('私有静态方法')

        @classmethod
        def __func(cls):
            print(cls, "私有类方法")

    obj = Foo("juan")
    # obj.__fun1()  # 无法访问
    # Foo.__display()  # obj.__display() # 类和对象都无法访问
    # Foo.__func()  # 无法访问

私有方法
私有方法

四、属性

  属性是通过实例方法改造出来的,属性也分为公有属性和私有属性,看如下有关属性的示例:

# ######示例一
    class Foo(object):
        @property  # 属性
        def start(self):
            return 1

        @property  # 属性
        def end(self):
            return 10

    obj = Foo()
    print(obj.start)  # 调用时不用加括号  结果为:1   
    print(obj.end)  # 调用时不用加括号  结果为:10   
    # 在公有属性方法名前加两个下划线就是私有属性,不再举例

属性总结:

    1)定义时:方法上方写@property、方法参数只有一个self;

    2)调用时:无需加括号,直接写  对象.方法   即可;

    3)应用场景:对于简单的方法,当无需传参且有返回值时,可以使用@property;

class Pagenation(object):
        """
        处理分页相关的代码
        """
        def __init__(self, data_list, page, per_page_num = 10):
            """
            初始化
            :param data_list: 所有的数据
            :param page: 当前要查看的页面
            :param per_page_num: 每页默认要显示的数据行数
            """
            self.data_list = data_list
            self.page = page
            self.per_page_num = per_page_num

        @property
        def start(self):
            """
            计算索引的起始位置
            :return:
            """
            return (self.page-1) * self.per_page_num

        @property
        def end(self):
            """
            计算索引的结束位置
            :return:
            """
            return self.page * self.per_page_num

        def show(self):
            """
            打印一页的内容
            :return:
            """
            result = self.data_list[self.start:self.end]
            for row in result:
                print(row)

    data_list = []
    for i in range(1, 901):
        data_list.append('alex-%s' % i)
    while True:
        page = int(input('请输入要查看的页码:'))
        obj = Pagenation(data_list,page)
        obj.show()

属性应用示例-分页
属性应用例子---页码分页

五、组合或嵌套(建模)

  这里的嵌套不是专业的词汇,是我们用大白话解释的。面向对象中的嵌套其实就是对象的相互嵌套,看如下一个对象嵌套的示例:

class School(object):  # 定义一个学校类
      def __init__(self, name, address):
          self.name = name
          self.address = address
      def speech(self):
          print('讲课')
  # 创建三个学校对象
  obj1 = School('北京校区', '昌平区')
  obj2 = School('上海校区', '浦东新区')
  obj3 = School('深圳校区', '南山区')
  class Teacher(object):  # 定义一个老师类
      def __init__(self, name, age, salary):
          self.name = name
          self.age = age
          self.__salary = salary
          self.school = None
  # 创建三个老师对象
  t1 = Teacher('李杰', 19, 188888)
  t2 = Teacher('sylar', 18, 60)
  t3 = Teacher('女神',16, 900000)
  # 给老师分配校区
  t1.school = obj1  # t1对象的school变量是一个obj1对象
  t2.school = obj1
  t3.school = obj2
  # 查看t1老师,所在的校区名称/地址
  print(t1.school.name)
  print(t1.school.address)
  print(t1.name)
  print(t1.age)
  t1.school.speech()
原文地址:https://www.cnblogs.com/wxj1129549016/p/9554747.html