python-面向对象编程-从入门到放弃

面向对象编程

class Person:       # 类名
    def __init__(self,name,sex,job,hp,weapon,ad):
        # 必须叫__init__这个名字,不能改变的,所有的在一个具体的人物出现之后拥有的属性
        self.name = name
        self.sex = sex
        self.job = job
        self.level = 0
        self.hp = hp
        self.weapon = weapon
        self.ad = ad
        # # 类名() 会自动调用类中的__init__方法
# 类名() 会自动调用类中的__init__方法
alex = Person('alex','不详','搓澡工',260,'搓澡巾',1)     # alex 就是对象  alex = Person()的过程 是通过类获取一个对象的过程 - 实例化
print(alex,alex.__dict__)
wusir = Person('wusir','male','法师',500,'打狗棍',1000)
print(wusir,wusir.__dict__)

print(alex.name)   # print(alex.__dict__['name'])  属性的查看
alex.name = 'alexsb'    # 属性的修改
print(alex.name)
alex.money = 1000000     # 属性的增加
print(alex.money)
print(alex.__dict__)
del alex.money           # 属性的删除
print(alex.__dict__)
  • 类名() 会自动调用类中的__init__方法

  • 通过对象名.__dict__就可以查看这个对象的属性和值

类和对象之间的关系?

  • 类 是一个大范围 是一个模子 它约束了事物有哪些属性 但是不能约束具体的值

  • 对象 是一个具体的内容 是模子的产物 它遵循了类的约束 同时给属性赋上具体的值

了解实例化对象所经历的步骤

  • # 实例化所经历的步骤
        # 1.的类名() 之后第一个事儿 :开辟一块儿内存空间
        # 2.调用 __init__ 把空间的内存地址作为self参数传递到函数内部
        # 3.所有的这一个对象需要使用的属性都需要和self关联起来
        # 4.执行完init中的逻辑之后,self变量会自动的被返回到调用处(发生实例化的地方)
    

初识方法

class Person:       # 类名
    def __init__(self,name,sex,job,hp,weapon,ad):
        self.name = name          # 对象的属性/实例变量
        self.sex = sex
        self.hp = hp
        self.ad = ad

    def 搓(self,dog):    # 方法,又有一个必须传的参数-->self对象
        dog.hp -= self.ad
        print('%s给%s搓了澡,%s掉了%s点血,%s当前血量%s'%(self.name,dog.dog_name,
                                            dog.dog_name,self.ad,dog.dog_name,dog.hp))

class Dog():
    def __init__(self,name,blood,aggr,kind):
        self.dog_name = name
        self.hp = blood
        self.ad = aggr
        self.kind = kind

    def 舔(self,person):
        # 狗舔了人,人调血,人掉的血量,应该是狗的攻击力
        if person.hp >= self.ad:
            person.hp -= self.ad
        else:
            person.hp = 0
        print(self.__dict__)
        print(person.__dict__)
        print('%s舔了%s,%s掉了%s点血,%s当前血量%s'%(self.dog_name,person.name,person.name,self.ad,person.name,person.hp))
alex = Person('alex','不详','搓澡工',260,'搓澡巾',1)  # 对象\实例 = 类名() -->  实例化的过程
print('alex : ',alex)
小白 = Dog('小白',5000,249,'柴犬')
# alex.搓(小白)
小白.舔(alex)
小白.舔(alex)

练习

定义一个圆形类,半径是这个圆形的属性,实例化一个半径为5的圆形,一个半径为10的圆形
    完成方法
        计算圆形面积
        计算圆形周长
 math import pi
class Circle:
    '''定义一个圆形类'''
    def __init__(self,radius):
        self.radius = radius
    def area(self):
        return pi*self.radius**2
    def perimeter(self):
        return 2*pi*self.radius

circle = Circle(5)  # 实例化
area1 = circle.area()  # 计算面积
print(area1)
per1 = circle.perimeter()  # 计算圆周长
print(per1)
定义一个用户类,用户名和密码是这个类的属性,实例化两个用户,分别有不同的用户名和密码
        登陆成功之后才创建用户对象
        设计一个方法 修改密码
import os
def login(name,passwd,filepath = 'userinfo'):
    with open(filepath,encoding='utf-8') as f:
        for line in f:
            user,pwd = line.strip().split('|')
            if user == name and passwd == pwd:
                return True
        else:
            return False

class User:
    def __init__(self,username,password):
        self.user = username
        self.pwd = password

    def change_pwd(self):
        oldpwd = input('输入原密码 :')
        newpwd = input('输入新密码 :')
        flag = False
        with open('userinfo',encoding='utf-8') as f1,open('userinfo1',mode='w',encoding='utf-8') as f2:
            for line in f1:
                username,password = line.strip().split('|')
                if username == self.user and password == oldpwd:
                    line = '%s|%s\n'%(username,newpwd)
                    flag = True
                f2.write(line)
        os.remove('userinfo')
        os.rename('userinfo1','userinfo')
        return flag
name = input('user : ')
passwd = input('pwd : ')
ret = login(name,passwd)
if ret:
    print('登录成功')
    obj = User(name,passwd)
    res = obj.change_pwd()
    if res:
        print('修改成功')

类的成员和命名空间

