python基础 编程思想
编程思想
面向过程
|
面向对象
|
|
区别
|
事物比较简单,可以用线性思维解决
|
事物比较复杂,使用简单的线性思维无法解决
|
共同点
|
面向过程和面向对象都是解决实际问题的一种思维方式
|
|
二者相辅相成,并不是独立的
解决复杂问题,通过面向对象方式便于我们从宏观上把握事物之间的复杂关系、方便我们分析整个系统,具体到微观操作,仍然使用面向过程方式来处理
|
类与对象
类:多个类似事物组成的群体的统称,能够帮助我们快速理解和判断事物的性质
数据类型:
不同数据类型属于不同的类
使用内置函数查看数据类型
对象:
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)