本文最后更新于:2019 , 八月 19日 星期一, 4:32 下午

0x00 初识类

python中一切皆对象

创建类

'''
class 类名:
    '类的文档'
    类体
'''

class Data:
    pass

关键字:class

访问属性

格式:类名.属性

类名的作用:操作属性,查看属性

#(注:这只是示范,实际操作请勿使用中文)
class Data:
    属性 = 'a'
print(Data.a)

实例化

格式:对象名 = 类名(参数)

类名()就是实例化,会自动触动__init__函数的运行,可以用类为每个实例定制自己的特征

class Person:
    def __init__(self,*args):
        self.name = args[0]
        self.age = args[1]
        self.heg = args[2]

alex = Person('Psycho',0,'???')
print(alex.name)
----------------------------------
'''
对象 = 类名()
过程:
    类名() 会创造出一个对象,创建一个self变量
    调用__inti__方法,类名()里面的参数会被这里接收
    执行__init__方法
    返回self
'''

实例化方法

格式:类名.方法名(对象名)

class Person:
    def __init__(self,*args):
        self.name = args[0]
        self.age = args[1]
        self.heg = args[2]

    def walk(self):
        print('%s'%self.name)


alex = Person('Psycho',0,'???')
print(alex.name)
Person.walk(alex)

__init__方法

这个方法一般用于初始化类
但是,当实例化一个类的时候,并不是第一个被调用的,第一个被调用的是__new__

Tips:对当前对象的实例的一些初始化,没有返回值

设置对象的初始属性:self.属性 = 形参

在创建对象时,使用类名(属性1,属性2...)进行调用

class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

info = Person('alex','22')

self

init方法的第一参数永远是self,表示创建类的实例化本身
因此,在init方法内部,就可以把各种属性绑定到self

self.name:表示某类的属性变量

self.name = name 就是把外部传来的参数name赋值给某类自己的属性变量

类属性

类的属性存储地址:
dir(类名)
类名.__dict__:查出的是一个字典,key为属性名,value为属性值

---------------------
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类
类名.__bases__# 类所有父类构成的元组
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)

其他内置方法

__str__

如果直接print(object)打印对象,会看到创建出来的对象在内存中的地址
当使用print(object)输出对象的时候,只要对象的类中定义了__str__(self)方法,就会打印该方法return的信息描述

class Person:
    def __str__(self):
        return "这是个信息模块"

    def __init__(self,name,age):
        self.name = name
        self.age = age

info = Person('alex','22')
print(info)

__del__

析构方法,当对象在内存中被释放时,自动触发执行
在删除一个对象之前,进行一些收尾工作

class Person:
    def __str__(self):
        return "这是个信息模块"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __del__(self):
        print('关闭对象')

info = Person('alex', '22')

__repr__

返回一个可以用来表示对象的可打印字符串
__repr____str__的备胎,但__str__不能做__repr__的备胎
如果__str__方法有,那么它返回的必定一个字符串

class A:

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __repr__(self):
        return str(self.__dict__)

    # def __str__(self):
    #     return '%s,%s'%(self.name,self.age)

a = A('xxx',20)
print(a)

Ps:%r,repr()都是走__repr__

__str__的区别:

  1. __str__():返回用户看到的字符串
  2. __repr__():返回程序开发者看到的字符串

内置的方法有很多,不一定全部都在object中

__call__

一个对象后面加括号,触发执行

class A:
    def __init__(self,name):
        pass

    def __call__(self):
        print('执行此处')
a = A('alex')

__getattr__

定义当用户试图获取一个不存在的属性时的行为,适用于对普通拼写错误的获取和重定向,对获取一些不建议的属性时给出警告或者处理一个AttributeError,只有当调用不存在的属性的时候才会被返回

class Student(object):  
    def__getattr__(self, attrname):  
        ifattrname =="age":  
            return40  
        else:  
            raiseAttributeError, attrname  

x =Student()  
print(x.age)       #40  
print(x.name)      #error text omitted.....AttributeError, name  

__setattr__

是一个封装的解决方案,无论属性是否存在,它都允许你定义对属性的赋值行为,以为这你可以对属性的值进行个性定制,实现__setattr__时要避免”无限递归”错误