class A:
    Country = '中国'     # 静态变量/静态属性 存储在类的命名空间里的
    def __init__(self,name,age):  # 绑定方法 存储在类的命名空间里的
        self.name = name
        self.age = age
    def func1(self):
        print(self)
    def func2(self):pass
    def func3(self):pass
    def func4(self):pass
    def func5(self):pass


a = A('alex',83)
print(a.name)  # alex
print(a.Country)  # 中国
print(A.Country)  # 中国
a.func1() # == A.func1(a)
class A:
    Country = '中国'     # 静态变量/静态属性 存储在类的命名空间里的
    def __init__(self,name,age,country):  # 绑定方法 存储在类的命名空间里的
        self.name = name
        self.age = age
        self.Country = country
    def func1(self):
        print(self)
    def func2(self):pass
    def func3(self):pass
    def func4(self):pass
    def func5(self):pass

a = A('alex',83,'印度')
b = A('wusir',74,'泰国人')
a.Country = '日本人'
print(a.Country)  # 日本人
print(b.Country)  # 泰国人
print(A.Country)  # 中国
  • 1.类中的变量是静态变量
    2.对象中的变量只属于对象本身,每个对象有属于自己的空间来存储对象的变量
    3.当使用对象名去调用某一个属性的时候会优先在自己的空间中寻找,找不到再去对应的类中寻找
    4.如果自己没有就引用类的,如果类也没有就报错
    5.对于类来说,类中的变量所有的对象都是可以读取的,并且读取的是同一份变量

  • 类中的静态变量的用处

    • 如果一个变量 是所有的对象共享的值,那么这个变量应该被定义成静态变量
      所有和 静态变量相关的增删改查 都应该使用类名来处理
      而不应该使用 对象名直接修改 静态变量
      
  • 将对象变成了一个属性

class Clas:  # 班级类
    def __init__(self,cname,begint,teacher):
        self.cname = cname
        self.begint = begint
        self.teacher = teacher
class Course:  # 课程类
    def __init__(self,name,period,price):
        self.name = name
        self.period = period
        self.price = price
py22 = Clas('python全栈22期','2019-4-26','小白')
linux57 = Clas('linux运维57期','2019-3-27','李导')
linux58 = Clas('linux运维58期','2019-6-27','李导')
python = Course('python','6 months',21800)
linux = Course('linux','5 months',19800)
py22.course = python
linux57.course = linux
linux58.course = linux
print(py22.course.period)  # 6 months
print(linux57.course.price)  # 19800
linux.price = 21800  # 修改属性
print(linux57.course.price)  # 21800
print(linux58.course.price)  # 21800

继承

  • 解决代码的重复
# 继承语法:
class A:
    pass
class B(A):
    pass
# B继承A,A是父类,B是子类
# A是父类 基类 超类
# B是子类 派生类
# 子类可以使用父类中的:方法 静态变量
class Animal:
    def __init__(self,name):
        self.name = name
    def eat(self):
        print('%s is eating'%self.name)
    def drink(self):
        print('%s is drinking'%self.name)
    def sleep(self):
        print('%s is sleeping' % self.name)
class Cat(Animal):
    def climb_tree(self):
        print('%s is climbing'%self.name)
class Dog(Animal):
    def house_keep(self):
        print('%s house keeping'%self.name)

小白 = Cat('小白')
# 实例化:
    # 先开辟空间,空间有一个类指针-->指向Cat
    # 调用init,对象在自己空间中找init没找到,到Cat类中找init也没找到
    # 找父类Animal中的init
小白.eat()  # 小白 is eating
小白.climb_tree()  # 小白 is climbing

小黑 = Dog('小黑')
小黑.eat()  # 小黑 is eating
  • 当子类和父类中的方法重名的时候,我们只使用子类的方法,不会调用父类的方法
class Animal:
    def __init__(self,name):
        self.name = name
    def eat(self):
        print('%s is eating'%self.name)
class Cat(Animal):
    def eat(self):
        print('%s吃猫粮'%self.name)

小白 = Cat('小白')
小白.eat()  # 小白吃猫粮
  • 子类想要调用父类的方法的同时,还想执行自己的同名方法
    • 比如猫和狗在调用eat时,既调用自己的也调用父类的,
    • 在子类的方法中调用父类的方法:父类名.方法(self)
class Animal:
    def __init__(self,name,food):
        self.name = name
        self.food = food
        self.blood = 100
        self.waise = 100
    def eat(self):
        print('%s is eating %s'%(self.name,self.food))

class Cat(Animal):
    def eat(self):
        self.blood +=100
        Animal.eat(self)
    def climb_tree(self):
        print('%s is climbing'%self.name)
class Dog(Animal):
    def eat(self):
        self.waise +=100
        Animal.eat(self)
    def house_keep(self):
        print('%s house keeping'%self.name)

小白 = Cat('小白','猫粮')
小黑 = Dog('小黑','狗粮')
小白.eat()
小黑.eat()
print(小白.__dict__)
print(小黑.__dict__)
>>>小白 is eating 猫粮
>>>小黑 is eating 狗粮
>>>{'name': '小白', 'food': '猫粮', 'blood': 200, 'waise': 100}
>>>{'name': '小黑', 'food': '狗粮', 'blood': 100, 'waise': 200}

  • 父类和子类方法的选择
    • 子类的对象,如果取去用方法永远优先调用自己的
    • 如果自己有 用自己
    • 如果没有 用父类的
    • 如果自己有,还想用父类的:直接在子类方法中调用父类的方法:父类名.方法名(self)
  • 思考一:下面代码的输出
