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__ 删除数据




原文地址:https://www.cnblogs.com/lilyxiaoyy/p/11988523.html