Python3学习集合

打印

print("hello")
print("这样","可以","连接","起来吗?",",自动识别为空格")
print("试试"+"加好可以连接吗?","事实证明是可以的")
print("100+200 =",100+200)
print(len("abc"))

list的使用

classmates = ["Nicolo","Tom","Jerry"]
print("从开始取:",classmates[0])
print("从末尾取:",classmates[-1])
print("获取list的长度:",len(classmates))
classmates.append('Adam')
print("list中追加元素到末尾:",classmates[-1])
classmates.insert(1, 'Jack')
print("按照索引插值:",classmates[1])
print("要删除list末尾的元素,用pop()方法,删除的东西",classmates.pop())
print("要删除指定位置的元素,用pop(i)方法,其中i是索引位置:", classmates.pop(1))
print("要把某个元素替换成别的元素,可以直接赋值给对应的索引位置:")
classmates[1] = 'Sarah'
print(classmates)

tuple元组

print("tuple一旦初始化就不能修改,比如同样是列出同学的名字")
classmates = ('Michael', 'Bob', 'Tracy')
print(classmates)
# 现在,classmates这个tuple不能变了,它也没有append(),insert()这样的方法。
# 其他获取元素的方法和list是一样的,你可以正常地使用classmates[0],classmates[-1],但不能赋值成另外的元素。
# 不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。

条件判断

# 输入用户年龄,根据年龄打印不同的内容,在Python程序中,用if语句实现:
age = 24
if age > 18:
    print("他的年龄是",age)
    print("他长大了")
else:
    print("他还是个小男孩")

if age >= 18:
    print('adult')
elif age >= 6:
    print('teenager')
else:
    print('kid')

循环

# Python的循环有两种,一种是for...in循环,依次把list或tuple中的每个元素迭代出来
names = ['Michael', 'Bob', 'Tracy']
for name in names:
    print (name)
    # 所以for x in ...循环就是把每个元素代入变量x,然后执行缩进块的语句。

# 计算1-10的整数之和,可以用一个sum变量做累加
sum = 0
for n in [1,2,3,4,5,6,7,8,9,10]:
    sum = sum +n
print(sum)
# 如果要计算1-100的整数之和,从1写到100有点困难,幸好Python提供一个range()函数
# 可以生成一个整数序列,再通过list()函数可以转换为list。
# print(list(range(101)))
sum1 = 0
for n in list(range(101)):
    sum1 = sum1 + n
print(sum1)

定义函数

# 定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:
# 然后,在缩进块中编写函数体,函数的返回值用return语句返回。
# 自定义一个求绝对值的my_abs函数

def my_abs(x):
    if x > 0:
        return x
    else:
        return - x

print(my_abs(0))
print(my_abs(-1))

# 定义空函数
# 占位符作用
def nop():
    pass


# 数据类型检查可以用内置函数isinstance()实现
def my_abs(x):
    if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
    if x >= 0:
        return x
    else:
        return -x



# 返回多个值
import math

def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny

函数的参数

# 定义注册函数
def enroll(name,gender,age,city):
    print('name:',name)
    print('gender:',gender)
    print('age:',age)
    print('city:',city)

enroll("Nicolo","male",24,"Xian")

#或定义某几个参数
def enroll2(name,gender,age= 24,city = "Xian"):
    print('name:',name)
    print('gender:',gender)
    print('age:',age)
    print('city:',city)
enroll2("Nicolo","male")

#可变参数
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum +n
    return sum

#test
print("1-2之和:",calc(1,2))

# Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去
nums = [1,2,3,4,5,6,7,8,9,10]
print("1-10之和:",calc(*nums))
# *nums表示把nums这个list的所有元素作为可变参数传进去。

递归函数

# 在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
# 计算阶乘n! = 1 x 2 x 3 x ... x n
def fact(n):
    if n == 1:
        return 1
    return n * fact(n-1)

print(fact(10))
# 使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。

函数作为返回值

# 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
# 通常情况下,求和的函数是这样定义的:

def calc_sum(*args):
    ax = 0
    for n in args:
        ax = ax +n
    return ax
print(calc_sum(1,2,3))

# 但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数:
def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax +n
        return ax 
    return sum

# 当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:
f = lazy_sum(1, 3, 5, 7, 9)
# 调用函数f时,才真正计算求和的结果:
print(f())

# 在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,
# 当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。