class Foo:
    def __init__(self):
        self.func()  # 在每一个self调用func的时候,我们不看这句话是在哪里执行,只看self是谁
    def func(self):
        print('in foo')

class Son(Foo):
    def func(self):
        print('in son')
Son()  # in son
  • 思考二:如何给猫定制个性的属性
class Animal:
    def __init__(self,name,food):
        self.name = name
        self.food = food
        self.blood = 100
        self.waise = 100
    def eat(self):
        print('%s is eating %s'%(self.name,self.food))
    def drink(self):
        print('%s is drinking'%self.name)
    def sleep(self):
        print('%s is sleeping' % self.name)

# 猫:eye_color眼睛的蓝色
class Cat(Animal):
    def __init__(self,name,food,eye_color):
        # Animal.__init__(self,name,food)  # 调用了父类的初始化,去完成一些通用属性的初始化
        super().__init__(name,food)
        self.eye_color = eye_color  # 派生属性
小白 = Cat('小白','猫粮','蓝色')
print(小白.__dict__)
  • 单继承
    • 调子类:子类自己有的时候
      调父类的:子类自己没有的时候
      调子类和父类的:子类父类都有,在子类中调用父类的
# class D:
#     def func(self):
#         print('in D')
# class C(D):
#     pass
# class A(C):
#     pass
# class B(A):
#     pass
# b = B()
# b.func()  # in D

# class D:
#     def func(self):
#         print('in D')
# class C(D):
#     pass
# class A(C):
#     def func(self):
#         print('in A')
# class B(A):
#     pass
# b = B()
# b.func()  # in A
  • 绑定方法和普通的函数
from types import FunctionType,MethodType
FunctionType : 函数
MethodType : 方法

isinstance            type
a = 1
b = 'abc'
print(isinstance(a,int))  # True
print(isinstance(a,float))  # False
print(isinstance(b,str))

a = 1
b = 'abc'
print(type(a) is int)
print(type(b) is str)


class Cat:
    pass
小白 = Cat()
print(type(小白) is Cat)  # <class '__main__.Cat'>  # True
print(isinstance(小白,Cat))

class Animal:
    pass
class Cat(Animal):
    pass
小白 = Cat()
print(type(小白) is Cat)  # True
print(type(小白) is Animal)  # False
print(isinstance(小白,Cat))  # True
print(isinstance(小白,Animal))  # True


绑定方法和普通的函数
from types import FunctionType,MethodType
FunctionType : 函数
MethodType : 方法
class A:
    def func(self):
        print('in func')

print(A.func)  # 函数  <function A.func at 0x000002477EA363A0>
a = A()
print(a.func)  # 方法  <bound method A.func of <__main__.A object at 0x000002477E9901C0>>
print(isinstance(a.func,FunctionType))  # False
print(isinstance(a.func,MethodType))  # True
print(isinstance(A.func,FunctionType))  # True
print(isinstance(A.func,MethodType))   # False
一:我们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值

二:特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串----查看注释
类名.__base__# 类的第一个父类
类名.__bases__# 类所有父类构成的元组
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中(python3))
class A:
    role = '法师'
    def func1(self):pass
    def func2(self):pass
class B:
    pass
class C(B,A):
    pass
print(A.__base__)  # <class 'object'>
print(C.__base__)  # <class '__main__.B'>
print(C.__bases__)  # (<class '__main__.B'>, <class '__main__.A'>)
print(A.__dict__)  # {'__module__': '__main__', 'role': '法师', 'func1': <function A.func1 at 0x0000024F54EB6430>, 'func2': <function A.func2 at 0x0000024F54EB64C0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
print(A.__name__)  # A
print(A.__class__)  # <class 'type'>
print(B.__class__)  # <class 'type'>
print(C.__class__)  # <class 'type'>
print(C.__module__)  # __main__

# __doc__:查看注释
def func():
    '''
    这个函数主要是用来卖萌
    :return:
    '''
    pass

print(func.__doc__)  
>>>
    这个函数主要是用来卖萌
    :return:

类的继承顺序

  • 只要继承object类就是新式类

  • 不继承object类的都是经典类

    扫描二维码关注公众号,回复: 9984274 查看本文章
    • python3 所有的类都继承object类,都是新式类
    • 在py2中 不继承object的类都是经典类
      • 继承object类的就是新式类了
  • 经典类 :在py3中不存在,在py2中不主动继承object的类

# 在py2中
class A:pass         # 经典类
class B(object):pass # 新式类
# 在py3中
class A:pass         # 新式类
class B(object):pass # 新式类
  • 深度优先
    • 在单继承方面(无论是新式类还是经典类都是一样的)
class A:
#     def func(self):pass
# class B(A):
#     def func(self):pass
# class C(B):
#     def func(self):pass
# class D(C):
#     def func(self):pass
# d = D()
# 寻找某一个方法的顺序:D->C->B->A
# 越往父类走,是深度
# 深度优先类:再找方法的时候,总是往深了找,一直找到头,没有再找下一条线
  • 经典类的多继承

    • 在经典类中,都是深度优先,总是在一条路走不通之后再换一条路,走过的点不会再走了
    • 深度优先类:再找方法的时候,总是往深了找,一直找到头,没有再找下一条线
  • 新式类的多继承

    • 广度优先
      • 在走到一个点,下一个点既可以从深度走,也可以从广度走的时候,总是先走广度,再走深度
    class A:
        def func(self):
            print('A')
    class B(A):
        pass
    class C(A):
        pass
    class D(B,C):
        pass
    
    # 查看在新式类中的继承顺序
    print(D.mro())  # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
    
    • mro练习
    class A:
        pass
    class B(A):
        pass
    class C(A):
        pass
    class D(B):
        pass
    class E(C):
        pass
    class F(D,E):
        pass
    print(F.mro())  # [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
    
  • # 广度优先遵循C3算法,要会用mro,会查看顺序
    # 经典类没有mro,但新式类有
    

