PythonDay7Advance

PythonDay7Advance

类和对象

面向对象概述

面向过程的编程思想:每一步的实现过程都是我们一步一步 参与实现的,相当于参与者【代表语言:C语言】 
面向对象的编程思想:我们在自己程序中,创建别人写好类 的对象,调用别人写好的功能,相当于指挥者 【代表语言:java,python】 
举例现实生活中面向对象的例子: 

      吃饭:
        面向过程的角度:自己买鸡蛋,自己打鸡蛋,自己煮饭,自己将蛋和饭一起炒,自己装盘 
        面向对象的角度:点一份蛋炒饭,饭店人员完成上面的事情 
      接水:
        面向过程的角度:自己拿起水杯,走到饮水机面前,选择热水还是冷水,接水
        面向对象的角度:祈求同桌接水,剩下事情,由同桌这个对象去完成
        
如何在python中描述或者使用现实生活中的一个对象呢? 
1. 需要我们先创建一个概念性的东西,用于描述某一种所有对象的共同特点,
在python中称之为类class 
2. 我们就可以根据创建好的类,来创建若干个对象
世间万物,皆为对象,同一种对象之间,会有相同的特点,都可以使用属性和行为对任意一个对象进行描述。

人: 
class Person: 
    	属性:姓名,年龄,性别... 
     成员变量:name,age,gender 
        行为:吃饭,睡觉,学习... 
     成员方法:eat(),sleep(),study()

在python中使用类描述一个事物

示例1:创建一个类

# 错误的写法 
class Person: 
    def eat(): 
        print("吃饭") 
    def call(name): 
        print(f"打电话给{name}")

注意:class类中的函数,必须要有一个参数,且是第一个定义,self

self: 表示当前调用该方法的对象

定义一个类 
class Person: 
    def eat(self): 
        print("吃饭") 
    def call(self,name): 
        print(f"打电话给{name}")

示例2:通过一个类创建一个对象

class Person: 
    def eat(self): 
        print("吃饭") 
    def call(self,name): 
        print(f"打电话给{name}") 
        # 相当于创建一个Person类的对象,将对象的地址值赋值 给变量p1 
        
p1 = Person() 
p1.eat() 
p1.call('马云')

示例3:通过一个类创建多个对象

类相当于一个汽车图纸,而创建出来的一个一个对象,是占用不同的内存空间,每个对象内部都有自己的属性和行为。

class Person: 
    def eat(self): 
        print("吃饭") 
        
    def call(self,name): 
        print(f"打电话给{name}") # 相当于创建一个Person类的对象,将对象的地址值赋值 给变量p1 
        
p1 = Person() # 在内存中开辟一个新的空间 
p1.eat() 
p1.call('马云') 
print("----------------------------") 
p2 = Person() # 在内存中开辟一个新的空间 
p2.eat()
p2.call('马云') 
print(id(p1)==id(p2)) # False 地址值不同

示例4:给对象赋予属性

  • 类中不写,创建对象的之后,单独为该对象创建新的属性
class Person: 
    def eat(self): 
        print("吃饭") 
    def call(self,name): 
        print(f"打电话给{name}") 
        
p1 = Person() 
p1.name = '小虎'
print(f"p1对象的姓名为:{p1.name}") 
p2 = Person() # 在内存中开辟一个新的空间
# print(f"p1对象的姓名为:{p2.name}") 
# 报错
  • 类中编写,创建对象的时候,直接就拥有了某个属性,并且可以直接赋值

在python中创建一个类的对象的时候

# 使用类名() 的方式创建对象,实际上底层调用的是类中 的__init__(self) 
# 若自己没写,默认一个类中有一个__init__(self),且只能有一个 
class Person: 
    def __init__(self,name): 
        # self.name 定义一个类中的属性,叫做name 
        self.name = name 
        
    def eat(self):
        print("吃饭") 
        
    
    def call(self,name): 
        print(f"打电话给{name}") 
        # 使用类名() 的方式创建对象,实际上底层调用的是类中 的__init__(self) 
        # 若自己没写,默认一个类中有一个__init__(self),且只能有一个 


