zoukankan      html  css  js  c++  java
  • [Python自学] day-7 (静态方法、类方法、属性方法、类的其他、类的来源、反射、异常处理、socket)

    一、类方法种类

    1.静态方法(@staticmethod)

    class Dog(object):
        def __init__(self):
            pass
    
        @staticmethod  
        def talk():   #静态方法
            pass

      静态方法与类没什么关系了,名义上归类管,但无法管理该方法。talk()中不自动传入self参数。

      注意:静态函数无法直接调用类或对象中的属性和方法,如果需要调用类属性和其他静态方法,需使用 类名.类属性名 或类名.静态方法名 来调用。如果需要调用对象属性和方法,则需要将对象作为参数传入静态函数,并使用该对象来调用。

    2.类方法(@classmethod)

    class Dog(object):
        type = "gloden"
    
        def __init__(self,name):
            self.name=name
    
        @staticmethod
        def talk():
            print("talking")
    
        def eat(self):
            pass
    
        @classmethod
        def foo(cls,hello):
            cls.talk()  #类方法中只能调用静态方法
            print(cls.type)  #类方法中只能调用类变量
    
    
    d = Dog("dd")
    d.foo("gogogo")

      上述代码中的foo就是一个类方法,第一个参数是cls,代表会自动将Dog类作为参数传入该方法。然后使用cls调用静态方法talk()。

      注意:类方法只能调用类中的静态方法,也只能调用类变量。

    3.属性方法(@property)

      将一个方法变为一个静态属性。看实例:

    class Flight(object):
        def __init__(self,name):
            self.name=name
    
        def check_status(self):     #航班实时状态只有航空公司知道,该函数调航空公司接口获取状态码
            print("check status of Flight [%s] ." % (self.name))
            return 1
    
        @property
        def flight_status(self):    #将该函数当做一个属性,但是可以实时的调用check_status方法来获取当前航班状态。(类似去哪儿网)
            stat = self.check_status()
            if stat == 0:
                print("Flight canceled")
            elif stat == 1:
                print("Flight arrived")
            elif stat == 2:
                print("Flight departured")
            else:
                print("Flight Can't confirmed")
            return stat
                
    f = Flight("CA980")
    s = f.flight_status     #用查看属性的方法来调用,并且可以使用变量接收返回值
    print(s)  #输出状态码1

      如果要给属性方法flight_status参数:

    class Flight(object):
        def __init__(self,name):
            self.name=name
            self.__test = None
    
        def check_status(self):     #航班实时状态只有航空公司知道,该函数调航空公司接口获取状态码
            print("check status of Flight [%s] ." % (self.name))
            return 1
    
        @property
        def flight_status(self):    #将该函数当做一个属性,但是可以实时的调用check_status方法来获取当前航班状态。(类似去哪儿网)
            stat = self.check_status()
            print(self.__test)  #在这里打印私有变量__test,
            if stat == 0:
                print("Flight canceled")
            elif stat == 1:
                print("Flight arrived")
            elif stat == 2:
                print("Flight departured")
            else:
                print("Flight Can't confirmed")
            return stat
    
        @flight_status.setter
        def flight_status(self,test):
            self.__test = test
    
    f = Flight("CA980")
    f.flight_status = "hello"  #使用setter传入参数test
    f.flight_status

      上述代码中使用@flight_status.setter来修饰flight_status(self,hello)方法。必须放在属性方法的后面,也就是说使用@flight_status.setter,前面必须已经存在flight_status属性方法。setter修饰的方法主要用来传参,将传入的参数test保存在一个私有属性中,在调用属性方法flight_status时就可以使用该私有属性了。

      

      如果要删除该私有属性:

    class Flight(object):
        def __init__(self,name):
            self.name=name
            self.__test = None
    
        def check_status(self):     #航班实时状态只有航空公司知道,该函数调航空公司接口获取状态码
            print("check status of Flight [%s] ." % (self.name))
            return 1
    
        @property
        def flight_status(self):    #将该函数当做一个属性,但是可以实时的调用check_status方法来获取当前航班状态。(类似去哪儿网)
            stat = self.check_status()
            print(self.__test)  #在这里打印私有变量__test,
            if stat == 0:
                print("Flight canceled")
            elif stat == 1:
                print("Flight arrived")
            elif stat == 2:
                print("Flight departured")
            else:
                print("Flight Can't confirmed")
            return stat
    
        @flight_status.setter   #给属性方法传参
        def flight_status(self,test):
            self.__test = test
    
        @flight_status.deleter  #删除属性方法关联的私有属性
        def flight_status(self):
            del self.__test
    
    f = Flight("CA980")
    f.flight_status = "hello"  #使用setter传入参数test
    del f.flight_status     #调用deleter删除__test
    f.flight_status   #这里因为删除了__test,所以会报错'Flight' object has no attribute '_Flight__test'

      总结:属性方法的目的就是隐藏实现细节,例如flight_status中的实现细节,对于用户来说看到的好像就是一个静态属性。

    四、类的其他内容

    1.__doc__

      __doc__:获取类的注释

    class Person(object):
        """这是一个描述人的类"""
        def __init__(self):
            pass
    
    print(Person.__doc__)

      上述代码中,使用""" """或者''' '''或者" "或者' '都可以。

    2.__module__

      __module__:获取当前操作的类或对象所属的类属于哪个模块

    #importfile.py
    
    class Dog(object):
        def __init__(self):
            pass
    #classother.py
    import importfile
    
    d = importfile.Dog()
    print(d.__module__)  #输出importfile

    3.__class__

      __class__:使用当前操作对象获取属于哪个类

    print(d.__class__)  #输出<class 'importfile.Dog'>

    4.__call__

      __call__:可以使用 对象名+括号的方式调用类中的__call__方法。

    class Dog(object):
        def __init__(self):
            pass
    
        def __call__(self,*args,**kwargs):
            print("__call__ ",args,kwargs)
    
    d = Dog()
    d(1,2,3,4,name="xiaohua")  #打印__call__  (1, 2, 3, 4) {'name': 'xiaohua'}

      或者使用类名()()调用:

    Dog()(1,2,3,4,name="xiaohua")

    5.__dict__

      __dict__:查看类或对象中的所有成员。

    class Dog(object):
        feet = 4
        def __init__(self,name,age):
            self.name = name
            self.__age = age
    
        def eat(self):
            pass
    
        def __call__(self,*args,**kwargs):
            print("__call__ ",args,kwargs)
    
    d = Dog("xiaohua",23)
    print(d.__dict__)  #{'name': 'xiaohua', '_Dog__age': 23} 对象里只有成员属性,不包含静态属性和方法(方法属于类)
    print(Dog.__dict__)  #{'__module__': '__main__', 'feet': 4, '__init__': <function Dog.__init__ at 0x0078F8E8>, 'eat': <function Dog.eat at 0x00794810>, '__call__': <function Dog.__call__ at 0x007948A0>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None}

    6.__str__

      __str__:默认打印一个对象信息。

    d = Dog("xiaohua",23)
    print(d)   #<__main__.Dog object at 0x00AEEC70>

      默认应该打印上述信息,描述一个对象属于的类和地址。

      可以通过重载__str__方法来修改该信息:

    class Cat(object):
        def __init__(self,name):
            self.name=name
    
        def __str__(self):
            return  "This is object [%s]" % (self.name)
    
    c = Cat("miaowu")
    print(c)  #打印This is object [miaowu]

    7.__getitem__、__setitem__、__delitem__

      __getitem__、__setitem__、__delitem__:使对象支持字典操作

    class Foo(object):
    
        def __getitem__(self,key):
            print("__getitem__",key)
    
        def __setitem__(self,key,value):
            print("__setitem__",key,value)
    
        def __delitem__(self,key):
            print("__delitem__",key)
    
    
    obj = Foo()
    result = obj["k1"]  #是对象可以像字典一样操作
    obj["k2"] = "Alex"
    del obj["k1"]

    8.__getattr__和__setattr__

    在python的类中,有两个很重要的特殊方法__getattr__(self,item)和__setattr__(self,key,value):

    class Foo(object):
        def __getattr__(self, item):
            print(item)
    
        def __setattr__(self, key, value):
            print(key, value)

    这两个方法是在使用该类对象进行"."操作的时候会被调用。例如:

    if __name__ == '__main__':
        obj = Foo()
        obj.name = 'Alex'  # __setattr__被调用,打印name Alex
        obj.age  # __getattr__被调用,打印age

    注意,我们平时在使用对象的"."操作时,一般不会定义这两个方法。所以默认情况下,都会找到object类的__setattr__和__getattr__来执行,而object类的这两个方法默认的功能就是设置属性和获取属性的值。

    如果我们在自己定义的类中重写了这两个方法,那么就可以自己设置"."操作的行为。

    考虑以下特殊场景:(构造函数的属性初始化也会触发__setattr__方法)

    class Foo(object):
        def __init__(self):
            self.storage = {}
    
        def __getattr__(self, item):
            print(item)
    
        def __setattr__(self, key, value):
            print(key, value)
    
    
    if __name__ == '__main__':
        obj = Foo()
        obj.name = 'Alex'

    在该类的构造方法中,我们初始化了一个对象属性storage。那么按照我们前面所叙述的__setattr__的触发机制。这里应该打印以下信息:

    storage {}
    name Alex

    即,构造函数中的self.storage = {}也会触发__setattr__方法。因为self代表Foo的对象obj(由__new__(Foo)产生),然后使用"."操作设置了storage。

    三、类怎么来的

    Python中一切皆对象,所以类也是对象,是type的实例化对象。

    1.通过Type类来产生类

      类定义的普通模式:

    class Foo(object):
        def __init__(self):
            pass
    
    f = Foo()

      类定义的特殊模式:

    def test_func(self):  #这里必须要有self,因为该方法要装载进类Goo中
        print("[name] : %s , [age] : %s" % (self.name,self.age))
    
    def init_func(self,name,age):  #给Goo定义一个__init__方法
        self.name=name
        self.age=age
    
    Goo = type("Goo",(object,),{"goo_func":test_func,"__init__":init_func})
    print(type(Goo))  #打印<class 'type'>
    
    g = Goo("Leo",32)
    print(type(g))  #打印<class '__main__.Goo'>
    g.goo_func()  #调用了前面定义好的test_func,goo_func是该方法在类中的方法名

       总结:类是由type类实例化产生的,哪type类是从哪里来的,答案是type是由python解释器直接实现的。

    2.__new__()

      __new__:用于实例化对象

    class Foo(object):
        def __init__(self,name):
            self.name = name
            print("Foo __init__")
    
        def __new__(cls, *args, **kwargs):  
            print("Foo __new__")
            return object.__new__(cls)
    
    f = Foo("Leo")  #在实例化f时,先执行的是__new__,后执行__init__

      如果将__new__中的return object.__new__(cls)注释掉:

    class Foo(object):
        def __init__(self,name):
            self.name = name
            print("Foo __init__")
    
        def __new__(cls, *args, **kwargs):
            print("Foo __new__")
            #return object.__new__(cls)
    
    f = Foo("Leo")  #只执行了__new__,而__new__中只进行了打印

      结论,说明__new__方法中返回的object.__new__(cls)真正实现了对f的实例化。而且__init__是由__new__来调用触发的。

    3.__metaclass__

      __metaclass__:用于指定类用哪个类来实例化(即用type还是自定义的type派生类)

       以python 2.7的类实例化过程为例(python 3.x有所不同,但大同小异)

    class Mytype(type):
        def __init__(self, what, bases=None, dict=None):
            print("---MyType init ---")
            super(Mytype,self).__init__(what, bases,dict)
    
        def __call__(self, *args, **kwargs):
            print("---MyType call---")
            obj = self.__new__(self, *args, **kwargs)
            self.__init__(obj, *args, **kwargs)
    
    class Foo(object):
        __metaclass__ = Mytype
    
        def __init__(self,name):
            self.name = name
            print("Foo __init__")
    
        def __new__(cls, *args, **kwargs):
            print("Foo __new__")
            return object.__new__(cls)
    
    f = Foo("Leo") 

      以上代码是使用MyType类来实例化Foo类,然后实例化Foo的对象f。

      如果把__call__中的最后两句代码注释掉,则Foo中的__new__和__init__都不会执行。具体的执行过程如下图:

      过程解释:

      1.MyType默认调用type父类的__new__产生一个类实例,即Foo。

      2.然后调用__init__初始化Foo。

      3.obj实例化的时候,MyType中的__call__会执行

      4.__call__中调用Foo中的__new__来生成obj实例

      5.__call__调用Foo中的__init__来初始化obj实例

    四、反射

    1.hasattr()

    hasattr(obj,"func_name"):判断一个对象中是否存在指定方法。

    class Dog(object):
        def __init__(self,name):
            self.name = name
    
        def eat(self,food):
            print("%s is eating %s" % (self.name,food))
    
    d = Dog("XiaoHua") #初始化d
    func_name = input(":>>").strip()  #输入想调用的方法名
    
    print(hasattr(d,func_name))  #输入eat,打印true

    2.getattr()

    getattr():获取该方法指针。并执行。

    class Dog(object):
        def __init__(self,name):
            self.name = name
    
        def eat(self,food):
            print("%s is eating %s" % (self.name,food))
    
    d = Dog("XiaoHua") #初始化d
    func_name = input(":>>").strip()  #输入想调用的方法名
    
    if hasattr(d,func_name):  #输入eat,打印true
        func = getattr(d,func_name)  #获取成员方法指针
        func("Baozi")   #调用该方法

    3.setattr()

    setatter(x,y,v):给对象添加属性或方法用,参数解释:x.'y' = v,x是对象,'y'是字符串,z是该属性的值。若要添加方法,v就是一个方法指向的地址。

    def bulk(self):
        print("%s is yelling" % {self.name})
    
    class Dog(object):
        def __init__(self,name):
            self.name = name
    
        def eat(self,food):
            print("%s is eating %s" % (self.name,food))
    
    d = Dog("XiaoHua") #初始化d
    func_name = input(":>>").strip()  #输入想调用的方法名
    
    if hasattr(d,func_name):  #输入eat,打印true
        func = getattr(d,func_name)  #获取成员方法指针
        func("Baozi")   #调用该方法
    else:
        setattr(d,func_name,bulk)  #假设输入的方法名是hello,对象d中会被创建一个叫hello(self)的成员方法
    
        func = getattr(d,func_name)  #获取该方法指针
        func(d)  #调用该方法,但是self参数必须手工传(注意)

      设置一个成员变量:

    setattr(d,attr_name,55)  #设置一个成员变量
    print( getattr(d,attr_name) )   #打印该成员变量的值

      如果要修改前面设置的变量值:

    setattr(d,attr_name,66)  #再次使用setattr覆盖

      删除成员变量:(删除添加的成员方法不行)

    delattr(d,attr_name)
    print( getattr(d,attr_name) ) #报错,说没有这个成员属性

    五、异常处理

    1.异常处理

    list = []
    
    try:
        print(list[1])  #列表中没有元素,访问报错
    except Exception as err: #捕获异常,并把异常的信息复制给err
        print("err is : ",err)   #打印异常详细信息

       按异常种类来捕获异常:

    names = []
    dicts = {}
    
    try:
        print(names[1])  #列表中没有元素,访问报错
        dicts['key']
    
    except IndexError as idx_err: #捕获IndexError异常
        print("err is : ",idx_err)   #打印异常详细信息
    
    except KeyError as key_err: #捕获KeyError异常
        print("err is : ",key_err)

      一次捕获所有种类的异常:(不建议直接使用,异常信息不够准确,建议用在最后补漏)

    names = []
    dicts = {}
    
    try:
        print(names[1])  #列表中没有元素,访问报错
        dicts['key']
    
    except Exception as e: #捕获所有种类的异常
        print("err is : ",e)   #打印异常详细信息

      出现未知错误:

    try:
        print(names[1])  #列表中没有元素,访问报错
        dicts['key']
    
    except IndexError as idx_err: #捕获IndexError异常
        print("err is : ",idx_err)   #打印异常详细信息
    except KeyError as key_err: #捕获KeyError异常
        print("err is : ",key_err)
    except Exception as e:  #建议在最后使用Exception
        print("出现未知错误 ",e)

       一切正常时:

    try:
        print(names[1])  #列表中没有元素,访问报错
        dicts['key']
    
    except IndexError as idx_err: #捕获IndexError异常
        print("err is : ",idx_err)   #打印异常详细信息
    except KeyError as key_err: #捕获KeyError异常
        print("err is : ",key_err)
    except Exception as e:
        print("出现未知错误 ",e)
    else:
        print("一切正常")  #一切正常时会执行,当出现异常时不执行

      不管错不错都要执行:

    try:
        print(names[1])  #列表中没有元素,访问报错
        dicts['key']
    
    except IndexError as idx_err: #捕获IndexError异常
        print("err is : ",idx_err)   #打印异常详细信息
    except KeyError as key_err: #捕获KeyError异常
        print("err is : ",key_err)
    except Exception as e:
        print("出现未知错误 ",e)
    else:
        print("一切正常")
    finally:
        print("不管有误错误都执行")

       常用的几种异常类型:

    • AttributeError :试图访问个对象没有的属性,如foo.x,但是foo中没有x属性。
    • IOError :输入输出异常。
    • ImportError :无法引入模块或包,基本上是路径问题或名称错误。
    • IndentationError :语法错误(的子类),代码没有正确对齐。
    • IndexError : 下标索引超出序列边界。
    • KeyError :试图访问字典里不存在的键。
    • SyntaxError :代码非法,代码不能编译。
    • TypeError :传入对象类型与要求的不符合。
    • ValueError:传入了一个调用者不期望的值,即使值的类型是正确的。

    2.自定义异常

    自定义异常:

    def test_func():
        test_num = input(">>")
        if int(test_num) < 10:
            raise MyException("test_func方法中,test_num < 10")
    
    
    class MyException(Exception):   #自定义异常继承于Exception
        def __init__(self,msg):    #实例化时传参
            self.msg = msg
    
        def __str__(self):  #异常错误信息
            return self.msg
    
    try:
        test_func()  #当输入的数字小于10时,触发raise MyException
    except MyException as err:
        print("捕捉到异常:",err)

    六、网络Socket编程

    1.实现socket的流程

       实现一个socket至少要分成以下几个步骤(伪代码):

    #伪代码
    Socket socket = getSocket(type = 'tcp') #设定好协议类型
    connect(socket, address = '1.2.3.4', port = '80')  #连接远程机器
    send(socket, 'HelloWorld!') #发送消息
    close(socket)   #关闭连接

      Socket Familyies(地址簇):

      socket.AF_UNIX  #unix本机进程间通信

      socket.AF_INET  #IPv4

      socket.AF_INET6  #IPv6

      Socket Type:

      socket.SOCK_STREAM  #TCP

      socket.SOCK_DGRAM  #UDP

      socket.SOCK_RAW  #原始套接字,普通套接字无法处理ICMP、IGMP等报文。

    2.Socket简单示例

      客户端:

    import socket   #引入socket模块
    
    client = socket.socket()    #声明socket类型,同时生成socket连接对象
    client.connect(('localhost',6969))  #连接远程socket
    
    client.send("我爱你".encode("utf-8"))  #python3.x中只能发送byte类型,2.x可以发送字符串
    
    data = client.recv(1024)    #等待接收来自远程的数据
    print("recv : ",data.decode())
    client.close()  #关闭socket

      服务器端:

    import socket   #引入socket模块
    
    server = socket.socket()    #创建socket实例
    server.bind(("localhost",6969)) #绑定监听网卡和端口
    server.listen() #开始监听
    
    conn,addr = server.accept() #等待接受客户端连接请求,并将连接实例赋值给conn,对端地址赋值给addr
    print(conn,addr)    #打印<socket.socket fd=536, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6969), raddr=('127.0.0.1', 50251)> ('127.0.0.1', 50251)
    
    data = conn.recv(1024)   #使用conn接受数据
    print("Recv : ",data.decode())
    conn.send((data.decode()+"你好").encode()) #使用conn发送数据
    
    server.close()  #关闭socket

      上述代码只是简单描述了一下socket如何创建和使用的。能够支持多客户端、多并发的socket在后面实现。

    ###

  • 相关阅读:
    三分钟学会.NET微服务之Polly
    redis设置密码和redis主从复制
    程序员工作之外,如何再赚一份工资?
    吞吐量(TPS)、QPS、并发数、响应时间(RT)概念
    TPS和QPS的区别和理解
    制定一套适合自己团队的GITflow标准化工作流
    UvaLive 6600 Spanning trees in a secure lock pattern 矩阵行列式
    从零開始学Xamarin.Forms(一) 概述
    Unity 之 C# 利用回调函数实现C++匿名函数
    hdu 4324 Triangle LOVE(拓扑判环)
  • 原文地址:https://www.cnblogs.com/leokale-zz/p/8488837.html
Copyright © 2011-2022 走看看