Python基础教程:面向对象编程

1、面向过程 与 面向对象

        1.1 面向过程

        (1)概念

        面向过程的编程思想是将一个功能分解为一个一个小的步骤, 我们通过完成一个一个小的步骤来完成一个程序。

        (2)优缺点

        优点:简单直观,性能高效,代码简洁。

        缺点:不易维护,不易扩展,代码重用性低。

        1.2 面向对象

        (1)概念

        面向对象的编程思想是将所有的功能统一保存到对应的对象中,如需使用某个功能,直接找到对应的对象即可。

        (2)优缺点

        优点:模块化,安全性高,代码重用性高。

        缺点:学习难度大,性能开销大,调试困难。

2、类 和 对象

        2.1 类的定义与实例化对象

        (1)类的定义和作用

        类是用户定义的数据结构,用于创建对象的模板。

        在Python中,类是通过 class 关键字定义的,类名通常首字母大写。

        类定义了一组相关的属性和方法,属性用于描述对象的状态,方法用于定义对象的行为。

        通过类,可以创建多个具有相同属性和方法的对象实例‌。

        (2)对象的定义和作用

        对象是类的实例,是属性和方法的集合。

        每个对象都是类的一个独特副本,拥有类中定义的属性和方法。

        对象的创建是通过类名后加括号来实现的,每个对象可以有不同的属性值。

        对象通过点运算符 访问属性和方法‌。

# 类的定义 与 实例化对象 示例:

class Student(object):
    id = '1001'
    name = '张三'
    def __init__(self):
        pass
    def fun_1(self):
        pass

# 实例化对象
s1 = Student()
s2 = Student()
print(s1.name)
print(s2.name)

        【如上面代码所示】:

        __init__() 方法 是一种特殊的方法,被称为类的构造函数或初始化方法;

        当创建了这个类的实例时,就会自动调用该方法;

        不是必须要定义的,可以在需要的时候再定义。

        self 是一个参数,表示对象自身(对象的id号),里面存放着对象自身的地址;

        如果希望类中的方法可以被对象调用,第一个参数必须是self ;

        作用是将实例对象与类的方法进行绑定,这样实例的每个对象都能调用“属于”自己的方法;

        传参时可以省略。

        2.2 访问属性&方法

# 使用符号 . 进行访问
# 访问 类的属性
    对象名.属性
# 访问 类的方法
    对象名.方法名()

         可以使用以下函数的方法来访问属性:

        (1)getattr(obj, name[, default]):访问对象的属性;

        (2)hasattr(obj, name):检查是否存在一个属性;

        (3)setattr(obj, name, value):设置一个属性(如果属性不存在,会创建一个新属性);

        (4)delattr(obj, name):删除属性;

        2.3 对象与类的关系

        (1)对象拥有类的所有属性和方法;

        (2)对象的属性和方法可以单独添加、删除、修改;

        (3)对象与对象之间的属性和方法不可共享;

        (4)对象不能独自创建,必须依托于类,类可以实例化N个对象;

# 对象与类的关系--示例1

class Student(object):
    id = '1001'
    name = '张三'
    def fun_1(self):
        pass

# 实例化对象
s1 = Student()
s2 = Student()
# 对象的属性可以单独修改、添加、删除
s1.name = '李四'      # 修改属性 name 的值
s1.age = 18         # 添加属性 age
del s1.age          # 删除属性 age

print(s1.name)
# print(s1.age)       # AttributeError: 'Student' object has no attribute 'age'
print(s2.name)

#【运行结果】:
# 李四
# 张三

# 对象与类的关系--示例2

from types import MethodType

class Student(object):
    id = '1001'
    name = '张三'
    def fun_1(self):
        print(f"{self.name}会吃饭")
    def fun_2(self):
        print(f"{self.name}会学习")

s1 = Student()
s2 = Student()
s1.name = '刘德华'
s2.name = '蔡徐坤'
s1.fun_1()
s2.fun_1()

def sing(self):
    print(f"{self.name}会唱歌")
def dance(self):
    print(f"{self.name}会跳舞")

# 拓展对象的方法
s1.sing = MethodType(sing, s1)
s2.dance = MethodType(dance, s2)

