Python for Datawhale Task5

1. 类和对象

Python是一门面向对象的语言,因而在Python中创建一个类和对象是很容易的。面向对象的一些基本技术有:

  • 类(class):用来描述具有相同属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量:类变量在整个实例化的对象是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或实例变量,用于处理类及实例对象的相关数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
  • 继承:即派生一个类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为基类对象对待。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

创建Dog类

class Dog():
    #一次模拟小狗的简单尝试
      
    def __init__(self,name,age):
        #初始化属性name和age
        self.name = name
        self.age = age
    def sit(self):
        #模拟小狗被命令时蹲下
        print(self.name.title() + " is now sitting.")
     
    def roll_over(self):
        #模拟小狗被命令时打滚
        print(self.name.title() + " rolled over!")

在这里定义了一个Dog类,类中的函数称为方法,第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法。该方法中包含了三个形参:self、name、age,形参self是必不可少的。
创建实例对象

dog1 = Dog("Ryan",5)
dog2 = Dog("Lai",3)

访问属性
要访问实例属性,可使用据点.来访问。

dog1.name
print("dog1's name is " + dog1.name + ".")
#输出结果
dog1's name is Ryan.
#添加、删除、修改属性
dog1.weight = 20 #添加一个”weight"属性
dog1.weight = 15 #修改"weight"属性
del dog1.weight  #删除"weight"属性