super方法:

class A(object):
    def func(self):
        print('A')
class B(A):
    def func(self):
        super().func()
        print('B')
class C(B):
    def func(self):
        super().func()
        print('C')
C().func()  # A--B--C
class A(object):
    def func(self):
        print('A')
class B(A):
    def func(self):
        super().func()
        print('B')
class C(A):
    def func(self):
        super().func()
        print('C')
class D(B,C):
    def func(self):
        super().func()
        print('D')
D().func()
print(D.mro())  # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
  • 在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能
class Animal:
    '''
    人和狗都是动物,所以创造一个Animal基类
    '''
    def __init__(self, name, aggressivity, life_value):
        self.name = name  # 人和狗都有自己的昵称;
        self.aggressivity = aggressivity  # 人和狗都有自己的攻击力;
        self.life_value = life_value  # 人和狗都有自己的生命值;

    def eat(self):
        print('%s is eating'%self.name)

class Dog(Animal):
    '''
    狗类,继承Animal类
    '''
    def __init__(self,name,breed,aggressivity,life_value):
        super().__init__(name, aggressivity, life_value) #执行父类Animal的init方法
        self.breed = breed  #派生出了新的属性

    def bite(self, people):
        '''
        派生出了新的技能:狗有咬人的技能
        :param people:  
        '''
        people.life_value -= self.aggressivity

    def eat(self):
        # Animal.eat(self)
        #super().eat()
        print('from Dog')

class Person(Animal):
    '''
    人类,继承Animal
    '''
    def __init__(self,name,aggressivity, life_value,money):
        #Animal.__init__(self, name, aggressivity, life_value)
        #super(Person, self).__init__(name, aggressivity, life_value)
        super().__init__(name,aggressivity, life_value)  #执行父类的init方法
        self.money = money   #派生出了新的属性

    def attack(self, dog):
        '''
        派生出了新的技能:人有攻击的技能
        :param dog: 
        '''
        dog.life_value -= self.aggressivity

    def eat(self):
        #super().eat()
        Animal.eat(self)
        print('from Person')

egg = Person('egon',10,1000,600)
ha2 = Dog('二愣子','哈士奇',10,1000)
print(egg.name)
print(ha2.name)
egg.eat()

C3算法:

# 单继承
A(O) = [AO]   ------A继承O
B(A) = [BAO]
C(A) = [CAO]
D(B) = [DBAO]
E(C) = [ECAO]
# 多继承
F(D,E) = merge(D(B) + E(C))
         = [F] + [DBAO] + [ECAO]
       F = [DBAO] + [ECAO]
    FD   = [BAO] + [ECAO]
    FDB  = [AO] + [ECAO]
    FDBE = [AO] + [CAO]
    FDBEC= [AO] + [AO]
    FDBECA= [O] + [O]
    FDBECAO
  • 算法的内容
    • 如果是单继承 那么总是按照从子类->父类的顺序来计算查找顺序

    • 如果是多继承 需要按照自己本类,父类1的继承顺序,父类2的继承顺序,…

      • merge的规则 :如果一个类出现在从左到右所有顺序的最左侧,并且没有在其他位置出现,那么先提出来作为继承顺序中的一个
        • 或 一个类出现在从左到右顺序的最左侧,并没有在其他顺序中出现,那么先提出来作为继承顺序中的一个
        • 如果从左到右第一个顺序中的第一个类出现在后面且不是第一个,那么不能提取,顺序向后继续找其他顺序中符合上述条件的类
  • 经典类 - 深度优先 新式类 - 广度优先
    广度优先遵循C3算法,要会用mro,会查看顺序
    经典类没有mro,但新式类有

抽象类

  • 是一个开发的规范 约束他的所有子类必须实现一些和他同名的方法

super

  • super遵循mro算法
  • 只在新式类中能使用(不区分py2 py3)
  • 在py2中的新式类中,需要我们主动传递参数super(子类的名字,子类的对象).函数名()
class A(object):
    def func(self):
        print('A')
class B(A):
    def func(self):
        super().func()
        print('B')
class C(B):
    def func(self):
        super().func()
        print('C')
C().func()  # A--B--C
# class A(object):
#     def func(self):
#         print('A')
# class B(A):
#     def func(self):
#         super().func()
#         print('B')
# class C(A):
#     def func(self):
#         super().func()
#         print('C')
# class D(B,C):
#     def func(self):
#         super().func()
#         print('D')
# D().func()
# print(D.mro())  # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

