python学习之路 - 面向对象编程

一、面向对象编程

1、成员方法

a、类的定义和使用

定义在类外面的函数称为函数,定义在类内部的函数称为方法

#类的定义语法
class 类名称:
	类的属性名: 属性值					#这里就是成员变量
	def 方法名(self,形参1,形参2...):		#这里就是成员方法,当外部调用此方法时,self参数可忽略不传
		方法体

#创建类的语法
对象 = 类名称()
b、案例

案例:创建一个人的类,编辑人的信息并调用方法输出信息

class people:
    name: None      #人名
    age: None       #年龄
    sex: None       #性别

    def introduce(self):
        print("我叫%s,今年%d岁,性别%s" % (self.name, self.age, self.sex))

p1 = people()
p1.name = "张三"
p1.age = 18
p1.sex = "男"

print(p1.name)
print(p1.age)
print(p1.sex)
p1.introduce()

结果为:
张三
18
男
我叫张三,今年18岁,性别男

2、类和对象

  • 类是指创建出一个模板,提供给具体的个人使用
  • 对象是基于模板的基础上创建一个具体实例,修改对象的属性不会更改类本身的内容,并且多个对象之间的数据值不会影响
  • 面向对象编程就是使用类创建对象,并且使用对象来完成具体的工作

3、构造方法

  • python类可以使用__init__()方法,称之为构造方法
  • 注意:构造方法前后各有两个下划线
  • 在创建类对象时,构造方法会自动执行,可以将参数自动传递给构造方法给对象赋值
  • 当有构造方法时,类中定义字段可省略
class people:
    name: None   #人名			此可省略
    age: None    #年龄			此可省略
    sex: None    #性别			此可省略

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

    def introduce(self):
        print("我叫%s,今年%d岁,性别%s" % (self.name, self.age, self.sex))

p1 = people("张三", 18, "男")
p1.introduce()

结果为:
我叫张三,今年18岁,性别男

4、其他内置方法(魔术方法)

  • __str__:字符串方法
    • 当类中未定义此方法时,输出类时输出的内容为内存地址
    • 当类中定义了此方法时,输出类时输出的是str方法中的内容
#当类中未定义此方法时,输出类为内存地址
class Student:
    name = None
    age = None
    address = None

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

student = Student("张三", 18, "北京")
print(student)
print(str(student))

结果为:
<__main__.Student object at 0x0000025921C64310>
<__main__.Student object at 0x0000025921C64310>
#当类中定义了此方法时,输出类时输出的是str方法中的内容
class Student:
    name = None
    age = None
    address = None

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

    def __str__(self):
        return f"我叫{self.name},今年{self.age}岁,地址{self.address}"

student = Student("张三", 18, "北京")
print(student)
print(str(student))

结果为:
我叫张三,今年18岁,地址北京
我叫张三,今年18岁,地址北京
  • __lt__:小于大于符号比较
    • 当类中未定义此方法, 两个对象比较会报错
    • 当类中定义了此方法,会根据此方法中定义的内容比较大小
#当类中未定义此方法, 两个对象比较会报错
class Student:
    name = None
    age = None
    address = None

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

student = Student("张三", 18, "北京")
student1 = Student("李四", 19, "上海")

print(student < student1)

报错信息:
Traceback (most recent call last):
  File "F:\Pycharm\workspaces\test\main.py", line 761, in <module>
    print(student < student1)
          ^^^^^^^^^^^^^^^^^^
TypeError: '<' not supported between instances of 'Student' and 'Student'
#当类中定义了此方法,会根据此方法中定义的内容比较大小
class Student:
    name = None
    age = None
    address = None

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

    def __lt__(self, other):
        return self.age < other.age     #定义根据年龄来比较

student = Student("张三", 18, "北京")
student1 = Student("李四", 19, "上海")

print(student < student1)

结果为:
True
  • __le__:小于等于、大于等于符号比较
    • 当类中未定义此方法, 两个对象比较会报错
    • 当类中定义了此方法,会根据此方法中定义的内容比较大小
# 当类中未定义此方法, 两个对象比较会报错
class Student:
    name = None
    age = None
    address = None

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

student = Student("张三", 18, "北京")
student1 = Student("李四", 19, "上海")

print(student <= student1)

报错信息为:
Traceback (most recent call last):
  File "F:\Pycharm\workspaces\test\main.py", line 764, in <module>
    print(student <= student1)
          ^^^^^^^^^^^^^^^^^^^
TypeError: '<=' not supported between instances of 'Student' and 'Student'
#当类中定义了此方法,会根据此方法中定义的内容比较大小
class Student:
    name = None
    age = None
    address = None

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

    def __le__(self, other):
        return self.age < other.age     #定义根据年龄来比较

