python基础(12):面向对象编程

一、面向对象

编程的方式

  • 面向过程:根据业务逻辑从上到下垒代码。
  • 函数式:将某功能封装到函数中,日后便无需重复编写,仅调用函数即可。
  • 面向对象:对函数进行分类和封装,让开发“更快更好更强……”

什么是面向对象:

        面向对象就不像面向过程那样按照功能划分模块了,它所关注的是软件系统有哪些参与者,把这些参与者称为对象,找出这些软件系统的参与者也就是对象之后,分析这些对象有哪些特征、哪些行为,以及对象之间的关系,所以说面向对象的开发核心对象

什么是类:

        面向对象编程的2个非常重要的概念:类和对象

        类是对象的类型,具有相同属性行为事物的统称。类是抽象的(不存在的),在使用的时候通常会找到这个类的一个具体存在

什么是对象:

        万物皆对象,对象拥有自己的特征和行为。

类和对象的关系:

        类是对象的类型,对象是类的实例。类是抽象的概念,而对象是一个你能够摸得着但得到的实体。二者相辅相成,谁也离不开谁。

类由三个部分构成:

  • 类的名称:类型
  • 属性:对象的属性
  • 方法:对象的方法

二、创建和使用:

类定义:

class 类名:
    属性列表
    方法列表

例:

'''
类定义
class 类名():
    # 类文档说明
    属性
    方法
'''

class person():
    '''
    这是一个人类
    '''
    country = '中国'   # 声明类属性并赋值
    
    # 实例属性通过构造方法来声明
    # self不是关键字,代表的是当前对象
    def __init__(self, name, age, sex):     # 构造方法
        # 构造方法不需要调用,在实例化的时候自动调用
        print('我是构造方法,在实例化的时候调用')
        self.name = name            # 通过self创建实例属性,并且赋值
        self.age = age
        self.sex = sex
        
    # 创建普通方法
    def getName(self):
        print('我的名字叫:%s,我来自%s'%(self.name, person.country)) # 在方法里面使用实例属性
        
# 实例化对象
people1 = person('joe', 1, '男')  # 在实例化的时候传进参数
# 这个people1就要具有三个属性,并且可以使用getName方法

# 访问属性
print(people1.name)  # 通过对象名.属性名 访问实例属性(对象属性)

# 通过对象调用实例方法
people1.getName()
# output:我的名字叫:joe,我来自中国

__init__()构造方法和self:

  • __init__()是一个特殊的方法,属于类的专有方法,被称为类的构造函数或初始化方法,方法的前面和后面都有两个下划线。
  • 这是为了避免Python默认方法和普通方法发生名称的冲突。每当创建类的实例化对象的时候,__init__()方法都会默认被运行。作用就是初始化已实例化后的对象。
  • 在方法定义中,第一个参数self是必不可少的。类的方法和普通的函数的区别就是self,self并不是Python关键字,你完全可以用其他单词取代,只是按照惯例和标准的规定,推荐使用self。

类的属性分类(创建一个people类):

  • 类属性
  • 实例属性
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。如果需要用,在函数中使用类名.类属性
  • 实例变量:定义在方法中的变量,只作用于当前实例的类。

针对类的属性的一些方法:

  • 可以使用实例化对象名+.来访问对象的属性
  • 也可以使用一下函数的方式来访问属性
'''
getattr(obj, name[, default]): 访问对象的属性
hasattr(obj, name): 检查是否存在一个属性
hasattr(obj, name, value): 设置一个属性。如果属性不存在,会创建一个新属性
delattr(obj, name): 删除属性
'''
print(getattr(people1, 'name'))  # output:joe
print(hasattr(people1, 'name'))  # output:True

setattr(people1, 'name', 'susan')
print(people1.name)     # output:susan

delattr(people1, 'name')
print(people1.name)         
# output:AttributeError: 'person' object has no attribute 'name'

内置类属性:

Python内置类属性:

  • __dict__:类的属性(包含一个字典,由 类的属性名:值 组成)实例化类名.__dict__
  • __doc__:类的文档字符串    (类名.)实例化类名.__doc__
  • __name__:类名,实现方式  类名.__name__
  • __bases__:类的所有父类构成元素(包含了由所有父类组成的元祖)
'''
内置类属性
'''
print(people1.__dict__)
# output:{'age': 1, 'sex': '男', 'name': 'susan'}
# 会将实例对象的属性和值通过字典返回

print(people1.__doc__)
# output:这是一个人类

print(person.__name__)  # 返回类名
# output:person

print(person.__bases__)
# output:(<class 'object'>,)

 __name__

  • __name__: 如果是放在Modules模块中,就表示是模块的名字;如果是放在Class类中,就表示类的名字;
  • __main__: 模块,xxx.py文件本身,被直接执行时,对应的模块名就是__main__了。可以在if __name__ == "__main__":中添加你想要的,用于测试模块,演示模块用法等代码。
  • 作为模块,被别的Python程序导入(import)时,模块名就是本身文件名XXX了。

 例:

假设有两个文件,一个是name1.py:

def a():
    print('我是a方法')

print(__name__)
# output:__main__

输出:

另一个文件是name2.ph:

import name1

 输出:

测试时,可以把name1.py写成:

def a():
    print('我是a方法')
if __name__ == '__main__':
    a()

即,只在当前脚本运行时,运行a(),其他脚本引入时,不运行a()。

三、继承和多态

继承:

        程序中,继承描述的是事物之间的所属关系,例如猫狗都属于动物,程序中可以描述为猫和狗都继承自动物。同理,波斯猫和家猫都继承自猫。程序中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称之为子类(subclass),而被继承的class称之为基类、父类或超类。子类继承了其父类所有属性和方法,同时还可以自定义自己的属性和方法。

        python时多继承的,即一个子类可以继承多个父类。

class Animal():
    def __init__(self, name, food):
        self.name = name
        self.food = food
        
    def eat(self):
        print('%s爱吃%s'%(self.name, self.food))
        
# Dog类继承Animal
class Dog(Animal):          # python中的继承,只要把父类名写在括号里就行
    def __init__(self, name, food, drink):
        super().__init__(name, food)      # 加载父类中的初始化方法
        self.drink = drink
    def drinks(self):
        print('%s爱喝%s'%(self.name, self.drink))
        
# Cat类继承Animal
class Cat(Animal):
    def __init__(self, name, food, drink):
        super().__init__(name, food)
        self.drink = drink
    def drinks(self):
        print('%s爱喝%s'%(self.name, self.drink))
        
# 子类(Dog和Cat)继承了父类(Animal)的全部功能,自动拥有了父类的eat()方法
dog1 = Dog('小狗','骨头','肉汤')
dog1.eat()
dog1.drinks()

cat1 = Cat('小猫','鱼','牛奶')
cat1.eat()
cat1.drinks()

输出:

多继承:

python中多继承的语法格式如下:

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    ...
    ...
    <statement-1>

        注意圆括号中父类的顺序,如果继承的父类中有相同的方法名,而在子类中使用时未指定,python将从左至右查找父类中是否包含方法啊。 

class A():
    def a(self):
        print('我是A里的a方法')
        
class B():
    def b(self):
        print('我是B里的b方法')
        
class C():
    def c(self):
        print('我是C里的c方法')
        
class D(A, B, C):
    def d(self):
        print('我是D里的d方法')
        
dd = D()
dd.a()
dd.b()
dd.c()
dd.d()

 输出:

四、类属性和实例属性

属性:

        尽量把需要用户传入的属性作为实例属性,而把同类都一样的属性作为类属性。实例属性在每创造一个类时都会初始化一遍,不同的实例的实例属性可能不相同,不同实例的类属性都形同。

1.实例属性:

        在__init__(self, ...)中初始化

        内部调用时都需要加上self。

        外部调用时用“对象名.属性名”调用

2.类属性:

        在__init__()里初始化

        在内部用classname.类属性名调用

        外部既可以用classname.类属性名,又可以用instancename.类属性名来调用