s1.sing()
s2.dance()

#【运行结果】:
# 刘德华会吃饭
# 蔡徐坤会吃饭
# 刘德华会唱歌
# 蔡徐坤会跳舞

        2.4 魔方方法:构造函数&析构函数

        (1)__init__  构造函数:

        完成对象的初始化工作,方便统一管理;调用类创建对象时,自动执行;

        (2)__del__ 析构函数:

        删除对象时执行一些操作,自动执行;

        (3)__str__  打印方法:

        输出执行信息,自动执行。

class Car(object):
    def __init__(self, name, color):
        self.name = name
        self.color = color

    def __str__(self):
        return f"车品牌:{self.name},颜色:{self.color}"

    def __del__(self):
        print(f"{self.name}已报废,请去车管所!")


c1 = Car("奥迪A6", "黑色")
c2 = Car("小米SU7", "紫色")

print(c1.name)
print(c2.name)
print(c1)
print(c2)

#【运行结果】:
# 奥迪A6
# 小米SU7
# 车品牌:奥迪A6,颜色:黑色
# 车品牌:小米SU7,颜色:紫色
# 奥迪A6已报废,请去车管所!
# 小米SU7已报废,请去车管所!

        2.5 类属性/方法、实例对象属性/方法、静态方法


Class
属性类属性在类定义时所定义的属性,用来说明类本身
实例属性对象本身的属性,存在于 __init__ 函数中,在实例化时会赋值给该对象
self 指代的
 
方法类方法使用 @classmethod 进行修饰,第一个参数传入 cls 参数,表示类本身,用于访问类本身的属性
类方法中,只能调用类属性和类方法
可以通过类名调用,对象名调用
实例方法第一个参数传入 self 参数,没有实例化前不能调用;
实例化后,也多用对象调用而不是类来调用
静态方法使用 @staticmethod 进行装饰,与类里的数据不共享;
有自己的参数,类和对象都可以调用
静态方法内不能调用类属性和对象属性
方便实现对类和对象“无关联”的操作,但是属于类内方法实现(比如:产品使用说明,游戏规则说明)
class Student(object):
    grade = 'py24101'

    @classmethod
    def class_fun(cls):
        """类方法中,只能调用 类属性 和 类方法"""
        print(f"班级名称是:{cls.grade}")

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def example_fun(self):
        """实例方法中,能调用 类属性、实例属性"""
        print(f"实例方法中,输出类属性:{self.grade}, 输出实例属性:{self.name}")

    @staticmethod
    def static_fun(x):
        print(f"{x}静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等")


s1 = Student('张三', 18)
# 调用 类方法
Student.class_fun()
s1.class_fun()

# 调用 实例方法
Student.example_fun(s1)
s1.example_fun()

# 调用 静态方法
Student.static_fun(3)
s1.static_fun(3)

#【运行结果】:
# 班级名称是:py24101
# 班级名称是:py24101
# 实例方法中,输出类属性:py24101, 输出实例属性:张三
# 实例方法中,输出类属性:py24101, 输出实例属性:张三
# 3静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等
# 3静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等

        2.6 Python的内置类属性

        (1)__dict__ :类的属性(包含一个字典,由类的数据属性组成);

        (2)__doc__ :类的文档字符串;

        (3)__name__ :类名;

        (4)__module__:类定义所在的模块(类的全名是 '__main__.className' ,如果类位于一个导入模块 mymod 中,那么 className.__module__  等于 mymod );

        (5)__bases__ :类的所有父类构成元素(包含了一个由所有父类组成的元组);

class Student(object):
    name = '张三'
    age = 18

    def method_1(self):
        pass

    def method_2(self):
        pass

print(Student.__dict__)
print(Student.__doc__)
print(Student.__name__)
print(Student.__module__)
print(int.__module__)
print(Student.__bases__)

#【运行结果】:
# {'__module__': '__main__', '__firstlineno__': 1, 'name': '张三', 'age': 18, 'method_1': <function Student.method_1 at 0x10084b4c0>, 'method_2': <function Student.method_2 at 0x10084b560>, '__static_attributes__': (), '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
# None
# Student
# __main__
# builtins
# (<class 'object'>,)

