课程链接:点击打开
类也是对象
给类增加一个属性(在类的外面通过赋值的方法):
class Money:
pass
one=Money()
Money.count=1 #给类增加一个属性
print(Money.count)
print(Money.__dict__)
类增加属性的方式二(在类的内部通过赋值的方法):
class Money:
age=28
count=1
num=666
one=Money()
print(Money.count)
print(Money.age)
print(Money.__dict__)
通过对像访问类属性:优先从对像自身上查找属性,找到则结束,如果没有找到,根据class找到对象对应的类,到这个类里面查找。
print(one.age)
print(one.aount)
更改对象的类:
class text:
pass
one.__class__ = text#更改对象的类
print(one.age)#不能访问
通过类名修改
class Money:
age=28
count=1
num=666
Money.age=22
print(Money.age)
不能通过对象修改类属性
del 类名 类属性
del Money.age
不能通过对象删除,del语句只能删除直系属性
类的属性的增、删、改只能通过类来访问,查询的时候可以通过对象和类来访问!
类属性的内存存储问题:一般情况下,属性存储在__dict__
字典当中,有些内置对象没有这个属性,一般对象可以直接修改__dict__
属性,类对象的__dict__
为只读,默认无法修改。
class Money:
age=28
count=1
num=666
one=Money()
one.__dict__['age'] = 999#对象的__dict__可以被修改
print(one.age)
class Money:
age=28
count=1
num=666
one=Money()
two=Money()
print(one.age)
print(two.age)
查看一个类的所有属性通过类名.__dict__
来查看
__slots__
class Person:
__slots__=['age'] #只有slots所限定的属性
pass
p1 = Person()
p1.age = 18
p1.name = '小狗' #将报错
描述一个目标的行为动作
和函数非常类似,都封装了一系列动作,都可以被调用之后执行一系列行为动作,最主要的时调用方式
class Person:
def eat2(self):
print(1)
print(2)
print(3)
p = Person()
p.eat2()
实例方法:默认第一个参数需要接收到一个实例
类方法:默认第一个参数需要接收到一个类
静态方法:一个默认参数也不接受
注意:1.划分依据是:方法第一个参数必须要接受的的数据类型。2.不管是哪一种给类型方法,都储存在类当中,没有在示例当中的。3.不同类型方法调用方式不同。
class Person:
def eat2(self):
print('这是一个实例方法',self)
@classmethod
def leifangfa(cls):
print('这是一个类方法',cls)
@staticmethod
def jiangtaifanfa():
print('这是一个静态方法')
__dict__
中,没有在实例当中的标准的调用方法:使用实例调用实例方法,不用手动调,解释器会把调用对象(实例)本身传递过去。如果实例方法没有接受任何单数则会报错。
class Person:
def eat(self,food):#self可以是aa、bb 等,一般是self
print('在吃饭',food)
p = Person()
p.eat('土豆')
#-------------------------------
class Person:
def eat(): #报错,因为实例方法必第一个必须接收实例作为第一个参数
print('在吃饭')
p.eat()
其他的的调用方法:使用类调用、间接调用,他们的本质就是直接找到函数本身来调用。
类方法可以被实例调用,也可以被类调用。
class Person:
@classmethod #装饰器的作用:在保证原函数不变的情况下,直接给这个函数增加一些功能
def leifangfa(cls,a):
print("这是一个类方法" , a)
Person.leifangfa(123)
p = person()
p.leifangfa(666)
func = Person.leifangfa
func(111)
既可以通过类调用,也可以通过示例调用
class Person:
@staticmethod #装饰器的作用:在保证原函数不变的情况下,直接给这个函数增加一些功能
def jingtai(cls):
print("这是一个类方法")
Person.jingtai()
p = Person()
p.jingtai()
func = Person.jingtai
func()
访问类属性:通过类和实例
访问实例属性:只能通过实例
class Person:
age = 0
def shilifangfa(self):
print(self)
print(self.age)
print(self.num)
@classmethod
def leifangfa(cls):
print(cls)
print(cls.age)
print(cls.num) #不能通过类访问实例属性
@staticmethod
def jingtaifangfa():
print(Person.age) #可以通过类访问类属性
P = person()
P.num = 10
元组:创建类对象的类
num = 1
print(num.__class__) #输出int
%------------------------------------------
s = "abc"
print(s.__class__) #输出str
%------------------------------------------
class Person:
pass
p = Person()
print(p.__class__) #输出Person
%------------------------------------------
print(int.__class__) #输出type
调用type函数创建
def run(self):
print(self)
xxx = type("Dog",(),{"count":0,"run":run})
print(xxx)
print(xxx.__dict__)
d.xxx() #不是d.Dog
print(d)
d.run()
类的创建流程:
__mateclass__
属性。__mateclass__
属性。__mateclass__
属性。#1模块的指定
__metaclass__ = xxx
#2
class Animal:
pass
#3
class Dog(Animal):
pass
#4
class Dog:
__metaclass__ = xxx
pass
class Person:
"""
关于这个类的描述,类的作用,类的构造函数等等;类属性的描述
Attributes:
count: int 代表人的个数
"""
count = 1
def run(self, disance, step):
"""
这个方法的作用效果
:param distance:blahblah
:param step:blahblah
:return:
"""
print("跑步")
return distance,step
help(Person) #
注释文档不包括源码,只包括函数名和它的描述
方式1.使用内置的模块:pydoc。具体步骤:
python3 -m pydoc 模块名称
python3- m pydoc-p 666
python3 -m pydoc -w 模块名称
命令行命令:
cd <代码路径>
python --help
python -m pydoc <文件名> #
python -m pydoc -k <关键字> #列出文件名中包含关键字的文件
python -m pydoc -p <端口号> #指定一个未用的端口号
python -m pydoc -b #自动指定端口号
python -m pydoc -w <文件名> #在当前目录生成一个html文件
还有其他方法,只是要安装第三方模块。
注意:python并没有真正的私有化支持,但是,可以使用下划线完成伪私有的效果。如_y
、__z
。
共有属性可以通过
class Animal:
x = 10
def test(self):
print(Animal.x)
print(self.x)
pass
%----------------------
class Dog(Animal):
def test2(self):
print(Dog.x)
print(self.x)
pass
a = Animal()
a.test() #类的内部访问,通过类内部定义的函数访问
d = Dog()
d.test2() #延伸类的访问(通过延伸类内部定义的函数访问)
print(Animal.x) #模块的其他部分
print(Dog.x)
print(a.x)
print(b.x)
import xxx #模块的其他部分访问
print(xxx.a)
from xxx import *
print(a)
class Animal:
_x = 10
def test(self):
print(Animal._x)
print(self._x)
pass
#--------------------
class Dog(Animal):
def test2(self):
print(Dog._x)
print(self._x)
pass
a = Animal()
a.test() #类的内部访问
d = Dog()
d.test2() #延伸类的访问
print(Animal._x) #模块的其他部分,可以强行访问,有警告
print(Dog._x)
print(a._x)
print(b._x)
import xxx #模块的其他部分访问,不可访问
print(xxx.a)
from xxx import *
print(a)
class Animal:
__x = 10
def test(self): #定义一个实例方法
print(Animal.__x)
print(self.__x)
pass
#--------------------
class Dog(Animal):
def test2(self):
print(Dog.__x)
print(self.__x)
pass
a = Animal()
a.test() #类的内部访问,可以访问
d = Dog()
d.test2() #延伸类的访问,不可以访问
print(Animal.__x) # 模块的其他部分,不可访问
print(Dog.__x)
print(a.__x)
print(d.__x)
a = 1
import xxx #模块的其他部分访问,不可访问
print(xxx.a)
from xxx import *
print(a)
名字重整:改_x
为另外一个名称,如:_类名_x
。
目的:
可以用重整后的名字访问
class Animal:
__x = 10
def test(self):
print(Animal.__x)
print(self.__x)
pass
print(Animal.__dict__)
ptint(Animal,_Animal__x)
数据保护 2.数据过滤
class Person:
#作用:当我们创建好一个实例对对象之后,会自动调用这个方法,来初始化这对象
#init是单词初始化initialization的省略形式
def __init__(self)
self.__age = 18
def setAge(self,value):
if isinstance(value,int) and 0<value<200:
self.__age = value
else:
print("您输入的数据有误,请重新输入")
def getAge(self):
return self.__age
p1 = Person()
p1.setAge(20)
p2 = Person()
print(p1.getAge()) #访问age
print(p1.__age) #报错,只能在类内部访问
print(p2.__age)
xx_
:避免与系统关键字冲突__xx__
:系统内置全部隐藏,通过私有化,即不能读取,也不能写入; 部分公开,通过方法实现(有弊端)
class Person:
def init(self): #初始化方法,通过方法设置属性
self.__age = 18
def getAge(self): #部分公开,通过方法实现
return self.__age
p1 = person()
print(p1.getAge())
## 49-python-面向对象-只读属性-方案一的优化
1. ```python
class Person(object):
def __init__(self):
self.__age = 18
# 主要作用:可以以使用属性的方法来使用这个方法
@property
def age(self): #部分公开,通过方法实现
return self.__age
p1 = person()
print(p1.age())
property的作用:将“一些属性的操作方法”关联到另一个属性,间接地管理私有属性。
class C(object):
def getx(self): return self._x
def setx(self,value): self._x = value
def delx(self): del self._x
x = property(getx, setx, delx)
经典类:没有继承object
新式类:继承object
class Person:
pass
print(Person.__bases__) #查看父类(基类)k
在python2中,定义一个类,没有显式的继承自object,那么这个类就是一个继承类,显式的继承自object,他才是一个新式类。
在python3中,定义一个类,会隐式的继承object,所以默认情况下,就已经是一个新式类。
建议,无论在python2和3,都显式的继承object。
property函数方法
class Person(object):
def __init__(self):
self.__age = 18
def get_age(self):
ruturn self.__age
def set_age(self, value):
self.__age = value
age = property(get_age, set_age)
p = Person()
print(p.age)
p.age = 30
print(p.age)
print(p.__dict__) #输出只有_person__age:
2.装饰器的方式
class Person(object):
def __init__(self):
self.__age = 18
@property
def age(self):
return self.__age
@age.setter
def age(self, value):
delf.__age = value
p = Person()
p.age = 20 #既可以读取也可以设置
在经典类中,property只会关联读取方法,不会关联设置和删除方法。
class Person(object):
def __init__(self):
self.__age = 18
def get_age(self):
ruturn self.__age
def set_age(self, value):
self.__age = value
age = property(get_age, set_age)
p = Person()
print(p.age) #可以读取,不会报错
p.age = 30 #不会设置属性,而是增加了一个age属性
print(p.age)
print(p.__dict__) #输出_person__age和age
#--------------------------
# 装饰器方法
#--------------------------
class Person(object):
def __init__(self):
self.__age = 18
@property
def age(self):
return self.__age
@age.setter
def age(self, value):
delf.__age = value
p = Person()
print(p.age) #可以读取,不会报错
p.age = 30 #不会设置属性,而是增加了一个age属性
print(p.age)
print(p.__dict__) #输出_person__age和age
虽然是私有属性,任然可以通过两种方法设置__age属性:
p._Person__age=xxx
p.__dict__['_Person__age']=xxx
做只读属性的方式二:
class Person:
#当我们通过实例.属性 = 值,给一个实力增加一个属性,或者修改属性的时候,就会自动调用这个方法,
#在这个方法内部才会正真地把这个属性,以及对应的数据存储到__dict__字典里面
def __settter__(self, key, value):
print(key, value)
#1.判定,key,是否是我们要设置的只读属性
if key = "age" and key in self.__dict__.keys():#只能新增属性,不能修改属性
print("这个属性是只读属性,不能设置数据")
#2.如果不是只读属性,就给他添加到实例里面去
else:
#self.key = value #这样会陷入死循环
self.__dict__[key] = value
类属性:
__dict__
:类属性__bases__
:类的所有父类构成元组__doc__
类的文档字符__name__
类名__module__
类定义所在模块实例属性:
__dict__
:类的实例__class__
:实例对应的类方法:在函数名前加两个下划线,与属性私有化相同,名字重整机制是相同的。
class Person:
def __run(self):
print("run")
p = Person()
print(Person.__dict__)
__str__
给初始化方法__init__
里边传递参数,即可创建不同的对象
class Person:
def __init__(self,n,a):
self.name = n
self.age = a
p1 = Person("zpc", 18) #可创建不同的对象
通过定义__str__
,就可以通过print(<对象>)
来查看指定的返回值
class Person:
def __init__(self,n,a):
self.name = n
self.age = a
def __str__(self):
return "这个人的姓名是%s,这个人的年龄是%s"%(self.name, self.age)
p1 = Person("zpc",18) #可创建不同的对象
s=str(p1)
print(s)
__repr__
__repr__
面向的对象是开发人员(解释器);__str__
面向的对象是用户。
def Person:
def __init__(self):
return"repr"
如果没有定义__str__
,那么str
也返回的是__repr__
的内容
触发__str__
的方法:
print(p1)
s=str(p1) print(s)
触发__repr__
的方法:
s=repr(p1) print(s)
__call__
-概念和作用__call__
的作用:使得对象具有当作函数来调用的能力(将对象变为可调用对象)
class Person:
def __call__(self):
print("xxx")
pass
p = Person()
p() #调用__call__函数
__call__
应用场景的简单案例首先创建一个类,类的属性只有一个(p_type),然后创建一个__call__
方法(只接收一个参数p_color),这样就可以通过<实例>(p_color)
。
class PenFactory:
def __init__(self, p_type):
self.p_type = p_type #这个类只有一个属性
def __call__(self, p_color):
print("创建了一个%s类型的画笔,他是%s颜色的"%(self.p_type, p_color))
gangbiF = penFactory("钢笔") #创建一个对象
gangbiF('红色')
以索引的方式操作python序列:
p[1] = 666
、p['name'] = sz
p[name]
、p[1]
del p[name]
、del p[1]
需要一个字典属性,才可以对对象进行索引操作。
class Person:
def __init__(self):
self.cache = {} #定义cache属性,为一个字典
def __setitem__(self, key, value):
self.cache[key] = value
def __getitem__(self, key):
return self.cache[key]
def __delitem__(self, key):
del self.cache[key]
p = Person()
p['name'] = 'sz' #执行这行代码的时候,会调用第一个方法
print(p['name']) #调用第二个方法
def __setitem__(self, key, value)
:def __getitem__(self, item)
:def __delitem__(self, key)
:class Person:
def __init__(self):
self.items = [1, 2, 3, 4, 5, 6, 7, 8] #定义了一个items属性
def __setitem__(self, key, value):
if isinstance(key,silce):
self.items[key] = value #注意切片操作只能修改,不能新增
#self.items.[key.start: key.stop: key.step] = value #这样赋值也可以
def __getitem__(self, key):
return(key.items[key]) #这里可能有错
def __delitem__(self, key):
del self[key]
p = Person()
p[0: 4: 2] = ["a","b"]
print(p.items[0: 4: 2])
为对象定义比较操作,调用此方法,就可以使对象可以向数一样比较大小!
class Person:
def __init__(self, age, height):
self.age = age
self.height = height
def __eq__(self, other):
return self.age == other.age #指定相等的比较通过哪个属性比较,
def __ne__(self, other):
return self.age != other.age #指定相等的比较通过哪个属性比较,
p1 = Person(18, 180)
p2 = Person(19, 183)
print(p1 == p2)
#类似的还有:
#gt >
#ge >=
#lt <
#le <=
#可以通过调换参数的方式定义比较方法,进而简化代码
import functools
@functools.total_ordering #此装饰器会自动补全所需要的方法
class Person
def __lt__(self, other):
pass
def __eq__(self, other):
pass
非空即为True
此方法使对象可以被作为一个布尔值使用。
class Person():
def __bool__(self): #通过bool值判定实例是True或False
return False #这里也可以是一个返回布尔值的语句
pass
p = Person()
if p:
print("xx")
__getitem__
遍历操作:
__getitem__
方法__iter__
方法class Person:
def __init__(self):
self.result = 1
def __getitem__(self, item):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
return relf.result
pass
p = person()
for i in p: #当执行for循环时,自动进入__getitem__方法,使用这个方法的返回值作为数据
print(i)
__iter__
__iter__
的优先级高于__getitem__
class Person:
def __init__(self):
self.result = 1
def __getitem__(self, item):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
return relf.result
def __iter__(self):
print("hfkjasdf")
p = person()
for i in p: #当执行for循环时,自动进入__geritem__方法,使用这个方法的返回值作为数据
print(i)
可迭代对象包含迭代器。
如果一个对象拥有__iter__
方法,其是可迭代对象;如果一个对象拥有__next__
方法,其是迭代器。
定义可迭代对象,必须实现__iter__
方法;定义迭代器,必须实现__iter__
和__next__
方法。
你也许会问,结论c与结论b是不是有一点矛盾?既然一个对象拥有了__next__
方法就是迭代器,那为什么迭代器必须同时实现两方法呢?
因为结论a,迭代器也是可迭代对象,因此迭代器必须也实现__iter__
方法。
首先调用__iter__
,返回一个迭代器,然后调用__next__
方法;
class Person:
def __init__(self):
self.result = 1
def __getitem__(self, item):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
#return iter([1,2,3,4]) 如果返回是迭代器,则自动进入迭代器的__next__方法
return relf.result
def __iter__(self):
return self
def __next__(self):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
return relf.result
p = person()
for i in p:
print(i)
__next__
通过next函数访问迭代器:
class Person:
def __init__(self):
self.result = 1
def __getitem__(self, item):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
#return iter([1,2,3,4]) 如果返回是迭代器,则自动进入迭代器的__next__方法
return relf.result
def __next__(self):
self.result += 1
if self.result >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
return relf.result
p = person()
print(next(p)) #直接进入__next__方法
print(next(p))
print(next(p))
print(next(p))
print(next(p)) #抛出异常,停止遍历
class Person:
def __init__(self):
self.age = 1
def __iter__(self):
self.age = 1 # 如果没有这行命令,那么迭代器只能使用一次
return self
def __next__(self):
self.age += 1
if self.age >=6: #不满足时,跳出循环
raise StopIteration("停止遍历")
return relf.age
p = person()
for i in p:
print(i)
import collection
print(isinstance(p, collection.Iterator))
#返回值为True,表明确实是一个迭代器,需要同时有两个方法__iter__、__next__
next(p) #只要有一个方法__next__就可以访问
import collection
print(isinstance(p, collection.Iterable))#判定是否为可迭代对象,只要一个方法__iter__就可以
一个可迭代对象一定可以通过for in
访问,可以通过for in
访问的不一定是可迭代对象
next()
函数访问对象,要想让iter()
对创建的对象起作用,需要在类里边定义方法:__getitem__
或者:__iter__
和__next__
(这两个方法必须同时都需要)。iter(<要转换的对象>,<停止数值>)
class Person:
def __init__(self):
self.__age = 10
@property
def age(self):
return self.__age
@age.setter
def age(self, value):
if value < 0:
value = 0
self.__age = value
@age.deleter
def age(self):
del self.__age
p = Person()
p.age #注意:这里的age是方法里面的age,不是属性的age
del p.age
对方式一进行优化,即多个属性时,由于操作内容不同,在主类中代码会过于繁琐,为简化代码,将属性的操作方法封装到类中,在主类中对方法类的实例对象进行操作即可
class Age: #描述器类
def __get__(self, instance, owner):
print("get")
def __set__(self, instance, value):
print("set")
def __delete__(self, instance):
print("delete")
class Person: #主类
age = Age()
p = Person()
p.age = 10
# 创建一个描述器的类,它的实例就是一个描述器
# 这个类要有__get__ __set__ 这样的方法
# 这种类是当做工具使用的,不单独使用
class M:
def __init__(self, x=1):
self.x = x
def __get__(self, instance, owner):
return self.x
def __set__(self, instance, value):
self.x = value
# 调用描述器的类
class AA:
m = M() # m就是一个描述器
aa = AA()
aa.m # 1
aa.m = 2
aa.m # 2
注意:不能通过Person类调用age属性,只能通过Person类定义的对象来调用age属性。
Person、Age必须全是经典类。
被操作属性值的存储问题:描述器定义方式二中有描述器类和主类两个类,当操作由主类产生的两个实例对象的同一个属性时,这个属性要被赋予不同的值,即两个实例赋值互不影响,这就要研究属性值的存储问题。由于操作的时同一个属性,所以进入的是同一个描述器类,如果将值存储在描述器类产生的实例上,由于存储地址相同,后面的赋值会覆盖前面的赋值;而主类产生的两个实例对象不同,分配了不同内存,因此,应将属性值存储在主类的实例中
__new__
方法__init__
方法__del__
方法python内部使用引用计数,来保持追踪内存中的对象。记录Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被当作垃圾回收。系统会去检查那些引用计数为0的对象,然后清除其在内存的空间。当内存中有不再使用的部分时,垃圾收集器就会把他们清理掉。
总结一下对象会在一下情况下引用计数加1:
引用计数减少情况
class Person:
pass
p1 = Person() #计数器+1
print(sys.getrefcount(p1)) #这里输出的是2
p2 = p1 #计数器+1 这个过程将p2指向Person()的内存
del p2 #计数器-1
del p1 #计数器-1
查看引用计数,需要包import sys
,sys.getrefcount(对象)
,注意:这里也引用了对象,所以计数器会增加1。
内存管理机制:当一个对象被引用,则+1;当一个对象被删除,则-1;为0时,被释放。
循环引用:
import objgraph
#objgraph.count()收入类名,查看垃圾回收器,跟踪对象个数
class Person:
pass
class Dog:
pass
p = Person()
d = Dog()
print(objgraph.count("Person"))#1
print(objgraph.count("Dog"))#1
p.pet = d
d.master = p
del p
del d
print(objgraph.count("Person"))#1
print(objgraph.count("Dog"))#1
垃圾回收机制的作用:从经历过“引用技术机制”任然未被释放的对象中找到“循环引用”,干掉相关对象。
怎样找到“循环引用”
做一个计算器,实现一些加减乘除的基本操作,然后打印操作的结果
面向过程的方法:这样的方法调用很麻烦,不断地保存变量,不断地传递变量。
def jia(n1, n2):
return n1 + n2
def jian(n1, n2):
return n1 - n2
def cheng(n1, n2):
return n1 * n2
#计算(2 + 6 - 4) + 5
r1 = jia(2, 6)
r2 = jian(r1, 4)
r3 = jia(r2, 5)
print(r3)
如 果不要不断地保存变量、不断地传递变量,就这样稿!
result = 0
def first_value(v):
global result
result = v
def jia(n):
global result
return += n
def jian(n):
global result
return -= n
def cheng(n1, n2):
global result
return *= n
#计算(2 + 6 - 4) + 5
first_value(2)
jia(5)
jian(4)
cheng(5)
print(result)
上面的代码任然不完美,下面通过类方法定义计数器!
class Calculator:
__result = 0
@classmethod
def first_value(cls, v):
cls.__result = v
@classmethod
def jia(cls, n):
cls.__result += n
@classmethod
def jian(cls, n):
cls.__result -= n
@classmethod
def cheng(cls, n):
cls.__result *= n
@classmethod
def show(self):
print("计算结果为:%d" %self.__result)
Calculator.first_value(2)
Calculator.jia(6)
Calculator.jian(4)
Calculator.cheng(5)
Calculator.show()
这样不能同时使用这个计数器同时进行多个运算,要想解决以上问题,这样做(通过实例方法):
class Calculator:
def __init__(self, num):
self.__result = num
def jia(self, n):
self.__result += n
def jian(self, n):
self.__result -= n
def cheng(self, n):
self.__result *= n
def show(self):
print("计算结果为: %d"%self.__result)
c1 = Calculator(2)
c1.jia(6)
c1.jian(4)
c1.cheng(5)
c1.show()
在上面的代码上增加一些容错处理:
class Calculator:
def __init__(self, num):
if not isinstance(num, int)
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
self.__result = num
def jia(self, n):
if not isinstance(num, int)
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
self.__result += n
def jian(self, n):
if not isinstance(num, int)
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
self.__result -= n
def cheng(self, n):
if not isinstance(num, int)
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
self.__result *= n
def show(self):
print("计算结果为: %d"%self.__result)
c1 = Calculator(2)
c1.jia(6)
c1.jian(4)
c1.cheng(5)
c1.show()
#-------------------上面代码冗余度很高!可以这样改(定义一个检查函数)-----------------------
class Calculator:
def check_num(self, num):
if not isinstance(num, int):
raise TypeError("当前这个数据类型有问题,应该是一个整型数据")
def __init__(self, num):
self.check_num(num)
self.__result = num
def jia(self, n):
self.check_num(n)
self.__result += n
def jian(self, n):
self.check_num(n)
self.__result -= n
def cheng(self, n):
self.check_num(n)
self.__result *= n
def show(self):
print("计算结果为: %d"%self.__result)
c1 = Calculator(2)
c1.jia(6)
c1.jian(4)
c1.cheng(5)
c1.show()
101、不想破坏代码的完整性?通过装饰器来给函数增加功能
class Calculator:
def check_num_zsq(func):
def inner(self, n): #这个函数的返回值要跟被修饰函数的返回值相同
if not isinstance(n, int):
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
return func(self, n) #因为这个func有返回值,所以是return(func(self, n))
@check_num_zsq
def __init__(self, num):
self.__result = num
@check_num_zsq
def jia(self, n):
self.__result += n
@check_num_zsq
def jian(self, n):
self.__result -= n
@check_num_zsq
def cheng(self, n):
self.__result *= n
def show(self):
print("计算机的结果是:%d" % self.__result)
c1 = Caculator(2)
c1.jia(6)
c1.jian("a")
c1.cheng(5)
c1.show()
为了不让外界当作函数调用所定义的装饰器,就把装饰器弄成私有方法:
class Calculator:
def __check_num_zsq(func):
def inner(self, n): #这个函数的返回值要跟被修饰函数的返回值相同
if not isinstance(n, int):
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
return func(self, n) #因为这个func有返回值,所以是return(func)
@__check_num_zsq
def __init__(self, num):
self.__result = num
@__check_num_zsq
def jia(self, n):
self.__result += n
@__check_num_zsq
def jian(self, n):
self.__result -= n
@__check_num_zsq
def cheng(self, n):
self.__result *= n
def show(self):
print("计算机的结果是:%d" % self.__result)
c1 = Caculator(2)
c1.jia(6)
c1.jian("a")
c1.cheng(5)
c1.show()
现在要求播报用户的每一个操作!开启声音的计算器!实现这种功能有好几种方案,调用Windows操作系统下面的一个接口就可以!
import win32com.client
#1.创建一个播报对象
speaker = win32com.client.Dispatch("SAPI.SpVoice")
#2.通过这个播报对象,直接播放相应的语音字符串就可以
speaker.speak("我的名字是zpc")
#-----------------------------------------#
#通过函数实现
#-----------------------------------------#
class Calculator:
def __say(self, word): #这里必须是一个实例方法
#1.创建一个播报对象
speaker = win32com.client.Dispatch("SAPI.SpVoice")
#2.通过这个播报对象,直接播放相应的语音字符串就可以
speaker.speak(word)
def __check_num_zsq(func):
def inner(self, n): #这个函数的返回值要跟被修饰函数的返回值相同
if not isinstance(n, int):
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
return func(self, n) #因为这个func有返回值,所以是return(func(self, n))
@__check_num_zsq
def __init__(self, num):
self.__say(num)
self.__result = num
@__check_num_zsq
def jia(self, n):
self.__say(n)
self.__result += n
@__check_num_zsq
def jian(self, n):
self.__say(n)
self.__result -= n
@__check_num_zsq
def cheng(self, n):
self.__say(n)
self.__result *= n
def show(self):
self.__say("计算机的结果是:%d" % self.__result)
print("计算机的结果是:%d" % self.__result)
c1 = Caculator(2)
c1.jia(6)
c1.jian("a")
c1.cheng(5)
c1.show()
不想破坏代码的结构吗?那使用装饰器好喽!
#-----------------------------------------#
#通过装饰器实现
#-----------------------------------------#
class Calculator:
def __say__zsq(func):
def inner(self, n):
#1.创建一个播报对象
speaker = win32com.client.Dispatch("SAPI.SpVoice")
#2.通过这个播报对象,直接播放相应的语音字符串就可以
speaker.speak(word)
return func(self, n)
return inner
def __check_num_zsq(func):
def inner(self, n): #这个函数的返回值要跟被修饰函数的返回值相同
if not isinstance(n, int):
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
return func(self, n) #因为这个func有返回值,所以是return(func(self, n))
@__check_num_zsq #先验证再播放
@__say_zsq
def __init__(self, num):
self.__say(num)
self.__result = num
@__check_num_zsq
@__say_zsq
def jia(self, n):
self.__say(n)
self.__result += n
@__check_num_zsq
@__say_zsq
def jian(self, n):
self.__say(n)
self.__result -= n
@__check_num_zsq
@__say_zsq
def cheng(self, n):
self.__say(n)
self.__result *= n
def show(self):
self.__say("计算机的结果是:%d" % self.__result)
print("计算机的结果是:%d" % self.__result)
c1 = Caculator(2)
c1.jia(6)
c1.jian(4)
c1.cheng(5)
c1.show()
装饰器的嵌套:
带参数的装饰器怎么定义呢?
def creat_say_zsq(word=""):
def __say_zsq(func):
def inner(self, n):
#1.创建了一个播报对象
speaker = win32com.client.client.Dispatch("SAPI.SpVoice")
#2.通过这个播报对象直接播报相应的语音字符串就可
speaker.Speak(word + str(n))
return func(self, n)
return inner
return __say_zsq
#下面分析一下这个函数,最外层creat_say_zsq是一个函数,他创建了一个装饰器,传入参数,并将装饰器返回!
def __check_num_zsq(func):
def inner(self, n): #这个函数的返回值要跟被修饰函数的返回值相同
if not isinstance(n, int):
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
return func(self, n) #因为这个func有返回值,所以是return(func(self, n))
@__check_num_zsq #先验证再播放
@creat__say_zsq
def __init__(self, num):
self.__say(num)
self.__result = num
@__check_num_zsq
@creak__say_zsq("加")
def jia(self, n):
self.__say(n)
self.__result += n
@__check_num_zsq
@@creak__say_zsq("减去")
def jian(self, n):
self.__say(n)
self.__result -= n
@__check_num_zsq
@creak__say_zsq("乘以")
def cheng(self, n):
self.__say(n)
self.__result *= n
def show(self):
self.__say("计算机的结果是:%d" % self.__result)
print("计算机的结果是:%d" % self.__result)
c1 = Caculator(2)
c1.jia(6)
c1.jian(4)
c1.cheng(5)
c1.show()
注意:show
函数不能通过上面的装饰器进心装饰,因为show
只接收一个参数,而其他的函数都接收两个参数!
要让计算器播报结果怎么办呢?
可以这样:
def show(self):
self.__say("计算机的结果是:%d" % self.__result)
#1.创建了一个播报对象
speaker = win32com.client.client.Dispatch("SAPI.SpVoice")
#2.通过这个播报对象直接播报相应的语音字符串就可
speaker.Speak("计算机的结果是:%d" % self.__result)
print("计算机的结果是:%d" % self.__result)
进一步的,如果在其他系统运行代码,就要改两处,这是麻烦的,现在进一步,可以这样操作(定义了一个播报器函数,以后调用这个函数即可,要改的话,只改这一个函数就可以了):
import win32com.client
class Caculator:
def __say(self, word):
#1.创建了一个播报对象
speaker = win32com.client.client.Dispatch("SAPI.SpVoice")
#2.通过这个播报对象直接播报相应的语音字符串就可
speaker.Speak(word
def __creat_say_zsq(word=""):
def __say_zsq(func):
def inner(self, n):
self.__say(word + str(n))
return func(self, n)
return inner
return __say_zsq
#下面分析一下这个函数,最外层creat_say_zsq是一个函数,他创建了一个装饰器,传入参数,并将装饰器返回!
def __check_num_zsq(func):
def inner(self, n): #这个函数的返回值要跟被修饰函数的返回值相同
if not isinstance(n, int):
raise TypeError("当前这个数据的类型有问题,应该是一个整形数据")
return func(self, n) #因为这个func有返回值,所以是return(func(self, n))
@__check_num_zsq #先验证再播放
@__creat__say_zsq
def __init__(self, num):
self.__say(num)
self.__result = num
@__check_num_zsq
@__creak__say_zsq("加")
def jia(self, n):
self.__say(n)
self.__result += n
@__check_num_zsq
@__creak__say_zsq("减去")
def jian(self, n):
self.__say(n)
self.__result -= n
@__check_num_zsq
@__creak__say_zsq("乘以")
def cheng(self, n):
self.__say(n)
self.__result *= n
def show(self):
self.__say("计算机的结果是:%d" % self.__result)
print("计算机的结果是:%d" % self.__result)
c1 = Caculator(2)
c1.jia(6)
c1.jian(4)
c1.cheng(5)
c1.show()
我们再加一个功能,使上面定义的类可以返回__result
,用什么方法呢?当然是描述器喽!
class Caculator:
#省略了一堆代码!
@property
def result(self):
return self.__result
c1 = Caculator(10)
c1.jia(6)
c1.jian(4)
c1.cheng(5)
c1.show
print(c1.result)
每次做运算都要写一个c1.
,这太麻烦了!有什么办法可以不写呢?
在定义的每个运算里面加一个return(self)
就可以了呀!这样的编程思路为:链式编程。
@__check_num_zsq #先验证再播放
@__creat__say_zsq
def __init__(self, num):
self.__say(num)
self.__result = num
return self
@__check_num_zsq
@__creak__say_zsq("加")
def jia(self, n):
self.__say(n)
self.__result += n
return self
@__check_num_zsq
@__creak__say_zsq("减去")
def jian(self, n):
self.__say(n)
self.__result -= n
return self
@__check_num_zsq
@__creak__say_zsq("乘以")
def cheng(self, n):
self.__say(n)
self.__result *= n
return self
def show(self):
self.__say("计算机的结果是:%d" % self.__result)
print("计算机的结果是:%d" % self.__result)
return self
#这样就可以这样运算了:
c1.Caculator(10)
c1.jia(6).jian(4).cheng(5).show()
print(c1.result)
在加一个清零的操作:
def clear(self):
self.__result = 0
result self
继承时,子类有父类的一些属性的使用权
父类也叫做:超类、基类
子类也叫做:派生类
继承的分类:单继承、多继承。
单继承:只继承了一个父类。
多继承:继承了多个父类。继承了多个类的话,就有很多父类的属性
class Animal:
pass
class xxx:
pass
class Dog(Animal, xxx):#多继承
pass
class Dog(Animal):#单继承
pass
怎么看一个类的父类:__bases__
怎么看一个实例的类:__class__
、type()
函数
在Python的世界中
object是父子关系的顶端,所有的数据类型的父类都是它;
type是类型实例关系的顶端,所有对象都是它的实例的。
先来看看type和object:
它们都是type的一个实例,表示它们都是类型对象。
type
和object
都属于type objects
。type objects翻译过来就是类型对象了。类型对象的特征:
User
会代表系统中所有的用户。int
会代表系统中所有整形数字。type
。type
Object是type的一个实例
>>> object.class
<type 'type'>
>>> object.bases # object 无父类,因为它是链条顶端。
()
#Type是object的子类
type.bases
(<type 'object'>,)
type.class # type的类型是自己
<type 'type'>
```python
>>> object
>>> type
#查看Dog的父类
print(Dog.__bases__)
print(Animal.__bases__) #输出object
#object也是一个类
设置不同权限属性的类型和方法,在继承当中进行测试,看在子类中能不能访问到这些资源。
class Animal:
a = 1
_b = 2 #受保护的属性
__c = 3 #私有属性
def t1(self):
print("t1")
def _t2(self):
print("t2")
def __t3(self):
print("t3")
def __init__(self):
print("init Animal")
class Person(Animal):
def test(self):
print(self.a)
print(self._b)
print(self.__c)#私有属性不可访问
self.t1()
self._t2()
self.__t3()#私有方法无法继承
self.__init__()
p = Person()
p.test()
#注意:这里的属性a是继承了父类的使用权,而不是又复制了一个a
class B:
age = 10
class A(B):
pass
print(A.age) #打印10
A.age = 9 #这时并没有改变B类中的age属性,而是在A中又创建了一个age属性,并赋值9
ses__`
怎么看一个实例的类:__class__
、type()
函数
在Python的世界中
object是父子关系的顶端,所有的数据类型的父类都是它;
type是类型实例关系的顶端,所有对象都是它的实例的。
先来看看type和object:
它们都是type的一个实例,表示它们都是类型对象。
type
和object
都属于type objects
。type objects翻译过来就是类型对象了。类型对象的特征:
User
会代表系统中所有的用户。int
会代表系统中所有整形数字。type
。type
Object是type的一个实例
>>> object.class
<type 'type'>
>>> object.bases # object 无父类,因为它是链条顶端。
()
#Type是object的子类
type.bases
(<type 'object'>,)
type.class # type的类型是自己
<type 'type'>
```python
>>> object
>>> type
#查看Dog的父类
print(Dog.__bases__)
print(Animal.__bases__) #输出object
#object也是一个类
设置不同权限属性的类型和方法,在继承当中进行测试,看在子类中能不能访问到这些资源。
class Animal:
a = 1
_b = 2 #受保护的属性
__c = 3 #私有属性
def t1(self):
print("t1")
def _t2(self):
print("t2")
def __t3(self):
print("t3")
def __init__(self):
print("init Animal")
class Person(Animal):
def test(self):
print(self.a)
print(self._b)
print(self.__c)#私有属性不可访问
self.t1()
self._t2()
self.__t3()#私有方法无法继承
self.__init__()
p = Person()
p.test()
#注意:这里的属性a是继承了父类的使用权,而不是又复制了一个a
class B:
age = 10
class A(B):
pass
print(A.age) #打印10
A.age = 9 #这时并没有改变B类中的age属性,而是在A中又创建了一个age属性,并赋值9