常用的访问属性的函数有:
getattr(obj,name[,default]):访问对象的属性
hasattr(obj,name,value):检查是否存在一个属性
setattr(obj,name,value):设置一个属性。如果属性不存在,会创建一个新属性。
delattr(obj,name):删除属性。
Python内置的类属性有
__dict__:类的属性(包含一个字典,由类的数据属性组成)
__doc__:类的文档字符串
__name__:类名
__module__:类定义所在的模块(类的全名是“__main__.className",如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
__bases__:类的所有父类构成元素(包含了一个由所有父类组成的元组)

class Employee:
    #所有员工的基类
    emCount = 0 #类变量
    
    def __init__(self,name,salary):
            self.name = name
            self.salary = salary
            Employee.emCount += 1
        
    def displayCount(self):
            print("Total Employee %d"% Employee.emCount)
        
    def displayEmployee(self):
            print("Name: ",self.name, ", Salary: ",self.salary)
        
print("Employee.__doc__:", Employee.__doc__)    #类的属性
print("Employee.__name__:", Employee.__name__)  #类的文档字符串
print("Employee.__module__:", Employee.__module__)  #类名
print("Employee.__bases__:", Employee.__bases__)    #类定义所在模块
print("Employee.__dict__:", Employee.__dict__)  #类的所有父类构成元素

#输出结果
Employee.__doc__: None
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {'__weakref__': <attribute '__weakref__' of 'Employee' objects>, '__doc__': None, 'emCount': 0, 'displayCount': <function Employee.displayCount at 0x000001B2D36A7950>, '__init__': <function Employee.__init__ at 0x000001B2D36A78C8>, '__dict__': <attribute '__dict__' of 'Employee' objects>, '__module__': '__main__', 'displayEmployee': <function Employee.displayEmployee at 0x000001B2D36A79D8>}

调用方法

dog1.sit()
dog1.roll_over()

#输出结果
Ryan is now sitting.
Ryan rolled over!

Python对象销毁(垃圾回收)
Python使用了引用计数这一简单计数来跟踪和回收垃圾。在Python内部记录着所有使用中的对象各有多少引用。一个内部跟踪变量,称为一个引用计数器。当对象被创建时,就创建了一个引用计数,当这个对象不在需要时,也就是说,这个对象的引用计数变为0时,它被垃圾回收,但是回收不是立即的,由解释器在适当的时机,将垃圾对象占用的内存空间回收。
垃圾回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用的情况。循环引用指的是,两个对象相互引用,但是没有其他变量引用他们。这种情况下,仅使用引用计数是不够的。Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。作为引用计数的补充, 垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。 在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环。

class Point:
   def __init__( self, x=0, y=0):
      self.x = x
      self.y = y
   def __del__(self):
      class_name = self.__class__.__name__
      print(class_name,"销毁")

pt1 = Point()
pt2 = pt1
pt3 = pt1
print(id(pt1), id(pt2), id(pt3)) # 打印对象的id
del pt1
del pt2
del pt3

#输出结果
2812311704688 2812311704688 2812311704688
Point 销毁

类的继承
面向 对象的编程带来的主要好处之一是代码重用,实现这种重用的方法之一是通过继承机制。通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类。
继承的一些特点为:

  • 如果在子类中需要父类的构造方法就需要显示的调用父类的构造方法,或者不重写父类的构造方法。
  • 在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数
  • Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
  • 如果在继承元组中列了一个以上的类,那么它就被称作“多重继承”。
class Parent:# 定义父类
    parentAttr = 100
    def __init__(self):
        print("调用父类构造函数")
 
    def parentMethod(self):
        print("调用父类方法")
 
    def setAttr(self, attr):
        Parent.parentAttr = attr
 
    def getAttr(self):
        print("父类属性 :", Parent.parentAttr)
 
class Child(Parent): # 定义子类
    def __init__(self):
        print("调用子类构造方法")
 
    def childMethod(self):
        print("调用子类方法")
 
c = Child()          # 实例化子类
c.childMethod()      # 调用子类的方法
c.parentMethod()     # 调用父类方法
c.setAttr(200)       # 再次调用父类的方法 - 设置属性值
c.getAttr()          # 再次调用父类的方法 - 获取属性值

#输出结果
调用子类构造方法
调用子类方法
调用父类方法
父类属性 : 200

方法重写
如果父类方法的功能不能满足需求,可以在子类重写父类的方法。

class Parent:        # 定义父类
   def myMethod(self):
      print '调用父类方法'
 
class Child(Parent): # 定义子类
   def myMethod(self):
      print '调用子类方法'
 
c = Child()          # 子类实例
c.myMethod()         # 子类调用重写方法

#输出结果
调用子类方法

基础重载方法

序号方法,描述及简单的调用
1init(self[,args…],构造函数,简单的调用方法: obj = className(args)
2_del(self),析构函数,删除一个对象,调用方法:del obj
3repr(self),转化为供解释器读取的形式,调用方法:repr(obj)
4str(self),用于将值转换为适于人阅读的形式,调用方法:str(obj)
5_cmp(self,x),对象比较,调用方法:cmp(obj,x)

运算符重载

class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b
 
   def __str__(self):
      return('Vector (%d, %d)' % (self.a, self.b))
   
   def __add__(self,other):
      return(Vector(self.a + other.a, self.b + other.b))
 
v1 = Vector(2,10)
v2 = Vector(5,-2)
print(v1 + v2)

#输出结果
Vector (7, 8)

2. 正则表达式

正则表达式是一个特殊的字符序列,使用正则表达式可以很方便地检查一个字符串是否与某种模式匹配。例如,判断一个字符串是否是合法的Email的方法为:
1.创建一个匹配Email的正则表达式:
2.用该正则表达式去匹配用户的输入来判断是否合法。
在正则表达式中,如果直接个诶出字符,就是精确匹配。用“\d”可以匹配一个数字,“\w”可以匹配一个字母或数字,句点“.”可以匹配任意字符。如:“00\d”可以匹配“007”,但无法匹配“00A”;“\d\d\d”可以匹配“010”;“\w\w\d”可以匹配“py3”;“py.”可以匹配“pyc”、“pyo”、“py!”等等。
要匹配变长的字符,在正则表达式中,用*表示任意个字符(包括0个),用+表示至少一个字符,用?表示0个或1个字符,用{n}表示n个字符,用{n,m}表示n-m个字符:

  • \d{3}表示匹配3个数字,例如’010’
  • \s可以匹配一个空格(也包括Tab等空白符),所以\s+表示至少有一个空格,例如匹配’ ‘,’ '等;
  • \d{3,8}表示3-8个数字,例如’1234567’。
    要做更精确地匹配,可以用[]表示范围,比如:
  • [0-9a-zA-Z_]可以匹配一个数字、字母或者下划线
  • [0-9a-zA-Z_]+可以匹配至少由一个数字、字母或者下划线组成的字符串,比如’a100’,‘0_Z’,'Py3000’等
  • [a-zA-Z_][0-9a-zA-Z_]*可以匹配由字母或下划线开头,后接任意个由一个数字、字母或者下划线组成的字符串,也就是Python合法的变量
  • [a-zA-Z_][0-9a-zA-Z_]{0, 19}更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)

3. re模块

Python提供re模块,包含所有正则表达式的功能。
判断正则表达式是否匹配:

>>> import re
>>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>

re.match函数
re.match函数尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
函数的语法如下:

re.match(pattern, string, flags=0)

参数说明:
pattern:匹配的正则表达式。
string:要匹配的字符串。
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式:
group(num=0):匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups():返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

import re
print(re.match('www', 'www.runoob.com').span())  # 在起始位置匹配
print(re.match('com', 'www.runoob.com'))         # 不在起始位置匹配

#输出
(0, 3)
None

re.search方法
re.search扫描整个字符串并返回第一个成功的匹配。函数语法如下:

re.search(pattern, string, flags=0)

参数说明与re.match类似。

print(re.search('www', 'www.runoob.com').span())  # 在起始位置匹配
print(re.search('com', 'www.runoob.com').span())         # 不在起始位置匹配

#输出结果
(0, 3)
(11, 14)

re.match与re.search的区别在于:re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
检索与替换re.sub
Python 的 re 模块提供了re.sub用于替换字符串中的匹配项。语法如下:

re.sub(pattern, repl, string, count=0, flags=0)

参数说明:
pattern:正则中的模式字符串。
repl:替换的字符串,也可以为一个函数。
string:要被查找替换的原始字符串。
count:模式匹配后替换的最大次数,默认0表示是替换所有需匹配。

import re
phone = "2004-959-559 # 这是一个国外电话号码"
 
# 删除字符串中的 Python注释 
num = re.sub(r'#.*$', "", phone)
print("电话号码是: ", num)
 
# 删除非数字(-)的字符串 
num = re.sub(r'\D', "", phone)
print("电话号码是 : ", num)

#输出结果
电话号码是:  2004-959-559
电话号码是 :  2004959559

re.compile函数
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
语法格式为:

re.compile(pattern[, flags])

参数说明:
pattern : 一个字符串形式的正则表达式。
flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
1.re.I 忽略大小写
2.re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
3.re.M 多行模式
4.re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
5.re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
6.re.X 为了增加可读性,忽略空格和 # 后面的注释

>>>import re
>>> pattern = re.compile(r'\d+')                    # 用于匹配至少一个数字
>>> m = pattern.match('one12twothree34four')        # 查找头部,没有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
>>> print m                                         # 返回一个 Match 对象
<_sre.SRE_Match object at 0x10a42aac0>
>>> m.group(0)   # 可省略 0
'12'
>>> m.start(0)   # 可省略 0
3
>>> m.end(0)     # 可省略 0
5
>>> m.span(0)    # 可省略 0
(3, 5)

4. datetime模块

datetime是Python处理日期和时间的标准库。
获取当前日期和时间

>>> from datetime import datetime
>>> now = datetime.now()
>>> print(now)
2019-08-13 15:04:52.567843
>>> type(now)
<class 'datetime.datetime'>

获取指定日期和时间
要指定某个日期和时间,我们直接用参数构造一个datetime:

>>> dt = datetime(2019,8,13,15,20)
>>> print(dt)
2019-08-13 15:20:00

将datetime转换为timestamp
在计算机中,时间实际上是用数字表示的。我们把1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time,记为0(1970年以前的时间timestamp为负数),当前时间就是相对于epoch time的秒数,称为timestamp。timestamp的值与时区毫无关系,因为timestamp一旦确定,其UTC时间就确定了,转换到任意时区的时间也是完全确定的,这就是为什么计算机存储的当前时间是以timestamp表示的,因为全球各地的计算机在任意时刻的timestamp都是完全相同的(假定时间已校准)。
把一个datetime类型转换为timestamp只需要简单调用timestamp()方法:

>>> dt.timestamp()
1565680800.0

timestamp转化为datetime
要把timestamp转换为datetime,使用datetime提供的fromtimestamp()方法:

>>> t = 14364960350.0
>>> print(datetime.fromtimestamp(t))
2425-03-17 10:45:50

str转换为datetime
很多时候,用户输入的日期和时间是字符串,要处理日期和时间,首先必须把str转换为datetime。转换方法是通过datetime.strptime()实现,需要一个日期和时间的格式化字符串:

>>> aday = datetime.strptime('2019-8-13 15:30:30','%Y-%m-%d %H:%M:%S')
>>> print(aday)
2019-08-13 15:30:30

datetime转换为str
如果已经有了datetime对象,要把它格式化为字符串显示给用户,就需要转换为str,转换方法是通过strftime()实现的,同样需要一个日期和时间的格式化字符串:

>>> now = datetime.now()
>>> print(now.strftime('%a, %b %d %H:%M'))
Tue, Aug 13 15:18

datetime加减
对日期和时间进行加减实际上就是把datetime往后或往前计算,得到新的datetime。加减可以直接用+和-运算符,不过需要导入timedelta这个类:

>>> from datetime import datetime,timedelta
>>> now = datetime.now()
>>> now
datetime.datetime(2019, 8, 13, 15, 21, 43, 358199)
>>> now + timedelta(hours =14)
datetime.datetime(2019, 8, 14, 5, 21, 43, 358199)
>>> now - timedelta(days = 2)
datetime.datetime(2019, 8, 11, 15, 21, 43, 358199)

本地时间转换为UTC时间
本地时间是指系统设定时区的时间,例如北京时间是UTC+8:00时区的时间,而UTC时间指UTC+0:00时区的时间。
一个datetime类型有一个时区属性tzinfo,但是默认为None,所以无法区分这个datetime到底是哪个时区,除非强行给datetime设置一个时区:

>>> from datetime import datetime,timedelta,timezone
>>> tz_utc_8 = timezone(timedelta(hours=8))
>>> now = datetime.now()
>>> now
datetime.datetime(2019, 8, 13, 15, 25, 47, 423455)
>>> dt = now.replace(tzinfo=tz_utc_8)
>>> dt
datetime.datetime(2019, 8, 13, 15, 25, 47, 423455, tzinfo=datetime.timezone(datetime.timedelta(

时区转换
可以先通过utcnow()拿到当前的UTC时间,再转换为任意时区的时间:

>>> utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
>>> print(utc_dt)
2019-08-13 07:28:06.993398+00:00
>>> bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
>>> print(bj_dt)
2019-08-13 15:28:06.993398+08:00
>>> tokyo_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
>>> print(tokyo_dt)
2019-08-13 16:28:06.993398+09:00

5. http请求

在Web应用中,服务器把网页传给浏览器,实际上就是把网页的HTML代码发送给浏览器,让浏览器显示出来。而浏览器和服务器之间的传输协议是HTTP,所以:

  • HTML是一种用来定义网页的文本,会HTML,就可以编写网页;
  • HTTP是在网络上传输HTML的协议,用于浏览器和服务器的通信。
    方法:GET还是POST,GET仅请求资源,POST会附带用户数据;
    路径:/full/url/path;
    域名:由Host头指定:Host: www.sina.com.cn
    以及其他相关的Header;
    如果是POST,那么请求还包括一个Body,包含用户数据。
    步骤2:服务器向浏览器返回HTTP响应,响应包括:
    响应代码:200表示成功,3xx表示重定向,4xx表示客户端发送的请求有错误,5xx表示服务器端处理时发生了错误;
    响应类型:由Content-Type指定,例如:Content-Type: text/html;charset=utf-8表示响应类型是HTML文本,并且编码是UTF-8,Content-Type: image/jpeg表示响应类型是JPEG格式的图片;
    以及其他相关的Header;
    通常服务器的HTTP响应会携带内容,也就是有一个Body,包含响应的内容,网页的HTML源码就在Body中。
    步骤3:如果浏览器还需要继续向服务器请求其他资源,比如图片,就再次发出HTTP请求,重复步骤1、2。
    Web采用的HTTP协议采用了非常简单的请求-响应模式,从而大大简化了开发。当我们编写一个页面时,我们只需要在HTTP响应中把HTML发送出去,不需要考虑如何附带图片、视频等,浏览器如果需要请求图片和视频,它会发送另一个HTTP请求,因此,一个HTTP请求只处理一个资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值