python3 面向对象
Posted YanYan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python3 面向对象相关的知识,希望对你有一定的参考价值。
""" 语法: class 类名 图纸就是一个类,根据图纸造出来的每辆车就是一个对象。 1、属性:能够描述一个对象的变量(变量) 2、动作:能够描述一个对象能执行的动作(函数)
在类中访问属性:self.属性
在类中访问动作:self.动作 """ class Car: def __init__(self, color): # self就是对象 self.color = color # 属性 def run(self): # 动作 print("我的车会跑") # 创建对象 init 初始化 出厂设置 c1 = Car("red") # 类名() => 实际上默认执行的是__init__函数 c2 = Car("white")
self到底是个什么鬼?
class Car: def __init__(self, color): # self就是对象 print(self) # self到底是个什么鬼 self.color = color # 属性 def run(self): # 动作 print("我的车会跑") c1 = Car("red") print(c1)
执行结果:
<__main__.Car object at 0x000000000228CEB8> <__main__.Car object at 0x000000000228CEB8>
结论:self就是对象
不同对象调用同一方法,会有什么样的效果呐?
class Car: def __init__(self, color): # self就是对象 print(self) # self到底是个什么鬼 self.color = color # 属性 def run(self): # 动作 print(f"我的{self.color}车会跑") c1 = Car("red") c2 = Car("white") c1.run() c2.run()
执行结果:
<__main__.Car object at 0x00000000029997F0> <__main__.Car object at 0x0000000002999828> 我的red车会跑 我的white车会跑
结论:不同对象调用同一属性或方法,调用的是对象自己的属性和方法。
接下来,看下类的成员-->变量
""" 类的成员 1、变量 1.实例变量 实例=对象 对象的属性值 必须用:对象.变量 2.类变量 直接写在类中的变量 推荐用:类名.变量 """ class Person: country = "中国" # 类变量 def __init__(self, name, age): self.name = name # 实例变量 self.age = age p = Person("lily", 18) print(p.name) # 对象.实例属性 print(p.age) print(p.country) # 不推荐使用,对象中没有,则去类中找 print(Person.country) # 推荐使用 # print(Person.name) # 报错AttributeError: type object \'Person\' has no attribute \'name\'
执行结果:
lily 18 中国 中国
对象.属性可以新建一个属性
class Person: country = "中国" # 类变量 def __init__(self, name, age): self.name = name # 实例变量 self.age = age p = Person("lily", 18) p.country = "大清" # 对象中没有,则新建一个country print(p.country) print(Person.country) # 类变量
执行结果:
大清
中国
对象访问类变量的情况(理解很重要!!!)
class Person: country = "中国" # 类变量 def __init__(self, name, age): self.name = name # 实例变量 self.age = age p = Person("lily", 18) print(p.country) print(Person.country) # 类变量 Person.country = "大清" print(p.country)
执行结果:
中国
中国
大清
类的成员-->方法
""" 类的成员 2、方法:在类中写的函数 1.实例方法 必须对象.方法 第一个参数必须是self 2.类方法 推荐使用类名.方法 添加@classmethod装饰器 第一个参数必须是cls 一般用来创建对象 3.静态方法 推荐类名.方法 添加@staticmethond装饰器 参数无要求 一般用来写逻辑运算 总结: 实例方法必须先创建对象,再通过对象访问实例方法 类方法和静态方法是在创建对象前执行的方法(不需要对象就能执行的方法:类方法和静态方法)。 """ class Person: def __init__(self, name): self.name = name def run(self): # 需要访问实例属性和方法的情况 print(f"我是run实例方法,我的名字是{self.name}") @classmethod def play(cls): # cls就是类 类方法一般用来创建对象 print("我是play类方法") @staticmethod def study(): # 静态方法一般用来写逻辑运算 print("我是study静态方法") p = Person("lily") p.run() # 实例方法,必须使用对象来访问 # Person.run() # TypeError: run() missing 1 required positional argument: \'self\' Person.play() # 推荐使用 类方法推荐使用类名来访问 p.play() # 不推荐使用 Person.study() # 推荐使用 静态方法推荐使用类名来访问 p.study() # 不推荐使用
执行结果:
我是run实例方法,我的名字是lily
我是play类方法
我是play类方法
我是study静态方法
我是study静态方法
cls是个什么鬼?
class Person: def __init__(self, name): self.name = name @classmethod def play(cls): # cls 就是类 print(cls) print("我是play类方法") p = Person("lily") print(Person) Person.play()
执行结果:
<class \'__main__.Person\'> <class \'__main__.Person\'> 我是play类方法
结论:cls就是类
类方法的使用实例(用户登录)
class User: menu = ["查看所有课程", "选择课程", "查看已选课程", "删除已选课程"] def __init__(self, username): self.username = username def display_menu(self): print("显示可菜单内容") @classmethod def login(cls): # 类方法,一般会用来创建对象 for i in range(2, -1, -1): username = input("Username: ").strip() password = input("Password: ").strip() if username == "lily" and password == "123": print("登录成功!") return cls(username) # 返回一个对象 else: print("登录失败!") return None if __name__ == \'__main__\': user_obj = User.login() if user_obj: user_obj.display_menu()
类的成员-->属性
"""
类的属性
在方法的上面加上一个@property的装饰器,可以把一个方法变成属性
"""
class Person:
def __init__(self, name ,birth_year):
self.name = name
self.birth_year = birth_year
@property # property装饰器可以把一个方法变成属性 从age中拿到数据
def age(self):
print(f\'今年是{time.strftime("%Y")}年\')
return int(time.strftime("%Y")) - self.birth_year
import time
p = Person("lily", 2001)
print(p.age)
执行结果:
今年是2019年
18
给age赋值
class Person: def __init__(self, name, birth_year): self.name = name self.birth_year = birth_year @property # property装饰器可以把一个方法变成属性 def age(self): print(f\'今年是{time.strftime("%Y")}年\') return int(time.strftime("%Y")) - self.birth_year @age.setter # 给age赋值 def age(self, value): self.birth_year = int(time.strftime("%Y")) - value if __name__ == \'__main__\': import time p = Person("lily", 2001) print(p.age) p.age = 10 print(p.age)
执行结果:
今年是2019年 18 今年是2019年 10
类的私有成员(双线划线开头的变量或方法都是私有的,只能在类中使用。)
""" 类的成员 私有:只能在类中使用,__双下划线开头的变量或方法都是私有的。 另外,_单线划线开头的变量或方法都是给子类使用的。 """ class Person: __hobby = "高尔夫" # 私有类变量 def __init__(self, username, wife_name): self.username = username self.__wife_name = wife_name # 私有变量 def tell(self): print(f"{self.username}妻子的名字叫{self.__wife_name}") def __play(self): # 私有方法 print(f"{self.username}偷偷的去耍牌去了") p = Person("吴奇隆", "刘诗诗") # print(p.__wife_name) # AttributeError: \'Person\' object has no attribute \'__wife_name\' p.tell() # print(p.__play()) # AttributeError: \'Person\' object has no attribute \'__play\' # print(Person.__hobby) # AttributeError: type object \'Person\' has no attribute \'__hobby\'
执行结果:
吴奇隆妻子的名字叫刘诗诗
类的特殊成员
""" 类的特殊成员 __new__ 开辟内存 __init__ 类名()的时候调用 __call__ 对象()的时候调用 __getitem__ 取数据 __setitem__ 设置数据 __delitem__ 删除数据 """ class Foo: def __init__(self): # 初始化 self.dic = {} print("类名()的时候调用") def __call__(self): print("对象()的时候调用") def __getitem__(self, item): print("取数据") return self.dic.get(item) def __setitem__(self, key, value): print("设置数据", key, value) self.dic[key] = value def __delitem__(self, key): print("删除数据") self.dic.pop(key) f = Foo() # __init__ f() # __call__ f["name"] # __getitem__ f["age"] = 18 # __setitem__ print(f["age"]) del f["age"] # __delitem__
执行结果:
类名()的时候调用 对象()的时候调用 取数据 设置数据 age 18 取数据 18 删除数据
__new__是个什么鬼?什么时候执行?__new__和__init__的先后顺序?
class Foo: def __new__(cls, *args, **kwargs): print("我是__new__") def __init__(self): print("我是__init__") f = Foo()
执行结果:
我是__new__
发现没有,__init__没有执行,只是执行了__new__方法。在每个类中默认都有一个__new__方法,用来开辟内存,这里写了,就覆盖了默认的__new__方法。那到底怎么开辟内存呐?
class Foo: def __new__(cls, *args, **kwargs): # 在每个类中默认有__new__方法,这里写了,就覆盖了默认的__new__方法 print("我是__new__") return object.__new__(cls) # 开辟内存 def __init__(self): print("我是__init__")
执行结果:
我是__new__
我是__init__
类的继承 (子类可以访问父类非私有的变量、方法和属性,父类不能访问子类独有的变量、方法和属性。)
""" 类的继承 子类可以访问父类的变量、方法和属性,父类不能访问子类独有的变量、方法和属性。 """ class Animal: def action(self): print("动物会动") class Cat(Animal): # Cat继承Animal def catch_mouse(self): print("猫会抓老鼠") a = Animal() c = Cat() a.action() c.action() # Cat类中没有action方法,也就是自己类中没有,就去父类中找 # a.catch_mouse() # 报错AttributeError: \'Animal\' object has no attribute \'catch_mouse\' c.catch_mouse()
执行结果:
动物会动
动物会动
猫会抓老鼠
子类和父类有相同的方法时,子类会重写父类的方法,子类实例会调用自己类中的方法。
class Animal: def action(self): print("动物会动") class Cat(Animal): # Cat继承Animal def action(self): # 重写父类的方法 print("猫会动") def catch_mouse(self): print("猫会抓老鼠") c = Cat() c.action()
执行结果:
猫会动
类的多继承
""" 类的多继承: 一个类可以继承多个类 先在对象自己类中找,找到了,就自己类中的方法,没找到,再去父类中找 ,根据mro的顺序查找。 """ class Father: def play(self): print("Father陪你玩!") class Mother: def play(self): print("Mother陪你玩!") class Child(Father, Mother): # Child继承Father和Mother pass s = Child() s.play() # 自己类中没有,按照继承的顺序(mro)去父类中找 print(Child.mro()) # mro: Method Resolution Order
执行结果:
Father陪你玩! [<class \'__main__.Child\'>, <class \'__main__.Father\'>, <class \'__main__.Mother\'>, <class \'object\'>]
super()在类的继承中的使用
class Father: def play(self): print("Father陪你玩!") class Mother: def play(self): print("Mother陪你玩!") class Child(Father, Mother): # Child继承Father和Mother def play(self): print("Child自己玩!") super(Child, self).play() # 使用self对象去执行mro里Child类的下一个类的play方法 super().play() # 执行mro里当前类的下一个类的play方法,结果同上(推荐使用这种方法) super(Father, self).play() # 使用self对象去执行mro里Father类的下一个类的play方法 s = Child() s.play() # 自己类中没有,按照继承的顺序(mro)去父类中找 print(Child.mro()) # mro: Method Resolution Order
执行结果:
Child自己玩! Father陪你玩! Father陪你玩! Mother陪你玩! [<class \'__main__.Child\'>, <class \'__main__.Father\'>, <class \'__main__.Mother\'>, <class \'object\'>]
初始化父类的__init__方法
class Father: def __init__(self, address): self.address = address class Child(Father): def __init__(self, name, age, address): super().__init__(address) # 继承父类的__init__方法 self.name = name self.age = age c = Child("lily", 18, "洛杉矶") print(c.address)
执行结果:
洛杉矶
python2和python3在继承这块的区别
""" 类的多继承: 一个类可以继承多个类 先在对象自己类中找,找到了,就自己类中的方法,没找到,再去父类中找 ,根据mro的顺序查找。 python3 新式类 广度优先 python2 经典类 深度优先 """ class Grandfather: def play(self): print("Grandfather陪我玩!") class Father(Grandfather): pass class Mother(Grandfather): def play(self): print("Mother陪我玩!") class Child(Father, Mother): pass c = Child() c.play() print(Child.mro())
执行结果:
Mother陪我玩! [<class \'__main__.Child\'>, <class \'__main__.Father\'>, <class \'__main__.Mother\'>, <class \'__main__.Grandfather\'>, <class \'object\'>]
需要记住:
python3 新式类 广度优先
python2 经典类 深度优先
类的成员
1、变量
1.实例变量 实例=对象 对象的属性值 必须用:对象.变量
2.类变量 直接写在类中的变量 推荐用:类名.变量
2、方法(在类中写的函数 )
1.实例方法 必须对象.方法 第一个参数必须是self
2.类方法 推荐使用类名.方法 添加@classmethod装饰器 第一个参数必须是cls 一般用来创建对象
3.静态方法 推荐类名.方法 添加@staticmethond装饰器 参数无要求 一般用来写逻辑运算
3、类的属性
在方法的上面加上一个@property的装饰器,可以把一个方法变成属性
4、类的成员
私有:只能在类中使用,__双下划线开头的变量或方法都是私有的。
另外,_单线划线开头的变量或方法都是给子类使用的。
5、特殊方法
__init__ 初始化
__call__ 对象()的时候调用
__getitem__ 取数据
__setitem__ 设置数据
__delitem__ 删除数据
以上是关于python3 面向对象的主要内容,如果未能解决你的问题,请参考以下文章