# 闭包

# 注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用

# 小结

# 一个函数可以返回一个计算结果,也可以返回一个函数。

# 返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。

切片

# 1行代码能实现的功能,决不写5行代码。请始终牢记,代码越少,开发效率越高。

#切片
# 取一个list或tuple的部分元素是非常常见的操作
L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
# 取前N个元素,也就是索引为0-(N-1)的元素,可以用循环:
print(L[0:3])
print(L[:3])
# L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3。即索引0,1,2,正好是3个元素。

# 从索引1开始,取出2个元素出来:
print(L[1:3])
# 支持倒数切片
print("倒数切片",L[-2:])
print("倒数切片",L[-2:-1])
# 记住倒数第一个元素的索引是-1。

# 其他操作
nums = list(range(100))
print("取前10个:",nums[:10])
print("取后10个:",nums[-10:])
print("取前11-20个数:",nums[11:20])
print("前10个数,每两个取一个:",nums[:10:2])
print("所有数,每5个取一个:",nums[::5])


# tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple
nums2 = (0, 1, 2, 3, 4, 5)[:3]
print(nums2)

# 字符串'xxx'也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串
str = 'ABCDEFGHIJKMLN'[:4]
print(str)

列表生成器

# 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
# 生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a = list(range(1, 11))
print(a)

# 生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?
#方法一
l = []
for x in range(1,11):
    l.append(x*x)
print("方法一",l)

# 方法二
L = [x*x for x in range(1,11)]
print("方法二",L)
# 写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来

# for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
L2 = [x*x for x in range(1,11) if x % 2 ==0]
print("筛选出仅偶数的平方",L2)

# 还可以使用两层循环,可以生成全排列
L3 = [m + n for m in "ABC" for n in "XYZ"]
print("生成全排列",L3)

# 列出当前目录下的所有文件和目录名
# 运用列表生成式,可以写出非常简洁的代码。

import os
L4 = [d for d in os.listdir('.')]
print("列出当前目录下的所有文件和目录名",L4)

# 列表生成式也可以使用两个变量来生成list
d = {'x': 'A', 'y': 'B', 'z': 'C' }
L5 = [k+'='+ v for k,v in d.items()]
print("使用两个变量来生成list",L5)

# 把一个list中所有的字符串变成小写:
L6 = ['Hello', 'World', 'IBM', 'Apple']
L7 = [s.lower() for s in L6]
print("所有的字符串变成小写",L7)

生成器

# 如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?
# 这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
# generator保存的是算法

# 第一种方法
# 只要把一个列表生成式的[]改成(),就创建了一个generator
L = [x*x for x in range(1,11)]
print(L)
g = (x*x for x in range(1,11))

# 创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。
# 可以通过next()函数获得generator的下一个返回值
print(next(g))
# 这种不断调用next(g)实在是太变态了,正确的方法是使用for循环

for n in g:
    print(n)

# 斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
# 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
# 斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易
def fib(max):
    n,a,b = 0,0,1
    while n<max:
        print(b)
        a,b=b,a+b
        n=n+1
    return 'done'
# fib函数实际上是定义了斐波拉契数列的推算规则
# 要把fib函数变成generator,只需要把print(b)改为yield b就可以了
def fib(max):
    n,a,b = 0,0,1
    while n<max:
        yield b
        a,b=b,a+b
        n=n+1
    return 'done'
    # 如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator

    # generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
    # 而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

# 举个简单的例子,定义一个generator,依次返回数字1,3,5
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)

# 调用该generator时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值:
# o = odd()
# next(o)

迭代器

# 可以直接作用于for循环的数据类型有以下几种:
# 一类是集合数据类型,如list、tuple、dict、set、str等;
# 一类是generator,包括生成器和带yield的generator function。
# 这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
# 可以使用isinstance()判断一个对象是否是Iterable对象

# 而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
# 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
# 可以使用isinstance()判断一个对象是否是Iterator对象:

# 如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。
# 在Python中,迭代是通过for ... in来完成的
# Python的for循环抽象程度要高于Java的for循环,因为Python的for循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上。
# list这种数据类型虽然有下标,但很多其他数据类型是没有下标的,但是,只要是可迭代对象,无论有无下标,都可以迭代,比如dict就可以迭代
d = {'a': 1, 'b': 2, 'c': 3}
for key in d:
    print("迭代出key值",key)
    #默认情况下,dict迭代的是key。

