Python基础(2)

目录
  • 函数
  • 面向对象编程(类/子类)
  • 文件读写
  • 迭代器/迭代对象
  • 生成器yield
函数/function
函数可以简单理解成 '打包' 好的一段代码。 函数的作用主要是为了使代码可以重用。 对于一些通用的代码,放到函数里,每次使用直接调就好了。节省时间,提高效率。
Python 里的函数是什么样子的?
先来看一个Python 写的 斐波拉切数列的 函数:
1
def fib(n):
2
    a, b = 0, 1
3
    for i in range(n):
4
        print(a, end=" ")
5
        a, b = b, a+b
从例子中可以看到:
  • 函数是以  'def ' 开头,我们称为 关键字;后面的 'fib' 是函数的名字;紧接着的小括号,里面是函数的参数,可以通过参数从外面传一些值到函数的内部。这里的参数只有一个,我们给函数的参数也起了一个名字'n' 。
  • 函数的参数可以是一个入上面的例子。也可以一个都没有,只有小括号。也可以是多个,参数之间用逗号隔开。
  • 接下来的  (冒号) 表示 函数的代码写在后面。Python的代码要求以统一的缩进开始。所以上面的函数 换行并缩进了。
  • 上面的函数并没有 返回值 ,Python默认返回了None。 如果要返回确定的值要用return。
  • 调用函数,直接函数名加小括号。有参数写到括号里。如:fib(10)
1
fib(10)
   0 1 1 2 3 5 8 13 21 34 
 
 
函数的参数可以设置 默认值/缺省参数
1
def my_sum_2(a, b=5):
2
    return a+b
3
4
my_sum_2(3,10)   #输出 13
5
my_sum_2(3,) # 第二个参数没有给,所以函数取默认值5。  3+8=8 输出8
  
  
python 函数的参数传递:
  • 不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。
比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
  • 可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

                            python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

python 传不可变对象实例

1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
 
4
def ChangeInt( a ):
5
    a = 10
6
7
b = 2
8
ChangeInt(b)
9
print b # 结果是 2

实例中有 int 对象 2,指向它的变量是 b,在传递给 ChangeInt 函数时,按传值的方式复制了变量 b,a 和 b 都指向了同一个 Int 对象,在 a=10 时,则新生成一个 int 值对象 10,并让 a 指向它。

传可变对象实例

1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
 
4
# 可写函数说明
5
def changeme( mylist ):
6
   "修改传入的列表"
7
   mylist.append([1,2,3,4]);
8
   print "函数内取值: ", mylist
9
   return
10
 
11
# 调用changeme函数
12
mylist = [10,20,30];
13
changeme( mylist );
14
print "函数外取值: ", mylist

实例中传入函数的和在末尾添加新内容的对象用的是同一个引用,故输出结果如下:

1
函数内取值:  [10, 20, 30, [1, 2, 3, 4]]
2
函数外取值:  [10, 20, 30, [1, 2, 3, 4]]

不定长参数

你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数。
加了星号(*)的变量名会存放所有未命名的变量参数。选择不多传参数也可。如下实例:
1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
 
4
# 可写函数说明
5
def printinfo( arg1, *vartuple ):
6
   print "输出: "
7
   print arg1
8
   for var in vartuple:
9
      print var
10
   return;
11
 
12
# 调用printinfo 函数
13
printinfo( 10 );
14
printinfo( 70, 60, 50 );

以上实例输出结果:

1
输出:
2
10
3
输出:
4
70
5
60
6
50
一个星号和两个星号:
1
def my_func(**x):
2
    if len(x)==0:
3
        print('None')
4
    else:
5
        print(x)
6
7
my_fun(b=1,c=2,d=3)
8
#输出 {'d': 3, 'c': 2, 'b': 1}
1
#两个 '*' 号
2
def my_func(x, y=1, *a, **b):
3
    print(x,y,a,b)   
4
my_func(1) # 输出 :   1 1 () {}
5
my_func(1,3) # 输出 : 1 3 () {}
6
my_func(1,2,3,4,5) #输出 : 1 2 (3, 4, 5) {}
7
my_func(1,2,3,4,5,tmp=6) #输出 :1 2 (3, 4, 5) {'tmp': 6}
8
9
# 可以看出来 一个星号 表示参数是一个tuple,两个星号表示参数为一个字典。
10
# 可以用type()函数来实验一下 
11
12
def my_func(x, y=1, *a, **b):
13
    print(type(a))
14
    print(type(b))
15
    print(x,y,a,b)
16
my_func(1,2,3,4,5,tmp=6) 
17
# 输出 :
18
# <class 'tuple'>
19
# <class 'dict'>
20
# 1 2 (3, 4, 5) {'tmp': 6}

匿名函数/lambda

匿名函数,是一个表达式,函数体比def定义的函数简单的多。
语法:
1
lambda [arg1 [,arg2,.....argn]]:expression

如下实例:

1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
 
4
# 可写函数说明
5
sum = lambda arg1, arg2: arg1 + arg2;
6
 