student = Student("张三", 18, "北京")
student1 = Student("李四", 19, "上海")

print(student <= student1)

结果为:
True
  • __eq__:==符号比较
    • 当未定义此方法时,会比较两个对象的内存地址是否一致
    • 当定义了此方法时,会根据方法中定义的内容进行比较
#当未定义此方法时,会比较两个对象的内存地址是否一致
class Student:
    name = None
    age = None
    address = None

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

student = Student("张三", 18, "北京")
student1 = Student("张三", 18, "北京")

print(student == student)	
print(student == student1)		#尽管赋值一样,对象不同内存地址也不同

结果为:
True
False
#当定义了此方法时,会根据方法中定义的内容进行比较
class Student:
    name = None
    age = None
    address = None

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

    def __eq__(self, other):
        return self.age == other.age        #根据对象年龄来比较

student = Student("张三", 18, "北京")
student1 = Student("李四", 18, "上海")

print(student == student)
print(student == student1)

结果为:
True
True

5、面向对象三大特性——封装

a、介绍:

封装就是将现实世界事务的属性和行为,封装到类中,描述为成员变量和成员方法,从而完成程序对现实世界事务的描述

b、表现形式:私有成员变量与私有成员方法
  • 在类中,只提供给内部使用的变量叫做私有成员变量,只提供给内部使用的方法叫做私有成员方法。封装最主要的表现形式就是私有成员变量和私有成员方法,其封装特性只能被内部调用,外部无法调用成功
  • 私有成员变量和方法,定义方式为在前面加上两个下划线即可
class Student:
    name = None
    age = None
    address = None
    __sex = None            #私有成员变量

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

    def __introduce(self):      #私有成员方法
        print(f"我叫{self.name},今年{self.age}岁,地址{self.address}")

student = Student("张三", 18, "北京")
student.__sex = '男' 			#此不会报错,但是赋值无效
student.introduce()

错误信息为:
Traceback (most recent call last):
  File "F:\Pycharm\workspaces\test\main.py", line 763, in <module>
    student.introduce()
    ^^^^^^^^^^^^^^^^^
AttributeError: 'Student' object has no attribute 'introduce'
c、作用

私有成员变量和方法能在类中提供仅供内部使用的属性和方法,而不对外开放,保护内部数据

6、面向对象三大特性——继承

a、介绍

如果新的类A中部分信息与现存的另一个类B中的内容一样,则可以类A直接继承类B,这部分重复信息就无需重复定义了

b、语法
class 子类名(父类1,父类2,父类3...):
	类内容体
c、分类
  • 单继承:只继承一个父类的叫单继承
#ClassA继承ClassB
class ClassB:
    name = None
    age = None

class ClassA(ClassB):			#类A继承类B,自动拥有类B中的全部内容
    sex = None

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
    def introduce(self):
        print(f"我叫{self.name},今年{self.age}岁,性别{self.sex}")
    
c = ClassA("张三", 18, "男")
c.introduce()

结果为:
我叫张三,今年18岁,性别男
  • 多继承:同时继承多个父类的叫多继承
#ClassA同时继承ClassBClassC
class ClassB:
    name = None
    age = None

class ClassC:
    address = None


class ClassA(ClassB,ClassC):
    name = None
    age = None
    address = None
    sex = None

    def __init__(self, name, age, address, sex):
        self.name = name
        self.age = age
        self.address = address
        self.sex = sex
    def introduce(self):
        print(f"我叫{self.name},今年{self.age}岁,地址{self.address},性别{self.sex}")

c = ClassA("张三", 18, "北京", "男")
c.introduce()

结果为:
我叫张三,今年18岁,地址北京,性别男

但是当多继承时多个父类中存在同名属性或者方法,按父类继承的顺序从左到右,优先使用左边的属性或者方法。左边优先级更高

#ClassA继承ClassBClassC,同时ClassBClassC中有同名属性age
class ClassB:
    name = "张三"
    age = 18

class ClassC():
    address = "北京"
    age = 20


class ClassA(ClassB,ClassC):
    pass

c = ClassA()				
print(f"年龄:{c.age}")		#继承时ClassBClassC左边,则会展示ClassB中的结果

结果为:
年龄:18
d、pass关键词

当某个子类同时继承多个父类,并且子类无需定义其他内容时,可以使用pass关键词

#ClassA同时继承ClassBClassC
class ClassB:
    name = "张三"
    age = 18

class ClassC():
    address = "北京"

class ClassA(ClassB,ClassC):
    pass						#类中无需定义其他内容时用pass关键字

c = ClassA()
print(f"姓名:{c.name},年龄:{c.age},地址:{c.address}")