封装

  • 把属性或者方法装起来

    • 广义 :把属性和方法装起来,外面不能直接调用了,要通过类的名字来调用
    • 狭义 :把属性和方法藏起来,外面不能调用,只能在内部偷偷调用
  • 给一个名字前面加上了双下划线的时候,这个名字就变成了一个私有的

    • 所有的私有的内容或者名字都不能在类的外部调 用,只能在类的内部使用了
    • 类的外部不能定义私有的概念
  • 所有的私有化都是为了让用户不在外部调用类中的某个名字

  • 如果完成私有化 那么这个类的封装度就更高了 封装度越高各种属性和方法的安全性也越高 但是代码越复杂

class User:
    def __init__(self,name,passwd):
        self.usr = name
        self.__pwd = passwd  # 私有的实例变量
alex = User('alex','sbsbsb')
print(alex.__pwd)  # 报错
print(alex.pwd)    # 报错

查看私有属性

class User:
    def __init__(self,name,passwd):
        self.usr = name
        self.__pwd = passwd  # 私有的实例变量/私有的对象属性
        
    def get_pwd(self):       # 表示的是用户不能改只能看 私有 + 某个get方法实现的
        return self.__pwd
alex = User('alex','sbsbsb')
print(alex.get_pwd())  # sbsbsb

修改私有属性

class User:
    def __init__(self,name,passwd):
        self.usr = name
        self.__pwd = passwd  # 私有的实例变量/私有的对象属性
    def get_pwd(self):       # 表示的是用户不能改只能看 私有 + 某个get方法实现的
        return self.__pwd
    def change_pwd(self):    # 表示用户必须调用我们自定义的修改方式来进行变量的修改 私用 + change方法实现
        pass
alex = User('alex','sbsbsb')
print(alex.get_pwd())
class User:
    __Country = 'China'   # 私有的静态变量
    def func(self):
        print(User.__Country)  # 在类的内部可以调用
        
# print(User.Country)  # 报错 在类的外部不能调用
# print(User.__Country)# 报错 在类的外部不能调用
User().func()
import  hashlib
class User:
    def __init__(self,name,passwd):
        self.usr = name
        self.__pwd = passwd  # 私有的实例变量

    def __get_md5(self):     # 私有的绑定方法
        md5 = hashlib.md5(self.usr.encode('utf-8'))  # 加盐处理
        md5.update(self.__pwd.encode('utf-8'))  # 使用update方法进行加密
        return md5.hexdigest()
	# 获取私有方法
    def getpwd(self):
        return self.__get_md5()
alex = User('alex','sbsbsb')
print(alex.getpwd())

加了双下划线的名字为啥不能从类的外部调用了?

class User:
    __Country = 'China'   # 私有的静态变量
    __Role = '法师'   # 私有的静态变量
    def func(self):
        print(self.__Country)  # 在类的内部使用的时候,自动的把当前这句话所在的类的名字拼在私有变量前完成变形
print(User.__dict__)
print(User._User__Country)  # 不建议使用
print(User._User__Role)  # 不建议使用
# __Country -->'_User__Country': 'China'
# __Role    -->'_User__Role': '法师'
User.__aaa = 'bbb'  # 在类的外部根本不能定义私有的概念
print(User.__dict__)

私有的内容能不能被子类使用呢? 不能

class Foo(object):
    def __init__(self):
        self.__func()  #只会与自己所在的类为准,即调用_Foo__func
    def __func(self):  # 变形为 _Foo__func
        print('in Foo')
class Son(Foo):
    def __func(self):  # 变形为 _Son__func
        print('in Son')
Son()  # in Foo
class Foo(object):
    def __func(self):
        print('in Foo')
class Son(Foo):
    def __init__(self):
        self.__func()
Son()  # AttributeError: 'Son' object has no attribute '_Son__func'

在其他语言中的数据的级别都有哪些?在python中有哪些

# public  公有的 类内类外都能用,父类子类都能用         python支持
# protect 保护的 类内能用,父类子类都能用,类外不能用    python不支持
# private 私有的 本类的类内部能用,其他地方都不能用     python支持

@property装饰器

  • 把一个方法伪装成一个属性,在调用这个方法的时候 不需要加() 就可以直接得到返回值
  • 变量的属性和方法?
    • 属性 :圆形的半径\圆形的面积
    • 方法 :登录 注册
from math import pi
class Circle:
    def __init__(self,r):
        self.r = r
        
    @property   # 把一个方法伪装成一个属性,在调用这个方法的时候不需要加()就可以直接得到返回值 
    def area(self):
        return pi * self.r**2

c1 = Circle(5)
print(c1.r)
print(c1.area)
  • 装饰的这个方法 不能有参数
import time
class Person:
    def __init__(self,name,birth):
        self.name = name
        self.birth = birth
    @property
    def age(self):   # 装饰的这个方法 不能有参数
        return time.localtime().tm_year - self.birth

太白 = Person('太白',1998)
print(太白.age)  # 22
  • 私有的属性合作的
class User:
    def __init__(self,usr,pwd):
        self.usr = usr
        self.__pwd = pwd
    @property
    def pwd(self):
        return self.__pwd

alex = User('alex','sbsbsb')
print(alex.pwd)
# 商业大酬宾
class Goods:
    discount = 0.8  # 静态变量
    def __init__(self,name,origin_price):
        self.name = name
        self.__price = origin_price
    @property
    def price(self):
        return self.__price * self.discount

apple = Goods('apple',5)
print(apple.price)

进阶

  • 给伪装的数学的方法赋值 @函数名.setter 装饰器
