编程思想
面向过程 | 面向对象 | |
区别 | 事物比较简单,可以用线性思维解决 | 事物比较复杂,使用简单的线性思维无法解决 |
共同点 | 面向过程和面向对象都是解决实际问题的一种思维方式 | |
二者相辅相成,并不是独立的 解决复杂问题,通过面向对象方式便于我们从宏观上把握事物之间的复杂关系、方便我们分析整个系统,具体到微观操作,仍然使用面向过程方式来处理 |
类与对象
类:多个类似事物组成的群体的统称,能够帮助我们快速理解和判断事物的性质
数据类型:
不同数据类型属于不同的类
使用内置函数查看数据类型
对象:
1,2,3等都是int类之下包含的相似的不同个例,这些个例专业术语称为实例或对象
类
创建类的语法
class 类名:
pass
类定义不能为空,但如果处于某种原因写了无内容的类定义语句,可以使用 pass 语句来避免错误
类的组成
类属性
实例方法
静态方法
类方法
__init__()函数
所有类都有一个名为 __init__() 的函数,它始终在启动类时执行。
使用 __init__() 函数将值赋给对象属性,或者在创建对象时需要执行的其他操作
每次使用类创建新对象时,都会自动调用 __init__() 函数
# # ----------类和对象---------- class Student: # student为类的名称,由一个或多个单词组成,每个单词首字母大写 place = 'XX' # 类属性 # def在类之内定义的称为方法,类之外的称为函数 def __init__(self,name,age): # name、age为实例属性 self.name = name self.age = age # 实例方法 def info(self): print("my name is ", self.name, 'age', self.age) # 类方法 @classmethod def cm(cls): print('类方法') # 静态方法 @staticmethod def sm(): print("静态方法")
self参数
self 参数是对类的当前实例的引用,用于访问属于该类的变量。
它不必被命名为self,可以随意被调用,但它必须是类中任意函数的首个参数
对象
对象的创建
对象的创建又称类的实例化
语法:
实例名 = 类名()
意义:有了实例,就可以调用类中的方法
# 创建student类的对象 stu = Student('张三',8) print(stu) # 输出student对象的内存地址,16进制 print(stu.eat()) # 对象名.方法名() print(Student.eat(stu)) # 类名.方法(类的对象),与上一行功能相同,都是调用Student中的eat方法
修改对象属性
# 修改对象属性 stu.name = '李四' print(stu.name, stu.age)
删除对象属性
# 删除对象属性 del stu.age print(stu.name, stu.age)
删除对象
使用del关键字删除对象
# 删除对象 del stu print(stu)
类属性、类方法、静态对象
类属性:类中方法外的变量称为类属性,被该类的所有对象所共享
类方法:使用@classmethod修饰的方法,使用类名直接访问的方法
静态方法:使用@staticmethod修饰的主法,使用类名直接访问的方法
# 类属性、类方法、静态方法 print(Student.place) stu = Student('a', 4) stu1 = Student('b', 3) print(stu.place) print(stu1.place) Student.place = 'AA' print(stu.place) print(stu1.place) # 类方法的使用方式 Student.cm() # 静态方法的使用方式 Student.sm()
动态绑定属性和方法
python是动态语言,在创建对象后,可以动态绑定属性和方法
stu = Student('A', 20) stu1 = Student('B', 18) # 动态绑定性别属性 stu.sex = '男' # 只适用于绑定的对象 print(stu.name, stu.age, stu.sex) # 动态绑定方法 def show(): print("show") stu.show = show stu.show()
面向对象的三大特征
封装
提高程序安全性
将数据和行为包装在类对象中,在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度。
在python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前面使用两个下划线‘__’
# ----------面向对象的三大特征---------- # 封装 class Tel: def __init__(self, brand): self.brand = brand def start(self): print("开机。") tel = Tel('小米13') print(tel.brand) tel.start() class St: def __init__(self, name, age): self.name = name self.__age = age def show(self): print(self.name, self.__age) s = St('张三',15) s.show() # print(s.name,s.__age) print(dir(s)) print(s._St__age) # 在类的外部可以通过_St__age进行访问
继承
提高代码的复用性
语法结构:
class 子类类名(parent,parent1):
pass
如果一个类没有继承任何类,则默认继承object
# 继承 class Person(object): # person继承了object def __init__(self, name, age): self.name = name self.age = age def info(self): print(self.name, self.age) class S(Person): def __init__(self, name, age, stu_no): super().__init__(name, age) self.stu_no = stu_no class Teacher(Person): def __init__(self, name, age, toy): super().__init__(name, age) self.toy = toy stu = S('张三', 20, '1001') tea = Teacher('李四', 40, 12) stu.info() tea.info() print(stu.stu_no, stu.name, stu.age)
python支持多继承
定义子类时,必须在其构造函数中调用父类的构造函数
# 多继承 class Book(object): def __init__(self, name, author, kind, price): self.name = name self.author = author self.kind = kind self.price = price def info(self): print(self.name, self.author, self.kind, self.price) class Author(object): def __init__(auth, aname, age, sex): auth.aname = aname auth.age = age auth.sex = sex def ainfo(auth): print(auth.aname, auth.age, auth.sex) class Reader(Book, Author): def __init__(self, name, author, kind, price, aname, age, sex, readername, rage): Book.__init__(self, name, author, kind, price) Author.__init__(self, aname, age, sex) self.readername = readername self.rage = rage rea = Reader('活着', '余华', '文学', '25.9', '余华', 60, '男', '张三', 20) print(rea.name, rea.author, rea.kind, rea.price, rea.aname, rea.age, rea.sex, rea.readername, rea.rage)
方法重写
如果子类堆积成子父类的某个属性或方法不满意,可以在子类中对其进行重新编写
子类重写后的方法中可以通过super().xxx()调用父类中被重写的方法
# 方法重写 class Person(object): def __init__(self, name, age): self.name = name self.age = age def info(self): print(self.name, '/n', self.age) class Staff(Person): def __init__(self, name, age, salare): super().__init__(name, age) self.salare = salare def info(self): super().info() print(self.salare) class Student(Person): def __init__(self, name, age): super().__init__(name, age) def info(self): print("学生名字:"+self.name+",年龄:"+str(self.age)) st = Staff('张三', 20, 3000) pe = Person('李四', 20) st.info() pe.info() a = Student('王五', 20) a.info()
object类
object类是所有类的父类,因此所有类都有object类的属性和方法
内置函数dir()可以查看指定对象所有属性
object有一个__str__()方法,用于返回一个对于‘对象的描述’,对应于内置函数str()经常用语print()方法,帮我们查看对象的信息,所以我们经常会对__str__()进行重写
class Student: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return '名字:{0},今年{1}岁'.format(self.name, self.age) stu = Student('张三', 20) print(dir(stu)) print(stu)
多态
简单来说,多态就是‘具有多种形态’,它指的是:即便不知道一个变量索引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法
提高程序的可扩展性和可维护性
类的多态特性,还要满足以下 2 个前提条件:
- 继承:多态一定是发生在子类和父类之间;
- 重写:子类重写了父类的方法。
# 多态 class Student: def __init__(self, name, age): self.name = name self.age = age def info(self): print('学生:%s,%d' % (self.name, self.age)) class Teacher: def __init__(self, name, age): self.name = name self.age = age def info(self): print('老师:%s,%d' % (self.name, self.age)) class Manager: def __init__(self, name, age): self.name = name self.age = age def info(self): print('领导:%s,%d' % (self.name, self.age)) s = Student('王五', 15) t = Teacher('李四', 35) m = Manager('张三', 55) s.info() t.info() m.info()
class whoInfo: def info(self, who): who.info() class Student: def info(self): print('学生') class Teacher: def info(self): print('老师') class Manager: def info(self): print('领导') a = whoInfo() a.info(Student()) a.info(Teacher()) a.info(Manager())
静态语言与动态语言关于多态的区别
静态语言实现多态的三个必要条件
继承
方法重写
父类引向子类对象
动态语言的多态崇尚‘鸭子类型’,当看到一只鸟走、跑、游都像鸭子,那这只鸟就可以被称为鸭子。在鸭子类型中,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为
特殊方法和特殊属性
方法 | 属性 |
__doc__ | 表示类的描述信息 |
__module__ | 表示当前操作的对象在那个模块 |
__class__ | 表示当前操作的对象的类 |
__init__() | 构造方法,通过类创建对象时,自动触发执行 |
__del__ | |
__call__ | |
__dict__ | 类或对象中的所有成员 |
__str__ | 如果一个类中定义了str方法,那么在打印对象时,默认输出该方法的返回值 |
__getitem__ | 用于索引操作,如字典。表示获取数据、设置数据、删除数据 |
__setitem__ | |
__delitem__ | |
__getslice__ | 该方法表示分片操作,如:列表 |
__setslice__ | |
__delslice__ | |
__iter__ | 用于迭代器,之所以列表、字典、元组可以进行for循环,因为类型内部定义了__iter_ |
__new__ | 类中有一个属性 __metaclass__,用来表示该类由谁来实例化创建,所以可以为__metaclass__设置一个type类的派生类,从而查看 类 创建的过程。 |
__metaclass__ | |
__repr__ |
在python解释器环境下,会默认显示对象的repr表示 如果__str__没有被定义,那么就会使用__repr__来代替输出 __str__和__repr__方法的返回值都必须是字符串 |
__format__ | |
__item__ | |
__new__ | __init__是在类实例被创建之后调用的,它完成的是类实例的初始化操作,而 __new__方法正是创建这个类实例的方法 |
__enter__ | 一个对象如果实现了__enter__和___exit__方法,那么这个对象就支持上下文管理协议,即with语句 |
__exit__ | |
__len__() | 拥有__len__方法的对象支持len(obj)操作 |
__hash__ | 拥有__hash__方法的对象支持hash(obj)操作 |
__eq__ | 拥有__eq__方法的对象支持相等的比较操作 |
__get__ | 调用一个属性时,触发 |
__set__ | 为一个属性赋值时,触发 |
__delete__ | 采用del删除属性时,触发 |
# # 特殊方法 class Foo: '''描述信息''' def func(self): pass # __doc__ print(Foo.__doc__) # 显示类描述信息 a = Foo() # __module__ print(a.__module__) __class__ print(a.__class__) class Student: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return '名字:{0},今年{1}岁'.format(self.name, self.age) stu = Student('张三', 20) print(a.name, a.age) # 张三 18 print(a.__dict__) # 实例对象,显示实例对象的属性字典 print(Foo.__dict__) # 类对象,显示属性对象的方法的字典 print(Foo.__bases__) # 输出Foo类的父类元组 print(Foo.__base__) # 输出Foo类的第一个父类 print(Foo.__mro__) # 类的层次结构 print(Foo.__subclasses__()) # 子类的列表 a = 20 b = 100 c = a + b d = a.__add__(b) print(c, d) class Student: def __init__(self,name): self.name = name def __add__(self, other): # 实现了两个对象的加法运算,此方法为特殊方法 return self.name+other.name def __len__(self): return len(self.name) stu1 = Student('张三') stu2 = Student('李四') stu = stu1.__add__(stu2) print(stu) stu = stu1+stu2 print(stu) print(len(stu)) print(stu.__len__()) print(stu1.__len__())
__new__()和__init__()
class Person: def __init__(self, name, age): print("__init__被调用了,self的id值为:{0}".format(id(self))) # 1963885026752 self.name = name self.age = age def __new__(cls, *args, **kwargs): print('当前cls的id为:{0}'.format(id(cls))) # 1963912247344 obj = super().__new__(cls) print("创建的对象的id为:{0}".format(id(obj))) # 1963885026752 return obj print('object类对象的id为:{0}'.format(id(object))) # 140707825368576 print('Person类对象的id为:{0}'.format(id(Person))) # 1963912247344 p1 = Person('zhangsan', 20) print("id:{0}".format(id(p1))) # 1963885026752
类的赋值与浅拷贝、深拷贝
变量的赋值操作
只是形成两个变量,实际上还是指向同一个对象
# # 类的赋值与浅拷贝、深拷贝 class Cpu: pass class Disk: pass class Computer: def __init__(self, cpu, disk): self.cpu = cpu self.disk = disk # 赋值 cpu1 = Cpu() cpu2 = cpu1
浅拷贝
python拷贝一般都是浅拷贝,拷贝时对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象
# 浅拷贝,相当于一个人的大小名,都指你,你的头发、鼻子都是同一个东西 disk = Disk() computer = Computer(cpu1, disk) import copy computer2 = copy.copy(computer) print(computer, computer.cpu, computer.disk) print(computer2, computer2.cpu, computer2.disk)
深拷贝
使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同
# 深拷贝,相当于克隆,内容一样,但你是你,他是他,你的东西是你自己的 computer3 = copy.deepcopy(computer) print(computer, computer.cpu, computer.disk) print(computer3, computer3.cpu, computer3.disk)
原创文章,作者:dweifng,如若转载,请注明出处:https://blog.ytso.com/275873.html