p1 = Person('小虎') 
print(f"p1对象的姓名为:{p1.name}") 
p2 = Person('张三') 
print(f"p2对象的姓名为:{p2.name}")
# 手机
''' 
手机:属性: 品牌, 价格, 颜色 
行为:打电话, 发短信 
'''

class Phone: 
    def __init__(self, brand, price, color): 
        self.brand = brand 
        self.price = price 
        self.color = color
        
    def call(self): 
        print("打电话") 
           
    def send_message(self): 
        print("发短信")
        
# 创建第一部手机 
p1 = Phone('小米15 pro', 5799, '黑色') 
print(f"手机的品牌为:{p1.brand}, 价格: {p1.price}, 颜色:{p1.color}") 
p1.call() 
p1.send_message()

面向对象编程那些改进场景

可以改进多个传参的问题

def fun1(a1,b1,c1,d1): 
    pass 
def fun2(a1,b1,c1,d1): 
    pass 
def fun3(a1,b1,c1,d1): 
    pass 
fun1(11,22,33,44) 
fun2(11,22,33,44)
fun3(11,22,33,44)


class Demo: 
    # 构造函数 
    def __init__(self,a1,b1,c1,d1): 
        self.a1 = a1 
        self.b1 = b1 
        self.c1 = c1 
        self.d1 = d1 
        
    def fun1(self): 
        print(f"a1:{self.a1},b1: {self.b1},c1:{self.c1},d1:{self.d1}") 
        
    def fun2(self): 
        print(f"a1:{self.a1},b1: {self.b1},c1:{self.c1},d1:{self.d1}") 
    def fun3(self): 
        print(f"a1:{self.a1},b1: {self.b1},c1:{self.c1},d1:{self.d1}") 
        
d1 = Demo(11,22,33,44) 
d1.fun1() 
d1.fun2() 
d1.fun3()

改进一个事物的封装

''' list1 = [
   		{'name':'张三1', 'age': 18}, 
   		{'name':'张三2', 'age': 19}, 
   		{'name':'张三3', 'age': 20},
        {'name':'张三4', 'age': 21},
        ... 
]
'''

user_list = [] 
while True:
    name = input("请输入用户的姓名:") 
    
    user_dict = {} 
    if name.upper()=='Q': 
        break
	age = input("请输入用户的年龄:") 
    user_dict['name'] = name 
    user_dict['age'] = age 
    user_list.append(user_dict)
    
print(user_list)
''' 
list1 = [ 
	p1, p2, p3,
	... 
]
'''

class Person: 
    def __init__(self,n1,a1): 
        self.name = n1 
        self.age = a1 
        
 	def eat(self): 
        print("吃饭") 
        
	def sleep(self): 
        print("睡觉")
        
user_list = [] 
while True: 
    name = input("请输入用户的姓名:") 
    if name.upper()=='Q': 
        break 
	age = input("请输入用户的年龄:") # 创建一个学生对象 
	p = Person(name,age) 
	user_list.append(p)
    
for per in user_list: 
    print(f"姓名:{per.name}, 年龄:{per.age}")

若直接使用对象名, 默认调用的是一个class类中的__str__()函数

''' 
list1 = [ 
 	p1, p2, p3, 
 	... 
]
'''

class Person: 
    def __init__(self,n1,a1): 
        self.name = n1 
        self.age = a1 
    
    def eat(self): 
        print("吃饭") 
        
    def sleep(self):
        print("睡觉")
        
# 该函数将来在直接使用对象名的时候,自动被掉调用 
# __str__()函数必须要有一个返回值 
    def __str__(self):
        return f"姓名:{self.name}, 年龄: {self.age}"
    # def show(self):
    # print(f"姓名:{self.name}, 年龄: {self.age}")
    