class Goods:
    discount = 0.8
    def __init__(self,name,origin_price):
        self.name = name
        self.__price = origin_price
    @property
    def price(self):
        return self.__price * self.discount
    # 修改价格
    @price.setter
    def price(self,new_value):
        if isinstance(new_value,int):
            self.__price = new_value

apple = Goods('apple',5)
print(apple.price)   # 调用的是被@property装饰的price   # 4.0    获取商品价格
apple.price = 10     # 调用的是被setter装饰的price       		 修改商品原价
print(apple.price)  # 8.0
class Goods:
    discount = 0.8
    def __init__(self,name,origin_price):
        self.name = name
        self.__price = origin_price
    @property
    def price(self):
        return self.__price * self.discount

    @price.setter
    def price(self,new_value):
        if isinstance(new_value,int):
            self.__price = new_value

    @price.deleter
    def price(self):
        del self.__price
apple = Goods('apple',5)
print(apple.price)
apple.price = 10
del apple.price    # 并不能真的删除什么,只是调用对应的被@price.deleter装饰的方法而已
print(apple.price)

反射

  • 通过字符串的形式操作对象相关的属性

    • 1.反射对象的 实例变量/绑定方法

    • class Person:
          def __init__(self,name,age):
              self.name = name
              self.age = age
          def qqxing(self):
              print('qqxing')
      
      alex = Person('alex',83)
      wusir = Person('wusir',74)
      # 对象名.属性名 ==> getattr(对象名,'属性名')
      ret = getattr(alex,'name')
      print(ret)
      ret = getattr(wusir,'name')
      print(ret)
      ret = getattr(wusir,'qqxing')
      print(ret)  # <bound method Person.qqxing of <__main__.Person object at 0x000001C33615E790>>
      print(wusir.qqxing)  # <bound method Person.qqxing of <__main__.Person object at 0x000001CD724AE790>>
      ret()
      
    • 2.反射类的 静态变量/其他方法

      • class A:
            Role = '治疗'  # 静态变量
            def __init__(self):
                self.name = 'alex'
                self.age = 84
            def func(self):
                print('wahaha')
                return 666
        
        a = A()
        print(getattr(a,'name')) # 反射对象的实例变量
        print(getattr(a,'func')()) # 反射对象的绑定方法
        print(getattr(A,'Role'))  # 反射静态变量
        
    • 3.模块中的 所有变量

      • # import a   # 引用模块中的任意的变量
        # print(getattr(a,'sww'),a.sww)  # <function sww at 0x0000023D5E73A940> <function sww at 0x0000023D5E73A940>
        #
        # getattr(a,'sww')()  # 爽歪歪
        # print(getattr(a,'lst'),a.lst)  # [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
        # print(getattr(a,'dic'),a.dic)  # {'k': 'v'} {'k': 'v'}
        # print(getattr(a,'we'),a.we)  # <a.Wechat object at 0x0000023D5E7309D0> <a.Wechat object at 0x0000023D5E7309D0>
        
      • 被导入的模块

        • a.py文件:
          class Wechat:pass
          class Alipay:pass
          
          def sww():
              print('爽歪歪')
          lst = [1,2,3,4,5]
          dic = {'k':'v'}
          we = Wechat()
          
          py文件
          import a
          print(a.Wechat)  # <class 'a.Wechat'>
          print(a.Alipay)  # <class 'a.Alipay'>
          # 对象名.属性名 ==> getattr(对象名,'属性名')
          # a.Alipay ==> getattr(a,'Alipay')
          print(getattr(a, 'Alipay'))
          print(getattr(a, 'Wechat'))
          
          import a
          import sys
          print(sys.modules['a'])  # <module 'a' from 'E:\\老男孩22期\\面向对象\\day26\\a.py'>
          print(a)  # <module 'a' from 'E:\\老男孩22期\\面向对象\\day26\\a.py'>
          print(sys.modules['a'].Alipay)  # <class 'a.Alipay'>
          print(a.Alipay)  # <class 'a.Alipay'>
          print(getattr(a,'Alipay'))  # <class 'a.Alipay'>
          print(getattr(sys.modules['a'],'Alipay'))  # <class 'a.Alipay'>
          
      • 当前执行的py文件 - 脚本(反射本文件中的内容)

      • wahaha = 'hahaha'
        print(getattr(sys.modules['__main__'],'wahaha'))
        
        import sys # 反射本模块中的名字
        cat = '小a'
        dog = '小b'
        def pig():
            print('小p')
        print(getattr(sys.modules['__main__'],'cat'))  # 小a
        print(getattr(sys.modules['__main__'],'dog'))  # 小b
        getattr(sys.modules['__main__'],'pig')()  # 小p
        
      • 反射的例子

class Payment:
    pass
class Alipay(Payment):
    def __init__(self,name):
        self.name = name
    def pay(self,money):
        dic = {'uname':self.name,'price':money}
        print('%s通过支付宝支付%s钱成功'%(self.name,money))

class WeChat(Payment):
    def __init__(self,name):
        self.name = name
    def pay(self,money):
        dic = {'username':self.name,'money':money}
        print('%s通过微信支付%s钱成功'%(self.name,money))

class Apple(Payment):
    def __init__(self,name):
        self.name = name
    def pay(self,money):
        dic = {'name': self.name, 'number': money}
        print('%s通过苹果支付%s钱成功' % (self.name, money))

class QQpay:
    def __init__(self,name):
        self.name = name
    def pay(self,money):
        print('%s通过qq支付%s钱成功' % (self.name, money))
