python学习笔记:第16天 面向对象

发布时间:2019-03-31 20:45:47编辑:auto阅读(1740)

    ⼀、类的成员介绍:

    ⾸先, 什么是类的成员. 很简单. 我么能在类中写什么? 写的内容就是成员. 到⽬前为⽌. 我们
    已经学过了⼀些成员了.

    class Foo:
        def __init__(self, a, b):
            self.a = a              # 这里的self.a和self.b都是成员
            self.b = b
    
        def method(self):           # 方法也是类的成员
            pass
    • 在上⾯代码中__init__和method都属于类的成员⽅法,⼜称为实例⽅法。总之这样的东⻄
      需要⽤对象来访问。
    • 上⽅的self.a = a这个代码的含义是给对象设置属性信息,含义是这个对象的xxx属性是xxxx. 这种东⻄⼜被称之为成员变量或者实例变量, 再或者被称之为字段。

    二、类的成员-变量

    在类中变量分成两⼤类:

    1. 实例变量(字段)
    2. 类变量(静态变量)

    1. 实例变量

    其实之前写的都是实例变量,所谓实例变量就是实例(也就是对象)的变量,实例也是就是指self,也是就是说,前面写的self.xxx都是实例变量:

    class Foo:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    f1 = Foo('Jerry', 18)
    f2 = Foo('James', 29)
    print(f1.name, f1.age)              # 每个对象都拥有自己的实例变量
    print(f2.name, f2.age)              # 实例变量都必须要通过实例来调用
    
    # 结果:
    # Jerry 18
    # James 29

    2. 类变量

    类变量是一个类所拥有的,每个实例也可以直接访问类变量。类变量就可以看作是一个类公有的一种变量,如果对象自己没有设置这个值,那么默认就用统一的类变量。

    class Person:
        country = '中国'                # 类变量
        
        def __init__(self, name, age):  # 实例变量中并没有设置country属性
            self.name = name
            self.age = age
    
    Person.country = '大清'
    print(Person.country)               # 打印结果是:大清
    
    p1 = Person('zzc', 26)
    print(p1.country)                   # 打印结果也是大清

    从上面的例子可以看出如果对象中没有country属性,那么会使用类变量country,下面再看一个例子:

    class Person:
        country = '中国'
        
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    Person.country = '大清'              # 类变量修改后变成了‘大清’ 
    
    p1 = Person('zzc', 26)
    print(p1.country)                   # 打印结果是:大清
    
    p2 = Person('milkgood', 27)
    print(p2.country)                   # 打印结果也是大清

    上面的例子说明,变量p1p2使用的都是同一个变量country,在手动把类变量的值修改过后,变量p1p2所对应的country也跟着改变了,所以他们是指向的同一块物理地址。下面我们把上面的程序改一下,来看⼀个和类变量息息相关的坑:

    class Person:
        country = '中国'
        
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    # Person.country = '大清'           # 这里先把修改类变量的语句注释了
    print(Person.country)               # 首次打印的是类变量最开始时候的值
    
    p1 = Person('zzc', 26)              # 然后实例化了一个对象p1
    p1.country = '大清'                 # 然后修改了对象中的country的值为大清
    print(p1.country)                   # 此时打印结果是:大清
    
    p2 = Person('milkgood', 27)         # 再次实例化了一个对象p2
    print(p2.country)                   # 打印结果还是中国
    
    # 输出结果:
    # 中国
    # 大清
    # 中国

    我们来看下面的图来分析:

    好了. 来对类成员中的变量做个简单的总结:

    • 实例变量:给对象⽤的.
    • 类变量:多个对象共享的. 最好是⽤类名来访问. 这样更加规范

    三、类的成员-方法

    类中的方法分为三种:

    1. 成员⽅法(实例⽅法)
    2. 静态⽅法
    3. 类⽅法

    1. 成员方法

    成员方法也是之前写的最多的方法,可以说之前写的方法都是成员方法,也就是说对象直接访问的方法就是成员方法

    class Car:
        def run(self):
            print('老司机永不翻车')
            
        def jump(self):                # 这中带self参数的都是实例方法,之前写的都是实方法
            print('you jump i jump')
            
    c = Car()
    c.run()
    c.jump()
    
    # 输出结果:
    # 老司机永不翻车
    # you jump i jump

    实例方法也能像实例变量一样赋值

    def fly():
        print('我是一辆会飞的车')
    
    class Car:
        def run(self):
            print('老司机永不翻车')
            
        def jump(self):                # 这中带self参数的都是实例方法,之前写的都是实方法
            print('you jump i jump')
            
    c = Car()
    c.fly = fly         # 像实例变量一样把函数名赋值给实例的一个属性
    c.fly()             # 打印结果: 我是一辆会飞的车

    2. 类方法

    跟类变量一样,是属于类的命名空间的,可以直接通过类名来访问(需要传入一个参数cls),但是要注意,类方法需要在函数上加上一个名为classmethod的装饰器

    class Person:
        def eat(self):
            print('i\'m eating')
        
        @classmethod                    # 加上classmethod装饰器
        def drink(cls):                 # 这个cls参数在使用类调用时,python解释器会自动传入
            print(cls)
            print('i\'m drinking')
            
    print(Person)
    Person.drink()                      # 使用类名直接访问
    
    p = Person()
    p.drink()                           # 也可以实例化对象后,通过对象访问,但是不建议这么做
    
    # 打印结果:
    # <class '__main__.Person'>
    # <class '__main__.Person'>
    # i'm drinking
    # <class '__main__.Person'>
    # i'm drinking

    3. 静态方法

    静态方法也跟类方法一样,跟对象无关,直接使用类直接访问且无需参数,但是要加上staticmethod装饰器

    class Foo:
        def __init__(self, user):
            self.user = user
    
        @staticmethod                       # 加上staticmethod装饰器
        def staticMthod():                  # 这里不用传入参数
            print('这是一个静态方法')
    
    Foo.staticMthod()                       # 直接使用类访问
    f = Foo('s')
    f.staticMthod()                         # 也可以通过对象访问,不过不建议
    
    # 输出结果
    # 这是一个静态方法
    # 这是一个静态方法

    既然静态方法和类方法都是跟对象无关的,都可以通过类来访问,那么他们有什么区别呢:

    • 类方法在传参的时候,需要传入一个类,而静态方法在使用时不需要传入任何参数,可以直接通过类调用
    • 类方法在传参的时候接收了一个参数,cls可以通过cls访问类中的变量,而静态方法则不行,静态方法需要使用类名来访问(即使在类的内部也是如此)

    四、类的成员-属性

    属性其实就是通过⽅法改造过来的⼀种变量的写法, 在⽅法上添加⼀个@property就可以了

    class Person:
        def __init__(self):
            pass
        @property
        def age(self):
            return 1
    
    p = Person()
    age = p.age
    print(age)

    应⽤场景: 我们⼀般保存数据的时候, 不会保存⼀个⼈的年龄. 因为随着时间的推移. 每个⼈的年龄都时刻在改变着. 那如何保存更加完美呢? 很简单. 保存出⽣年⽉⽇. 然后⽤程序来计算,你当前的年龄. 实时的. 那这个时候就需要进⾏相应的计算了. ⽽计算属于⼀个功能. 当然要写⽅法⾥了. 但是对于年龄这个属性⽽⾔. 他应该是⼀个数值. ⽽不是动作. 所以python就提供了这样⼀种机制. 通过⽅法来描述⼀个属性.

    注意:

    • ⽅法参数只能有⼀个self
    • ⽅法上⽅要写@property
    • 调⽤的时候, 我们不需要写括号. 直接当成属性变量来⽤就可以了.
    • 这种套路只能取值. 不能设置值

    五、私有属性

    在python的类中使用__xx(以双下划线开头,不能以双下划线结尾)来定义一个私有属性,定义的私有属性一般(除去使用特殊的方法)是从外面获取不到的。

    class Foo:
        __c = 30                # 私有类变量
        def __init__(self):
            self.a = 10
            self.__b = 20       # 私有的实例变量
    
        def __func(self):       # 私有方法也跟私有变量一样
            print('私有方法')
    
    f = Foo()
    print(f.a)                  # 下面的都会报错
    print(f.__b)                # AttributeError: 'Foo' object has no attribute '__b'
    print(Foo.__c)              # AttributeError: type object 'Foo' has no attribute '__c'
    f.__func()                  # AttributeError: 'Foo' object has no attribute '__func'

关键字