面向对象基本特征
1.类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
2.类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
3.数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
4.方法重载:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重载。
5.实例变量:定义在方法中的变量,只作用于当前实例的类。
6.继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
7.实例化:创建一个类的实例,类的具体对象。
8.方法:类中定义的函数。
9.对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
创建类
class Employee:
'所有员工的基类'
empCount = 0 #类变量,公开变量,它的值将在这个类的所有实例间共享,可供内外部类调用
__secretCount = 1 #私有变量,以__开头,只能在类的内部调用,外部调用会报错
def __init__(self,name,salary):#构造函数,创建了这个类的实例是就会调用该方法
self.name = name
self.salary = salary
self.__secretCount += 1 #内部调私有属性需要用self
Employee.empCount += 1
def displayCount(self):
print('员工总数',Employee.empCount)
def displayEmployee(self):
print('姓名:',self.name,',薪资:',self.salary)
def __secretMethod(self):#私有方法,以__开头,只能在类的内部调用,需要self
print('我是私有方法')
内置类属性
print(Employee.__doc__) #类的说明
print(Employee.__name__) #类名
print(Employee.__module__) #类定义所在模块
print(Employee.__bases__) #类的所有父类构成元素
print(Employee.__dict__) #类的属性
创建类的实例对象
emp1 = Employee('star',3000)
#访问属性
emp1.displayCount()
emp1.displayEmployee()
#添加/修改/删除属性
emp1.age = 24
emp1.sex = '男'
emp1.salary = '5000'
del emp1.sex
'''
私有变量和方法只能在内部调用
print(emp1.__secretCount)
emp1.__secretMethod()
'''
'''
也可以用下面的方法
hasattr(emp1, 'age') # 如果存在 'age' 属性返回 True。
getattr(emp1, 'age') # 返回 'age' 属性的值
setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
delattr(empl, 'age') # 删除属性 'age'
'''
类的继承
在python中继承中的一些特点:
在继承中基类的构造(init()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
class Parent: #父类
parentAttr = 100
def __init__(self):
print("调用父类构造函数")
def parentMethod(self):
print("调用父类方法")
def setAttr(self,attr):
Parent.parentAttr = attr
def getAttr(self):
print("父类属性:",Parent.parentAttr)
class Child(Parent,Employee): #定义子类,可以继承多个类
def __init__(self):
print('调用子类构造方法')
def childMethod(self):
print("调用子类方法")
#创建实例
c = Child()
c.childMethod()
c.parentMethod()
c.setAttr(200)
c.getAttr()
c.displayCount()
#继承关系判断
print(issubclass(Child,Parent)) #判断一个类是另一个类的子类或子孙类
print(isinstance(c,Child)) #判断一个对象是另一个类的实例对象
销毁对象、垃圾回收
Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。作为引用计数的补充, 垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。 在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环。
class Point:
def __init(self, x = 0, y = 0):
self.x = x
self.y = y
def __del__(self):#析构函数,当对象不再被使用时运行
class_name = self.__class__.__name__
print(class_name,"destroyed")
pt1 = Point()
pt2 = pt1
pt3 = pt1
print(id(pt1),id(pt2),id(pt3))
del pt1
del pt2
del pt3
#类,创建对象的模板
class MyClass():
pass
#创建一个类的实例
mc = MyClass()
print(mc,type(mc))
#isinstance()检查一个对象是否是一个类的实例
result = isinstance(mc,MyClass)
print(result)
#向对象中添加变量,对象.属性名 = 属性值
mc.name = "晓红"
print(mc.name)
#类和对象都是现实生活中事物或者程序中内容的抽象
#类中可以定义公共的变量(属性)和函数(方法),每一个由类创建的实例都可以去调用,属性和方法一般都是多个对象所共有的特性
#与普通函数调用不同的是实例调用类的方法会默认传递一个参数,所以在创建类的方法时至少设置一个形参,这个形参就是调用方法的对象本身
#封装类
class Person:
#公共属性
eat:'foods'
#对象的初始化方法(魔术方法),每次实例化对象时都会调用,给每一个对象添加自己的专用属性
def __init__(self,name,age):
#为防止别人随意篡改属性,在这儿设置属性名的时候,以_(单下划线)开头表示私有属性,以__(双下划线)开头表示隐藏属性
self._name = name
self._age = age
#获取属性getter方法
def get_name(self):
return self._name
#设置属性setter方法
def set_name(self,name):
self._name = name
#使用@property装饰器,可以将get方法转化为对象的属性,方法名必须和属性名保持一致
@property
def age(self):
return self._age
#使用@属性名.setter装饰器,可以将set方法转化为对象的属性
@age.setter
def age(self,age):
self._age = age
#其他方法
def say_love(self):
print("I Love %s" %self._name)
#实例化对象
p1 = Person('晓红',24)
p2 = Person('星星',25)
#方法调用获取修改
print(p1.get_name())
print(p2.get_name())
p1.set_name('逸轩')
p2.set_name('逸筱')
#装饰器调用获取修改
print(p1.age)
print(p2.age)
p1.age = 18
p2.age = 20
#调用其他公共方法
p1.say_love()
p2.say_love()
#继承
#父类
class Animal:
#父类属性
def __init__(self,name):
self._name = name
#父类方法
def run(self):
print('我会跑~~~')
def sleep(self):
print('我要睡觉~~~')
#子类继承父类,可直接使用父类的属性和方法
class Dog(Animal):
#子类自己的属性
def __init__(self,name,age):
#super()可以用来获取当前类的父类,并且通过super()返回对象调用父类方法,里面可以不用写self
super().__init__(name)
self._age = age
#子类自己的方法-
def eat(self):
print('我要吃饭~~~')
@property
def age(self):
return self._age
@age.setter
def age(self,age):
self._age = age
#实例化对象
d = Dog('哈士奇',18)
d.run()
d.sleep()
d.eat()
print(d.age)
d.age = 20
print(d.age)
#__bases__属性用于获取当前类的所有父类,以元组的形式展示
print(Dog.__bases__)
#多重继承
class A:
def test(self):
print('A中的测试方法')
class B:
def test(self):
print('B中的测试方法')
def copy(self):
print('B中的复制方法')
#继承多个父类
class C(A,B):
pass
c = C()
#如果调用的方法在多个父类中都存在,谁先被继承就先用谁的方法
c.test()
c.copy()
#多态:可以对不同类的对象使用同样的从操作
class P1:
def __init__(self,name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class P2:
def __init__(self,name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
def say_hello(obj):
#不会去考虑类的问题,只要对象有name属性就可以用这个方法
print('你好%s'%obj.name)
p1 = P1('晓红')
p2 = P1('星星')
say_hello(p1)
say_hello(p2)
'''
面向对象的三大特征:
封装:
确保对象中数据的安全性
继承:
确保对象的可扩展性
多态:
保证对象的灵活性
'''
'''
类中的方法与属性:
类属性:公共属性,所有的实例均可以去调用
实例属性:只有实例能够访问和修改,其他属性和方法都可以通过实例和类去访问与修改
类方法:通过装饰器@classmethod去创建,需要传入cls参数,即当前类
实例方法:需要传入self参数,即调用的实例
静态方法:通过装饰器@staticmethod去创建,不需要参数,相当于讲一个普通函数放到了类中,无实际意义,只是调用的区别
'''
class A:
attr = '我是类属性'
def __init__(self):
self.name = '我是实例属性'
@classmethod
def test(cls):
print('我是类方法')
def test1(self):
print('我是实例方法')
@staticmethod
def test2():
print('我是静态方法')
a = A()
print(A.attr)
print(a.attr)
A.test()
a.test()
print(a.name)
#print(A.name)
A.test1(a)
a.test1()
A.test2()
a.test2()
#垃圾回收
#垃圾:python中未被引用的对象就是垃圾
#python中有垃圾自动回收机制,它会将没有被引用的对象删除,不用手动去清除
#程序结束,所有对象将被回收
class C:
def __init__(self):
self.name = '我被引用了'
#内置特殊方法,垃圾回收前被执行
def __del__(self):
print('垃圾回收前执行')
c = C()
print(c.name)
c = None
input('按回车结束程序~~~')
#特殊方法,在特定的时候调用
class D:
#限制实例的属性,只允许实例添加age和name属性
__slots__ = ('name','age')
#对象创建完成的时候调用
def __init__(self,name,age):
self.name = name
self.age = age
#print()打印的时候调用
def __str__(self):
return '可以打印我们自定义的数据格式'
#交互模式中直接输出的效果
def __repr__(self):
return '指定交互模式中直接输出什么'
#__len__()获取长度
#对两个实例进行大小的比较
def __gt__(self,other):#两个参数分别表示两个对象
return self.age > other.age
#通过调用对象来调用实例方法
def __call__(self):
print('%s 爱你'%self.name)
d1 = D('晓红',24)
d2 = D('星星',25)
#d1.sex = '女'
print(d1)#相当于print(str(d1))
print(d2)
print(repr(d1))
print(repr(d2))
print(d1 > d2)
d1()
#callable()函数,判断一个对象是否是“可调用”对象
print(callable(d1))
class E:
def __init__(self,path='http://www.abc.com'):
self.path = path
#对于未定义的属性动态返回一个属性
def __getattr__(self,path):
#模仿地址栏动态拼接
return E('%s/%s'%(self.path,path))
#输出地址栏
def __str__(self):
return self.path
print(E().abc.cab.bac)
#给类动态添加方法
def getName(self):
return self.name
D.getName = getName
print(d1.getName())
#类的特殊方法使实例仿列表一样去实现某些功能
class Fib():
def __init__(self):
self.a,self.b = 0,1
#实现for...in循环
def __iter__(self):
return self
#迭代对象
def __next__(self):
self.a,self.b = self.b,self.a + self.b
if self.a > 100:
#退出循环
raise StopIteration()
return self.a
#实现按照下标取出元素
def __getitem__(self,n):
#判断传进来的n是索引还是切片处理
if isinstance(n,int):
#range用于循环指定次数
for x in range(n):
self.a,self.b = self.b,self.a + self.b
return self.a
if isinstance(n,slice):
start = n.start
stop = n.stop
if start is None:
start = 0
l = []
for x in range(stop):
if x >= start:
l.append(self.a)
self.a,self.b = self.b,self.a + self.b
return l
for s in Fib():
print(s)
print(Fib()[5])
print(Fib()[:3])
print(Fib()[0:1])
#使用枚举类定义常量
from enum import Enum,unique
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
#更精确的控制枚举类型
@unique #检查保证没有重复值
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
print(Weekday.Sun)
#获得枚举常量
print(Weekday.Sun.value)
#一个实例的类型是class类,而一个类的类型就是type
#class的定义是运行时动态创建的,而创建class的方法就是使用type()函数
#type()既可以查看对象的类型,又可以创建出一个新的类型
def fn(self,name='晓红'):
print('你好%s'%name)
Hello = type('Hello',(object,),dict(hello = fn))
'''
type有三个参数:
类名
继承的父类集合
class方法名称与函数绑定
'''
h = Hello()
h.hello()
#元类metaclass
'''
class A:#定义类
pass
a = A()#创建实例的同时创建类
先定义类,然后创建实例
使用metaclass可以实现先创建类,也可以修改类
先定义metaclass,创建类,最后创建实例
'''
#metaclass是类的模板,所以必须从type类型派生
#metaclass的类名总是以Metaclass结尾
#通过metaclass给自定义的MyList增加一个add方法
class ListMetaclass(type):
def __new__(cls,name,bases,attrs):
'''
__new__()方法四个参数的含义:
1.当前准备创建的类的对象
2.类的名字
3.类继承的父类集合
4.类的方法集合
'''
attrs['add'] = lambda self, value:self.append(value)
return type.__new__(cls,name,bases,attrs)
#定义类
#传入了关键字参数,metaclass时,它指示Python解释器在创建MyList时,要通过listMetaclass.__new__()来创建
class MyList(list,metaclass = ListMetaclass):
pass
L = MyList()
L.add(2)
L.add(3)
print(L)
'''
ORM框架
ORM,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表。所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来
'''
#Field类,用于保存数据库表的字段名和字段类型:
class Field(object):
def __init__(self,name,column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '<%s:%s>'%(self.__class__.__name__,self.name)
#StringField
class StringField(Field):
def __init__(self,name):
#super用于获取当前类
super(StringField,self).__init__(name,'varchar(100)')
#IntegerField
class IntegerField(Field):
def __init__(self,name):
super(IntegerField,self).__init__(name,'star')
#定义元类
class ModelMetaclass(type):
def __new__(cls,name,bases,attrs):
#禁止对Model类修改
if name == 'Model':
return type.__new__(cls,name,bases,attrs)
print('Found model:%s'%name)
#创建字典,用于存放关系映射
mappings = dict()
for k,v in attrs.items():
if isinstance(v,Field):
print('Found mapping:%s ==> %s'%(k,v))
mappings[k] = v
#将之前已经保存的从attrs中删除,防止循环赋值
for k in mappings.keys():
attrs.pop(k)
attrs['__mappings__'] = mappings #保存属性和列的映射关系
attrs['__table__'] = name #假设表明和类名一致
#有了表和映射关系之后就可以对数据进行相关处理
return type.__new__(cls,name,bases,attrs)
#Model
class Model(dict,metaclass=ModelMetaclass):
def __init__(self,**kw):
super(Model,self).__init__(**kw)
def __getattr__(self,key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Model' object has no attribute '%s'" %key)
def __setattr__(self,key,value):
self[key] = value
def save(self):
fields = []
params = []
args = []
for k,v in self.__mappings__.items():
fields.append(v.name)
params.append("?")
args.append(getattr(self,k,None))
sql = 'insert into %s (%s) values (%s)'%(self.__table__,','.join(fields),','.join(params))
print('SQL:%s'%sql)
print('ARGS:%s'%str(args))
#使用者使用
class User(Model):
#定义类的属性到列的映射
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
#创建一个实例
u = User(id=12,name='star',email='aaa@cic.com',password='k123')
#保存到数据库
u.save()