import sys
def pay(name,price,kind):
    class_name = getattr(sys.modules['__main__'],kind)
    obj = class_name(name)
    obj.pay(price)
    # if kind == 'Wechat':
    #     obj = WeChat(name)
    # elif kind == 'Alipay':
    #     obj = Alipay(name)
    # elif kind == 'Apple':
    #     obj = Apple(name)
    # obj.pay(price)

pay('alex',400,'WeChat')
pay('alex',400,'Alipay')
pay('alex',400,'Apple')
pay('alex',400,'QQpay')
  • 与反射有关的内置函数 callable
class A:
    Role = '治疗'
    def __init__(self):
        self.name = 'alex'
        self.age = 84
    def func(self):
        print('wahaha')
        return 666

a = A()
# print(getattr(a,'sex'))  # AttributeError: 'A' object has no attribute 'sex'
# print(hasattr(a,'sex'))  # False
# print(hasattr(a,'age'))  # True
# print(hasattr(a,'func'))  # True
# 检测是否含有某属性
if hasattr(a,'func'):
    # 检查一个对象是否是可调用的
    if callable(getattr(a,'func')):
        getattr(a,'func')()  # wahaha

getattr

def getattr(object, name, default=None): # known special case of getattr
    """
    getattr(object, name[, default]) -> value
    
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
    """
    pass

@classmethod

  • 被装饰的方法会成为一个类方法

  • 定义了一个方法,默认传self,但是这个self没有被使用

classmethod
class Goods:
    __discount = 0.8
    def __init__(self):
        self.__price = 5
        self.price = self.__price*self.__discount
    def change_discount(self,new_discount):
        # 不能写self.__discount  ---->在self的命名空间创建
        Goods.__discount = new_discount
# 定义了一个方法,默认传self,但是这个self没有被使用
apple = Goods()
# 调用实例变量
print(apple.price)  # 4.0
# 修改折扣
apple.change_discount(0.6)
apple2 = Goods()
print(apple2.price)  # 3.0
  • 把一个对象绑定的方法,修改成一个类方法
class Goods:
    __discount = 0.8
    def __init__(self):
        self.__price = 5
        self.price = self.__price*self.__discount

    @classmethod  # 把一个对象绑定的方法,修改成一个类方法
    def change_discount(cls,new_discount):
        # cls指向当前所在类的名字,而不是self指向对象的名字
        # print(cls,Goods)
        cls.__discount = new_discount
#
#
Goods.change_discount(0.6)  # 可以通过类名调用
apple = Goods()
print(apple.price)  # 3.0
apple.change_discount(0.5)  # 可以通过对象名调用
apple2 = Goods()
print(apple2.price)  # 2.5>
apple2 = Goods()
print(apple2.price)  # 3.0
  • 在自己的类里,做了对自己类的实例化
import time
class Date:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
    @classmethod
    def today(cls):
        struct_t = time.localtime()
        # 在自己的类里,做了对自己类的实例化
        date = cls(struct_t.tm_year,struct_t.tm_mon,struct_t.tm_mday)
        return date

date的对象 = Date.today()
print(date的对象.year)
print(date的对象.month)
print(date的对象.day)
  • 何时使用classmethod?
    • 1.定义了一个方法,默认传self,但是这个self没有被使用
    • 2.并且在这个方法里用到了当前的类名,或者你准备使用这个类的内存空间的名字的时候
  • classmethod:
    • 1.在方法中可以引用类中的静态变量
    • 2.可以不用实例化对象,就直接用类名在外部调用这个方法
      • 可以通过类名调用
      • 可以通过对象名调用

@staticmethod

  • 被装饰的方法会成为一个静态方法
  • 什么时候用?
    • 帮助我们把一个普通的函数挪动到类中来直接使用,制造静态方法用的
class Uers():
    pass

    @staticmethod
    def login(a,b):  # 本身是一个普通的函数,被移动到类的内部执行,直接给这个函数添加staticmethod装饰器
        print('登录的逻辑',a,b)
        # 在函数的内部既不会用到self(对象)变量,也不会用到cls类

obj = User()
# 通过类名.方法名   调用
Uers.login(1,2)
  • 能定义到类中的内容
    • 静态变量 是个所有的对象共享的变量 由对象\类调用 不能重新赋值

    • 绑定方法 是个自带self参数的函数 由对象调用

    • 类方法 是个自带cls参数的函数 由对象\类调用

    • 静态方法 是个啥都不带的普通函数 由对象\类调用

    • property属性 是个伪装成属性的方法 由对象调用,但不加()

class A:
    country = '中国'  # 静态变量
    def func(self):  # 绑定方法
        print(self.__dict__)
    @classmethod  # 类方法
    def clas_func(cls):
        print(cls)
    @staticmethod  # 静态方法
    def stat_func():
        print('这是一个普通函数')
    @property  # 将一个方法伪装成属性
    def name(self):
        return 'wahaha'

魔术方法

new

  • 实例化的时候
    • 先创建一块空间,有一个指针能指向类—>new
    • 然后调用init
class A:
    def __new__(cls, *args, **kwargs):  # 构造方法
        print('执行new')
        return super().__new__(cls)
    def __init__(self):
        print('执行init')

A()
执行我了
执行init
class A:
    def __new__(cls, *args, **kwargs):  # 构造方法
        o = super().__new__(cls)
        print('执行new',o)
        return o
    def __init__(self):
        print('执行init',self)

