
?
面向对象:
1.所有的类名要求首字母大写,多个单词时使用驼峰式命名
2.所有自定义类的祖先是object
3.在类中的方法有四种:普通方法,类方法,静态方法,魔术方法。
##简单面向对象举例
class car: #自动继承了object
brand = '红旗'
print(car)
#使用类创建对象 (利用一个模子来复刻)
jsy = car() #对象的产生
print(jsy)
print(jsy.brand) #使用类中定义好了的属性
jsy.brand = '特斯拉' #使用类中的属性并自己定义值
print(jsy.brand)
输出:
<class '__main__.car'>
<__main__.car object at 0x000001996AABBFD0>
红旗
特斯拉
属性:
属性可分为类属性和对象属性
class Student:
#类属性
name = 'Jack'
age = 18
JSY = Student()
JSY.gender = '男'
print(JSY.gender)
#修改类中的属性
Student.name = 'JackLove'
print(JSY.name) #JSY对象里没有定义name,所以使用类中的属性name
输出:
男
JackLove
注意:当对象调用属性时,先在对象属性(自己的空间)里找,再在类属性(模型的空间)里找
? ? ? ? ? ?对于类属性每个对象都可调用
普通(对象)方法:
格式:
def? 方法名(self,[参数,参数]):
? ? ? ?方法内容
class Phone:
brand = 'HuaWei'
price = 3999
type = 'nava 4'
#Phone里面的方法:call
def call (self):
print(self) #self是调用该函数的对象
print('正在打电话...')
print('主人:',self.name)
phone1 = Phone()
phone1.name = 'Jack'
print(phone1)
phone1.call() #call方法中的self表示,谁调用call函数就会把自身作为参数传给call
输出:
<__main__.Phone object at 0x000001560191BE80>
<__main__.Phone object at 0x000001560191BE80>
正在打电话...
主人: Jack
注意:可以用类名来调用普通函数,但是参数需为对象名:Phone.call(phone1)
类方法:
格式:
@classmothod
def test(cls,[参数],[参数]):
? ?pass
特点:
1.定义需要依赖装饰器@classmothod
2.类方法中只能用类属性,不能使用对象属性
3.类方法中不能调用对象方法,对象方法里能调用类方法
4.类方法的参数不是一个对象(self),而是类(cls)
类方法作用:
类方法只能访问类属性和其他类方法,所以在对象创建之前,如果需要完成一些动作(功能),可使用类方法。
类方法是不依赖对象,独立于对象之外的方法。
###举例说明
class Dog:
def __init__(self,nickname):
print('init')
self.nickname = nickname
def run(self): #self 对象 || 对象方法
print(self) #打印是对象名和对象空间
print('{}正在睡觉!'.format(self.nickname))
Dog.test() #对象方法里可通过类名或是对象(self)来调用类方法
self.test()
def eat(self):
print('饿了么...')
self.run()
@classmethod #装饰器
def test(cls): #cls class ||类方法
print(cls) #打印是类名
# print(cls.nickname) #类空间里没有nickname这个参数
print(Dog)
Dog.test() #类方法不依赖对象,在对象出现之前也可调用
dog = Dog('旺财')
# dog.run()
dog.eat()
输出:
<class '__main__.Dog'>
<class '__main__.Dog'>
init
饿了么...
<__main__.Dog object at 0x0000015D8D4FCFA0>
旺财正在睡觉!
<class '__main__.Dog'>
<class '__main__.Dog'>
可见,在普通方法里可以通过类名或是对象来调用类方法?
? ? ? ? ? ?在类方法里不能调用对象的属性,只能调用类属性
? ? ? ? ? ?类方法不依赖于对象,在对象创建之前便可以通过类名调用
? ? ? ? ? ?对象可以调用类方法,对象(普通)方法;但是类只能调用类方法
静态方法:
格式:
@staticmethod
def test():
? ?pass
特点:
1.需要装饰器 @staticmethod
2.静态方法无需传递参数(cls,self等)
3.只能访问类的属性和方法(使用类名来调用静态方法,也可以通过类名调用类的私有化属性),对? ? ?象的属性无法访问
4.加载时机同类方法一致,使用时与类方法类似
##举例说明
class Person:
__age = 21 #属性私有化,外界无法通过类来访问该属性
def __init__(self,name):
self.name = name
def show(self):
print('年龄:{}'.format(self.__age)) #此时的__age可以通过(对象方法)self来访问,达到封装数据的目的
@classmethod
def update_age(cls):
cls.__age = 18 #也可以(借助类方法)通过cls来访问
print("类方法")
@classmethod
def show_age(cls):
print(cls.__age)
@staticmethod
def test(): #没有自带参数,里面不能出现self,cls
print('静态方法')
print(Person.__age)
p = Person('Jack')
p.update_age()
p.show()
Person.update_age()
Person.show_age()
Person.test()
注意:类里的属性在定义时,在属性名前加两个下划线会将其定义为私有化属性(外界无法访问)
? ? ? ? ??
输出:
类方法
年龄:18
类方法
18
静态方法
18
总结:
类方法? 与? 静态方法
不同:
1.装饰器不同
2.类方法有参数,静态方法无参数
相同:
1.都只能访问类的属性和方法,并通过类名可以互相调用,对象的无法访问
2.都可以通过类名来被调用
3.都可以在创建对象之前使用,因为不依赖对象
普通()对象方法与两者的区别:
1.普通方法没有装饰器
2.普通方法永远依赖对象,因为每一个普通方法都有一个self
3.只有创建了对象才能调用普通方法
魔术方法(Magic Method):
所有以双下划线''__''包起来的方法,称为魔术方法,魔术方法在满足一定条件下会自动执行。
常见的魔术方法:
__init__:初始化魔术方法
触发时机:初始化对象时触发(和实例化不同,但与实例化在同一操作中)
__new__:(必须有返回值)用于对象实例化的魔术方法,开辟内存空间,返回对象实例(地址空间)
触发时机:在实例化时触发
__call__:调用对象方法(使对象可作为函数调用)
触发时机:将对象作为函数调用时触发,默认执行该函数里的内容
__del__:析构魔术方法? ? #理解Python里的垃圾回收机制
触发时机:当对象没有任何变量引用(没有用)时触发
__str__:必须要有返回值(return),将返回值传给对象
触发时机:打印对象名的时候,自动触发调用__str__
对于__init__和__new__的运行机制:
当在类中定义了__init__和__new__时
1.在创建对象时,先执行__new__ ,开辟空间,并将空间地址作为返回值传给__init__
2.再执行__init__,self即为开辟的地址空间
3.执行完毕__init__后,才将self的地址空间传给了对象
##举例说明
class Person:
def __init__(self, name): #初始化实例
print('init')
print(self)
self.name = name
print(name)
def __new__(cls,*args,**kwargs): #创建并返回这个类的实例,必须要有返回值
print('魔术方法:_new_',args)
# return super(Person, cls).__new__(cls) #返回值给了_init_里的self
space = object.__new__(cls) #作用同上
print(space)
return space
def __call__(self, name):
print('魔术方法:__call__')
print('执行对象传入的参数是:',name)
p = Person('Jack') # 先触发_new_方法,实例化一个对象;再触发_init_方法
print(type(p))
print(p)
p('jsy') #把对象当成函数调用
输出:
魔术方法:_new_ ('Jack',)
<__main__.Person object at 0x000001FA562CCF70>
init
<__main__.Person object at 0x000001FA562CCF70>
Jack
<class '__main__.Person'>
<__main__.Person object at 0x000001FA562CCF70>
魔术方法:__call__
执行对象传入的参数是: jsy
注意:在使用__new__时,需创建并返回该类的实例,然而python2和python3对super函数不同? ? ? ? ? ? ?的写法:python3的__new__()不用其他参数。写成__new__(cls) 即可。
? ? ? ? ? ?对于__call__方法,参数为self,与对象相关,在出现将对象以函数方式调用的情况下,自? ? ? ? ? ? ?动触发该方法,而且允许有返回值。
对于__del__魔术方法的说明:
1.对象赋值
? ?p = Person()
? ?p1 = p? ? ? ? ?#p和p1共同指向同一个地址
2.删除地址的引用
? ?del? p1? ? ? ? #删除p1对地址的引用
3.查看对象的引用次数
? ?import? sys
? ?sys.getrefcount(p)
4.当一块空间没有了任何的引用,默认执行__del__()
(Python自带垃圾回收机制,每执行完程序自动释放资源,故在程序结束后自动执行__del__)
##举例说明
import sys
class Man:
def __init__(self,name):
self.name=name
def __del__(self): #在删除完引用之后,并执行剩余代码后,才去执行_del_
print('魔术方法:del')
p = Man('J')
p1 = p
p2 = p
print(p,p1)
print(p1.name)
print(sys.getrefcount(p1))
p1.name = 'Tom'
print(p1.name,p.name) #修改其中一个的值,其他指向该地址的变量也随之而变
print(p2)
输出:
<__main__.Man object at 0x000001B9B448CBE0> <__main__.Man object at 0x000001B9B448CBE0>
J
4
Tom Tom
<__main__.Man object at 0x000001B9B448CBE0>
魔术方法:del
可见,p和p1,p2共同指向一块地址空间,且修改其中一个的值,其他指向该地址的变量也随之而变。
__del__的执行是在删除完引用,并执行完所有代码后才会进行
对于__str__魔术方法的说明:
对于开发者来说,单纯打印对象名,输出的是对象的地址空间(无太大意义),所以使用__str__来给对象传入想要的信息(传值)。
##举例说明
class Human:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
return '姓名:'+self.name+'年龄:'+self.age #将返回值给对象
p = Human('JSY','22') #此时的对象p值为__str__的返回值
print(p)
输出:
姓名:JSY年龄:22
注意:使用__str__时,必须要有返回值,且返回值应该是字符串形式,当打印对象名的时候触发

|