• python面向对象


    1,什么是对象,

      对象 即类   在python中将要描述的东西或者事物用类来表示 作为对象,

    2对象的特点

      1封装:将要表示的对象具有的属性定义好,或者动作

      2继承:子类将自动拥有父类的非私有 类的属性

      3多态:即类的高度可扩展性

    3

    1. 简述编写类和执行类中方法的流程
      class Car:
          def __init__(self,color,speed):
              self.color=color
              self.speed=speed
          def msg(self):
              print("%s的车以%s的速度跑着"%(self.color,self.speed))
      my_car=Car("金色","80码")
      my_car.msg()
      》》》金色的车以80码的速度跑着  
      1. 将以下函数改成类的方式并调用:
         def func(a1):
              print(a1)
    class func:
        def func(self,a1):
            print(a1)

    方法和函数的区别?

    
    

    首先摒弃错误认知:并不是类中的调用都叫方法

    
    

    看举例看代码


    class
    Foo(object): def func(self): pass #实例化 obj = Foo() # 执行方式一:调用的func是方法 obj.func() #func 方法 # 执行方式二:调用的func是函数 Foo.func(123) # 函数

    是的!例子中很明确,类对象调用func是方法,类调用func是函数,并且是自己传递参数123!

    最大的区别是参数的传递参数,方法是自动传参self,函数是主动传参

    那么以后我们就可以直接看参数是如何传递的来判断,

    如果还不确定可以打印类型看看

    from types import FunctionType,MethodType
    print(isinstance(obj.func,MethodType))    ---># True
    print(isinstance(Foo.func,FunctionType))  ---># True     

    什么是构造方法?

    构造方法与其他普通方法不同的地方在于,当一个对象被创建后,会立即调用构造方法。

    在python中创建一个构造方法很简单,只需要把init方法的名字从简单的init修改为魔法版本__init__即可。

    class foobar:

      def __init__(self):

        self.somevar = 42

    >>> f = foobar()
    >>> f.somevar
    42

    如果给构造方法传递几个参数的话,会怎么样呢?

    >>> class foobar:
    ...     def __init__(self, value = 42):
    ...             self.somevar = value
    ... 
    >>> f = foobar('this is a test')
    >>> f.somevar
    'this is a test'

    **************************************************************************

     重写一般方法和特殊的构造方法

    每个类都可能有一个或者多个超类,它们从超类那里继承行为方式,如果一个方法在b类的一个实例中被调用,但在b类中没有找到该方法,那么就去它的超类a里面找

    class a:

      def hello(self):

        print "hello,i'am a."

    class b(a)

    a类定义了一个叫做hello的方法,被b类继承,下面是一个说明类是如何工作的列子

    >>>A = a()

    >>>B = b()
    >>>A.hello()hello,i'am a

    >>>B.hello()

    hello,i'am a

    因为b类没有定义自己的hello方法,所以当hello被调用的时候,原始的信息就被打印出来。

    在子类中增加功能的最基本的方法就是增加方法,但是也可以重写一些超类的方法来自定义继承的行为。b类也能重写这个方法,比如下面的列子中b类的定义被修改了。

    class b(a):

      def hello(self):

        print "hello,i'am b."

    重写是继承机制中的一个重要内容,对于构造方法尤其重要,构造方法用来初始化新创建的对象的状态,大多数子类不仅要拥有自己的初始化代码,还要拥有超类的初始化代码,虽然重写的机制对于所有方法来说都是一样的,但是当重写构造方法和普通重写方法更容易遇到特别的问题,比如,如果一个类的构造方法被重写,那么就需要调用超类的构造方法,否则,对象可能不会被正确的初始化。

    面向对象中的self指的是什么?

    刚开始学习Python的类写法的时候觉得很是麻烦,为什么定义时需要而调用时又不需要,为什么不能内部简化从而减少我们敲击键盘的次数? 你看完这篇文章后就会明白所有的疑问。 self代表类的实例,而非类。 实例来说明

    class Test:
        def prt(self):
            print(self)
            print(self.__class__)
     
    t = Test()
    t.prt()

    执行结果如下

    <__main__.Test object at 0x000000000284E080>
    <class '__main__.Test'>
    

      从上面的例子中可以很明显的看出,self代表的是类的实例。而self.__class__则指向类。 self不必非写成self 有很多童鞋是先学习别的语言然后学习Python的,所以总觉得self怪怪的,想写成this,可以吗? 当然可以,还是把上面的代码改写一下。

    class Test:
        def prt(this):
            print(this)
            print(this.__class__)
     
    t = Test()
    t.prt()

    改成this后,运行结果完全一样。 当然,最好还是尊重约定俗成的习惯,使用self。 self可以不写吗 在Python的解释器内部,当我们调用t.prt()时,实际上Python解释成Test.prt(t),也就是说把self替换成类的实例。 有兴趣的童鞋可以把上面的t.prt()一行改写一下,运行后的实际结果完全相同。 实际上已经部分说明了self在定义时不可以省略,如果非要试一下,那么请看下面: 

    class Test:
        def prt():
            print(self)
     
    t = Test()
    t.prt()

    运行时提醒错误如下:prt在定义时没有参数,但是我们运行时强行传了一个参数。 由于上面解释过了t.prt()等同于Test.prt(t),所以程序提醒我们多传了一个参数t。

    Traceback (most recent call last):
      File "h.py", line 6, in <module>
        t.prt()
    TypeError: prt() takes 0 positional arguments but 1 was given

    当然,如果我们的定义和调用时均不传类实例是可以的,这就是类方法。

    class Test:
        def prt():
            print(__class__)
    Test.prt()

    运行结果如下 <class '__main__.test'=""> 

    在继承时,传入的是哪个实例,就是那个传入的实例,而不是指定义了self的类的实例。

    class Parent:
        def pprt(self):
            print(self)
     
    class Child(Parent):
        def cprt(self):
            print(self)
    c = Child()
    c.cprt()
    c.pprt()
    p = Parent()
    p.pprt()

    运行结果如下 

    <__main__.Child object at 0x0000000002A47080>
    <__main__.Child object at 0x0000000002A47080>
    <__main__.Parent object at 0x0000000002A47240>

    解释: 运行c.cprt()时应该没有理解问题,指的是Child类的实例。 但是在运行c.pprt()时,等同于Child.pprt(c),所以self指的依然是Child类的实例,由于self中没有定义pprt()方法,所以沿着继承树往上找,发现在父类Parent中定义了pprt()方法,所以就会成功调用。 在描述符类中,self指的是描述符类的实例 不太容易理解,先看实例:

    class Desc:
        def __get__(self, ins, cls):
            print('self in Desc: %s ' % self )
            print(self, ins, cls)
    class Test:
        x = Desc()
        def prt(self):
            print('self in Test: %s' % self)
    t = Test()
    t.prt()
    t.x
    self in Test: <__main__.Test object at 0x0000000002A570B8>
    self in Desc: <__main__.Desc object at 0x000000000283E208>
    <__main__.Desc object at 0x000000000283E208> <__main__.Test object at 0x0000000002A570B8> <class '__main__.Test'>

    题外话:由于在很多时候描述符类中仍然需要知道调用该描述符的实例是谁,所以在描述符类中存在第二个参数ins,用来表示调用它的类实例,所以t.x时可以看到第三行中的运行结果中第二项为。而采用Test.x进行调用时,由于没有实例,所以返回None。 总结 self在定义时需要定义,但是在调用时会自动传入。 self的名字并不是规定死的,但是最好还是按照约定是用self self总是指调用时的类的实例。 以上所有代码在Python3.4中均测试通过。

    class cirle:
        def __init__(self,PI):
            self.PI=PI
        def s(self,r):
            return self.PI*r**2
        def long(self,r):
            return 2*self.PI*r
    cirle=cirle(3.14)
    print(cirle.s(3))
    print(cirle.long(3))

    面向对象中为什么要有继承?

    继承
    我们不想把同一段代码写好几,之前使用的函数避免了这种情况。但现在又有个更微妙的问题。如果已经有了一个类,又想建立一个非常类似的类,只是添加几个方法。
    比如有动物类,我们又想在动物类的基础上建立鸟类、鱼类,哺乳动物类。

    面向对象的第二个特征是继承。

    可以将多个类共有的方法提取到父类中,子类仅需继承父类;

    基本语法为class新类名(父类1,父类2,..)

    单继承与多继承区别:   

    Python同时支持单继承与多继承,当只有一个父类时为单继承,当存在多个父类时为多继承。

    继承的性质特征:

    子类会继承父类的所有的属性和方法,子类也可以覆盖父类同名的变量和方法。

    调用方法执行顺序:(见案例)

    在调用方法时,先调用子类自己的方法,子类无,再去父类中查找。查找顺序是自左(从上往下)向右。

    如果多个父类,再无共同的父类,则自左执行到顶,再往右执行。

    如果有共同的父类,则自左执行到倒数第二层,再向右执行,最后再执行最顶层。

    640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

    案例1:

    F2继承F1:类似于把F1中的功能在F2中又写了一遍,如果有一个方法F2自己无,则去父类F1中去找找看

    class F1:#父类,基类
      def show(self):
    print('show')
    def foo(self):
    print(self.name)
    class F2(F1):#把F1的方法再次引用到F2;子类、派生类
      def __init__(self,name):
    self.name=name
    def bar(self):
    print('bar')
    def show(self):
    print('F2.show')
    obj=F2('hh')
    print('-----foo方法执行结果--------')
    obj.foo()#执行结果:hh,需要去父类里面找
    print('-----show方法执行结果--------')
    obj.show()#执行结果F2.show,优先执行自己的方法,再执行父类的方法

    执行结果:

    0?wx_fmt=png

    案例2:如果父类和子类有相同的方法,则优先执行子类自己的方法,如果子类无再去父类找

    #self一直代表的是对象自己
    # 如果一个方法,自己有,则执行自己的方法,如果自己没有,再去往上去父类寻找
    class S1:
    def F1(self):
    self.F2()
    def F2(self):
    print('S1.F2')
    class S2(S1):
    def F3(self):
    self.F1()
    def F2(self):
    print('S2.F2')

    print('----S1.F2-------------')
    #实例化s1
    obj1 = S1()
    obj1.F1() # 先去S1执行F1,再看S1中有没有F2,有,则执行自己的F2
    print('----S2.F3-------------')
    #实例化s2
    obj2=S2()
    #1)先去s2执行F3,因为s2自己无F1,去S1中执行F1,F1方法需要执行F2
    #2)self代表s2本身,因s2自己有F2,再执行S2的F2
    obj2.F3()

    执行结果:

    0?wx_fmt=png

    案例3:多继承,无共同的父类,执行顺序:从左(先往上)再往右。

    左右类无共同父类封顶的继承及执行的顺序:

    0?wx_fmt=png

    
    
    #先左,在左上,左上找到顶层,则再往右边的类找
    class c0:
    def f2(self):
    print('c0.f2')
    class c1(c0):
    def f1(self):
    print('c1.f1')
    class c2:
    def f2(self):
    print('c2.f2')
    def f4(self):
    print('c2.f4')
    class c3(c1,c2):
    def f3(self):
    pass
    obj=c3()#实例化c3对象
    print('------c3.f2-------')
    obj.f2()#先去找c3,c3无f2,再去c1,c1无f2,则去c0找
    print('------c3.f1-------')
    obj.f1()#先去找c3,c3无f1,再去c1
    print('------c3.f4-------')
    obj.f4()#先去找c3,c3无f4,再去c1,c1无f4,则去c0找,c0无f4,再去c2

    执行结果:

    0?wx_fmt=png

    案例4:多继承,有共同的父类,执行到倒数第二层,再向右执行0?wx_fmt=png

    #找到倒数第二层停止,再往后找,最后找共同

    class c0:
    def f4(self):
    print('c0.f2')
    class c_2(c0):
    def f2(self):
    print('c_2.f2')
    class c21(c_2):
    def f1(self):
    print('c21.f1')
    class c_1(c0):
    def f1(self):
    print('c_1.f2')
    class c11(c_1):
    def f1(self):
    print('c11.f1')
    class c3(c11,c21):
    def f3(self):
    print('c3.f3')
    #实例化对象
    obj=c3()
    obj.f3()#依次找寻c3找到,执行结果c3.f3
    obj.f1()#依次找寻c3,c11找到,执行结果c11.f1
    obj.f2()#依次找寻c3,c11,c_1,c21,c_2,找到,执行结果c_2.f2
    obj.f4()#依次找寻c3,c11,c_1,c21,c_2,c0找到,执行结果,c0.f2

    执行顺序:

    0?wx_fmt=png

    面向对象的第三个特征是多态:指参数的“有多种形式”、多种形态,意味着就算不知道变量所引用的对象类是什么,还是能对它进行操作,而它也会根据对象(或类)类型的不同而表现出不同的行为。

       其他编程语言如java在定义参数时,需要制定参数类型,且传入参数时,需要符合类型要求。但python基本上不用管这个特征,因为python定义变量时,可以不指定类型。如下案例,可以传入不同的参数类型,比如字典、列表、数字、string等。

    比如案例:

    def func(arg):
    print(arg)

    func(1)
    func("hh")
    func(["a","b",6])
    func({"a":1,"c":2})

    案例链接:https://pan.baidu.com/s/1skU53lV 密码:ifah

    # #案例1:F2继承F1,类似于把F1中的功能在F2中又写了一遍,如果有一个方法F2自己无,则去父类F1中去找找看
    # class F1:#父类,基类
    #     def show(self):
    #        print('show')
    #     def foo(self):
    #         print(self.name)
    # class F2(F1):#把F1的方法再次引用到F2;子类、派生类
    #     def __init__(self,name):
    #         self.name=name
    #     def bar(self):
    #         print('bar')
    #     def show(self):
    #         print('F2.show')
    # obj=F2('hh')
    # print('-----foo方法执行结果--------')
    # obj.foo()#执行结果:hh,需要去父类里面找
    # print('-----show方法执行结果--------')
    # obj.show()#执行结果F2.show,优先执行自己的方法,再执行父类的方法
     
    # #案例2:如果父类和子类有相同的方法,则优先执行子类自己的方法,如果子类无再去父类找
    # #self一直代表的是对象自己
    # # 如果一个方法,自己有,则执行自己的方法,如果自己没有,再去往上去父类寻找
    # class S1:
    #     def F1(self):
    #         self.F2()
    #     def F2(self):
    #         print('S1.F2')
    # class S2(S1):
    #     def F3(self):
    #         self.F1()
    #     def F2(self):
    #         print('S2.F2')
    #
    # print('----S1.F2-------------')
    # #实例化s1
    # obj1 = S1()
    # obj1.F1() # 先去S1执行F1,再看S1中有没有F2,有,则执行自己的F2
    # print('----S2.F3-------------')
    # #实例化s2
    # obj2=S2()
    # #1)先去s2执行F3,因为s2自己无F1,去S1中执行F1,F1方法需要执行F2
    # #2)self代表s2本身,因s2自己有F2,再执行S2的F2
    # obj2.F3()
     
     
    # #案例3:多继承,从左(先往上)再往右
    # #先左,在左上,左上找到顶层,则再往右边的类找
    # class c0:
    #     def f2(self):
    #         print('c0.f2')
    # class c1(c0):
    #     def f1(self):
    #         print('c1.f1')
    # class c2:
    #     def f2(self):
    #         print('c2.f2')
    #     def f4(self):
    #         print('c2.f4')
    # class c3(c1,c2):
    #     def f3(self):
    #         pass
    # obj=c3()#实例化c3对象
    # print('------c3.f2-------')
    # obj.f2()#先去找c3,c3无f2,再去c1,c1无f2,则去c0找
    # print('------c3.f1-------')
    # obj.f1()#先去找c3,c3无f1,再去c1
    # print('------c3.f4-------')
    # obj.f4()#先去找c3,c3无f4,再去c1,c1无f4,则去c0找,c0无f4,再去c2
     
    class c0:
        def f4(self):
            print('c0.f2')
    class c_2(c0):
        def f2(self):
            print('c_2.f2')
    class c21(c_2):
        def f1(self):
            print('c21.f1')
    class c_1(c0):
        def f1(self):
            print('c_1.f2')
    class c11(c_1):
        def f1(self):
            print('c11.f1')
    class c3(c11,c21):
        def f3(self):
            print('c3.f3')
    obj=c3()
    obj.f3()#依次找寻c3找到,执行结果c3.f3
    obj.f1()#依次找寻c3,c11找到,执行结果c11.f1
    obj.f2()#依次找寻c3,c11,c_1,c21,c_2,找到,执行结果c_2.f2
    obj.f4()#依次找寻c3,c11,c_1,c21,c_2,c0找到,执行结果,c0.f2
    View Code

    Python多继承时,查找成员的顺序遵循什么规则?

    python中使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承,也叫菱形继承问题)等

    MRO

    MRO即method resolution order,用于判断子类调用的属性来自于哪个父类。在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法,定义类时需要继承object,这样的类称为新式类,否则为旧式类

    从图中可以看出,旧式类查找属性时是深度优先搜索,新式类则是广度优先搜索

    C3算法最早被提出是用于Lisp的,应用在Python中是为了解决原来基于深度优先搜索算法不满足本地优先级,和单调性的问题。

    • 本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。
    • 单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序

    示例

    看下面的例子

    复制代码
    class X(object):
        def f(self):
            print 'x'
    
    class A(X):
        def f(self):
            print 'a'
    
    def extral(self):
            print 'extral a'
    
    class B(X):
        def f(self):
            print 'b'
    
    def extral(self):
            print 'extral b'
    
    class C(A, B, X):
        def f(self):
            super(C, self).f()
            print 'c'
    
    print C.mro()
    
    c = C()
    c.f()
    c.extral()
    复制代码

    根据广度搜索原则最先搜索到A,所以结果很明显,如下所示

    类C没有extral函数,调用的是子类的该函数。这种类的部分行为由父类来提供的行为,叫做抽象超类.

    补充代码实现:

    user_list = []
    while True:
            user = input(“请输入用户名:”)
            pwd = input(“请输入密码:”)
            email = input(“请输入邮箱:”)

    user_list = []
    class Account:
        def __init__(self,user,pwd,email):
            self.user=user
            self.pwd=pwd
            self.email=email
    while True:
        user = input("请输入用户名:")
        pwd = input("请输入密码:")
        email = input("请输入邮箱:")
        Account = Account(user, pwd, email)
        user_list.append(Account)
        if len(user_list)==3:
            for el in user_list:
                print("我叫%s,邮箱是%s"%(el.user,el.email))
            break

    补充代码

    class User:
        def __init__(self,name,pwd):
            self.name=name
            self.pwd=pwd
    class Account:
        def __init__(self):
            self.user_list=[]
        def login(self,input_user,input_pwd):
            self.input_user=input_user
            self.input_pwd=input_pwd
            if input_user=="bigc" and input_pwd=="123":
                print("恭喜登录成功!")
                return True
            else:
                return False
        def resiger(self,user,pwd):
            # self.user=input("输入用户名:")
            # self.pwd=input("输入密码:")
            self.user_list.append(user)
            self.user_list.append(pwd)
            f=open("User.txt",mode="a",encoding="utf-8")
            f.write(str(self.user_list)+"
    ")
            f.flush()
            f.close()
            return
        def run(self):
            Account.resiger(user=input("输入注册用户名:"),pwd=input("输入密码:"))
            Account.resiger(user=input("输入注册用户名:"),pwd=input("输入密码:"))
            count=0
            while count<3:
                if Account.login(input_user=input("输入你要登录的用户名:"),input_pwd=input("输入登录密码:")):
                    break
                else:
                    print("用户名或密码错误,你还剩%s次机会登录!"%(2-count))
                count+=1
            return
    Account=Account()
    Account.run()
    class User:
        def __init__(self,name,pwd):
            self.name=name
            self.pwd=pwd
    class Account:
        def __init__(self):
            self.user_list=[]
        def login(self,input_user,input_pwd):
            for el in self.user_list:
                if input_user==el.name and input_pwd==el.pwd:
                    print("恭喜登录成功!")
                    return True
            else:
                return False
        def resiger(self):
            user=input("输入用户名:")
            pwd=input("输入密码:")
            user
            self.user_list.append(User(user,pwd))
            for el in self.user_list:
                f=open("User.txt",mode="a",encoding="utf-8")
                f.write(str(el.name)+"_"+str(el.pwd)+"
    ")
                f.flush()
                f.close()
            return
        def run(self):
            Account.resiger()
            Account.resiger()
            count=0
            while count<3:
                if Account.login(input_user=input("输入你要登录的用户名:"),input_pwd=input("输入登录密码:")):
                    break
                else:
                    print("用户名或密码错误,你还剩%s次机会登录!"%(2-count))
                count+=1
            return
    Account=Account()
    Account.run()
    class User:
        def __init__(self,name,pwd):
            self.name=name
            self.pwd=pwd
    class Account:
        def __init__(self):
            self.user_list=[]
    
        def login(self):
            user = input("输入你要登录的用户名:")
            pwd = input("输入登录密码:")
            f = open("User.txt", mode="r", encoding="UTF-8")
            for line in f:
                if line.strip() == user+"_"+pwd:
                    f.close()
                    return True
            else:
                f.close()
                return False
        def chack_save(self,user, pwd): # wusir
            # 1. 检查用户名是否重复
            f = open("User.txt", mode="r+", encoding="utf-8")
            for line in f:
                if line == "": # 防止空行影响程序运行
                    continue
                user_info_username = line.split("_")[0]
                if user == user_info_username: # 用户名重复了
                    return False
            else:
                # 2. 写入到文件中
                f.write(user+"_"+pwd+"
    ")
    
            f.flush()
            f.close()
            return True
        def resiger(self):
            user=input("输入用户名:")
            pwd=input("输入密码:")
            self.chack_save(user,pwd)
        def run(self):
            self.resiger()
            self.resiger()
            count=0
            while count<3:
                if self.login():
                    break
                else:
                    print("用户名或密码错误,你还剩%s次机会登录!"%(2-count))
                count+=1
            return
    accunt=Account()
    accunt.run()
  • 相关阅读:
    设计模式学习笔记--迭代器模式
    设计模式学习笔记--组合模式
    设计模式学习笔记--备忘录模式
    Asp.Net Core IdentityServer4 中的基本概念
    Asp.Net Core 中间件应用实践中你不知道的那些事
    Asp.Net Core Filter 深入浅出的那些事-AOP
    ASP.NET CORE 内置的IOC解读及使用
    ASP.NET CORE 管道模型及中间件使用解读
    ASP.NET CORE 启动过程及源码解读
    Linux +Docker +Nginx 部署代理转发初探
  • 原文地址:https://www.cnblogs.com/bigc008/p/9699685.html
Copyright © 2020-2023  润新知