A()

设计模式 – 单例模式

  • 一个类 从头到尾 只会创建一次 self的空间
class Baby:
    def __init__(self,cloth,pants):
        self.name = cloth
        self.age = pants

# 开辟了两块内存空间
b1 = Baby('红毛衣','绿皮库')
b2 = Baby('白衬衫','黑豹文')
print(b1)  # <__main__.Baby object at 0x0000027BD7914580>
print(b2)  # <__main__.Baby object at 0x0000027BD792EDC0>

# 只开辟一块内存空间
class Baby:
    __instance = None
    def __new__(cls,*args,**kwargs):
        if cls.__instance is None:
            cls.__instance = super().__new__(cls)
        return cls.__instance

    def __init__(self,cloth,pants):
        self.cloth = cloth
        self.pants = pants


b1 = Baby('红毛衣','绿皮库')
print(b1.cloth)  # 红毛衣
b2 = Baby('白衬衫','黑豹文')
print(b1.cloth)  # 白衬衫
print(b2.cloth)  # 白衬衫

call

  • 对象() 调用这个类中的__call__方法
# callable(对象)
# 对象() 能不能运行就是callable判断的事儿

class A:
    def __call__(self, *args, **kwargs):
        print('-------')

obj = A()
print(callable(obj))  # True
obj()  # 对象()   调用__call__
A()()  # A()--对象  A()()--对象()
# Flask框架的源码

len

  • len(对象) 需要实现这个类中的__len__方法
class Cls:
    def __init__(self,name):
        self.name = name
        self.students= []

py22 = Cls('py22')
py22.students.append('杜相玺')
py22.students.append('董宇航')
py22.students.append('大壮')
# 查看班里有几个同学
print(len(py22.students))  # 3
class Cls:
    def __init__(self,name):
        self.name = name
        self.students= []
    def __len__(self):
        return len(self.students)
py22 = Cls('py22')
py22.students.append('杜相玺')
py22.students.append('董宇航')
py22.students.append('大壮')
# 查看班里有几个同学
print(len(py22))  # len(对象) 需要实现这个类中的__len__方法
class Pow():
    def __init__(self,n):
        self.n = n
    def __pow2__(self):
        return self.n**2
def pow2(obj):
    return obj.__pow2__()
obj = Pow(10)
print(pow2(obj))

str__和__repr

class Course:
    def __init__(self,name,price,period):
        self.name = name
        self.price = price
        self.period = period
    def __str__(self):
        return self.name
python = Course('python',21800,'6 months')
linux = Course('linux',19800,'5 months')
mysql = Course('mysql',12800,'3 months')
go = Course('go',15800,'4 months')
# 在打印一个对象的时候 调用__str__方法

print(go)  # go
lst = [python,linux,mysql,go]
for index,c in enumerate(lst,1):  # enumerate内置函数
	# 用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标
    print(index,c)
num = int(input('>>>'))
course = lst[num-1]
print('恭喜您选择的课程为 %s  价格%s元'%(course.name,course.price))
class clas:
    def __init__(self):
        self.student = []
    def append(self,name):
        self.student.append(name)
    def __str__(self):  # 只能返回一个字符串数据类型
        return str(self.student)

py22 = clas()
py22.append('大壮')
print(py22)  # ['大壮']-----字符串数据类型
# 在str一个对象的时候 调用__str__方法
print(str(py22))  # ['大壮']
# 在%s拼接一个对象的时候 调用__str__方法
print('我们py22班 %s'%py22)  # 我们py22班 ['大壮']
print(py22)  # ['大壮']
py22.append('大壮')
print(py22)  # ['大壮', '大壮']
  • 在打印一个对象的时候 调用__str__方法
  • 在%s拼接一个对象的时候 调用__str__方法
  • 在str一个对象的时候 调用__str__方法
class clas:
    def __init__(self):
        self.student = []
    def append(self,name):
        self.student.append(name)
    def __repr__(self):  # 只能返回一个字符串数据类型
        return str(self.student)

py22 = clas()
py22.append('大壮')

print(py22)  # ['大壮']-----字符串数据类型

print(str(py22))  # ['大壮']

print('我们py22班 %s'%py22)  # 我们py22班 ['大壮']

print(py22)  # ['大壮']
py22.append('大壮')
print(py22)  # ['大壮', '大壮']
  • 当我们打印一个对象 或用%s进行字符串拼接 或者str(对象)总是调用这个对象的__str__方法

  • 如果找不到__str__,就调用__repr__方法

  • __repr__不仅是__str__的替代品,还有自己的功能

  • 用**%r进行字符串拼接** 或者用repr(对象)的时候总是调用这个对象的__repr__方法

class clas:
    def __init__(self):
        self.student = []
    def append(self,name):
        self.student.append(name)
    def __repr__(self):
        return str(self.student)
    def __str__(self):
        return 'aaa'

py22 = clas()
py22.append('大壮')
print(py22)  # aaa
print(str(py22))  # aaa
print('我们py22班 %s'%py22)  # 我们py22班 aaa
print('我们py22班 %r'%py22)  # 我们py22班 ['大壮']
print(repr(py22))  # ['大壮']
发布了6 篇原创文章 · 获赞 33 · 访问量 3108

猜你喜欢

转载自blog.csdn.net/qq_35632689/article/details/104922452