3、类的封装(私有属性与方法)

        封装是类的三大特性之一;

        封装指的是隐藏对象中一些不希望让外部所访问的属性或方法。

        python 中封装其实是通过设置访问权限来体现的;

        私有属性 和 私有方法 是控制访问权限的组成部分。

        3.1 私有属性

        在类的内部使用,不希望外部直接访问的变量。

        在python中,使用双下划线作为前缀来定义私有属性。

        私有属性在类外不能访问。

class Bank(object):
    def __init__(self, name, pwd):
        self.name = name
        self.__pwd = pwd

    # 为了在某些场景需要的时候访问到私有属性,所以需要在类内部设置两个接口;
    def get_pwd(self):
        return self.__pwd

    def set_pwd(self, new_pwd):
        self.__pwd = new_pwd

b1 = Bank('张三', '123456')

print(b1.name)
print(b1.get_pwd())
#【运行结果】:
# 张三
# 123456

b1.set_pwd('666888')
print(b1.get_pwd())
#【运行结果】:
# 666888

        3.2 私有方法

        与私有属性是一样的。

class Bank(object):
    def __init__(self, name, pwd):
        self.name = name
        self.__pwd = pwd

    def __info(self):
        print(f"名字:{self.name},密码:{self.__pwd}")

    def get_info(self):
        self.__info()

b1 = Bank('李四', '123456')
b1.get_info()

#【运行结果】:
# 名字:李四,密码:123456

        3.3 属性装饰器

        属性装饰器:实现把 方法 转为 属性 的装饰器。

        作用:

        (1)把方法转为属性,便于操作属性;

        (2)实现对属性的更改(验证)、查看、删除;

        语法格式:

class 类名(object):
    def __init__(self):
        self.__名字 = xxx
    
    @property
    def 函数名(self):
        return self.__名字
    
    @函数名.setter
    def 函数名(self, s):
        self.__名字 += s

        示例:

class Student(object):
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, new_name):
        if not isinstance(new_name, str):
            print('名字必须是一个字符串!')
        else:
            self.__name = new_name

    @name.deleter
    def name(self):
        print("已删除名字")
        del self.__name

s1 = Student('张三')
print(s1.name)

s1.name = 111       # 非字符串则提示:名字必须是一个字符串!

s1.name = '华清远见'
print(s1.name)
del s1.name

#【运行结果】:
# 张三
# 名字必须是一个字符串!
# 华清远见
# 已删除名字

4、类的继承

        面向对象的编程带来的主要好处之一就是代码的重用,实现这种重用的方法之一就是通过继承机制。

        通过继承创建的新类称之为【子类】或者【派生类】;

        被继承的类称之为【父类】、【基类】、【超类】。

        4.1 继承语法格式

class 子类名(父类名列表):
    pass

        示例:

class Parent(object):
    par_attr = 100
    def __init__(self):
        print("初始化父类")
    def par_fun_1(self):
        print("父类方法1")
    def par_fun_2(self):
        print("父类方法2")

class Child(Parent):
    child_attr = 666
    def __init__(self):
        print("初始化子类")
    def child_fun_1(self):
        print("子类方法1")

c1 = Child()
print(c1.child_attr)
c1.child_fun_1()

print(c1.par_attr)
c1.par_fun_1()
c1.par_fun_2()

#【运行结果】:
# 初始化子类
# 666
# 子类方法1
# 100
# 父类方法1
# 父类方法2

       

        4.2 多继承语法(明白即可,不建议乱用)

        如果在继承的 元组() 里面有一个以上的类,就称之为多继承。

class A:
    pass
class B:
    pass
class C:
    pass
class D(A, B, C):
    pass

d1 = D()
# python中提供了一个函数 mro() 用于查看继承的顺序。
print(D.mro())

#【运行结果】:
# [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]

       

        4.3 继承重写父类方法

        如果你的父类方法不能满足你得要求,则可以在这个类中重写父类的方法。

class Parent(object):
    def method(self):
        print(f"{self}的方法")

class Child(Parent):
    pass

c = Child()
c.method()


