面向过程和面向对象
面向过程
- 把完成一个需求的所有步骤从头到尾逐步实现
- 根据开发需求,将某些功夫独立的代码封装成一个又一个函数
- 最后完成的代码,就是顺序地调用不同地函数
面向对象
- 面向对象编程关注点在于谁来做
- 在完成需求时,首先确定职责
- 根据职责确定不同对象,在对象内部封装不同的方法
- 最后完成代码,就是顺序调用不同对象的相应方法
面向对象的语法
定义类:使用class
class类名:类名一般遵守大驼峰命名法,每一个单词首字母都大写
1.class <类名>
2.class <类名>(object)
class Student(object):
def __init__(self,name,height):
#在__init__方法里,以参数形式定义特征,我们称之为属性
self.name=name
self.height=height
def run(self):
print('正在跑步')
def eat(self):
print('正在吃东西')
#Student()====>会自动调用__init__方法
#s1和s2都有name,height属性,同时都有run和eat方法
s1=Student('小明',1.75)
#Student(’小明‘,1.75)具体的操作:
#1.调用__new__申请一份内存空间
#2.调用__init__,并让self指向申请的那段内存空间
#3.让s1也指向开辟的内存空间
s2=Student('小美丽',1.65)
#根据业务逻辑,让不同的对象执行不同的行为
s1.run()
s1.eat()
s2.eat()
python的动态属性
#print(s1.city)会报错,但是创建添加并赋值就不会报错
s1.city='beijing'
print(s1.city)
改变动态属性的方法:slots
class Student(object):
__slots__ = ('name','height')
def __init__(self, name, height):
# 在__init__方法里,以参数形式定义特征,我们称之为属性
self.name = name
self.height = height
s1=Student('小明',1.75)
print(s1.name)
s1.city='beijing'#此时这排报错
print(s1.city)
魔法方阵
魔法方法,也叫魔术方法,是在内里的特殊的一些方法
特点
1.不需要手动调用,会在合适的时机自动调用
2.这些方法,都是从_开始,使用 下划线结束
3.方法名都是系统规定好的,在合适的时机自己调用
class Person(object):
def __init__(self,name,age):
print("init调用了")
self.name=name
self.age=age
def __del__(selfs):
#当对象被销毁时,会自动调用这个方法
print('__del__方法被调用了')
def __repr__(self):
return 'hello'
def __call__(self,*args,**kwargs):
print('')
p=Person('zhangsan',18)
#我们虽然没有销毁p,但是程序结束会自动销毁
#如果不做任何修改,直接打印一个对象,是文件的__name.类型 内存地址
print(p)
#当打印一个对象的时候,会调用这个对象的__str__或者__repr__方法
print(p)
#魔法方法一般自动调用,但也可以手动
print(p.__repr__())
p()#对象名()=====>调用这个对象的__call__方法
#如果类中没有call就会报错,有就不报错
#()中还可以写参数
p(1,2,3,4,m='good',n='hehehe',p='heiheihei')
其他魔法方法
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
p1=Person('zhangsan',18)
p2=Person('zhangsan',18)
#p1,p2不是同一个内存空间,只是数据相同
print('0x%x'%id(p1))
print('0x%x'%id(p2))
#is 身份运算符,可以判断两个对象是否为同一个对象
print(p1 is p2)
print(p1==p2)
nums1=[1,2,3]
nums2=[1,2,3]
#is 是比较内存地址 ==是比较值
#== 是调用对象的__eq__方法,获取这个方法的比较结果
print(nums1 is nums2)#False
print(nums1==nums2)#True
有关上面p1等于p2是错误的原因,是因为==会调用对象的__eq__方法,获取这个方法的结果,eq不重写默认是比较内存地址,我们可以改写eq让他做的值比较,将类进行如下改变即可:
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def __eq__(self,other):
if self.name==other.name and self.age==other.age:
return True
return False
self的理解:
和运算符相关的魔法方法:
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def __eq__(self,other):
return self.name==other.name and self.age==other.age
#def __ne__(self,other):
# pass
def __gt__(self,other):
return self.age>other.age
def __ge__(self,other):#使用>=时会调用
return self.age >= other.age
p1=Person('zhangsan',18)
p2=Person('zhangsan',18)
print(p1 is p2)#False
#==运算符本质时调用对象的__eq方法,获取__eq__方阿飞的返回结果
#a==b =====>a.__eq__(b)
print(p1==p2)#p1.__eq__(p2)
#!=本质时调用__ne__方法 或者__eq__方法取反
print(p1!=p2)
#使用>会自动调用__gt__,没写就报错,写了就会用
print(p1>p2)
print(p1>=p2)
#使用< __lt__
#使用<= __le__
#+ __add__
#- __sub__
#* __mul__
#/ __truediv_
# % __mod__
#** __pow__
#str()将对象转换为字符串,会自动调用__str__方法
#1.str()默认会转化成为类型+内存地址
#2.打印对象会调用
#print(p1)
将对象当作字典使用
class Person(object):
"""这是一个人类"""
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print(self.name+'正在吃饭')
p=Person('张三',18)
#'name':'zhangsan',’age‘:18,'eat':<function>
print(dir(p))#列出所有属性
print(p.__class__)#说明时什么类
print(p.__dict__)#把属性和值转换晨会一个人字典
print(p.__doc__)#打印类的说明
print(p.__module__)#__main__
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def __setitem__(self,key,value):
print('setitem被调用,key={},value={}'.format(key,value))
p.__dict__[key]=value
def __getitem__(self,item):
return self.__dict__[item]
p=Person('张三',12)
print(p.__dict__)
#不能直接把一个对象当作字典来使用
#不能设置新值
p['name']='jack'#[]语法会调用对象的__setitem__方法
#只有重写了setitem才会不报错
print(p.name)
#不能当字典获取值,只有写了getitem才可用
print(p['name'])
内置属性
class Person(object):
"""这是一个人类"""
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print(self.name+'正在吃饭')
p=Person('张三',18)
#'name':'zhangsan',’age‘:18,'eat':<function>
print(dir(p))#列出所有属性
print(p.__class__)#说明时什么类
print(p.__dict__)#把属性和值转换晨会一个人字典
print(p.__doc__)#打印类的说明
print(p.__module__)#__main__
对象属性和类属性
类属性是所有实例对象共有的属性
class Person(object):
type='人类'
#type是类属性,保存在类对象中,实例对象不保存
#定义在类里,函数之外,我们称之为类属性
def __init__(self,name,age):
self.name=name
self.age=age
p1=Person('张三',18)
p2=Person('李四',19)
#p1p2是通过Person类创建出来的实例对象
#类属性是可以通过类对象和实例对象获取
print(Person.type)
print(p1.type)
#p1本身内存是没有type的,当在自身内存没有找到时,就会往类中找
#类属性只能通过类对象来修改,而实例对象不能改
p1.type='human'#并不会改变类属性,会给实例对象添加一个新的对象属性
print(Person.type)
Person.type='human'
print(p2.type)
私有属性的使用
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
self.__money=100
#__开头的是私有变量,不能通过直接获取print(p.__money)
def get_money(self):
return self._money
def set_money(self,x):
self._money=x
def __test(self):#以两个下划线开始的函数,是私有函数,在外部无法使用
print('我是test')
p1=Person('zhang',18)
#获取私有变量的方式:
#1.使用对象._类名_私有变量名获取
print(p1._Person__money)
#2.定义get和get获取
print(p1.get_money)
p1.set_money(100)
#3.使用property
类方法和静态方法
class Person(object):
type='人'
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self,food):#对象方法有一个参数self,指的是实例对象
print(self.name+'正在吃'+food)
#如果一个方法里没有用的实例对象的任何属性,可以将其设置为static
@staticmethod
def demo():
print('hello')
@classmethod
def test(cls):#如果函数只用到了类属性,我们可以定义为一个类方法
print('yes') #cls==Person ==>True
print(cls.type)
#cls也不用手动传参,会自动传参
#cls指的是类对象
#在实例对象中调用方法时,不需要给形参self传参,会自动把实例对象传递给self
p=Person('张三',18)
#eat对象的、方法可以直接使用实例对象.方法名(参数)调用
#使用对象名.方法名(参数)调用的方式,不需要传递self
#会自动将对象名传递给self
#实例对象调用实例方法时,会自动将实例对象传递给self,所以会执行实例方法中的操作
p.eat('泡面')
p2=Person('李四',18)
#对象方法还可以使用类对象来调用类名.方法名()
#这种方式,不会自动给self传参,需要手动的指定self
Person.eat(p2,'西红柿')
#静态方法的调用:可以不用创建对象,直接用类调用
Person.demo()
p.demo()
#类方法:可以使用实例对象和类对象调用
Person.test()
p.test()