user_list = [] 
while True: 
    name = input("请输入用户的姓名:") 
    if name.upper()=='Q': 
        break 
    age = input("请输入用户的年龄:") 
    # 创建一个学生对象 
    p = Person(name,age) 
    user_list.append(p) 
    for i in user_list: 
        print(i) # 若直接使用对象名, 默认调用的是一 个class类中的__str__()函数

面向对象的四大特征

封装

继承

多态【在python语言中,多态体现不明显,因为python是 动态数据类型的语言】

抽象【python中独有的特点】

封装

# 需求:定义一个学生类,根据学生类创建一个学生对象, 并修改年龄
class Student: 
    def __init__(self,name,age): 
        self.name = name 
        self.age = age
        
    def __str__(self): 
        return f"姓名:{self.name}, 年龄: {self.age}" 
    
    def eat(self): 
        print("吃饭") 
        
    def sleep(self): 
        print("睡觉")
        
        
s1 = Student("张成阳", 18) 
print(s1) 
print("----------------------------------- ")
s1.age = 1900 
print(s1)

我们按照类和对象的使用方式,程序本身是没有任何语法的问题,但是呢我们在给学生年龄赋值的时候,可以赋值一些不合现实情况的值。

我们应该在赋值之前,先判断一下这个值是不是合理的,如果合理才允许赋值。

判断一下,是一个多个语句,不能直接加在变量上,需要额外写一个函数专门对年龄进行赋值

class Student: 
    def __init__(self,name,age): 
        self.name = name 
        self.age = age 
   
	def __str__(self): 
        return f"姓名:{self.name}, 年龄: {self.age}" 
    
    def set_age(self,age): 
        if 120>=age>0: 
            self.age = age 
            
        else:print("您给的年龄不合法,默认已修改为 18!") 
            self.age = 18 
            
    def eat(self): 
        print("吃饭") 
        
    
    def sleep(self): 
        print("睡觉")
        
s1 = Student("张成阳", 11) 
print(s1) 
print("----------------------------------- ")
# s1.age = 1900 
s1.set_age(29) 
print(s1)

虽然创建一个给年龄赋值的函数,但是我们依旧可以采用原始的直接获取属性进行赋值的方式。依旧可以赋值一些不合法的年龄,如果我们能够让外界无法直接获取对象的属性就好了

class Student: 
    def __init__(self,name,age): 
        self.name = name 
        self.__age = age 
        
    def __str__(self): 
            return f"姓名:{self.name}, 年龄: {self.__age}" 
        
    def set_age(self,age): 
        if 120>=age>0: 
            self.__age = age 
        else:
            print("您给的年龄不合法,默认已修改为 18!") 
            self.__age = 18
            
    def eat(self):
        print("吃饭") 
        
    def sleep(self): 
        print("睡觉") 

s1 = Student("张成阳", 11) 
print(s1) 
print("----------------------------------- ")
        # s1.age = 1900 
        # 这里的age相当于是一个新的属性 
        # s1.__age = 1900 
        # 使用不了__的属性 
        
s1.set_age(29) 
print(s1)

在init函数中定义的属性前面加上__,就表示该属性为私有属性,而私有属性只能在一个class内部随意访问,出了class就访问不到了。上午说了半天的例子,实际上就是想传达一个封装的思想封装:将一个类中的成员进行私有化,只对外提供公共函数,对外隐藏类实现细节类中私有的函数,可以间接地使用非私有的函数调用

class Student: 
    def __init__(self,name,age): 
        self.__name = name
        self.__age = age
        
    def __str__(self): 
        return f"姓名:{self.__name}, 年龄: {self.__age}"
    
    def set_name(self,name): 
        self.__name = name
        
	def get_name(self): 
        return self.__name 
    
    def set_age(self,age): 
        if 120>=age>0: 
            self.__age = age 
            
        else:
            print("您给的年龄不合法,默认已修改为 18!") 
            self.__age = 18 
            
    def get_age(self): 
        return self.__age 
    
    def eat(self): 
        print("吃饭") 
        
    def sleep(self):
        print("睡觉") 
        print("hello world") 
        
    def fun2(self): 
        self.__fun1() 
        
