python面向对象

编程思想

目前普遍的编程思想有2种:面向过程、面向对象
简单点理解,面向过程就是体现过程,面向对象是针对某一类事物。
比如去饭店吃饭,面向过程就是:客户点单->厨师拿到菜单做菜->服务员上菜->客户吃饭;而面向对象,则将过程中客户、厨师、服务员分为3个不同的对象,客户负责点单、吃饭,厨师负责做菜,服务员负责上菜,每个对象负责自己范围内的事情,将整个流程走通。不像面向过程一样,来多个客户就又有多个过程,面向对象中,对于客户来说,只关心菜有没有(点单)以及上没上,厨师和服务员对客户来说不影响,而对厨师来说,客户相当于不存在,只关心客户产生的订单,所以来了多少客户都没有关系,按照订单上的菜品做菜就行。面向对象就比较方便管理、维护,后续如果有什么流程优化,只需要针对各个对象去优化,而不必像面向过程一样,整个过程去优化和考虑。

类(class):抽象的概念,一类事物。
方法:类中定义的函数,对外提供的服务。
类变量:类变量在整个实例化的对象中是公用的
实例引用:实例化一个对象
实例变量:以‘self.变量名’的方式定义的变量

类定义

# 以“class 类名”的方式来定义类
class ClassName:
	xxx

类对象

对象

类一般是通过类名(参数)来实例化对象,对象可通过对象名.变量名来访问对象的属性,通过对象名.方法名(参数)来调用类的实例方法。

class MyClass:
    # 在类内部,以“变量名=值”的方式来定义实例变量(属性),实例变量即在通过类实例化成对象时,对象都有该实例变量,并有默认值
    var1 = "xxx"
    var2 = "xxx2"

    # 在类内部,以“def 方法名(self[,参数]): 执行语句”的格式来定义实例方法
    def method1(self, param):
        print(param)
        print(f"实例方法内部调用:{self.var1}, {self.var2}")

# 实例化MyClass类
obj = MyClass()
# 访问实例(对象)的属性和方法
print(obj.var1, obj.var2)
obj.method1("实例方法调用")

以上执行结果为:

xxx xxx2
实例方法调用
实例方法内部调用:xxx, xxx2

构造方法

类中有且仅有一个构造方法__init__(),该方法在类实例化时会自动调用

class MyClass:
    def __init__(self):
        print("构造方法")


obj1 = MyClass()
print("---------------")
obj2 = MyClass()

执行结果为:

构造方法
---------------
构造方法

构造方法可以有参数,当构造方法的参数无默认值的时候,实例化对象时,必须传入参数

class MyClass:
    var1 = "default"

    def __init__(self, var1, var2=45):
        self.var1 = var1
        print(var1, var2)

obj3 = MyClass(123)
print("---------------")
obj4 = MyClass("离职", 88)

执行结果为

123 45
---------------
离职 88

实例方法的第一个参数

在定义实例方法的时候,第一个参数必须是self,这个参数表示实例对象自己,在方法中可以通过self.xxx来调用实例方法和访问对象属性。self代表类的实例,代表当前对象的地址。我们可以通过__class__来确定当前实例的类

class MyClass:
    var = "不知道"

    def method1(self, var1):
        self.var = var1
        print(f"method1方法:{self.var}")

    # 实例方法的第一个参数并不一定是self,可以取其他名字,总之是代表对象本身,但是按照惯例,使用self比较好
    def method2(xxx, var1):
        xxx.var = var1
        print(f"method2方法:{xxx.var}")


obj = MyClass()
obj.method1(67)
obj.method2("风扇")
# 直接打印obj变量,是打印出来对象的地址
print(f"对象的地址:{obj}")
# 通过__class__可以获取该对象的类
print(f"对象的类是:{obj.__class__}")

执行结果为:

method1方法:67
method2方法:风扇
<__main__.MyClass object at 0x0000026738003EB0>
<class '__main__.MyClass'>

类变量

类变量是区别于实例变量的说法,类变量是以类名.变量名的方式访问的,类变量的更新会影响到后续实例化对象,不影响已实例化的对象,实例化对象的更新不影响类变量

class MyClass:
    var = "不知道"

    def method(self, var1):
        self.var = var1
        print(f"method1方法:{self.var}")


obj1 = MyClass()
print("---------更新前---------")
# 通过类名.变量名来访问类变量
print(f"类的var:{MyClass.var}")
print(f"对象的var:{obj1.var}")

print("---------对象的var更新---------")
obj1.var = 345
print(f"类的var:{MyClass.var}")
print(f"对象的var:{obj1.var}")

print("---------类的var更新---------")
MyClass.var = 89
print(f"类的var:{MyClass.var}")
print(f"对象的var:{obj1.var}")
print(f"类的var更新,再创建的新对象的var:{MyClass().var}")

执行结果如下:

---------更新前---------
类的var:不知道
对象的var:不知道
---------对象的var更新---------
类的var:不知道
对象的var:345
---------类的var更新---------
类的var:89
对象的var:345
类的var更新,再创建的新对象的var:89

类方法

类方法就是通过类就可以访问的方法,与实例方法不同,实例方法需要通过实例化对象,以对象来调用。
1、类方法的调用为类名.方法名,对象调用类方法会报错。
2、类方法需要经过@classmethod来修饰,实例方法不用。
3、类方法的第一个参数一般是cls(也可以是其他名字),表示该类。实例方法的一个参数表示实例本身。即实例方法是在类实例化的基础上进行使用,必须进行类的实例化,而类方法可以在类、实例上使用。且类方法不能调用该类的实例方法(实例方法需要类实例化)。
4、类方法可以调用类内的类方法和类变量,但是不能调用实例方法和实例变量;实例方法可以调用类方法