当试图对象的item特性赋值的时候将会被调用

# -*- coding:utf-8 -*-
class Student:
    def __getattr__(self, item):
        return item + ' is not exits'

    def __setattr__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, item):
        return self.__dict__[item]

    def __setitem__(self, key, value):
        self.__dict__[key] = value


s = Student()
print(s.name)  # 调用__getattr__方法 输出'name is not exits'
s.age = 1  # 调用__setattr__ 方法
print(s.age)  # 输出 1
print(s['age'])  # 调用 __getitem__方法 输出1
s['name'] = 'tom'  # 调用 __setitem__ 方法
print(s['name'])  # 调用 __getitem__ 方法 输出 'tom'

__delattr__

__setattr__相同,删除一个属性

class A(object):
    def __delattr__(self, *args, **kwargs):  
        print 'call func del attr'  
        return object.__delattr__(self, *args, **kwargs)  

__getattribute__

定义了你的属性被访问时的行为,在支持__getattribute__的python版本,调用__getattr__前必定会调用__getattribute__,不要尝试实现__getattribute__

容易出bug

class Tree(object):
    def __init__(self,name):
        self.name = name
        self.cate = "plant"
    def __getattribute__(self,obj):
        print("哈哈")
        return object.__getattribute__(self,obj)
aa = Tree("大树")
print(aa.name)

item系列

__getitem__

当访问不存在的属性时会调用该方法

可以让对象实现迭代功能,以及p[key]取值

# data['key']取值
class DataTest:
    def __init__(self, name,id):
        self.name = name
        self.id = id

    def __getitem__(self, item):
        return self.__dict__[item]

data = DataTest('alex','1')
print(data['name'])

# 实现迭代功能
class DataTest:
    def __init__(self, name,id):
        self.name = name
        self.id = id

    def __getitem__(self, item):
        return self.name[item]

data = DataTest(['alex','lie','psycho'],'1')
for i in data:
    print(i)

__setitem__

每当属性被赋值的时候都会调用该方法,因此不能在该方法内(self.name = value)赋值,否则会死循环!

class DataTest:
    def __init__(self, name,id):
        self.name = name
        self.id = id

    def __getitem__(self, item):
        return self.__dict__[item]

    def __setitem__(self, key, value):
        self.__dict__[key]=value

data = DataTest(['alex','lie','psycho'],'1')
data['alex'] = '女'
print(data['alex'])

__delitem__

当删除属性时调用该方法

lass DataTest:
    def __init__(self, name,id):
        self.name = name
        self.id = id

    def __getitem__(self, item):
        return self.__dict__[item]

    def __setitem__(self, key, value):
        self.__dict__[key]=value

    def __delitem__(self, key):
        del self.__dict__[key]

data = DataTest(['alex','lie','psycho'],'1')
data['alex'] = '女'
print('删除前:%s'%data.__dict__)
del data['alex']
print('删除后:%s'%data.__dict__)

__new__

构造方法:创建一个对象(只负责创建)

class DataTest:

    __instance = False

    def __init__(self, name,id):
        self.name = name
        self.id = id

    def __new__(cls, *args, **kwargs):
        if cls.__instance:
            return cls.__instance
        cls.__instance = object.__new__(cls)
        return cls.__instance

data = DataTest('alex','1')
nas = DataTest('nice','2')
print(data)
print(nas)

__eq__

当判断两个对象是否相等时,触发

class DataTest:

    def __init__(self, name,id):
        self.name = name
        self.id = id

    def __eq__(self, other):
        if self.__dict__ == other.__dict__:
            return True
        else:
            return False

data = DataTest('alex','1')
nas = DataTest('nice','2')
print(data == nas)

__len__

返回元素的个数
如果一个类表现得像一个list,要获取有多少个元素,就得用len()函数,要让len()函数正常工作,类必须提供一个特殊方法len()

class DataTest:

    __instance = False

    def __init__(self, name,id):
        self.name = name
        self.id = id

    def __len__(self):
        return len(self.name)

data = DataTest(['alex','nice'],'1')
print(len(data.name))