# 重写
class Parent(object):
    def method(self):
        print(f"{self}的方法")

class Child(Parent):
    def method(self):
        print("Hello Class")
        print(f"{self}的方法")

c = Child()
c.method()

#【运行结果】:
# <__main__.Child object at 0x10048e900>的方法
# Hello Class
# <__main__.Child object at 0x10048ea50>的方法

        以下列出了一些通用的功能,可以在自己的类重写:

        (1)__init__ (self [,args...]):构造函数

                简单的调用方法:obj = className(args)

        (2)__del__(self):析构方法,删除一个对象

                简单的调用方法:del obj

        (3)__repr__(self):转化为供解释器读取的形式

                简单的调用方法:repr(obj)

        (4)__str__(self):用于将值转化为适于人阅读的形式

                简单的调用方法:str(obj)

        (5)__cmp__ (self, x):对象比较

                简单的调用方法:cmp(obj, x)

        4.4 python继承特点

        在子类中如果需要父类的构造方法,需要显式调用父类的构造方法;或者不重写父类的构造方法。

        在子类中调用父类的方法,需要显式调用,且第一个参数 self 不能省略。

class Parent(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def method(self):
        print(f"{self}的方法")

class Child(Parent):
    def fun_1(self):
        print(self.x , self.y)

# 不重写父类构造方法
c = Child(1, 2)
c.fun_1()

#【运行结果】:
# 1 2

class Parent(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def method(self):
        print(f"{self}的方法")

class Child(Parent):
    def __init__(self, x, y, z):
        Parent.__init__(self, x, y)
        self.z = z

    def fun_1(self):
        print(self.x , self.y, self.z)

# 重写父类构造方法、里面显式调用父类构造方法
c = Child(1, 2, 33)
c.fun_1()

#【运行结果】:
# 1 2 33

class Parent(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Child(Parent):
    def __init__(self, x, y, z):
        super().__init__(x, y)
        self.z = z

    def add(self):
        return self.x + self.y + self.z

c = Child(1, 1, 1)
print(c.add())

#【运行结果】:
# 3

class Parent(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def add(self):
        return self.x + self.y

class Child(Parent):
    def __init__(self, x, y, z):
        super().__init__(x, y)
        self.z = z

    def add(self):
        return super().add() + self.z

c = Child(1, 1, 1)
print(c.add())

#【运行结果】:
# 3

        4.5 运算符重载

        在Python中,并没有像其他语言(如C++)中那样的内置机制来重载运算符。

        但是,可以通过定义特定的方法来模拟运算符重载的行为。

        以下是一些常见运算符以及它们对应的特殊方法:

加法:+__add__
减法:-__sub__
乘法:*__mul__
除法:/__truediv__
取模:%__mod__
幂运算:**__pow__

位运算:<<

__lshift__

位运算:>>__rshift__
位运算:&__and__
位运算:|__or__
位运算:^__xor__
class Operator(object):
    def __init__(self, x):
        self.x = x

    def __add__(self, other):
        return self.x + other.x * 3

o1 = Operator(1)
o2 = Operator(3)
print(o1 + o2)

#【运行结果】:
# 10

class Operator(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return self.x * other.x + self.y * other.y

o1 = Operator(1, 2)
o2 = Operator(3, 4)
print(o1 + o2)

#【运行结果】:
# 11

5、类的多态

        python中的多态也可以通过方法重写进行。

        同一个方法,不同对象显式的结果不同。

class Animal(object):
    name = '动物'
    age = 0
    def speak(self):
        print("动物的声音")

class Dog(Animal):
    def speak(self):
        print("汪汪汪")

class Cat(Animal):
    def speak(self):
        print("喵喵喵")

a = Animal()
d = Dog()
c = Cat()

a.speak()
d.speak()
c.speak()

#【运行结果】:
# 动物的声音
# 汪汪汪
# 喵喵喵
# 

6、关于下划线说明

        (1)__foo__ :以双下划线开头双下划线结尾,定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的,自动执行。

        (2)_foo:以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import ...

        (3)__foo:双下划线的表示的是私有类型( private )的变量, 只能是允许这个类本身进行访问了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值