s1 = Student("张成阳", 11)
print(s1) 
print("----------------------------------- ")
def __fun1(self):   
# s1.age = 1900 
# 这里的age相当于是一个新的属性 
# s1.__age = 1900 
# 使用不了__的属性 
# s1.set_age(29)
# print(s1) 
# print(s1.__age)
# print(s1.get_age())
# s1.fun1() 
s1.fun2() # 间接地调用私有的函数

局部变量和成员属性同名的情况

class Demo1: 
    def __init__(self, age): 
        self.age = age 
        
    def fun1(self): 
        # age = 10 
        print(self.age) 
        # 获取当前对象的属性 age 
        # print(age) 
        # 获取当前函数中的局部变量 
age d1 = Demo1(18) 
d1.fun1()

继承

继承是将多个类中的相同的部分,单独提取到一个类中,这些类于单独提出来的这个类产生一个关系这个关系,就叫做继承关系,其他类中也就拥有了相同的部分,不需要特地定义出来。

class Student: 
    def __init__(self,sid,name,age): 
        self.sid = sid 
        self.name = name 
        self.age = age
        
    def __str__(self): 
        return f"Student:({self.sid}, {self.name}, {self.age})" 
    
    def study(self): 
        print("学生学习") 
        
    def like(self): 
        print("学生的爱好") 
        
class HighStudent: 
    def __init__(self, sid, name, age): 
        self.sid = sid 
        self.name = name 
        self.age = age 
        
    def __str__(self): 
        return f"Student:({self.sid}, {self.name}, {self.age})" 
    
    def study(self): 
        print("学生学习") 
        
    def like(self): 
        print("学生的爱好") 
        
s1 = Student('1001','张三',18) 
s1.study() 
s1.like()

s2 = HighStudent('1002','李四',19) 
s2.study() 
s2.like()

如果多个类中,相同的部分太多了,每一类都写一遍的话,语法上没有问题,但是从代码美观来说,冗余度太大了。

# 继承的语法改进 
class 父类:       父类| 超类| 基类 
    xxxx 
    
class 子类(父类): 
    子类| 派生类 
    pass ------------------------------ 

class Father:
    xxxx 
    
class Son(Father): 
    pass

通过继承,子类拥有了父类中的成员

class Person: 
    def __init__(self,sid,name,age): 
        self.sid = sid 
        self.name = name 
        self.age = age
    
    def __str__(self):
        return f"Student:({self.sid}, {self.name}, {self.age})" 
    
    def study(self): 
        print("学生学习") 
        
    def like(self): 
        print("学生的爱好") 
        
class Student(Person):
    pass 

class HighStudent(Person): 
    pass 


s1 = Student('1001','张三',18) 
s1.study() 
s1.like() 
s2 = HighStudent('1002','李四',19) 
s2.study() 
s2.like()
  • 子类无法继承父类中私有的成员
class Fu: 
    def fun1(self): 
        print("好好学习,天天向上!") 
        
    def __fun2(self): 
        print("这是父类中私有的成员函数__fun2") 
        
class Son(Fu): 
    pass 

s1 = Son() 
s1.fun1() 
s1.__fun2()
  • 若子类中出现与父类的函数名以及函数参数都一样,只是实现不一样的情况,子类对象调用的是自己的函数
class Fu: 
    def fun1(self): 
        print("好好学习,天天向上!")
        
    def __fun2(self): 
        print("这是父类中私有的成员函数__fun2") 
        
    def fun3(self): 
        self.__fun2() 
        
class Son(Fu): 
    def fun1(self):
        print("这是子类中的函数fun1") 
        pass 
    
s1 = Son() 
s1.fun1()

子类中出现与父类的函数名以及函数参数都一样,只是实现不一样的情况,称之为函数的重写 override

  • 子类继承父类的同时,可以出现父类中没有的行为