# 如果要迭代value,可以用for value in d.values()
for value in d.values():
    print("迭代出value值",value)

# 如果要同时迭代key和value,可以用for k,v in d.items()
for k,v in d.items():
    print("迭代出key和value值",k,v)

map/reduce

# map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
# 比如我们有一个函数f(x)=x2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下
def f(x):
    return x * x
r = map(f,[1,2,3,4,5,6,7,8,9])
print(list(r))
# 结果r是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。

# 一行代码
print(list(map(f,[1,2,3,4,5,6,7,8,9])))

# reduce把一个函数作用在一个序列[x1, x2, x3, ...]上
# 这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
# reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
from functools import reduce
def add(x,y):
    return x + y
print(reduce(add,[1,2,3,4,5,6,7,8,9]))

filter

# filter()函数用于过滤序列
# 和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。


# 在一个list中,删掉偶数,只保留奇数,可以这么写:
def is_odd(n):
    return n % 2 == 1

print(list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])))

# 把一个序列中的空字符串删掉
def not_empty(s):
    return s and s.strip()
print(list(filter(not_empty,['A','','B','',None,'c','d'])))

sorted

# sorted排序算法
# 排序算法

# 排序也是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。
# 如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。

# Python内置的sorted()函数就可以对list进行排序
# 从小到大
print("一般使用",sorted([112,3,4,54,23,67,85]))

# sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:
print("带参排序",sorted([12,53,-213,-65,2,-52],key = abs))

# 要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True
print("反向排序",sorted([112,3,4,54,23,67,85],reverse=True))

lambda 匿名函数

# 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。

# 在Python中,对匿名函数提供了有限支持。还是以map()函数为例,计算f(x)=x2时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:
print(list(map(lambda x: x * x,[1,2,3,4,5,6,7,8,9])))


# 通过对比可以看出,匿名函数lambda x: x * x实际上就是:
# def f(x):
#     return x * x

# 关键字lambda表示匿名函数,冒号前面的x表示函数参数。

# 匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
# 用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:

f = lambda x: x * x
print("lambda使用",f(5))


# 也可以把匿名函数作为返回值返回
def build(x,y):
    return lambda: x*x + y*y
build(2,3)

# 小结

# Python对匿名函数的支持有限,只有一些简单的情况下可以使用匿名函数。

Decorator装饰器

# 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
def now():
    print('2017-7-25')
f = now
f()

# 函数对象有一个__name__属性,可以拿到函数的名字:
print(now.__name__)
print(f.__name__)

# # 假设我们要增强now()函数的功能,
# 比如,在函数调用前后自动打印日志,
# 但又不希望修改now()函数的定义,
# 这种在代码运行期间动态增加功能的方式,
# 称之为“装饰器”(Decorator)。
# 本质上,decorator就是一个返回函数的高阶函数。


# 要定义一个能打印日志的decorator,可以定义如下:

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper  

# 观察上面的log,因为它是一个decorator,
# 所以接受一个函数作为参数,并返回一个函数。
# 我们要借助Python的@语法,把decorator置于函数的定义处

@log
def now():
    print('2017-7-25')

# 调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:

now()

偏函数

# 在介绍函数参数的时候,我们讲到,通过设定参数的默认值,可以降低函数调用的难度。而偏函数也可以做到这一点
# int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换
print("默认十进制",int('123456'))
# 但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:
print("八进制",int('12345',base = 8))

def int2(x, base=2):
    return int(x, base)
print("二进制",int2('1000000'))


# functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2

import functools
int2 = functools.partial(int, base = 2)

# 简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
# 注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:
int2('1000000', base=10)

字典dic和set

# Python内置了字典:dict的支持,dict全称dictionary
# 在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。
# 这个通过key计算位置的算法称为哈希算法(Hash)。
# []:list
# ():tuple
# {}: dict

# 学生成绩
score = {"Nicolo":100,"Tom":99,"Jerry":99}
print("打印Nicolo的成绩:",score["Nicolo"])
# 把数据放入dict的方法,除了初始化时指定外,还可以通过key放入
score["Nicolo"] = 101
print("打印Nicolo的成绩:",score["Nicolo"])

# 要避免key不存在的错误,有两种办法,一是通过in判断key是否存在:
print("Nicolo" in score)
# 要删除一个key,用pop(key)方法,对应的value也会从dict中删除:
score.pop("Jerry")
print(score)