__hash__

如果定义可变对象的类实现了__eq__放阿飞,就不要再实现__hash__方法,否则这个对象的hash值发生变化会导致被放在错误的哈希中

class DataTest:
    def __init__(self):
        self.name = 'alex'
        self.id = '2'

    def __hash__(self):
        return hash(str(self.name)+str(self.id))

a = DataTest()
print(hash(a))

面向对象的三大特性

  • 继承:实现代码重用
  • 多态:不同的对象调用相同方法,产生不同的执行结果
  • 封装:根据职责将属性和方法封装到一个抽象的类中

0x02 继承

继承是一种创新类的方式,实现代码的重用,相同的代码不需要重复的编写

继承的传递性子类拥有父类的所有方法属性父类的的父类封装的所有属性和方法

Ps:继承父类的时候,前提条件必须有那个类的存在!

Ps:如果在自己的类中有该方法,先用自己的,没有再从父类中寻找

1. 继承分为:

  • 单继承
  • 多继承

2. 通过继承创建的新类:

  • 子类
  • 派生类

3. 被继承的类:

  • 基类
  • 父类
  • 超类

查看继承:__bases__

单继承

继承的语法:

class 类名(父类名):
        pass

子类拥有父类的所有方法属性

class Arm:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

class Person(Arm):
    pass

class Dog(Arm):
    pass

jin = Dog('jin',500,20)
print(jin.name)

多继承

子类可以拥有多个父类,并且具有所有父类的属性和方法

class 类名(父类1,父类2...):
    pass

多继承中,我们子类的对象调用一个方法,默认是就近原则 经典类中 深度优先 新式类中 广度优先 2.7 新式类和经典类共存,新式类要继承object python3 只有新式类

class ParentClass1: #定义父类
    pass

class ParentClass2: #定义父类
    pass

class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
    pass

class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
    pass

Ps:父类之间存在同名的属性或方法,应该尽量避免使用多继承,容易产生混淆

重用性

在程序开发的过程中,定义了一个A类与一个B类,但是这两个类的大部分内容都相同 我们可以通过继承的方式,让B类继承A的所有属性,实现代码重用

class Arm:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

class Dog(Arm):
    pass

jin = Dog('jin',500,20)
print(jin.name)

方法的重写与派生

当父类的方法实现不能满足子类的需求时,可以对方法进行重写

重写父类的方法有两种情况:

  1. 覆盖父类方法
  2. 对父类方法进行扩展

覆盖父类

具体的实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现

重写之后,在运行时,只会调用子类中重写的方法,而不再会调用父类封装的方法

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def ack(self):
        print('wu')


class name(Person):

    def ack(self):
        print('%s ackti'%self.name)

info = name('alex',20)
info.ack()
print(info.age)

重写父类方法(扩展)

在子类执行父类的方法也可以直接用super()方法

super本质:不是单纯找父类,而是根据调用者的节点位置的广度优先顺序来的

格式:super().父类方法

class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

class Arm(Person):
    def __init__(self,name,age,kind):
        super().__init__(name,age)
        self.kind = kind

sex = Arm('alex',20,50)
print(sex.kind)

派生属性

派生属性/方法:父类中没有的属性或方法,在子类中出现的

一旦重新定义了自己的属性且父类重名,那么调用新的属性时,就以自己为准

class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

class Arm(Person):
    def __init__(self,name,age,kind):
        Person.__init__(self,name,age)
        self.kind = kind

sex = Arm('alex',50,20)
print(sex.kind)

只要是子类的对象调用,子类中有的名字一定用子类的,子类中没有才找父类的

如果父类也没有 报错

如果父类 子类都有,用子类的,如果还想用父类的,需要单独调用父类的,需要自己传self参数

class Arm:
    def __init__(self,name,aggr,hp):
        self.name = name
        self.aggr = aggr
        self.hp = hp

    def eat(self):
        print('吃药回血')
        self.hp += 100

class Dog(Arm):
    def __init__(self,name,aggr,hp,kind):
        Arm.__init__(self,name,aggr,hp)
        self.kind = kind

    def eat(self):
        Arm.eat(self)
        self.Thear = 2

    def bite(self,person):
        person.hp -= self.aggr


