U6面向对象设计
Unit6 面向对象设计
这是编程思想的差别,相比与C语言的面向对象设计,大概就是由各种功能的方法组成项目,比较具体,缺少抽象,对于类似的操作不能很好的复用。在语言语法上多了类Class,继承,多态这些。
6.1 类
'''
Python 类/对象
Python 是一种面向对象的编程语言。
Python 中的几乎所有东西都是对象,拥有属性和方法。
类(Class)类似对象构造函数,或者是用于创建对象的“蓝图”。
'''
class MyClass:
x = 5
p1 = MyClass()
print(type(p1))
print(p1.x)
#_init_()函数
'''
所有类都有一个名为 __init__() 的函数,它始终在启动类时执行。
使用 __init__() 函数将值赋给对象属性,或者在创建对象时需要执行的其他操作
相当于 java里的无参构造
'''
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
p2 = Person("zhl",21)
print(p2.name)
print(p2.age)
#对象方法
class Person1:
def __init__(self,name,age):
self.name = name
self.age = age
def myFunc(self):
print("hello my name is " + self.name)
p3 = Person1("zhl",21)
p3.myFunc()
#self参数
'''
self 参数是对类的当前实例的引用,用于访问属于该类的变量。
它不必被命名为 self,您可以随意调用它,但它必须是类中任意函数的首个参数
'''
class Person3:
def __init__(mySillyObject, name, age):
mySillyObject.name = name
mySillyObject.age = age
def myfunc(abc):
print("hello my name is " + abc.name)
print(f"my age is {abc.age}")
p4 = Person3("zhl",21)
p4.myfunc()
#修改对象属性
p4.age = 40
p4.myfunc()
#删除对象属性
del p4.age
#删除对象
del p4
class Person5:
pass
6.2 继承
'''
Python 继承
继承允许我们定义继承另一个类的所有方法和属性的类。
父类是继承的类,也称为基类。
子类是从另一个类继承的类,也称为派生类。
'''
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname
def printname(self):
print(self.firstname, self.lastname)
# 使用 Person 来创建对象,然后执行 printname 方法:
x = Person("Bill", "Gates")
x.printname()
#创建子类
class student(Person):
pass
EM = student("Elon","Musk")
EM.printname()
'''
#添加_init_()函数
#次使用类创建新对象时,都会自动调用 __init__() 函数。
#当添加 __init__() 函数时,子类将不再继承父的 __init__() 函数。
子的 __init__() 函数会覆盖对父的 __init__() 函数的继承。
如需保持父的 __init__() 函数的继承,请添加对父的 __init__() 函数的调用
'''
class Student(Person):
def __init__(self, fname, lname):
Person.__init__(self, fname, lname)
x = Student("Elon", "Musk")
x.printname()
'''
super()函数
'''
class Student(Person):
def __init__(self, fname, lname):
super().__init__(fname, lname)
x = Student("Elon", "Musk")
x.printname()
#和java一样,可以添加属性,添加方法
6.3 类属性和实例属性
class student:
school = "CSUFT"
#初始化方法
def __init__(self, studentName, age):
self.name = studentName
self.age = age
def show(self):
print(f"my name is {self.name}, today {self.age} years old.")
#静态方法
@staticmethod
def sm():
#print(self.name)
#self.show()
print("这是一个静态方法,不能去调用实例属性,和使用方法")
#类方法
@classmethod
def cm(cls):#cls -->class的简写
#print(self.name)
#self.show()
print("这是一个类方法,不能调用实例属性,也不能调用实例方法")
#实例化
p1 =student("zhl",12)
#实例方法
p1.show()
#类属性直接调用
print(p1.name, p1.age)
print(p1.school)
#类方法
p1.cm()
#静态方法
p1.sm()
6.4 创建类对象
class Student:
school = "CSUFT"
def __init__(self, sn, age):
self.name = sn
self.age = age
def show(self):
print(f"我叫{self.name},今年{self.age}岁了")
#创建对象
stu1 = Student("小明",18)
stu2 = Student("小明1",18)
stu3 = Student("小明2",18)
stu4 = Student("小明4",18)
print(type(stu1))
print(type(stu2))
print(type(stu3))
print(type(stu4))
Student.school = "NO.1 Scholl CSUFT"
lst = [stu1,stu2,stu3,stu4]
for i in lst:
i.show()
6.5 动态绑定属性和方法
class Student:
school = "CSUFT"
def __init__(self, sn, age):
self.name = sn
self.age = age
def show(self):
print(f"我叫{self.name},今年{self.age}岁了")
stu = Student("zhl",21)
print(stu.name, stu.age)
stu.name = "good man"
print(stu.name, stu.age)
6.6 python的getter和setter
class Student():
#
def __init__(self,name,age,gender):
#self._name受保护,只能本类和子类去访问
self._name = name
#self.__age 标识是由的,只能类本身去访问
self.__age = age
self.gender = gender
def _fun1(self):#protected
print("子类以及本身可以访问")
def __fun2(self):#private
print("本身可以访问")
def fun3(self):#default
print("都可以访问")
def show(self):
self._fun1()
self.__fun2()
print(self._name)
print(self.__age)
stu = Student("zhl", 21,"男")
#类的外部
print(stu._name)
#print(stu.__age)
stu._fun1()
#AttributeError: 'Student' object has no attribute '__fun2'. Did you mean: '_fun1'?
#stu.__fun2()
#私有的实例属性和方法不能直接访问
print(stu._Student__age)#可以访问
stu._Student__fun2()#可以访问
print(dir(stu))
'''
getter and setter
'''
class Student:
def __init__(self, name, gender):
self.__name = name
self.__gender = gender
# @property 修改方法,将方法转成属性使用
@property
def gender(self):
return self.__gender
@gender.setter
def gender(self,value):
if value != "男" and value != "女":
raise ValueError("性别只能是'男’或'女'")
self.__gender = value
def getName(self):
return self.__name
stu = Student("zhl","男")
print(stu.getName(),"的性别是",stu.gender)
print(type(stu.getName()))
print(type(stu.gender))
stu.gender = "女"
print(stu.getName(),"的性别是",stu.gender)
stu.gender = "1"
print(stu.getName(),"的性别是",stu.gender)
6.7继承
class Person:#默认继承了 Object
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(f"hello i'm {self.name}, my age is {self.age}")
class Student(Person):
#编写初始化的方法
def __init__(self, name, age, stuNo):
#调用父类的初始化方法
super(Student, self).__init__(name, age)
self.stuNo = stuNo
#Doctor 继承Person
class Doctor(Person):
#初始化
def __init__(self, name, age, department):
super(Doctor, self).__init__(name, age)
self.department = department
#实例化对象
stu1 = Student("张三",20,"1001")
stu2 = Student("李四",20,"1002")
stu1.show()
stu2.show()
doctor1 = Doctor("王五", 32,"外科")
doctor1.show()
6.8多继承
class Father1():
def __init__(self,name):
self.name = name
def show1(self):
print("父类1中的方法")
class Father2():
def __init__(self,age):
self.age = age
def show2(self):
print("父类2中的方法")
#多继承
class Son(Father1, Father2):
def __init__(self, name, age, gender):
#需要调用两个父类的初始化方法
Father1.__init__(self, name)
Father2.__init__(self, age)
self.gender = gender
son1 = Son("张三",20,"男")
son1.show1()
son1.show2()
6.9重写
#c重写
class Person:#默认继承了 Object
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(f"hello i'm {self.name}, my age is {self.age}")
class Student(Person):
#编写初始化的方法
def __init__(self, name, age, stuNo):
#调用父类的初始化方法
super(Student, self).__init__(name, age)
self.stuNo = stuNo
def show(self):
super(Student, self).show()
print("我是学生")
#Doctor 继承Person
class Doctor(Person):
#初始化
def __init__(self, name, age, department):
super(Doctor, self).__init__(name, age)
self.department = department
def show(self):
super(Doctor, self).show()
print("我是医生")
#实例化对象
stu1 = Student("张三",20,"1001")
stu2 = Student("李四",20,"1002")
stu1.show()
stu2.show()
doctor1 = Doctor("王五", 32,"外科")
doctor1.show()
6.10多态
class Person():
def eat(self):
print("人吃饭")
class Cat():
def eat(self):
print("猫吃鱼")
class Dog():
def eat(self):
print("狗吃骨头")
def fun(obj):
obj.eat()
#创建三个类对象
per = Person()
cat = Cat()
dog = Dog()
#调用fun函数
fun(per)
fun(cat)
fun(dog)
6.11 Object
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(f"hello i'm{self.name}, age is {self.age}")
#实例化
per = Person("张三",20)
print(dir(per))
print(per) #自动调用了 __str__方法
6.12 __str__方法的重写
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(f"hello i'm{self.name}, age is {self.age}")
#重写
def __str__(self):
return "这是一个Person Class"
#实例化
per = Person("张三",20)
print(dir(per))
print(per) #自动调用了 __str__方法
6.12 深拷贝与浅拷贝
-
浅拷贝(Shallow Copy):
- 浅拷贝创建一个新对象,其字段值与原始对象相同。如果字段是基本数据类型,那么复制的是基本数据类型的值;如果字段是对象的引用,则复制的是引用,而不是引用的对象本身。
- 对于字段是对象引用的情况,浅拷贝后的新对象和原始对象会共享这些对象引用。这意味着如果通过新对象改变了引用指向的对象,原始对象中相应的对象也会被改变。
- 浅拷贝可以通过多种方式实现,例如在Python中可以使用
copy
模块的copy()
函数。
-
深拷贝(Deep Copy):
- 深拷贝创建一个新对象,并且递归地复制所有对象的字段值。这意味着如果字段是对象的引用,那么深拷贝会创建这些对象的副本,而不是仅仅复制引用。
- 深拷贝后的新对象与原始对象完全独立,对新对象的任何修改都不会影响原始对象。
- 深拷贝通常需要更多的时间和内存,因为它需要创建更多的对象副本。
- 在Python中,可以使用
copy
模块的deepcopy()
函数来实现深拷贝。
class CPU():
pass
class Disk():
pass
class Computer():
def __init__(self, cpu, disk):
self.cpu = cpu
self.disk = disk
'''
输出结果
<__main__.Computer object at 0x000002ADC80F9010> 子对象的内存地址 <__main__.CPU object at 0x000002ADC80F8F90> <__main__.Disk object at 0x000002ADC80F8FD0>
<__main__.Computer object at 0x000002ADC80F9010> 子对象的内存地址 <__main__.CPU object at 0x000002ADC80F8F90> <__main__.Disk object at 0x000002ADC80F8FD0>
'''
cpu= CPU()
disk = Disk()
com = Computer(cpu,disk)
com1 = com
print(com, "子对象的内存地址",com.cpu, com.disk)
print(com1, "子对象的内存地址",com1.cpu, com1.disk)
print("*"*50)
#浅拷贝
import copy
com2 = copy.copy(com)
print(com, "子对象的内存地址",com.cpu, com.disk)
print(com2, "子对象的内存地址",com2.cpu, com2.disk)
print("*"*50)
#深拷贝
com3 = copy.deepcopy(com)
print(com, "子对象的内存地址",com.cpu, com.disk)
print(com3, "子对象的内存地址",com3.cpu, com3.disk)