class MyClass:
    var1 = "value1"

    @classmethod
    def method1(cls, param1):
        cls.var1 = param1

print(MyClass.var1)
MyClass.method1(45)
print(MyClass.var1)
print(MyClass().var1)

执行结果为

value1
45
45

在类方法中,第一个参数代表了当前类,所以有一些比较有趣的用法,可以用该参数去创建实例,示例如下:

class DateFormat:
    def __init__(self, year=2022, month=1, day=1):
        self.year = year
        self.month = month
        self.day = day

    def out_date(self):
        print(f"{self.year}年,{self.month}月,{self.day}日")

    @classmethod
    def json_format(cls, json_data: dict):
        year, month, day = json_data.values()
        # 因为cls代表了当前类,所以cls(year, month, day)实际上是:DateFormat(year, month, day),即调用了构造方法(参数与构造方法一致)
        return cls(year, month, day)

dd = DateFormat(2022, 5, 19)
print(dd)
dd.out_date()
print("--------------------------")

json_date = {"year": 2022, "month": 8, "day": 28}
demo = DateFormat.json_format(json_date)
print(demo)
demo.out_date()

执行结果为:

<__main__.DateFormat object at 0x000001959DF23D90>
2022年,5月,19日
--------------------------
<__main__.DateFormat object at 0x000001959DF22C20>
2022年,8月,28日

私有属性和私有方法

私有属性以两个下划线__开头进行修饰,私有属性不能在类的外部被使用或直接访问,在实例方法中使用。
私有方法也是以两个下划线__开头修饰,私有方法只能在类的内部调用。

class MyClass:
    publicVar = "public"
    __secretVar = "secret"

    def __method1(self):
        print("这个是私有方法")

    def method2(self):
        self.publicVar = "public_chn"
        self.__secretVar = "secret_chn"
        self.__method1()

mc = MyClass()
print(mc.publicVar)
mc.method2()
print(mc.publicVar)
# __secretVar是私有方法,不能类的外部使用,会报错
print(mc.__secretVar)

执行结果为:

Traceback (most recent call last):
  File "E:\hogwart\demo\demo.py", line 17, in <module>
    print(mc.__secretVar)
AttributeError: 'MyClass' object has no attribute '__secretVar'
public
这个是私有方法
public_chn
类的专有方法:
__init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__truediv__: 除运算
__mod__: 求余运算
__pow__: 乘方

继承、多态

继承:类似于子承父业,即定义一个类A1继承了另一个类A,则称A1为A的子类,A为A1的父类。A1默认有A的属性和方法。

class 子类名称(父类名称):
    <statement-1>
    .
    .
    .
    <statement-N>

子类继承

子类会继承父类的属性和方法

class people:
    name = ""
    age = 0
    __gender = None

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

    def __method1(self):
        print("父类:私有方法")

    def get_info(self):
        self.__method1()
        print(f"姓名:{self.name},年龄:{self.age},性别:{self.__gender}")

    @classmethod
    def method2(cls):
        print("父类:类方法")

class student(people):
    pass

st = student("张三", 19, "男")
st.get_info()
student.method2()

执行结果为:

父类:私有方法
姓名:张三,年龄:19,性别:男
父类:类方法

子类同样继承了父类的私有方法,比如__init__构造方法,如果是st = student()这样调用,会报错

    st = student()
TypeError: people.__init__() missing 3 required positional arguments: 'name', 'age', and 'gender'

子类方法重写

如果父类已有的方法不适合子类使用,可以重写父类的方法或者子类自己增加自己使用的方法。

class people:
    name = "父类name"

    def get_info(self):
        print(f"父类的姓名:{self.name}")

class student(people):
    name = "子类name"
    def get_info(self):
        print(f"对父类方法重写,子类的姓名:{self.name}")

    def sub_method(self):
        print("子类自己的方法")


st = student()
st.get_info()
st.sub_method()

执行结果

对父类方法重写,子类的姓名:子类name
子类自己的方法

多继承

一个类可以继承多个类(有好几个爸o(╥﹏╥)o),即多继承。
在该类实例化后,调用属性或方法时,以多继承时的顺序从左到右搜索,即先看看自己有没有该方法,自己没有,从定义时的第一个父类中找有没有该方法,有就调用该父类的方法,没有就到第二、第三至最后,还未找到就报错。
格式:

class 子类名称(父类1, 父类2, ..., 父类n):
    <statement-1>
    .
    .
    .
    <statement-N>

示例:

class A:
    def method1(self):
        print("A类")

    def method2(self):
        print("A类独有")

class B:
    def method1(self):
        print("B类")

    def method2(self):
        print("B类独有")

class C(A, B):
    def method1(self):
        print("C类")

demo = C()
# method1方法在实例所属的类C中就有,所以就调用自己重写的方法
demo.method1()
# method2方法在实例所属的类C中没有,就依照定义类C的继承的父类顺序找,即从类A->类B这样的顺序,找到调用即止
demo.method2()

执行结果:

C类
A类独有

静态方法

在类中,被@staticmethod修饰的方法为静态方法,静态方法无法直接使用该类的任何类变量、类方法或者实例方法、实例变量,即没有和类本身有关的参数(包括self、cls等)。静态方法类似于在类中的“函数”。
调用方法为类名.方法名实例.方法名

class A:
    @staticmethod
    def method1(param):
        print(f"类方法:{param}")

    def method2(self):
        self.method1("袜子")
        print("实例方法")
A.method1("人民币")
a = A()
a.method2()

执行结果:

类方法:人民币
类方法:袜子
实例方法

注意:静态方法不能调用类中的类变量、类方法或实例方法,会报错(这些方法需要类或者实例参数,但是静态方法是没有的),但是类方法和实例方法可以调用静态方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值