class Person(Arm):
    def __init__(self,name,aggr,hp,sex):
        Arm.__init__(self,name,aggr,hp)
        self.sex = sex
        self.money = 0

    def attack(self,dog):
        dog.hp -= self.aggr

    def get_weapon(self,weapon):
        if self.money >= weapon.price:
            self.money -= weapon.price
            self.weapon = weapon
            self.aggr += weapon.aggr
        else:
            print("余额不足,请充值")

jin = Dog('jin',500,20,10)
jin.eat()

MRO(方法搜索顺序)

python针对类提供的一个内置属性,可以查看方法的搜索顺序

主要用于在多继承时判断,方法,属性的调用路径

从左到右的顺序查找,在当前类中找到方法就执行,不再搜索

没有找到,继续查找下一个类

最终没找到,报错

class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

class Arm(Person):
    def __init__(self,name,age,kind):
        super().__init__(name,age)
        self.kind = kind

print(Arm.__mro__)

0x03 封装

广义上的面向对象封装:代码的保护,面向对象的思想本身就是一种,只让自己的对象能调用自己类中的方法

狭义封装:面向对象的三大特性之一,属性和方法都隐藏起来

封装的三种方式:

  • public(对外公开,不封装)
  • protected(对外不公开,对子类公开)
  • private(对谁都公开)

python中一切皆对象

类是一个特殊的对象 – 类对象,使用一个类可以创建出很多歌对象实例

处了封装实例的属性和方法外,类对象还可以拥有自己的属性和方法

类属性

给类对象中定义的属性

通常用来记录与这个类相关的特征

类属性不会用于记录具体对象的特征

调用:类名.的方式

# 计算人数
class Person:
    count = 0

    def __init__(self, name):
        self.name = name
        Person.count += 1

name1 = Person('alex')
print(Person.count)

属性的获取机制:向上查找机制

  1. 首先在对象内部查找对象属性
  2. 没有找到就会向上寻找类属性

访问类属性有两种方式:

  1. 类名.类属性
  2. 对象.类属性(不推荐)

Ps:如果使用对象.类属性 = 值赋值语句,只会给对象添加一个属性,而不会影响到类属性的值

私有方法和属性

私有属性和方法是对象的隐私,不对外公开,外界及子类都不能直接访问

通常用于做一些内部的事情

  • 对象的私有属性
  • 类中的私有方法
  • 类中静态私有属性

定义私有属性与方法:__属性或方法

只要在类的内部使用私有属性,就会自动带上__类名

Ps:所有的私有,都不能在类的外部使用

在外部调用的方法:对象._类名__属性(不推荐使用,仅供了解)

class Person:

    __manger = 'admin' # 静态私有属性


    def __init__(self,username,passwod):
        self.username = username
        self.__password = passwod # 私有属性

    def __mange(self): # 私有方法
        print("管理员登录")

    def login(self):
        if self.__password != self.username:
            return ("请输入正确的账号密码")
        else:
            if self.username == self.__manger:
                return self.__mange()
            else:
                return ("登录成功")

username = 'admin'
password = 'admin'

win = Person(username,password)
login = win.login()
print(login)

property

内部装饰器,在面向对象中使用

把方法伪装成属性@property

Ps:装饰器中不能跟任何参数

class Person:
    def __init__(self,name):
        self.name = name

    @property
    def work(self):
        return '111'

x = Person('admin')
print(x.work)

修改@property伪装的方法

Ps:现有@property再有@方法名.setter,再创建一个一样的方法

@方法名.setter:把被装饰的方法变成属性来赋值

# 例子1
class Person:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, new_name):
        self.__name = new_name


tiger = Person('nice')
print(tiger.name)

tiger.name = 'fuck'
print(tiger.name)

###################################################

# 例子2
class Person:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.deleter
    def name(self):
        del self.__name


tiger = Person('nice')
print(tiger.name)

del tiger.name
print(tiger.name)

# deleter和del互相关联了

classmethod

method:方法

classmethod:类方法

