文章目录
一. 面对对象初步
Python支持面向过程,面向对象,函数式编程等多种编程范式
- 面向过程(procedure oriented):
更关注程序的逻辑流程,执行者思维,适合简单,不需要协作的任务 - 面向对象(Object Oriented):
更关注软件中对象之间的关系,设计者思维,适合编写大规模程序
1. 面对对象和面对过程对比
- 面对对象相当于横向展开,面对过程相当于纵向展开
- 复杂问题,必须先横向拆分,再纵向执行两种思路相辅相成
2. 对象的进化
- 简单数据
- 数组:将同类数据放到一起
- 结构体:不同类数据放到一起
- 对象:将不同类型和方法放到一起
二. 类的定义
- 将对象比作饼干,类就是制造饼干的模具
- 通过类定义数据类型的属性(数据)和方法(行为),属性通过变量表示,方法通过函数表示
- 对象称为类的实体,对象共享类的行为(类中定义的方法),但会有自己的属性(不共享状态)
- 类名首字母大写,使用驼峰原则
1. __init__和__new__构造
- 名称必须是__init__
- 第一个参数必须是self
- 用来初始化实例对象的实例属性
- 通过类名(参数列表)来调用构造函数,将创建好的对象返回给相应变量
- new()无需重新定义,用来创建对象
2. 实例属性
- 实例属性是从属于实例对象的属性
- 初始化定义:
def __init__(self,name,score): #self必须位于第一个参数,若不传入name,score参数,在下面定义,则这一类所有属性都唯一确定
self.name=name
- 在本类的其他方法中,也通过self.实例属性名进行访问
- 创建实例对象后,通过实例对象访问
- 通过实例对象访问时,可以更改已有属性值,也可以添加新属性
3. 实例方法
- 定义实例方法时,第一个参数必须为self,self指当前实例对象
- 调用时例方法时,不能给self传参,self由解释器自动传参
4. 其他操作
- dir(obj)获得对象所有属性,需要print,不只是定义的属性和方法,还有一些基础的属性
- obj.dict()获得对象的属性字典,只有属性,没有方法
- pass 空语句
- isinstance(对象,类型)判断对象是不是指定类型
5. 代码
class Student: #首字母大写,驼峰原则
#构造函数
def __init__(self,name,score): #self必须位于第一个参数,若不传入name,score参数,在下面定义,则这一类所有属性都唯一确定
self.name=name
self.score=score
def say_score(self): #self必须位于第一个参数
print("{0}的分数是:{1}".format(self.name,self.score))
s1=Student("gaogao",18) #相当于用__new__(一般无需重新定义此方法)创建对象,用__init__(需要在类中定义该方法)初始化
s1.say_score()
s1.name="wang"
s1.age=20
print(s1) #<__main__.Student object at 0x000001BE7BAFE4C8>
s1.say_score() #类中定义的属性可以在复制以后更改
print(dir(s1)) #获得对象所有!属性方法(不只有定义的属性和方法(也是一种属性),还有更底层的属性)
print(s1.__dict__) #对象的属性字典(返回字典类型,里面是定义的属性键对值(不包含方法))
print(isinstance(s1,Student)) #判断对象是不是指定类
s2=Student("li",32)
s2.say_score()
print(s2.__dict__) #没有age的属性,因为age是s1自定义的,只有方法共享!1
class Student: #首字母大写,驼峰原则
def __init__(self): #self必须位于第一个参数,若不传入name,score参数,在下面定义,则这一类所有属性都唯一确定
self.name="gaogao"
self.score=18
def say_score(self): #self必须位于第一个参数
self.sex="man" #定义在行为里的初始状态是共享的,但是可以修改
print("{0}的分数是:{1}".format(self.name,self.score))
s1=Student() #
s1.say_score()
s1.sex="female"
print(s1.sex)
#空语句用pass
class Student:
pass
三. 类对象/类属性/类方法
1. 类对象
- 当解释器执行class语句时,就会创建一个类对象
- 类对象可以赋值,类对象的类型是type,实例对象的类型是对应的类名
2. 类属性
- 类属性是从属于类对象的属性,也称为类对象,可以被所有实例对象共享
- 类属性通过类名来访问
class Student: #创建类对象
company="abc" #类属性
count=0
def __init__(self,name,score): #创建实例对象
self.name=name
self.score=score
Student.count+=1 #类属性通过类名来访问
def say_score(self):
print("my company is:",Student.company)
print("my score is:",self.score)
S1=Student
s2=S1("gao",100)
print(type(S1)) #<class 'type'>类型是“类”,S1是一个类对象
print(type(s2)) #<class '__main__.Student'>Student类型,是一个实例对象
s1.say_score()
3. 类方法
- 类方法是从属于类对象的方法
- 通过@classmethod来定义,必须位于类方法定义上一行
- 第一个参数必须是cls
- 调用类方法格式:类名.类方法名(参数列表),不用传cls值
- 类方法中访问实例属性和实例方法会导致错误
- 实例方法可以调用类方法,用self.函数名调用!!!
class Student:
company="abc" #类属性
@classmethod #类方法定义上一行要加@classmethod
def printcompany(cls): #类方法必须用cls作为第一个参数
print(cls.company)
def a(self): #实例方法可以调用类方法,用self.函数名调用!!!
self.printcompany()
A=Student()
A.a()
Student.printcompany() #通过类名加函数名调用类方法
4. 静态方法
- 定义与类对象无关的方法,称为静态方法
- 需要通过类调用
- 通过装饰器@staticmethod调用
class Student:
company="sbc"
@staticmethod #静态方法定义上一行加@staticmethod
def add(a,b): #不用cls参数
print("{0}+{1}:{2}".format(a,b,(a+b)))
return (a+b)
Student.add(1,2)
5. 析构函数
- 实现对象被销毁时所需的操作
- Python垃圾回收机制:当对象引用数为0时,垃圾回收器调用__del__方法
- 系统会提供__del__方法,不需要自定义
class Person:
def __del__(self):
print("销毁对象:{0}".format(self))
P1=Person()
P2=Person()
del P2
print("程序结束")
#P1也被销毁了,因为引用数为0
6. __call__方法和可调用对象
class SalaryAccount:
def __call__(self,salary):
print("计算工资")
yearsalary=salary*12
daysalary=salary/22.5
hoursalary=daysalary/8
return dict(yearsalary=yearsalary,daysalary=daysalary,mothsalary=salary,hoursalary=hoursalary)
S=SalaryAccount()
print(S(30000))
四. Python方法没有重载
- 其他语言可以定义多个重名的方法,只要保证方法签名一致即可,方法签名包括三部分:方法名,参数数量,参数类型
- Python中,参数没有声明类型,而且参数数量可以有可变参数控制,所以Python没有方法重载
- 如果在类体中定义多个重名方法,只有最后一个方法有效
五. 方法的动态性
- Python是动态语言,可以在外部通过引用类方法动态的为类添加新的方法,或者动态地修改已有类方法
class Person:
def work(self):
print("努力上班")
def play_game(s): #可以用s也可以用self
print("{0}玩游戏".format(s))
def work2(s):
print("好好工作,努力上班")
#用类名增加方法
Person.play=play_game
#用类名修改方法
Person.work=work2
p=Person()
p.play() #Person.play(p)
p.work() #Person.work(p)
六. 私有属性和私有方法
- Python对于类成员没有严格的访问控制
- 通常规定,两个下划线开头的属性是私有的,其他的为公共的
- 类内部可以访问私有属性和方法
- 类外部不能直接访问私有属性和方法
- 类外部通过“_类名__私有属性(方法)名”访问私有属性(方法)
#测试私有属性
class Employee:
__company="abc"
def __init__(self,name,age):
self.name=name
self.__age=age
e=Employee("gao",18)
print(e.name)
print(e._Employee__age)
print(e._Employee__company)
print(dir(e))
print(e.__dict__) #{'name': 'gao', '_Employee__age': 18}私有属性在类里面的名字已更改
#私有方法
class Employee:
__company = "abc"
def __init__(self, name, age):
self.name = name
self.__age = age #私有属性
def __work(self): #私有方法
print("{0}:{1}岁".format(self.name,self.__age)) #有__,没有_Employee
print("{0}".format(self.__company)) #实例方法中调用私有类方法,可以用类名调用,也可以用self
#print("{0}".format(Employee.__company)) # 实例方法中调用私有类方法,可以用类名调用,也可以用self
e = Employee("gao", 18)
print(e.name)
print(e._Employee__age)
print(e._Employee__company)
e._Employee__work()
print(dir(e))
print(e.__dict__) # {'name': 'gao', '_Employee__age': 18}私有属性在类里面的名字已更改
七. @property装饰器
- @property可以将一个方法的调用变成属性调用
- @方法名.setter:调用方法并给方法赋值时,执行此方法
#测试property用法
class Employee:
@property
def salary(self):
return 10000
emp1=Employee()
print(emp1.salary)
#print(emp1.salary()) #若没有property,要这样使用
#@property和@setter应用
class Employee:
def __init__(self,name,salary):
self.__name=name
self.__salary=salary
@property
def salary(self):
return self.__salary
@salary.setter
def salary(self,salary):
if 1000 < salary < 50000:
self.__salary = salary
else:
print("录入错误,重新输入")
'''
若不用setter方法,要写判断函数,在调用时更换函数
def get_salary(self):
return self.__salary
def set_salary(self):
if 1000<salary<50000:
self.__salary=salary
else:
print("录入错误,重新输入")
'''
emp1=Employee("gao",60000)
print(emp1.salary)
emp1.salary=70000 #这一步是继续调用的是salary.setter
print(emp1.salary)