一个例子:
"""定义一个狗的类"""
country = "中国"
class Dog: # 类具有数据属性和函数属性
"""狗的类"""
name = "dog"
country = "China"
l = [1,2,3]
def __init__(self,name,sex,age):
print(country)
self.name = name
self.sex = sex
self.age = age
def run(self):
print("%s runing" % self.name)
def call(self):
print("%s calling" % self.name)
dog = Dog("PIZZA","g","5") # 实例只有数据属性,调用函数属性时现在def __init__(self)中找,没有再去上一层(class Dog)找
dog.call() #PIZZA calling
print(dog.__dict__) #{'name': 'PIZZA', 'sex': 'g', 'age': '5'}
print("="*20)
# 增加类属性
print(Dog.name)
Dog.lan = "汪"
print(Dog.lan)
# 删除类属性
del Dog.lan
print(Dog.__dict__)
# 向类中增加一个方法
def cry(self):
print("%s is crying" % self.name)
Dog.cry = cry
dog.cry() # PIZZA is crying
dog.l.append(4) # 这里改的是类的属性 dog.l = ["a","b"] ,这样改的是实例的属性,这是为实例新加一个属性
print(dog.l)
0. 静态属性,静态类,静态方法
静态属性
@property:封装逻辑,将一个有返回值的函数属性变成一个数据属性,可以直接调用执行而不用加小括号
@property
def cal_v(self):
print("The %s is %s m" % (self.name,self.length * self.width * self.high))
使用@property
我们可以在类中定义一个方法,在实例中将它当成属性来用,用@property实现
例:
"""
请利用@property 给一个 Screen 对象加上 width 和 height 属性,以及一个
只读属性 resolution:
# -*- coding: utf-8 -*-
class Screen(object):
----
pass
----
# test:
s = Screen()
s.width = 1024
s.height = 768
print(s.resolution)
assert s.resolution == 786432, '1024 * 768 = %d ?' % s.resolution
"""
#!/urs/bin/env python3
# -*- coding: utf-8 -*-
class Screen(object):
@property # 把getter定义为属性,获取这个属性
def width(self):
"""h获取属性"""
return self.__width
@width.setter # 对这个属性进行设置
def width(self,val):
"""设置属性"""
if not isinstance(val,int):
raise ValueError("it's not a digit")
elif 0>val or val>100:
raise ValueError("Range Error(0-100)")
self.__width = val
@property
def height(self):
return self.__height
@height.setter
def height(self,val):
if not isinstance(val,int):
raise ValueError("It's not a digit")
elif 0>val or val>100:
raise ValueError("Range Error(0-100)")
self.__height = val
@property
def resolution(self):
"""只读属性,因为可以通过上面两个属性计算得到,不需设置"""
return self.__height + self.__width
screen = Screen()
screen.width = 89
screen.height = 100
print(screen.width,screen.height)
print(screen.resolution)
"""
D:\python37\python.exe E:/资源/python/DOME.C/LIAOXUEFENG2/property.py
89 100
189
Process finished with exit code 0
"""
@property可以很大程度的简化代码,像上面的例子如果没使用这个
那么类中的方法就要写成
def get_width(self):
return self.__width
def set_width(self,val):
....ship...
self.__width = val
向实例中添加width属性就要这样写:
screen = Screen()
screen.set_width(60)
screen.get_width()
>>>60
相比较而言使用@property后的代码,变得更加简洁
class Lazypro:
def __init__(self,func):
self.func = func # func就是are
def __get__(self, instance, owner):
print("触发__get__")
if instance == None:
return self
sel = self.func(instance)
setattr(instance,self.func.__name__,sel)
return sel
class Hourse:
def __init__(self,length,width):
self.length = length
self.width = width
# @property #are = property(are),使被调用的函数直接被执行而不加小括号
@Lazypro
def are(self):
return self.length * self.width
h = Hourse(1,2)
#用实例调用静态方法
# print(h.are)
# 用类也可以调用,但类调用时传入的参数是None
# print(Hourse.are) # 报错,因为instance为None
"""
Traceback (most recent call last):
File "E:/python/DOME.C/s3_28/利用描述符自定制property.py", line 19, in <module>
print(Hourse.are)
File "E:/python/DOME.C/s3_28/利用描述符自定制property.py", line 5, in __get__
return self.func(instance)
File "E:/python/DOME.C/s3_28/利用描述符自定制property.py", line 13, in are
return self.length * self.width
AttributeError: 'NoneType' object has no attribute 'length'
"""
#那么系统自带的property是怎么做的呢,它返回一个对象<property object at 0x000001D92BE24D68>
# print(Hourse.are) # 再使用类调用静态属性就不会报错,而是返回一个对象<__main__.Lazypro object at 0x0000023764BA5080>
# 但是每次调用都要进行一次计算,如果计算重复且计算量很大,就有必要将第一次的计算结果存起来
print(h.are) # 只有这次调用会触发__get__,但要注意优先级
print(h.are)
print(h.are)
property补充:静态属性不能被设置和删除,解决方法如下
# 写法一
# class Good:
# def __init__(self,name,price,many):
# self.name = name
# self.price = price
# self.many = many
# @property
# def pay_money(self):
# return self.price * self.many
# @pay_money.setter
# def pay_money(self,s):
# print("触发setter",s)
# @pay_money.deleter
# def pay_money(self):
# print("触发delter")
#
# g = Good("name",10,10)
# g.pay_money = 10
# del g.pay_money
#写法二
class Good:
def __init__(self,name,price,many):
self.name = name
self.price = price
self.many = many
def get_pay_money(self):
print("触发get")
return self.price * self.many
def set_pay_money(self,s):
print("触发set",s) # s = 10
def del_pay_money(self):
print("触发del")
pay_money = property(get_pay_money,set_pay_money,del_pay_money)
g = Good("name",10,10)
print(g.pay_money)
g.pay_money = 10 # 传入参数用'='
del g.pay_money
静态类
@classmethod:当类调用方法时需要传入一个实例,而这样封装就不需要,因为这是专门为类提供的方法
它会自动出传入一个类。
@classmethod
def house_test(cls): # cls就是自动传入的类,cls.(类属性)这能这样调用
pass
静态方法
@staticmethod:类的工具包,不需要传递类或者实例,也不能调用类和实例的属性。类和实例都能调用
@staticmethod
def s_test(x,y):
print(x,y)
1.面向对象
"""
面向对象编程——Object Oriented Programming,简称 OOP,是一种程
序设计思想。 OOP 把对象作为程序的基本单元,一个对象包含了数据和
操作数据的函数。
面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数
的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,
即把大块函数通过切割成小块函数来降低系统的复杂度。
而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象
都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执
行就是一系列消息在各个对象之间传递。
"""
举例:
class Dog:
def __init__(self,name):
self.name = name
2.类和实例:
面向对象的编程中最重要的就是‘类’和‘实例’
类是一个对象的模板,实例就是根据模板创建出的对象
下面创建一个学生成绩的类:
class Student():
def __init__(self,name,score):
self.name = name
self.score = score
def show_score(self):
print('%s的成绩是:%s分' % (self.name,self.score))
st1 = Student('Bob',98)
st2 = Student('liny',100)
st1.show_score()
st2.show_score()
输出结果是:
"""
D:\python37\python.exe E:/资源/python/DOME.C/LIAOXUEFENG2/student_lei.py
Bob的成绩是:98分
liny的成绩是:100分
Process finished with exit code 0
"""
3.访问限制
上面的学生成绩例子中,创建好的实例参数已经传入,但是之后还可以对参数进行任意修改
如果想让参数变得不可修改,可以在参数前面加上'__'双下划线
但是解释器只是把它在类外的调用改成了别的名字,并没有真正的限制访问,python没有这种机制
例:
>>> class S():
def __init__(self,name,score):
self.__name = name
self.__score = score
def show_sc(self):
print("%s,%s" % (self.__name,self.__score))
>>> st1 = S('bob',98) #创建一个实例
>>> st1.show_sc() #使用实例的方法
bob,98
>>> st1.__name = 'lis' #为实例创建一个数据属性
>>> st1.__name
'lis'
>>> st1.show_sc()
bob,98
>>>
4.类的三大:继承、多态和封装
继承:
在编写类的时候我们会在第一行这样写:
class Student(object):
括号中的object就是Student类继承的类,继承与被继承是子类与父类的关系
子类拥有父类全部的属性和方法,父类也叫超类,子类要想继承父类的属性,
需要调用父类的__init__方法
supper().__init__(name,score)
多态是子类继承于父类的方法可以在子类中修改,而调用该方法时调用子类中修改后的方法
下面创建一个学生成绩的类:
class Student():
def __init__(self,name,score):
self.name = name
self.score = score
def show(self):
print("name:%s score:%s)" % (self.name,self.score))
我们再创建一个男学生类,继承学生类:
class Men_st(Student):
def __init__(self,name,score):
super().__init__(name,score)
def men_show(self):
"""输出这个学生的性别"""
print('%s is a boy' % self.name)
st1 = Men_st('Bob',29)
st1.show()
st1.men_show()
"""
输出为:
name:Bob score:29
Bob is a boy
"""
下面我们对学生类中的show()函数在男学生类中做修改:
class Men_st(Student):
def __init__(self, name, score):
super().__init__(name, score)
def show(self):
print("score:%s name:%s" % (self.score,self.name))
def men_show(self):
"""输出这个学生的性别"""
print('%s is a boy' % self.name)
st1 = Men_st('Bob',29)
st1.show()
st1.men_show()
"""
输出为:
score:29 name:Bob
Bob is a boy
"""
当子类和父类中都有同一个方法时,子类中的方法会覆盖父类中的方法
每次调用该方法时都是调用子类中的
接口类、抽象类
接口是一组功能的入口,要调用某一组功能,需要通过接口来进行调用,
而不需要关注这组功能是如何实现的,要的只是结果。在类里,接口是提取了一群类共同的函数,
可以把接口当做一个函数的集合。
抽象类定义的方法,继承它的子类必须全部实现,接口类使用抽象实现归一思想
import abc
class Animal(metaclass=abc.ABCMeta): # 定义基类(抽象类),抽象类不能产生实例
@abc.abstractmethod # 抽象这个方法
def read(self): # 定义接口
pass
@abc.abstractmethod
def write(self): # 定义接口
pass
class Med(Animal):
def read(self):
print("Med_read")
def write(self):
print("Med_write")
class Disk(Animal):
def read(self):
print("disk_read")
med = Med()
disk = Disk() # 因为这个类中缺少write方法,所以运行会报错
报错:
Traceback (most recent call last):
File "E:/python/DOME.C/s3_25/接口继承.py", line 19, in <module>
disk = Disk()
TypeError: Can't instantiate abstract class Disk with abstract methods write
继承顺序:发生继承是会创建mro列表,里面就保存着继承顺序 f.__mro__
在新式类(python3都是新式类,继承object,但不必写出来)上采用广度优先,
在经典类(python2默认经典类,不继承object)上采用深度优先
多态:
多态只是继承的一种体现方式,对于源于同一子类的不同实例,要使用该子类父类的相同方法,
这一动作表现为多态
封装:
5.获取对象信息
想要获取一个对象的类型可以使用type()
>>> type(int)
<class 'type'>
>>> type('1234')
<class 'str'>
>>> type(1234)
<class 'int'>
>>> type([1,2,3])
<class 'list'>
>>>
想要判断是否是继承或者包含关系可以使用isinstance()
TypeError: isinstance() arg 2 must be a type or tuple of types
某一变量是否属于某一类型
>>> isinstance(1,int)
True
某一实例是否属于某一类(子类/父类)
print(isinstance(st1,Student))
结果为:True
想要知道一个对象的所有属性和方法使用dir()
>>> dir(abs)
['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__le__',
'__lt__', '__module__', '__name__', '__ne__', '__new__',
'__qualname__', '__reduce__', '__reduce_ex__', '__repr__',
'__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'__text_signature__']
想要知道一个属性或者方法是否在对象内使用hasattr()
>>> class Student():
def __init__(self,name,score):
self.name = name
self.score = score
def show(self):
print('%s %s' % (self.name,self.score))
>>> st = Student('Bob',100)
>>> st.show()
Bob 100
>>> st.name
'Bob'
>>> st.score
100
>>> hasattr(st,'name')
True
>>> hasattr(st,show) # 属性和方法都需要加小括号,否则会报错NameError
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
hasattr(st,show)
NameError: name 'show' is not defined
>>> hasattr(st,'show')
True
如果想获取对象中的变量和方法可以使用getattr()
>>> st_name = getattr(st,'name')
>>> st_name
'Bob'
>>> st_score = getattr(st,'score')
>>> st_score
100
>>> st_show = getattr(st,'show')
>>> st_show
<bound method Student.show of <__main__.Student object at 0x0000014FA19ACFD0>>
>>> st_show()
Bob 100
如果想设置一个属性可以使用estattr()
>>> setattr(st,'grade',6)
>>> st.grade # 添加一个属性
6
>>> setattr(st,'score',89)
>>> st.score # 对原有属性进行修改
89
6.类属性和实例属性
实例属性是通过实例变量或者self变量绑定的属性
类属性是在定义实例属性之前定义的,并且是公开的,但如果实例属性
和类属性同名,实例属性会屏蔽掉类属性,比方说我们先定义了一个类属性
通过实例也可以调用它,但接着我们又定义了一个和它同名的实例属性
再通过实例调用这个属性就只会调用实例属性,但通过类属性还是可以调用它
例:
>>> class Std():
name = 'shcool'
def __init__(self,score):
self.score = score
>>> st = Std(100)
>>> st.name
'shcool'
>>> setattr(st,'name','Bob')
>>> st.name
'Bob'
>>> del st.name # 删除实例属性
>>> st.name
'shcool' # 删除实例属性后,再次调用name属性,调用的就是类属性
7.组合
将没有共同点的两个类关联起来
8.反射/自省
主要指程序可以访问、检测和修改它本身状态或行为的
一种能力(自省)
举例:
class BlackMe:
def __init__(self,name,addr):
self.name = name
self.addr = addr
def sell_house(self):
print("%s 正在卖房子" % self.name)
obj1 = BlackMe("置业",'碧桂园')
# python提供的四个反射方法
# 1 hasattr, 检测属性是否存在,返回True/False
print(hasattr(obj1,"name")) #True
print(hasattr(obj1,"save")) #False
# 2 getattr, 获取该属性,存在返回属性值,不存在报错,或者指定返回值
print(getattr(obj1,"name")) #置业
# print(getattr(obj1,"save")) #报错,AttributeError: 'BlackMe' object has no attribute 'save'
print(getattr(obj1,"save","属性不存在")) #属性不存在
# 3 setattr ,为对象添加或者修改一个属性
# print(obj1.__dict__) # {'name': '置业', 'addr': '碧桂园'}
setattr(obj1,"sb","123")
# print(obj1.__dict__) # {'name': '置业', 'addr': '碧桂园', 'sb': '123'}
# 4 delattr
print(obj1.__dict__) # {'name': '置业', 'addr': '碧桂园', 'sb': '123'}
delattr(obj1,"sb")
print(obj1.__dict__) # {'name': '置业', 'addr': '碧桂园'}
9.动态导入模块
# 动态导入模块,将模块中的函数赋值给一个变量两种方法
# 1 __import__
m = __import__("m1.t")
print(m) # <module 'm1' (namespace)> 不管调用的是第多少层的模块,返回的总是最顶级模块
m.t.test1() # test1
m.t.test2() #test2
# 2 import importlib
import importlib
m = importlib.import_module("m1.t") # 返回的就是调用的模块
print(m) #<module 'm1.t' from 'E:\\python\\DOME.C\\s3_26\\m1\\t.py'>
m.test1() #test1
m.test2() #test2
10.__getattr__ __setattr__ __delattr__ 针对实例的内置方法 使用'.'操作属性时会触发
同样的还有__getitem__ __setitem__ __delitem__ 使用'[]'操作属性时会触发
举例:
# class BlackMe:
# def __init__(self,name,addr):
# self.name = name
# self.addr = addr
# # def __getattr__(self, item):
# # print("__getattr__正在执行")
# def __setattr__(self, key, value):
# print("__setattr__正在执行")
#
# s = BlackMe("dv","akduvg")
# # 1 __getattr__
# # print(s.iwbvi) # __getattr__正在执行 ,调用不存在的属性时会触发
# s.save = "sb"
# print(s.save) # AttributeError: 'BlackMe' object has no attribute 'save'
# class BlackMe:
# def __init__(self,name,addr):
# self.name = name
# self.addr = addr
# # def __getattr__(self, item):
# # print("__getattr__正在执行")
# def __setattr__(self, key, value):
# print("__setattr__正在执行")
# self.__dict__[key] = value
#
# s = BlackMe("dv","akduvg")
# # 1 __getattr__
# # print(s.iwbvi) # __getattr__正在执行 ,调用不存在的属性时会触发
# s.save = "sb"
# print(s.save) # sb
# class BlackMe:
# s = 1
# def __init__(self,name,addr):
# self.name = name
# self.addr = addr
# # def __getattr__(self, item):
# # print("__getattr__正在执行")
# def __delattr__(self, item):
# print("__delattr__正在执行")
#
# print(BlackMe.__dict__)
# del BlackMe.s
# print(BlackMe.__dict__)
class BlackMe:
def __init__(self,name,addr):
self.name = name
self.addr = addr
# def __getattr__(self, item):
# print("__getattr__正在执行")
def __getattr__(self, item):
print("__getattr__正在执行")
s = BlackMe("ssfb","veb")
print(s.name) #ssfb
print(s.sssss) #__getattr__正在执行 属性不存在时才会触发
11.__str__ __repr__:修改实例的返回值
举例:
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return "%s 的年龄是 %s" % (self.name,self.age)
f = Foo("alxe",10)
print(f) #alxe 的年龄是 10,__str__可以指定实例的返回
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return "%s 的年龄是 %s" % (self.name,self.age)
def __repr__(self):
return "%s 的 %s" % (self.name, self.age)
f = Foo("alxe",10)
print(f) #alxe 的年龄是 10,__repr__可以指定实例的返回,会先寻找__str__,没有时会找到__repr__执行
12.__format__
举例:
# s = "{0}-{1}-{2}".format("2019","8","6")
# print(s) #2019-8-6
date_dic = {
"ymd":'{0.year}{0.mon}{0.day}',
"mdy":'{0.mon}:{0.day}:{0.year}',
"y-m-d":'{0.year}-{0.mon}-{0.day}'
}
class Foo:
def __init__(self,year,mon,day):
self.year = year
self.mon = mon
self.day = day
def __format__(self, format_spec):
print(format_spec)
return date_dic[format_spec].format(self)
s =Foo(2019,8,6)
print(format(s,"y-m-d"))
print('=========','{0.year}{0.mon}{0.day}'.format(s))