Ps:把一个方法,变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象

当这个方法的操作只涉及静态属性的时候,就应该使用classmethod来装饰这个方法

对应的方法不需要实例化,不用self参数,当第一个参数需要是表示自身类的cls参数,可以来调用类的属性和方法及实例化对象等

调用:类名.方法,也可以通过cls访问类的属性和其他的类方法

@classmethod
def 类方法名(cls):
    pass
# 例子
class Person:
    __discount = 0.8

    def __init__(self,price):
        self.__price = price

    @property
    def price(self):
        return self.__price * Person.__discount

    @classmethod
    def price_discount(cls,new_discount):
        cls.__discount = new_discount


apple = Person(5)
print(apple.price)

Person.price_discount(1)
print(apple.price)

staticmethod

staticmethod:静态方法

在完全面向对象的程序中,如果一个函数,即和对象没有关系,也和类没有关系,就将一个函数变成一个静态方法

调用:类名.方法

@staticmethod
def 静态方法名():
    pass
class Login:
    def __init__(self,username,password):
        self.__username = username
        self.__password = password

    def login(self):
        pass

    @staticmethod
    def get_input():
        user = input('username:')
        pwd = input('password:')
        Login(user,pwd)

Login.get_input()

Ps:类方法和静态方法 都是类调用的
对象可以调用类方法和静态方法,一般情况下,推荐用类名调用
类方法 有一个默认参数 cls代表这个类

0x04 多态

python天生支持多态,多态指的是同一种事物的多种状态

多态不同的子类对象调用相同的父类方法,产生不同的执行结果

  • 增加代码的灵活度
  • 以继承和重写父类方法为前提
  • 是调用方法的技巧,不会影响到类的内部设计

0x05 组合

一个对象的属性值是另一个类的对象

在一个类中以另外一个类的对象作为数据属性,成为类的组合

# 例子1
class Date:
    def __init__(self,year,mon,day):
        self.year=year
        self.mon=mon
        self.day=day

    def birth_info(self):
        print("The birth is %s-%s-%s"%(self.year,self.mon,self.day))

class People:
    def __init__(self,name,age,year,mon,day):
        self.name=name
        self.age=age
        self.birth=Date(year,mon,day)

    def walk(self):
        print("%s is walking"%self.name)

class Teacher(People):
    def __init__(self,name,age,year,mon,day,course):
        People.__init__(self,name,age,year,mon,day)
        self.course=course

    def teach(self):
        print("%s is teaching"%self.name)

class Student(People):
    def __init__(self,name,age,year,mon,day,group):
        People.__init__(self,name,age,year,mon,day)
        self.group=group

    def study(self):
        print("%s is studying"%self.name)
t1=Teacher("alex",28,1989,9,2,"python")
s1=Student("jack",22,1995,2,8,"group2")
print(t1.birth.birth_info())
# 例子2
class BirthDate:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day

class Couse:
    def __init__(self,name,price,period):
        self.name=name
        self.price=price
        self.period=period

class Teacher:
    def __init__(self,name,gender,birth,course):
        self.name=name 
        self.gender=gender
        self.birth=birth
        self.course=course
    def teach(self): 
        print('teaching')

p1=Teacher('egon','male', 
            BirthDate('1995','1','27'), 
            Couse('python','28000','4 months')
           ) 

print(p1.birth.year,p1.birth.month,p1.birth.day) 

print(p1.course.name,p1.course.price,p1.course.period)
''' 
运行结果: 
1 27 
python 28000 4 months 
'''

0x06 单例设计模式

设计模式:前任工作的总结和提炼,为了可重用代码,让代码更容易被人理解

单列设计模式:机制:当你第一次实例化这个类的时候,就创建一个实例化的对象,当你之后再实例化,就用之前创建的对象,把原来的重复的属性覆盖,而不同的属性则继承下来

重写__new__方法

利用__new__方法

使用类名()创建对象时,Python解释器首先会调用__new__方法为对象分配空间

主要作用:

  1. 在内存中为对象分配空间
  2. 返回对象的引用

Python的解释器获得对象的引用后,将引用作为第一个参数,传递给__init__方法