class Fu2: 
    def fun1(self):
        print("shujia") 
        
class Zi2(Fu2):
	def show(self): 
        print("shujia666") 
        # d1 = Fu2() 
        # d1.fun1() 
        # d1.show() 
        
d2 = Zi2() 
d2.fun1() 
d2.show()
  • 子类中可以使用super()来调用父类中非私有的成员
class Fu: 
    def fun1(self): 
        print("这是父类中的fun1") 

class Zi(Fu): 
    def fun1(self): 
        print("这是子类中的fun1") 
     
    def show(self): 
        self.fun1() 
        # 调用的是子类中重写后的 fun1函数
        # 调用父类中的fun1 
        
super().fun1() 
z = Zi() 
z.show()
  • 子类中可以定义父类中没有的成员属性
class Fu: 
    def __init__(self,name,age): 
        self.name = name 
        self.age = age
        
class Zi(Fu): 
    def __init__(self, name, age, sid):
        super().__init__(name,age) 
        self.sid = sid 
        
z1 = Zi('张三',18, 1001) 
print(z1.name,z1.age,z1.sid)
  • 在python中一个类可以同时继承多个类
class Fu: 
    def fun1(self): 
        print("这是父亲中的函数fun1") 
        
class Mather: 
    def fun2(self):
        print("这是母亲中的函数fun2") 

class Son(Fu, Mather): 
    def function1(self): 
        print("这是儿子自己的函数")
        
s1 = Son() 
s1.fun1() 
s1.fun2() 
s1.function1()

若同时继承的类中有相同的函数名,谁先写就调用谁的

class Fu: 
    def fun1(self): 
        print("这是父亲中的函数fun1") 
        
    def show(self):
        print("这是父亲中的函数show")

class Mather: 
    def fun2(self): 
        print("这是母亲中的函数fun2") 
        
    def show(self): 
        print("这是母亲中的函数show") 
        
class Son(Mather,Fu): 
    def function1(self): 
        print("这是儿子自己的函数") 
        
s1 = Son()
s1.fun1() 
s1.fun2() 
s1.function1() 
s1.show() # 调用的是母亲中的show

多态

表示的是某一个事物在不同时刻下的不同状态在python中默认支持多态,因为python是动态数据类型语言

''' 
水【气态的水, 固态的水, 液态的水】 
动物【狗, 猫, 猪】 
''' 

class Animal: 
    def __init__(self, name, age): 
        self.name = name 
        self.age = age 
        
    def __str__(self): 
        return f"name:{self.name}, age: {self.age}" 
    
    def eat(self): 
        print("吃") 
        
    def sleep(self):
        print("睡")
        
class Dog(Animal): 
    pass a1 = Animal('小黄',2) 

a1 = Dog('小黑',3) 
print(a1) 
# Animal a = new Dog('小黑',3)

抽象

class Animal: 
    def __init__(self, name, age): 
        self.name = name 
        self.age = age
        
    def __str__(self): 
        return f"name:{self.name}, age: {self.age}" 
    
    @abstractmethod 
    def eat(self): 
        pass 
    
    @abstractmethod 
    def sleep(self): 
        pass
    

class Dog(Animal): 
    @override 
    def eat(self): 
        print("🐕吃🥩") 
        
    
    @override 
    def sleep(self): 
        print("🐕趴着睡")

# a1 = Animal('小黄',2) 
a1 = Dog('小黑',3) 
a1.eat() 
a1.sleep()	

类变量

将变量定义在类中函数外

class Demo1: 
    # 类变量 
    a = 100 
    
    def fun1(self):
        a = 10 
        print(a)
        print(Demo1.a) 
        
d1 = Demo1()
d1.fun1()
# print(Demo1.a)
# 通过类名直接访问 
print(d1.a) # 也可以通过对象名进行访问
posted @ 2024-12-01 20:10  Roxan  阅读(9)  评论(0编辑  收藏  举报