面向对象
-
类和对象:
-
定义 类 :具有某些属性和方法的对象全体称为一个类
-
class <类名>: ** #类名遵守大驼峰命名法**
-
class <类名>(object):
-
使用**__inin__函数定义类具有的特征,这写特征称为属性**
-
通过一个个函数取定义这个类的行为,称为方法
-
用类创建一个新的对象的过程:
- 首先调用**__new__方法申请一段内存地址**;
- 接着调用**_init_传入参数,并让self指向该内存空间.并填充数据**;
- 让s1也指向那段内存地址
-
谁调用方法,就针对谁进行操作
#小明今年18,身高1.78m,喜欢跑步,正在吃饭 #小美几年17,身高1.65m,不喜欢跑步,正在吃饭 class Student: #使用__inin__将类定义类具有的特征,这写特征称为属性 def __init__(self,x,y,z): self.name=x self.age=y self.height=z #通过一个个函数取定义这个类的行为,称为方法 def run(self): print('喜欢跑步') def eat(self): print('正在吃饭') def say_hello(self): print('大家好,我是',self.name) #利用类创建两个具体的对象:他们都具有name,age,height属性,也都具有run和eat方法 s1=Student('小明',18,1.78) #1.首先调用__new__方法申请一段内存地址; #2.接着调用__init__传入参数,并让self指向该内存空间.并填充数据; #3.让s1也指向那段内存地址 s2=Student('小美',17,1.65) print('s1的地址是ox%X'%id(s1)) print('s1的名字是{}'.format(s1.name)) #谁调用方法,就针对谁进行操作 s1.run() s1.eat() s1.say_hello() s2.eat() #result s1的地址是ox1E6E448 s1的名字是小明 喜欢跑步 正在吃饭 大家好,我是 小明 正在吃饭
-
-
**_slots_**方法
-
在python中,类的属性是一种动态属性,就是可以修改和添加:通过赋值语句实现
-
使用**_slots_**方法可以使得类的属性无法添加
-
**_slots_**直接定义在类里,是一个元组,用来规定类可以存在的属性
#s1.city 会直接报错,因为在__init__里面,并没有定义city这个属性 #可以通过赋值语句,给对象添加或者修改属性 s1.city='上海' #如果没有该属性那么就添加,如果有就修改 print(s1.city)、 #result 上海
class Student: __slots__ = ('name','age','height') def __init__(self,x,y,z): self.name=x self.age=y self.height=z s=Student('小明',18,1.78) #s.city='上海' #此时会报错
-
-
魔方方法
-
特点
- 不需要手动调用,会在合适的时机自己调用
- 这些方法都是以**__开始**,以**__结束**
- 这些方法名都是系统规定好的,在合适的时机自己调用,可以手动调用
-
**_init_**方法: 创建对象时,会自动调用这个方法
-
**_del_**方法: 销毁对象时,会自动调用
-
**_str_方法和_repr_**方法:打印对象时调用,打印return的结果,优先_str_,必须是字符串
-
**_call_**方法: 可以使得对象可以像函数一样
-
算术运算符
- **_eq_**方法: 出现==时调用,如果不写,默认是比较内存地址
- is 身份运算符,判断是否是同一个对象,比较的是内存地址
- == ** 使用的时候是调用_eq_**方法,默认也是比较内存地址,除非重写
- **_ne_方法:出现!=**时调用,如果不写默认__eq__方法取反
- **_gt_**方法:出现 > 时调用
- **_ge_方法:出现>=**时调用
- **_lt_方法:出现<=**时调用
- **_le_方法:出现<=**时调用
- **_add_方法:出现+**时调用
- **_sub_方法:出现-**时调用
- **_mul_方法:出现***时调用
- **_truediv_方法:出现/**时调用
- **_pow_方法:出现****时调用
-
转换运算符
- _str_: 使用**str()**转换成字符串的时候调用
-
_int_: 使用**int()**时调用
- _float_: 使用**float()**时调用
class Person: #__init__方法:创建对象时,会自动调用这个方法 def __init__(self,name,age,height): print('是__init__方法,我被调用了') self.name=name self.age=age self.height=height def __del__(self): #注意程序运行结束,对象会被自动销毁 print('我是__del__方法,我被调用了') def __str__(self): return '姓名{},年龄{},身高{}'.format(self.name,self.age,self.height) def __repr__(self): return 'hello world' def __call__(self, *args, **kwargs): return kwargs['fn'](args[0],args[1]) #算术运算符 def __eq__(self, other): return self.name==other.name and self.age==other.age and self.height==other.height def __ne__(self, other): return not(self.name==other.name and self.age==other.age and self.height==other.height) def __gt__(self, other): return self.age>other.age def __ge__(self, other): return self.age>other.age def __lt__(self, other): return self.age<other.age def __le__(self, other): return self.age<=other.age def __add__(self, other): return self.age+other.age def __sub__(self, other): return self.age-other def __mul__(self, other): return self.name*other def __truediv__(self, other): return self.age/other def __pow__(self, power, modulo=None): return self.age**power #转换运算符 __str__:使用str()转换成字符串的时候调用 __int__:使用int()时调用 __float__:使用float()时调用 p=Person('zhangsan',18,178) # time.sleep(10) print(p) #如果没有__str__和__repr__,会打印__name__.类名和地址 print(p.__repr__) #自己手动调用不是特别好 print(repr(p)) #会触发__repr__方法 m=p(13,34,fn=lambda x,y: x+y) #使用__call__方法,可以让对象当成函数被调用 print(m) p1=Person('zhangsan',18,178) p2=Person('zhangsan',18,178) #此时p1和p2指向不同的内存地址,只是里面的内容是一样的 print('p1的内存地址{},p2的内存地址{}'.format(id(p1),id(p2))) # is 身份运算符,判断是否是同一个对象,比较的是内存地址 # == 使用的时候是调用__eq__方法,默认也是比较内存地址,除非重写 # != 使用时调用__ne__方法,或者__eq__方法取反,获取返回值 print(p1 is p2) print(p1==p2) num1=[1,2,3] num2=[1,2,3] print('num1的内存地址{},num2的内存地址{}'.format(id(num1),id(num2))) print(p1+p2) print(p1>p2) print(p1*2) print(p1-3) #result 是__init__方法,我被调用了 姓名zhangsan,年龄18,身高178 <bound method Person.__repr__ of hello world> hello world 47 是__init__方法,我被调用了 是__init__方法,我被调用了 p1的内存地址33243016,p2的内存地址33242888 False True num1的内存地址3953160,num2的内存地址3953672 36 False zhangsanzhangsan 15 我是__del__方法,我被调用了 我是__del__方法,我被调用了 我是__del__方法,我被调用了
-
-
内置属性
-
dir() 内置函数获取对象的所有属性
-
_class_ 获取(对象的)类名
-
_dict_ 以字典的形式输出对象的属性名与对应的值
-
_doc_ 获取(对象所在)类的帮助文档
-
_module_ 获取所在的模块名
class Person(object): """ 这是一个人类 """ def __init__(self,name,age): self.name=name self.age=age def eat(self): print('{}正在吃饭'.format(self.name)) p=Person('zhangsan',18) #内置属性 print(dir(p)) #获取对象的所有属性 print(p.__class__) #获取对象的类名 print(Person.__class__)#获取对象的类名 print(p.__dict__) #以字典的形式输出对象的属性名与对应的值 print(p.__doc__) #获取对象所在类的帮助文档 print(Person.__doc__)#获取类的帮助文档 print(p.__module__) #获取所在的模块名
-
-
将对象像字典那么操作
-
__setitem__方法:当出现[]在赋值语句里面时调用
-
__getitem__方法:当出现[]在打印时调用
def __setitem__(self, key, value): #self.key=value 这个代码的意思是给对象增加key这个属性并赋值 self.__dict__[key]=value def __getitem__(self, item): return self.__dict__[item] print(p.__dict__)#以字典的形式输出对象的属性名与对应的值,但每次这么写太麻烦了 p['name']='Jack' #如果没用__setitem__方法会报错 print(p) print(p['name']) #如果没有__getitem__方法会报错 #result {'name': 'zhangsan', 'age': 18} name=Jack,age=18 Jack
-
-
类属性和对象属性
-
类属性保存在类里,但不在任何方法或者属性里
-
可以通过类和对象访问类属性,如果对象的属性没有对应的,会搜索类属性
-
只能通过类修改类属性
class Person: type='人类' def __init__(self,name,age): self.name=name self.age=age #通过类和对象访问类属性 print(Person.type) print(p1.type) #修改类属性 p1.type='human' #不是修改类属性,而是给p1这个对象增加了type的对象属性 print(p2.type) Person.type='monkey' #修改了类属性 print(p2.type) print(Person.type) print(p1.type) #只有p1没有type属性时,才会返回类属性 #result 人类 人类 人类 monkey monkey human
-
-
私有变量和私有函数
-
私有变量
- 以两个下划线开始的变量是私有变量,在内部可以直接访问
- 定义私有变量的原因
- 不希望别人访问到,只在内部做;
- 有了get方法后,可以对这些变量进行额外的操作
- 想要在外部获取私有变量的方式:直接拿回报错
- 对象._类名__私有变量
- 使用get方法:在函数内部定义一个接口
- 使用property方法获取
-
私有函数
-
以两个下划线开始的函数称为私有函数,可以内部访问
-
在外部私有函数不能直接访问
-
使用对象名._类名__函数()可以强行调用
import datetime as dt class Person(object): def __init__(self,name,age): self.name=name self.age=age self.__money=0 #以两个下划线开始的变量是私有变量,在内部可以直接访问, def get__money(self): #get方法得到私有变量 print('{}查询了余额'.format(dt.datetime.now()))#可以进行额外的操作 return self.__money def set__money(self,qian): #set方法修改私有变量 self.__money=qian def __demo(self): #以两个下划线开始的函数称为私有函数,可以内部访问 print('__demo函数被调用') def test(self): self.__demo() p1=Person('zhangsan',18) #p1.__money 不使用get方法,直接这么写会报错 print(p1._Person__money) print(p1.get__money()) #类似的使用set方法可以修改私有变量 p1.set__money(100) #修改了私有和属性 print(p1.get__money()) #在外部私有函数不能直接访问 #p1.__demo 不能直接调用私有函数 p1._Person__demo() #使用对象名._类名__函数()可以强行调用 p1.test()
-
-
-
普通方法,静态方法,类方法
-
普通方法
- 方法(函数)是存在类里面的,所以可以通过类访问到
- 实例对象调用方法的时候,是将方法与这个实例对象绑定
- 使用实例对象名.方法名不需要给形参self传参,self的参数就是实例对象
- 通过类调用函数的时候需要给self指定实例对象
class Person(object): #定义一个Person类 def __init__(self,name,age): self.name=name self.age=age def eat(self,food): print('{}正在吃{}'.format(self.name,food)) p1=Person('zhangsan',18) p2=Person('lisi',19) print(p1.eat) print(p2.eat) print(p1.eat is p2.eat) #这两个不一样,是类的函数与不同的实例对象绑定 print(Person.eat) Person.eat(p1,'红烧牛肉泡面')#需要指定一个实例对象 #result <bound method Person.eat of <__main__.Person object at 0x00000000021CE088>> <bound method Person.eat of <__main__.Person object at 0x00000000021CE188>> False <function Person.eat at 0x00000000021CF168> zhangsan正在吃红烧牛肉泡面
-
静态方法
- 创建方法的时候,默认是对象方法
- 如果创建的方法不需要对象的值,那么可以定义成static,使用**@staticmethod**
- 一般用在我们将一些工具打包成一个类
- 静态方法,可以通过对象和类调用
class Person(object): #定义一个Person类 def __init__(self,name,age): self.name=name self.age=age def eat(self,food):#创建方法的时候,默认是对象方法 print('{}正在吃{}'.format(self.name,food)) #如果创建的方法不需要对象的值,那么可以定义成static @staticmethod def demo(): print('hello') p1=Person('zhangsan',18) p1.demo() Person.demo() class Calcualator(object): #定义一个计算器 @staticmethod def add(a,b): return a+b @staticmethod def minus(a,b): return a-b @staticmethod def mul(a,b): return a*b @staticmethod def division(a,b): return a/b print(Calcualator.add(1, 2))
-
类方法
- 如果定义的方法只和类属性相关,可以定义成类方法,使用**@classmethod**
- cls就是类,可以在定义的类方法里,使用这个类,就想self一样
class Person(object): #定义一个Person类 type='human' def __init__(self,name,age): self.name=name self.age=age def eat(self,food):#创建方法的时候,默认是对象方法 print('{}正在吃{}'.format(self.name,food)) #如果定义的方法只和类属性相关,可以定义成类方法 @classmethod def test(cls):#这个cls就是类 print(type) print(cls.type) p1=Person('zhangsan',18) #类方法可以通过类和对象调用 p1.test() Person.test() #result <class 'type'> human <class 'type'> human
-
-