重写__new__方法的代码非常固定

一定要return super().__new__(cls)

否则Python解释器得不到分配了空间的对象引用,就会调用对象的初始化方法

在调用时需要主动传递cls参数(静态方法)

*:多参数元组形式

**:多参数字典形式

# 例子1
class Person:
    def __new__(cls, *args, **kwargs):
        print('test')
        instance = super().__new__(cls)
        return instance

    def __init__(self, name):
        self.name = name

name1 = Person('alex')
# 例子2
class DataTest:
    __instance = False

    def __init__(self, name,id):
        self.name = name
        self.id = id

    def __new__(cls, *args, **kwargs):
        # 判断属性是否赋值
        if cls.__instance:
            return cls.__instance
        cls.__instance = object.__new__(cls)
        return cls.__instance

data = DataTest('alex','1')
nas = DataTest('nice','2')
print(data)
print(nas)

初始化方法执行一次

让初始化方法只执行一次:

  1. 标记是否执行过初始化方法
  2. __init__进行判断
  3. 然后修改标记
class Person:
    info = False
    __instance = False

    def __new__(cls, *args, **kwargs):
        # 判断属性是否赋值
        if cls.__instance:
            return cls.__instance
        cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self, name):
        if Person.info:
            return
        self.name = name
        Person.info = True

name1 = Person('alex')
print(name1)
name2 = Person('alex2')
print(name2)

0x07 异常

异常和错误的概念

错误:语法错误,逻辑错误

异常:程序运行时发生的错误信号 程序一旦发生错误,就从错误的位置停下来,不在继续执行后面的内容

Ps:抛出异常的一瞬间,程序并不会立即终止,而是会把异常传递给函数/方法的调用一方,如果传递到主程序,任然没有异常处理,程序才会被终止

基础语法

try:
    被检测的代码块
except:
    try中一旦检测到异常,就会执行这个位置的逻辑

异常类

异常名称 描述
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告

Tips:异常类只能用来处理指定的异常情况,如果非指定异常则无法处理

s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print e

多分支与万能异常

多分支

s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)

万能异常(Exception):

  • 捕获任意异常

    try:
        被检测的代码块
    except Exception as e:
        print(e)

主动抛出异常:根据应用程序特有的业务需求主动抛出异常

  1. 创建一个Exception的对象
  2. 使用raise关键字抛出异常对象

raise:显示引发异常,一旦执行了raise语句,raise后面的语句将不能执行

raise [Exception [, args [, traceback]]]
def input_pwd():
    pwd = input("请输入密码")
    if len(pwd) >= 8:
        return pwd
    print("错误")
    ex = Exception("密码长度不够8位")
    raise ex

try:
    print(input_pwd())
except Exception as result:
    print(result)

如果你想要的效果是,对于不同的异常我们需要定制不同的处理逻辑,那就需要用到多分支

s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)
except Exception as e:
    print(e)

finally

无论异常是否发生,在程序结束前,finally中的语句都会被执行 finally和return相遇的时候,依然会执行 函数里做异常处理用,不管是否异常去做一些收尾工作

try:
    被检测的代码块
finally:
    print('xxxx')
# -*- coding: UTF-8 -*-
def tryTest():  
    try:  
        demo = input("input a number:")  
        x = 1.0/int(demo)  
        print x  
        return 1 
    except Exception, e:  
        print e  
        return 0 
    finally:  
        print "this is a finally test" 

if __name__ == '__main__':
    result = tryTest()  
    print result

0x08 模块

模块:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名+.py的后缀

在模块中定义的全局变量,函数,类都是提供给外界直接使用的工具

import加载的模块分为四个通用类别:

  1. 使用python编写的代码(.py文件)
  2. 已被编译为共享库或DLL的C或C++扩展
  3. 包好一组模块的包
  4. 使用C编写并链接到python解释器的内置模块

模块可以包含可执行的语句和函数定义,这些语句的目的是初始化模块 它们只在模块名第一遇到导入import语句时才执行 为了防止你重复导入

python的优化手段:第一次导入后就将模块加载到内存了,后续的iimport语句仅是对已加载大内存中的模块对象增加一个引用,不会重新执行模块内的语句