# set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。
s  = set([1,2,3])
# 通过add(key)方法可以添加元素到set中,可以重复添加,但不会有效果:
s.add(4)
print(s)
# 通过remove(key)方法可以删除元素
s.remove(4)
print("移除后的",s)

模块

# 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里
# 这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式
# 在Python中,一个.py文件就称之为一个模块(Module)

# 使用模块有什么好处?

# 最大的好处是大大提高了代码的可维护性。
# 其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。
# 我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。
# 引入了包以后,只要顶层的包名不与别人冲突,那所有模块都不会与别人冲突。
# 现在,abc.py模块的名字就变成了mycompany.abc,类似的,xyz.py的模块名变成了mycompany.xyz。
# 每一个包目录下面都会有一个__init__.py的文件
# 这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。
# __init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是mycompany。

# 使用模块


# 以内建的sys模块为例,编写一个hello的模块:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

' a test module '
__author__ = 'Nicolo'

import sys

def test():
    args = sys.argv
    if len(args)==1:
        print('Hello, world!')
    elif len(args)==2:
        print('Hello, %s!' % args[1])
    else:
        print('Too many arguments!')

if __name__=='__main__':
    test()

# 第1行和第2行是标准注释,第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行,第2行注释表示.py文件本身使用标准UTF-8编码;

# 第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;

# 第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;

# 以上就是Python模块的标准文件模板,当然也可以全部删掉不写,但是,按标准办事肯定没错。

# sys模块有一个argv变量,用list存储了命令行的所有参数。argv至少有一个元素,因为第一个参数永远是该.py文件的名称,例如:
# 运行python3 hello.py获得的sys.argv就是['hello.py'];
# 运行python3 hello.py Nicolo获得的sys.argv就是['hello.py', 'Nicolo']。

# 注意到这两行代码:

# if __name__=='__main__':
#     test()

# 在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__
# 而如果在其他地方导入该hello模块时,if判断将失败
# 因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。


# 安装第三方模块

pip install XXX

面向对象编程

# 如果要打印一个学生的成绩,首先必须创建出这个学生对应的对象
# 然后,给对象发一个print_score消息,让对象自己把自己的数据打印出来。
class Student(object):

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

    def print_score(self):
        print('%s: %s' % (self.name, self.score))


bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)
bart.print_score()
lisa.print_score()

类和实例

# ClassANDInstance
# 类和实例
# Python中,定义类是通过class关键字:
class Student1(object):
    pass
# class后面紧接着是类名,即Student,类名通常是大写开头的单词
# 紧接着是(object),表示该类是从哪个类继承下来
# 继承的概念我们后面再讲,通常,如果没有合适的继承类
# 就使用object类,这是所有类最终都会继承的类。

# 定义好了Student类,就可以根据Student类创建出Student的实例,创建实例是通过类名+()实现的:
bart1 = Student1()
bart1.name = 'Bart Simpson'

# 由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。
# 通过定义一个特殊的__init__方法,在创建实例的时候,就把name,score等属性绑上去:
class Student2(object):
    def __init__(self,name,score):
        self.name = name 
        self.score = score

# 注意:特殊方法“init”前后有两个下划线!!!
# 注意到__init__方法的第一个参数永远是self,表示创建的实例本身
# 因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
# 有了__init__方法,在创建实例的时候,就不能传入空的参数了
# 必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:
bart2 = Student2('Bart Simpson', 59)
print("姓名",bart2.name)
print("成绩",bart2.score)

# 和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self
# 并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别
# 所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。

# 数据封装

# 面向对象编程的一个重要特点就是数据封装。
# 在上面的Student类中,每个实例就拥有各自的name和score这些数据。
# 我们可以通过函数来访问这些数据,比如打印一个学生的成绩:
# 既然Student实例本身就拥有这些数据,要访问这些数据,就没有必要从外面的函数去访问
# 可以直接在Student类的内部定义访问数据的函数,这样,就把“数据”给封装起来了。
# 这些封装数据的函数是和Student类本身是关联起来的,我们称之为类的方法:
class Student3(object):

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

    def print_score(self):
        print('%s: %s' % (self.name, self.score))

# 要定义一个方法,除了第一个参数是self外,其他和普通函数一样。
# 要调用一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入:
bart3 = Student3('Nicolo', 99)
bart3.print_score()