3.私有属性:

        (1)双下划线__开头:外部不可通过“对象名.属性名”来访问或者更改实际将其转化为了“_类名__属性名”

class person():
    '''
    这是一个人类
    '''
    country = '中国'   # 声明类属性并赋值
    
    # 实例属性通过构造方法来声明
    # self不是关键字,代表的是当前对象
    def __init__(self, name, age, sex, address):     # 构造方法
        # 构造方法不需要调用,在实例化的时候自动调用
        print('我是构造方法,在实例化的时候调用')
        self.name = name            # 通过self创建实例属性,并且赋值
        self.age = age
        self.sex = sex
        self.__address = address # 双下划线开头的属性是私有属性
        
    # 创建普通方法
    def getName(self):
        print('我的名字叫:%s,我来自%s'%(self.name, person.country)) # 在方法里面使用实例属性
        
# 实例化对象
people1 = person('joe', 1, '男')  # 在实例化的时候传进参数

# 通过对象名.属性名访问私有属性
print(people1.__address)

 输出:AttributeError: 'person' object has no attribute '__address'

        私有属性只能在类内使用!

或者强制访问:

print(people1._person__address)

输出: 

再或者:外部要修改私有属性,预留一个借口去访问或者修改私有属性。例如,可在类内加如下方法。

def getAddre(self):
    return self.__address

 单下划线、双下划线、头尾双下划线说明:

  • __foo__: 定义的是特殊方法,类似__init__()之类的。
  • _foo: 以单下划线开头的表示的是protected类型的变量,即保护类型只能允许其本身与子类进行访问(创建的实例可以访问),不能用于from module inport *
  • __foo: 双下划线的表示的是私有类型(private)的变量,只能是允许这个类本身进行访问。

五、访问限制

  • 设置为私有属性不能直接通过对象访问属性,但可以通过“实例化对象._类名__属性名”直接访问。但不建议这样操作。不同版本的Python解释器可能会把“__属性名”改成不同的变量名。总的来说,python本身没有任何机制阻止你干坏事,一切全靠自觉。
  • 通过“对象名.__属性名”直接修改私有属性。表面上看好像修改了,其实并没有。因为python解释器已经将对象内部的属性名解释成“_类名__属性名”。如果在外部修改相当于另外声明一个属性。
people1.__address = '上海'
# 看上去改了,其实没有。你给当前对象声明了一个新属性

print(people1.__address)
print(people1.getAddre())

输出:

六、类方法与静态方法 

1. 普通方法:

def fun_name(self, ...):
    pass
外部用实例调用

2.静态方法:通过装饰器 @staticmethod 装饰

  • 不能访问实例属性
  • 参数不能传入self
  • 与类相关但是不依赖于实例的方法
    # 创建一个静态方法
    @staticmethod
    def aa():           # 不需要传递实例
        print('我的名字叫:%s'%self.name)

people1 = person('joe', 1, '男')
people1.aa()

会报错:name 'self' is not defined

所以只能访问类属性

    # 创建普通方法
    def getName(self):
        print('我的名字叫:%s,我来自%s'%(self.name, person.country)) # 在方法里面使用实例属性
        
    # 创建一个静态方法
    @staticmethod
    def aa():           # 不需要传递实例
        print('我来自:%s'%person.country)

people1 = person('joe', 1, '男')
people1.aa()

输出:

3. 类方法:@classmethod

  • 不能访问实例属性
  • 参数必须传入cls(即代表了此类对象,区别,self代表实例对象),并且用此来调用雷属性:cls.类属性名
    # 类方法
    @classmethod
    def bb(cls):        # class   也不是关键字
        # 类方法不能访问实例属性
        print('我的名字叫:%s'%cls.country)  # 就用cls访问类属性
        
people1 = person('joe', 1, '男')
people1.bb()

输出:

        静态方法与类方法都可以通过类或实例来调用。特点都是不能调用实例属性。静态方法不需要接受参数,使用类名.类属性

猜你喜欢

转载自blog.csdn.net/qq_26271435/article/details/89812826
今日推荐