Ps:从sys.modules中找到当前已经加载的模块,sys.modules是一个字典,内部包含模块名与模块对象的映射,该字典决定了导入模块时是否需要重新导入

导入模块

每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称当做全局名称空间 这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会被导入时,与使用者的全局变量冲突

原则:每一个文件都应该是可以被导入的,在导入文件时,文件中所有没有任何缩进的代码,都会被执行一遍

首次导入模块时会做的三件事

  • 为源文件创建新的名称空间
  • 在新建命名空间中执行模块中包含的代码
  • 创建名称***来引用该命名空间
  • import导入

    import 模块1,模块2

    导入之后:通过模块名.使用模块提供的工具 – 全局变量,函数,类

    Ps:在导入模块时,每个导入应独占一行

  • from...import...导入

    from 模块 import 方法
    
    # 例子
    from time import sleep

    如果希望从某一个模块中,导入部分的函数功能,就可以使用

    直接使用模块提供的函数

    Ps:如果两个模块,存在同名的函数,那么导入模块的函数,会覆盖掉先导入的函数

  • from...import *(仅限了解)

    from time import *

    导入所有的方法和属性

    不推荐使用,因为函数重名并有任何的提示,出现问题不好debug

指定模块别名

使用as

在模块名太长的情况下,可以使用as指定模块的名称

import 模块 as 模块别名

#例子
import time as f

Ps:模块别名应该符合大驼峰命名规则,form...import导入方式同样适用

模块搜索顺序

python的解释器在导入模块时:

  1. 搜索当前目录指定模块名的文件,如果有就直接导入
  2. 没有,再搜索系统目录

在开发时,给文件起名,不要和系统的模块文件重名

__file__:查看模块的完整路径

import random
print(random.__file__)

在模块文件中测试

使用__name__属性,记录着一个字符串

__name__:在其他脚本调用(导入)的的时候name显示的是模块的名字 而在原模块调用的时候显示的是__main__

if __name__ == '__main__':
    pass

通过上面的方式,python就可以分清楚哪些是主函数,进入函数执行,并且可以调用其他模块的各个函数等等

0x09 包(Package)

:一个包含多个模块的特殊目录,目录下有一个特殊的文件__init__.py

包即模块 import导入文件时,产生名称空间中的名字来源于文件,import包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件

在python3中,即使包下没有__init__.py文件,import包任然不会报错

在python2中,包下一定要有该文件,否则import包会报错

Ps:导入包遵循的原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法,item.subitem.subsubitem 对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数(它们都可以用点的方式调用自己的属性)

import 包名

from...import...导入

from glance.api import policy

Ps:from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误

_init_.py文件 不管是哪种方式,只要是第一次导入包或是包的任意其他部分,都会依次执行包下的__init__.py这个文件可以为空,但是也可以存放一些初始化包的代码

绝对导入和相对导入

  • 绝对导入

    格式:from glance.api import policy
    
    # 路径图
    glance/                   
    ├── __init__.py      from glance import api
                         from glance import cmd
                         from glance import db
    
    ├── api                  
    │   ├── __init__.py  from glance.api import policy
                         from glance.api import versions
    │   ├── policy.py
    │   └── versions.py
    
    ├── cmd                 from glance.cmd import manage
    │   ├── __init__.py
    │   └── manage.py
    
    └── db                   from glance.db import models
        ├── __init__.py
        └── models.py
  • 相对导入

    ...的方式为起始

    格式:from .api import policy
    
    # 路径图
    glance/                   
    ├── __init__.py      from . import api  #.表示当前目录
                         from . import cmd
                         from . import db
    ├── api                  
    │   ├── __init__.py  from . import policy
                         from . import versions
    │   ├── policy.py
    │   └── versions.py
    
    ├── cmd              from . import manage
    │   ├── __init__.py
    │   └── manage.py    from ..api import policy   
    #..表示上一级目录,想再manage中使用policy中的方法就需要回到上一级glance目录往下找api包,从api导入policy
    └── db               from . import models
        ├── __init__.py
        └── models.py

    Ps:一定要在与glance同级的文件中测试 包里的模块如果想使用其他模块的内容只能使用相对路径,使用了相对路径就不能在包内直接执行了 可以用import导入内置或者第三方模块,但是要绝对避免使用import来导入自定义包的子模块, 应使用from…import…的绝对或者相对导入且包的相对导入只能用from的形式