结果为:
姓名:张三,年龄:18,地址:北京
e、复写
  • 普通复写
    子类继承父类的成员属性和成员方法后,如果对其不满意,则可以进行复写,即在子类中重新定义同名的属性和方法即可
#子类ClassA复写父类ClassB的属性和方法
class ClassB:
    name = "我是ClassB的成员属性"

    def introduce(self):
        print(f"这是ClassB的成员方法,属性内容为:{self.name}")

class ClassA(ClassB):
    name = "我是ClassA的成员属性"

    def introduce(self):
        print(f"这是ClassA的成员方法,属性内容为:{self.name}")

c = ClassA()
c.introduce()		#这里输出的是子类中复写后的结果

结果为:
这是ClassA的成员方法,属性内容为:我是ClassA的成员属性
  • 调用父类内容
    当子类对父类进行复写后,还想要获取父类中原先的成员变量和方法,有两种方式
class ClassB:
    name = "我是ClassB的成员属性"

    def introduce(self):
        print(f"这是ClassB的成员方法,属性内容为:{self.name}")

class ClassA(ClassB):
    name = "我是ClassA的成员属性"

    def introduce(self):		
    	#方式1:调用父类成员
    	#直接使用父类名.属性或者父类名.方法就可以获得父类的信息
        print(f"父类的成员变量为{ClassB.name},父类的成员方法为{ClassB.introduce(self)}")
        
        #方式2:使用super()调用父类成员
        print(f"父类的成员变量为{super().name},父类的成员方法为{super().introduce()}")

c = ClassA()
c.introduce()

结果为:
这是ClassB的成员方法,属性内容为:我是ClassA的成员属性
父类的成员变量为我是ClassB的成员属性,父类的成员方法为None
这是ClassB的成员方法,属性内容为:我是ClassA的成员属性
父类的成员变量为我是ClassB的成员属性,父类的成员方法为None

7、类型注解

a、介绍
  • Python在3.5版本之后引入了类型注解,以方便静态类型检查工具。
  • 类型注解是对变量或者方法中的形参和返回值进行类型标注,方便程序员调用时使用正确的类型数据
  • 方法调用时鼠标停留在调用的地方可以显示类型注解的内容
  • 类型注解只是提示性的,非决定性的。如果定义的类型注解和实际类型不一致,也不会报错

在这里插入图片描述

b、变量的类型注解
  • 语法1:
    变量:类型
#基础数据类型注解
var_1: int = 10
var_2: float = 3.1415
var_3: bool = True
var_4: str = 'test'

#基础容器类型注解
my_list: list = [1,2,3]
my_tuple: tuple = (1,2,3)
my_set: set = {1,2,3}
my_dict: dict = {"age": 18}
my_str: str = "test"

#容器类型详细注解
my_list: list[int] = [1,2,3]
my_tuple: tuple[str,int,bool] = ("test",18,True)		#元组类型设置详细注解需要将每个元素类型都标注出来
my_set: set[int] = {1,2,3}
my_dict: dict[str,int] = {"age": 18}		#字典类型设置详细注解需要标注key和value的类型

#调用函数方法类型的注解
class Student:
	pass
stu: Student = Student()
  • 语法2
    #type:类型
#对基础数据类型注解
var_1 = random.randint(1,10)	#type: int
var_2 = json.loads(data)		#type: dict[str, int]
var_3 = func()					#type: Student
c、函数(方法)的类型注解
  • 形参注解
#语法:
def 函数方法名(形参名:类型,形参名:类型,....)
	函数内容体

#案例,定义add函数传入两个int类型数字
def add(x:int,y:int):
    return x + y
  • 返回值注解
#语法:
def 函数方法名(形参名:类型,形参名:类型,....) -> 返回值类型
	函数内容体

#案例,定义add函数传入两个int类型数字,返回int类型结果
def add(x:int,y:int) -> int:
    return x + y
c、Union类型
  • 语法:
    Union[类型1,类型2,类型3…]

  • 案例

#对变量进行类型注解
from typing import Union

my_list:list[Union[str,int]] = ['1', 2, 3]
my_dict:dict[str,Union[str,int]] = {"name":"张三", "age": 18}

#对函数(方法)进行类型注解
def add(x:Union[str,int],y:Union[str,int]) -> Union[str,int]:
    return x + y

在这里插入图片描述

8、面向对象三大特性——多态

a、介绍

多态指多种状态,完成某个行为时,使用不同的对象会得到不同的状态

b、普通示例
class Dog:
    def speak(self):
        print("汪汪汪")

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

def make_sound(animal):
    animal.speak()

dog = Dog()
cat = Cat()
make_sound(dog)
make_sound(cat)

