(十)nonlocal和global关键字
nonlocal用来在内部函数中声明外层的局部变量,然后再使用
global是在函数内声明全局变量,然后再使用
(十一)LEGB规则
发生变量名字冲突时,按照LEGB规则来找
Local:函数或者类的内部
Enclosed:嵌套函数
Global:模块中全局变量
Built in:Python为自己保留的特殊名称
29 对象和类
(一)面向过程和面向对象
面向对象:“设计者思维”,首先思考怎么设计,将复杂事物分解,需要很多协作完成,具体到实现部分的微观操作,仍然需要面向过程去处理
面向过程:“执行者思维”,适合简单事物,关注如何执行
(二)类
类是图纸,根据图纸造出对象
属性(变量)是状态,方法(函数)是行为,把具有相同属性和方法的对象归为一类
从一个类创建对象时,每个对象会共享这个类的方法,但会有自己的属性值
class 类名:
类体
1.类名必须符合“标识符”规则,一般规定首字母大写,多个单词使用“驼峰原则”
2.类体中可以定义属性和方法
3.属性用来描述数据,方法(函数)用来描述数据相关的操作
class Student:
def __init__(self,name,score): #定义构造方法,局部变量变成类的属性,在其他方法里也可以使用
self.name = name #name和score本身是局部变量,在这里处理完后就变成了属性
self.score = score
def say_score(self):
print("{0}的分数是{1}".format(self.name,self.score))
s1 = Student("zhangsan",80) #s1对象实际调用的是构造方法
print(s1.name,s1.score)
s1.say_score()
#zhangsan 80
#zhangsan的分数是80
(三)__init__构造方法
1.名称固定,必须为__init__()
2.第一个参数固定,必须为self。self指的是刚刚创建好的实例对象
3.通过“类名”来调用构造函数,调用后,将创建好的对象返回给相应的变量
4.__init__()方法:初始化创建好的对象,初始化指的是:“给实例属性赋值”
__new__()方法:用于创建对象,但一般无需重定义该方法
如果不定义带参的__init__(),系统会提供一个默认的无参的
(四)实例属性
实例属性是从属于实例对象的属性,也叫“实例变量”
1.实例属性一般在__init__()中,通过如下定义:
self.实例属性名=初始值
2.在本类其他实例方法中,也是通过self进行访问:
3.创建实例对象后通过实例对象访问:
obj01=类名()
obj01实例属性名=值#给已有属性赋值,也可以新加属性
如果在创建的某个实例对象下新增属性,则该属性只在该实例对象内,其他实例对象无法调用
新增属性一般都放在构造函数里,比较整齐
(五)实例方法
def 方法名(self,形参)
函数体
对象.方法名([实参列表])
定义实例方法,第一个参数也必须为self,调用实例方法不能给self传参
class Student:
def __init__(self,name,score): #定义构造方法,局部变量变成类的属性,在其他方法里也可以使用
self.name = name #name和score本身是局部变量,在这里处理完后就变成了属性
self.score = score
def say_score(self):
print("{0}的分数是{1}".format(self.name,self.score))
a = Student("zhangsan",80)
a = Student()
a.say_score(68)
#实例对象的方法调用本质是Student.say_score(a,68)
print(dir(a)) #返回a这个对象的所有属性和方法
print(a.__dict__) #返回a这个对象的所有属性
print(isinstance(a,Student)) #判断a是不是Student这个类的实例对象
(六)类对象
在定义类时,执行class语句,就是在生成一个类对象
对象类型就是type
class Student:
pass
Stu = Student #Stu和s都指向了同一个类对象Student
s = Stu()
print(s)
(七)类属性
类属性是从属于“类对象”的属性,也称为“类变量”,可以被所有实例对象共享
class Student:
count = 0 #类属性
def __init__(self,name,score):
self.name = name #实例属性
self.score = score
Student.count = Student.count + 1 #统计有多少个学生,因为每一次都会调用构造函数
def say_score(self): #实例方法
print(self.name,'的分数是:',self.score)
s1 = Student("zhangsan",80) #s1是实例对象
s2 = Student("lisi",70)
s1.say_score()
print("一共创建{0}个Student对象".format(Student.count))
#zhangsan 的分数是: 80
#一共创建2个Student对象
(八)类方法
类方法是从属于“类对象”的方法
@classmethod
def 类方法名(cls,[形参列表]):
方法体
第一个cls必须有,cls指的是“类对象”本身
类方法中不能调用实例属性,实例方法
(九)静态方法
静态方法在模块中定义普通函数没有区别,只是“静态方法”放到了“类的名字空间里”,需要通过“类调用”
@ staticmethod
def 静态方法名([形参列表]):
方法体
静态方法中也不能访问实例属性和实例方法
(十)__del__方法(析构函数)
当对象没有被引用时,由垃圾回收器调用__del__()
__del__()用于实现对象被销毁时所需的操作
class Student:
count = 0 #类属性
def __init__(self,name,score):
self.name = name #实例属性
self.score = score
Student.count = Student.count + 1 #统计有多少个学生,因为每一次都会调用构造函数
def __del__(self):
print("qingchu")
def say_score(self): #实例方法
print(self.name,'的分数是:',self.score)
s1 = Student("zhangsan",80) #s1是实例对象
s2 = Student("lisi",70)
s1.say_score()
#s2.say_score()
del s2
print("一共创建{0}个Student对象".format(Student.count))
'''zhangsan 的分数是: 80
qingchu
一共创建2个Student对象
qingchu
'''
???
(十一)__call__方法和可调用对象
在调用函数时,本质上就使用了__call__()
class Car:
def __call__(self,age,money):
print("call 方法")
print("车龄{0},金额{1}".format(age,money))
c = Car()
c(3,200000)
#call 方法
#车龄3,金额200000
(十二)方法没有重载以及方法的动态性
定义多个重名的方法,只有最后一个有效
动态给类添加方法,动态修改类方法
class Person:
def work(self):
print("努力工作")
def play_game(s): #s是必要的,如果没有s添加到类里再调用时会报错,相当于没有self,s是为了给self留位置,添加到类系统会将其自动转为self
print("玩游戏")
def work2(s):
print("好好工作")
Person.play = play_game #给Person类里新加函数play
Person.work = work2 #将Person类里的work函数修改为work2
p = Person()
p.play()
p.work()
#玩游戏
#好好工作
(十三)私有属性和私有方法
Python对于类的成员没有严格的访问控制限制,只是约定:
1.双下划线开头是私有
2.类内部可以访问私有属性(方法)
3.类外部不能直接访问私有属性(方法)
4.类外部可以通过“_类名__私有属性名”访问私有属性
class Employee:
__company = "lll" #解释器运行时,把__company转成了_Employee__company
def __init__(self,name,age):
self.name = name
self.__age = age
def say_company(self):
print("我的公司是:",Employee.__company)
print("我的年龄是:",self.__age) #内部调用的时候不用换名字
print(Employee._Employee__company) #在外部调用的时候要换名字
a = Employee("lmh",18)
a.say_company()
#lll
#我的公司是: lll
#我的年龄是: 18
(十四)_@property装饰器
@property装饰器可以将一个方法的调用方式变成“属性调用”
@property主要用于帮助我们处理属性的读操作、写操作。对于某一个属性,我们可以直接通过:
emp1.salary=30000
class Employee:
def __init__(self,age):
self.__age = age
@property
def age1(self):
print("我的年龄是:", self.__age)
return self.__age
a = Employee(18)
print(a.age1)
#我的年龄是: 18
#18
看似调用的是属性,其实调用的是方法
(十五)属性和类的命名规则
_xxx:保护成员,不能用from module import*导入,只有类对象和子类对象能访问这些成员
_xxx_:系统定义的特殊成员e.g._init_()
_xxx:类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但在类外部可以通过对象名._类名_xxx这种方式访问)