单独导入

单独导入包名称时不会导入包中所有包含的所有子模块

在glance同级中的.py文件中

import glance
glance.api.policy()

'''
结果:AttributeError: module 'glance' has no attribute 'cmd'
'''

解决方法

# glance/__init__.py
from . import cmd

# glance/cmd/__init__.py
from . import manage

再次执行

# 在于glance同级的.py中
import glance
glance.api.policy()

__init__.py文件

要在外界使用包的模块,需要再__init__.py中指定对外界提供的模块列表

当前目录下导入

from . import send_message



all

__all__可用于模块导入时限制 此时被导入模块若定义了__all__属性,则只有all内指定的属性,方法,类可被导入

glance/                   
├── __init__.py     from .api import *
                    from .cmd import *
                    from .db import *    
├── api                  
│   ├── __init__.py   __all__ = ['policy','versions'] 
│   ├── policy.py
│   └── versions.py
├── cmd               __all__ = ['manage']    
│   ├── __init__.py
│   └── manage.py    
└── db                __all__ = ['models']              
    ├── __init__.py
    └── models.py

import glance
policy.get()

发布模块及安装

  • 创建setup.py

       from distutils.core import setup

    setup( name = “包名”,
    ​ version = “版本”,
    ​ description = “描述信息”,
    ​ long_description = “完整描述”,
    ​ author = “作者”,
    ​ url = “主页”,
    ​ py_modules = [
    ​ “包.模块”,..]
    )

  • 构建模块

    python3 setup.py build
  • 生成发布压缩包

    python3 setup.py sdist

安装模块

  1. 先解压
  2. 进行安装
tar -zxvf 压缩包
sudo python3 setup.py install

卸载模块

直接从安装目录下,把安装模块的目录删除就可以

cd /usr/loacl/lib/python3.x/dist-packages/
sudo rm -r 模块*

pip 安装第三方模块

sudo pip3 install 模块名

安装IPython

# MAC下
sudo pip install ipython

# Linux下
sudo apt install ipython
sudo apt install ipython3

0x10 文本操作

文件:存储在某种长期储存设备上的一段数据

文件的作用:将数据长期保存下来,在需要的时候使用

文件存储方式:以二进制的方式保存在磁盘上的

文本文件

  • 可以使用文本编辑软件查看
  • 本质上还是二进制文件

二进制文件

  • 保存的内容不是给人直接阅读的,而是提供给其他软件使用的
  • 二进制文件不能使用文本编辑软件查看

文件的基本操作

基本步骤:

  • 打开(open()

  • 读/写

    • readlines()    #读取所有行的内容
      readline(n)    #n:代表最长字节数,视频,图片,(rb,bytes按照字节读)
      read()    #读取所有行的内容
    • write()
  • 关闭(close())

文件指针(光标)

文件指针标记从哪个位置开始读取数据

第一次打开文件时,通常文件指针会指向文件的开始位置

当执行了read方法后,文件指针会移动到读取内容的末尾

  • file.sekk()

    移动文件读取指针到指定位置

    sekk(offset,whence=0)
    
    '''
    offset:开始的偏移量,也就是代表需要移动偏移的字节数
    whence:给offset参数一个定义,表示要从哪个位置开始偏移,0代表从文件开头算起,1代表开始从当前位置开始算起,2代表从文件末尾开始算起,当有换行时,会被换行截断
    seek()无返回值
    '''
  • tell()

    tell是获取文件指针位置

  • truncate()

    用于截断文件并返回截断的字节长度

    fileObject.truncate([size])

其他

  • readable()

    是否可读可写

  • writable()

    是否可写

删除文件与重命名

import os

# 删除文件
os.remove()
# 重命名
os.rename('xxxx.txr','rrrr')

Python      Python

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

zip密码暴力破解-python
Python基础