结果为:
汪汪汪
喵喵喵
c、抽象类示例
  • 使用多态的属性,可以直接在父类中定义有那些方法,方法体为pass, 在子类中具体实现
  • 方法体是pass的称为抽象方法,含有抽象方法的类叫做抽象类
class Animal:               #此为抽象类
    def speak(self):        #此为抽象方法
        pass

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

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

def make_sound(animal):
    animal.speak()

结果为:
汪汪汪
喵喵喵
  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 魔术方法是Python中的特殊方法,它们以双下划线开头和结尾,例如__init__、__str__、__add__等。这些方法可以在类的实例化、运算符重载、属性访问等方面提供特殊的行为。 __init__方法是一个特殊的构造函数,用于初始化类的实例。__str__方法用于返回对象的字符串表示形式,可以通过print函数输出。__add__方法用于重载加法运算符,可以实现自定义的加法操作。其他常用的魔术方法还包括__eq__、__lt__、__gt__等,用于比较运算符的重载。 学习魔术方法可以让我们更好地理解Python面向对象编程的特性,提高代码的可读性和可维护性。 ### 回答2: 魔术方法是Python中最有趣且也是最强大的概念之一。魔术方法(也称为特殊方法或双下划线方法)是一些特殊的方法,它们以双下划线(__)开头和结尾,并具有特定的名称。 这些特殊方法可以为我们提供许多有用的功能,例如重载操作符,处理类的属性,实现自定义迭代器,使用描述符等。 下面是一些常见的魔术方法: __init__:这是最常见的魔术方法。当创建一个实例时,它会被自动调用。它用于初始化对象的属性。 __str__:当你想要将一个对象转换成字符串时,这个方法会被调用。如果你不指定__str__方法,Python默认会使用对象的类名和内存地址来表示对象。 __repr__:这个方法和__str__方法类似,也是用于将对象转换成字符串。但是__repr__方法在调试时有很大的作用,因为它返回的字符串可以用来唯一地标识对象。 __len__:这个方法可以返回对象的长度。例如,如果你想获取一个字符串的长度,你可以使用len("hello"),在底层,它实际上是调用了字符串对象的__len__方法。 __getattr__和__setattr__:这些方法允许你动态地获取和设置对象的属性。当你访问一个不存在的属性时,__getattr__方法会被调用。当你设置一个属性时,__setattr__方法会被调用。 __call__:这个方法允许你将对象作为函数调用。当你调用一个对象时,Python实际上是在调用对象的__call__方法。 除了上面列举的方法,还有许多其他的魔术方法,例如__cmp__,__hash__,__iter__等等。学习这些魔术方法将使你能够更好地理解Python面向对象编程模型。 总之,学习和理解魔术方法是Python面向对象编程中的一个关键概念,因为它们可以帮助你实现更加灵活和强大的代码。如果你想成为一名Python高手,那么深入学习魔术方法是不可避免的。 ### 回答3: Python中的“魔术方法”指的是每个类中定义的特殊方法,它们以双下划线(__)开头和结尾,并且有着特定的用途。通过使用这些魔法方法,我们可以自定义类的行为,并为程序提供更高级别的功能。 以下是Python中常用的一些魔术方法: 1. __init__:这是最常用的魔术方法之一,它用于初始化一个类的对象,以及定义类的属性和方法。 2. __str__:此方法用于返回对象的字符串表示形式,类似于Java中的toString()方法。 3. __repr__:与__str__类似,但是返回的是对象的“官方”字符串表示形式,通常用于调试和开发。 4. __getattr__:当试图访问一个不存在的属性时,此方法被调用。 5. __setattr__:当尝试设置类的属性时,此方法被调用。 6. __delattr__:当尝试删除类的属性时,此方法被调用。 7. __call__:将对象作为函数调用时,此方法被调用。 8. __len__:返回对象的长度。 9. __getitem__:允许通过索引访问对象的元素。 10. __setitem__:允许通过索引设置对象的元素。 11. __delitem__:允许通过索引删除对象的元素。 通过了解和使用这些魔术方法,我们可以编写出更高效、更灵活、更具可读性的Python代码,并且实现类似于内置类型一样的功能。例如,我们可以实现一个自定义列表,类似于Python的list类型,然后使用上述魔术方法来访问、设置和删除元素。同时,我们还可以自定义变量和函数的行为,使我们的Python代码变得更具有表现力和弹性。 总之,了解和掌握Python的魔术方法是Python编程中必不可少的一部分,对于理解和编写实际应用程序非常有价值。在实践中,我们可以根据实际情况选择恰当的魔术方法,从而创建更灵活、更高效的Python类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值