private 访问限制

# 果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,
# 在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
# 所以,我们把Student类改一改:

class Student(object):

    def __init__(self, name, score):
        self.__name = name #私有变量
        self.__score = score #私有变量

    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))
# 如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法:
class Student(object):
    ...

    #get方法
    def get_name(self):  
        return self.__name

    def get_score(self):
        return self.__score

# 允许外部代码修改score怎么办?可以再给Student类增加set_score方法:

class Student(object):
    ...

    #set方法
    def set_score(self, score):
        self.__score = score

# 在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量
# 特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。

继承和多态

# 编写了一个名为Animal的class,有一个run()方法可以直接打印:
class Animal(object):
    def run(self):
        print('Animal is running...')
    def eat(self):
        print('Eating meat...')

# 当我们需要编写Dog和Cat类时,就可以直接从Animal类继承:
class Dog(Animal):
    def run(self):
        print('Dog is running...')
    
class Cat(Animal):
    def run(self):
        print('Cat is running...')
# 对于Dog来说,Animal就是它的父类,对于Animal来说,Dog就是它的子类。Cat和Dog类似。
# test
dog = Dog()
dog.run()
dog.eat()

cat = Cat()
cat.run()
# cat.eat()当子类和父类都存在相同的run()方法时,我们说,子类的run()覆盖了父类的run(),在代码运行的时候,总是会调用子类的run()。这样,我们就获得了继承的另一个好处:多态。

获取对象信息

# 当我们拿到一个对象的引用时,如何知道这个对象是什么类型、有哪些方法呢?
# 使用type()

# 首先,我们来判断对象类型,使用type()函数:

# 基本类型都可以用type()判断:
# type(123)

# 使用isinstance()
# 对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。

# 使用dir()

# 如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:

print(x for x % 7 == 0 in range(101) )

实例属性和类属性

# 由于Python是动态语言,根据类创建的实例可以任意绑定属性。

# 给实例绑定属性的方法是通过实例变量,或者通过self变量:
class Student(object):
    def __init__(self, name):
        self.name = name

s = Student('Bob')
s.score = 90

# 但是,如果Student类本身需要绑定一个属性呢?可以直接在class中定义属性,这种属性是类属性,归Student类所有:
class Student(object):
    name = 'Student'

# 在编写程序的时候,千万不要把实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏aCloudDeveloper

C++基础题

刚在网上转看到几道对于巩固基础很有帮助的C++基础题,反正闲着也是闲着,就做了下,具体题型如下: 答案是我自己写,不一定对,如果有朋友看到不对的,欢迎指正,万分...

23150
来自专栏北京马哥教育

Python 运算符,你知道多少?

糖豆贴心提醒,本文阅读时间5分钟,文末有秘密! ? 编辑 | 糖豆 图 | 来源网络 ? 什么是运算符? 本章节主要说明Python的运算符。举个简...

49040
来自专栏阿炬.NET

正则表达式学习笔记

28970
来自专栏我的博客

sizeof用法

sizeof()功能:计算数据空间的字节数 1.与strlen()比较 strlen()计算字符数组的字符数,以”\0″为结束判断,不计算为’\...

30740
来自专栏书山有路勤为径

1.C与C++

使用c++中的标准库类型vector可以很轻松的完成任务。 不需要管理内存分配,对不同的类型都可以处理

14040
来自专栏数据科学学习手札

(数据科学学习手札46)Scala中的面向对象

  在Scala看来,一切皆是对象,对象是Scala的核心,Scala面向对象涉及到class、object、构造器等,本文就将对class中的重点内容进行介绍...

14550
来自专栏平凡文摘

7大经典的排序算法总结实现

15520
来自专栏数据小魔方

左手用R右手Python系列之——迭代器与迭代对象

接触过Python的小伙伴儿肯定都知道,Python中关于迭代器和可迭代对象运用的很广泛。迭代器可以以一种非常友好的方式使用在循环中,不仅节省内存,还能优化代码...

40580
来自专栏菩提树下的杨过

python:函数的高级特性

24030
来自专栏编程

Go语言中new和make的区别

Go语言中new和make是内建的两个函数,主要用来创建分配类型内存。在我们定义生成变量的时候,可能会觉得有点迷惑,其实他们的规则很简单,下面我们就通过一些示例...

20670

扫码关注云+社区

领取腾讯云代金券