7
# 调用sum函数
8
print "相加后的值为 : ", sum( 10, 20 )
9
print "相加后的值为 : ", sum( 20, 20 )

以上实例输出结果:

1
相加后的值为 :  30
2
相加后的值为 :  40
面向对象的编程/class入门
Python通过class来定义类。类可以看做是我们自定义的一种数据结构。
Python语言自带了一些数据结构(int,float,str,list)。我们可以通过class来定义一下我们自己的类。

说起面向对象,首先一定要明白 类和实例的的概念。
类可以看做是 实例 的 '图纸'(模板)。
比如:我们盖房子的时候需要'图纸',盖房子的图纸可以就几张,但是房子却可以盖很多。
也可以看做是写文章时,脑子里想好的大纲。虽然脑子想写什么都想到了。但是终究是还没有'实现'。
这里的 实际存在的房子,动笔写好的稿子,都可以看做是类的'实例'。
等房子盖好了,稿子写好了,我们就可以说我们的 '类' 已经 '实现' 了(创建了'实例')。
关键字: 类、实例、实现
  • 我们可以把int当做一个类, a = 5,a是就是一个int类型的对象(instance 实例)。int->类,=号->实现,a->一个实例,名字叫做'a'。
  • Python 中的实例被统称为'对象'(object), class就是某一种对象的模板。
创建类

1
class Employee(object):
2
    # python中的__init__表示初始化类。函数中的第一个参数self 是指类的实例自己(即Employee的实例),Python默认会把自己传给初始化的函数的第一个参数,定义初始化函数时一定不要忘了写self参数。
3
    def __init__(self,name,ID,title,salary,manager=None):
4
        self.name = name
5
        self.title = title
6
        self.salary = salary
7
        self.manager = manager
8
    def get_info(self):
9
        return "Employee name:{},title:{},salary:{},manager:{}"\
10
    .format(self.name, self.title, self.salary,"" if self.manager==None else self.manager)
11
    
12
    def __eq__(self, other):
13
        return self.ID == other.ID
1
# 初始化对象/实例
2
ceo = Employee('user1', 1, 'CEO', 10000000)
3
user2 = Employee('user2', 10, 'employee', 100, ceo) 
1
ceo.get_info()
2
# 输出: '(Employee name:user1, title:CEO, salary:10000000, manager:)'
1
user2.get_info()
2
# 输出: 'Employee name:user2, title:CTO, salary:100, manager:<__main__.Employee object at 0x7fd7affaa940>'
1
# 定义一个类
2
class Company(object):
3
    def __init__(self, name, employees=[]):
4
        self.name = name
5
        self.employees = employees
6
    
7
    def hire(self, employee):
8
        if not employee in self.employees:
9
            self.employees.append(employee)
10
    
11
    def fire(self, employee):
12
        if employee in self.employees:
13
            self.employees.remove(employee)
14
            
15
    def get_info(self):
16
        res = "Company:{}, employees:".format(self.name)
17
        for employee in self.employees:
18
            res += ", {}".format(employee.get_info())
19
        return res
1
com = Company("com")
2
com.hire(ceo)
3
com.hire(user2)
4
com.get_info()

子类/继承

子类可以继承基类的的field、method,复用代码,也可以再基类的基础上扩展自己特有的field、method。
在python中继承中的一些特点:
  • 1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
  • 2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
  • 3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。


语法:

派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:

1
class SubClassName (ParentClass1[, ParentClass2, ...]):
2
   'Optional class documentation string'
3
   class_suite
1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
 
4
class Parent:        # 定义父类
5
   parentAttr = 100
6
   def __init__(self):
7
      print "调用父类构造函数"
8
 
9
   def parentMethod(self):
10
      print '调用父类方法'
11
 
12
   def setAttr(self, attr):
13
      Parent.parentAttr = attr
14
 
15
   def getAttr(self):
16
      print "父类属性 :", Parent.parentAttr
17
 
18
class Child(Parent): # 定义子类
19
   def __init__(self):
20
      print "调用子类构造方法"
21
 
22
   def childMethod(self):
23
      print '调用子类方法'
24
 
25
c = Child()          # 实例化子类
26
c.childMethod()      # 调用子类的方法
27
c.parentMethod()     # 调用父类方法
28
c.setAttr(200)       # 再次调用父类的方法 - 设置属性值
29
c.getAttr()          # 再次调用父类的方法 - 获取属性值

以上代码执行结果如下:

1
调用子类构造方法
2
调用子类方法
3
调用父类方法
4
父类属性 : 200

你可以继承多个类

1
class A:        # 定义类 A
2
.....
3
4
class B:         # 定义类 B
5
.....
6
7
class C(A, B):   # 继承类 A 和 B
8
.....

你可以使用issubclass()或者isinstance()方法来检测。

  • issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
  • isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。

方法重写

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

实例:

1
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
 
4
class Parent:        # 定义父类
5
   def myMethod(self):
6
      print '调用父类方法'
7
 
8
class Child(Parent): # 定义子类
9
   def myMethod(self):
10
      print '调用子类方法'
11
 
12
c = Child()          # 子类实例
13
c.myMethod()         # 子类调用重写方法

执行以上代码输出结果如下:

1
调用子类方法
Abstract Base class
  • 抽象类不能实例化
  • 抽象类中定义的抽象方法,子类必须重写。

1
from abc import ABC, abstractmethod
2
3
class Person(ABC):
4
    @abstractmethod
5
    def __init__(self, name, ID):
6
        self.name  = name
7
        self.ID = ID
8
    
9
    @abstractmethod
10
    def get_info(self):
11
        return "name:{}".format(self.name)
上面的Person继承了ABC。定义了两个抽象方法__init__和get_info
1
class Student(Person):
2
    def __init__(self, name, ID, level=0):
3
        super().__init__(name, ID) # 通过super()方法调用基类的方法
4
        self.level = level
5
    
6
    def get_info(self):
7
        return "{}, level:{}".format(super().get_info(), self.level)# 通过super()方法调用基类的方法
8
    
9
    def take_exam(self, grade):
10
        if grade.upper() in ['A', 'B', 'C']:
11
            self.level += 1
12
        return self.level
13
    
14
    def graduate(self):
15
        self.get_info()
16
        if self.level >= 5:
17
            print('congratulations, you have graduated from school')
18
            return True
19
        else:
20
            print('Sorry, you need more practice')
21
            return False
1
stud_1 = Student('xiaoming', 10, 2)
2
stud_1.get_info()
3
# 输出 : 'name:xiaoming, level:2'   

文件读写

1
#读到一个字符串里
2
f = open('./ShangHai.txt', 'r', encoding='utf-8') # 使用open读取文件
3
content = f.read() 
4
f.close() #关闭文件流
5
6
#读取到一个数组里,每一行作为数组的一个元素
7
f = open('./ShangHai.txt', 'r', encoding='utf-8')
8
contents = f.readlines() 
9
10
# 可以再for中直接循环输出
11
for line in open('./ShangHai.txt', 'r', encoding='utf-8'):
12
    print(line.strip())
13
    print("\n\n")
下面做一个小例子:统计词频
1
# 定义一个统计词频函数
2
def my_count(in_file, out_file):
3
#读取文件并统计词频
4
    word_count = {}
5
    for line in open(in_file, encoding='utf-8'):
6
        words = line.strip().split(" ")
7
        for word in words:
8
            if word.lower() in word_count:
9
                word_count[word.lower()] += 1
10
            else:
11
                word_count[word.lower()] = 1
12
    # 写文件
13
    out = open(out_file, 'w', encoding='utf-8')
14
    for word in word_count:
15
        #print(word, word_count[word])
16
        out.write(word+" : "+str(word_count[word])+"\n")
17
    print("count successfully!")
18
    out.close()
1
in_file = 'ShangHai.txt'
2
out_file = 'WordCount.txt'
3
my_count(in_file, out_file) 

迭代器/可迭代对象

迭代器,简单的可以理解每次只取一个元素。类似 sql中的游标

迭代是Python最强大的功能之一,是访问集合元素的一种方式。。

迭代器是一个可以记住遍历的位置的对象。

迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

迭代器有两个基本的方法:iter()  next()

字符串,列表或元组对象都可用于创建迭代器:

1
list=[1,2,3,4]
2
it = iter(list)    # 创建迭代器对象
3
print (next(it))   # 输出迭代器的下一个元素
4
# 输出 1
5
print (next(it))
6
# 输出 2
迭代器对象可以使用常规for语句进行遍历:
1
#!/usr/bin/python3
2
 
3
list=[1,2,3,4]
4
it = iter(list)    # 创建迭代器对象
5
for x in it:
6
    print (x, end=" ")
7
    
8
# 输出 : 1 2 3 4
实用next()函数,每次取一个元素:
1
#!/usr/bin/python3
2
 
3
import sys         # 引入 sys 模块
4
 
5
list=[1,2,3,4]
6
it = iter(list)    # 创建迭代器对象
7
 
8
while True:
9
    try:
10
        print (next(it))
11
    except StopIteration:
12
        sys.exit()
13
14
# 输出  
15
1
16
2
17
3
18
4

生成器yield

  • yield关键字的作用和return相似,都是返回一个值。
        不同的是,yield返回值之后,yield后面的代码还会继续执行,return则会直接结束代码。
  • 生成器就是指实用了yield的函数。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
  • 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行 next()方法时从当前位置继续运行。
以下实例使用 yield 实现斐波那契数列:
1
#!/usr/bin/python3
2
 
3
import sys
4
 
5
def fibonacci(n): # 生成器函数 - 斐波那契
6
    a, b, counter = 0, 1, 0
7
    while True:
8
        if (counter > n): 
9
            return
10
        yield a
11
        a, b = b, a + b
12
        counter += 1
13
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
14
 
15
while True:
16
    try:
17
        print (next(f), end=" ")
18
    except StopIteration:
19
        sys.exit()
20
21
# 输出: 0 1 1 2 3 5 8 13 21 34 55

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值