Python基础知识总结(常见问题与知识点)

1.举例说明zip()函数用法:

传入两个可迭代对象,将对象中的元素对应打包成一个元组,返回由这些元组组成的列表(列表长度由传入的可迭代对象最短长度确定)

a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9, 10]
z = zip(a, b)   # 返回 [(1, 4), (2, 5), (3, 6)]
z = zip(a, c)   # 返回 [(1, 7), (2, 8), (3, 9)]  长度由最短可迭代对象确定
z = zip(*z)    # zip的逆过程,还原为元组组成的列表 [(1, 2, 3), (7, 8, 9)]

2.常用sql语句:

INSERT INTO tablename (`title`, `url`, `keyword`, `updated_time`) VALUES (xx,xx,xx,xx);
  # 插入表tablename xx,xx,xx,xx数据
  
DELETE FROM tablename;  # 全删

  DELETE FROM tablenaem WHERE url=xxxxxxx;# 删一个
  
UPDATE tablename SET title=’abc’ WHERE url=xxxxxxxx;  # 改url的title为abc

SELECT * FROM tablenaem  # 全查

	 SELECT url, title FROM tablename  # 查tablename表中的url和title列
	 
DROP TABLE IF EXISTS `xxx`;  # 如果xxx这个表存在,删除xxx这个表
# 建表xxx
CREATE TABLE `xxx`(
`title` text COLLATE utf8_unicode_ci,
`url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`keyword` text COLLATE utf8_unicode_ci,
`updated_time` datetime DEFAULT NULL,
PRIMARY KEY(‘url’) USING BTREE
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

# COLLATE关键字告知mysql该列的排序和比较规则
# COLLATE=utf8_unicode_ci 排序规则,_ci表示忽视大小写(准确度高,校对慢)
# USING BTREE (还有一种HASH索引) 使用BTREE索引存储
# CHARSET=utf8  默认字符集的编码

注:

一.MySQL使用索引:(BTREE索引, HASH索引)
(1)使用索引后减少了存储引擎需要扫描的数据量,加快查询速度
(2)索引可以把随机I/O变为顺序I/O
(3)索引可以帮助我们对所搜结果进行排序以避免使用磁盘临时表
BTREE索引:
B-TREE以B+树结构存储数据,大大加快了数据的查询速度
B-TREE索引在范围查找的SQL语句中更加适合(顺序存储)where全职匹配
HASH索引:
Hash索引基于hash表实现,只有查询条件精确匹配Hash索引中的所有列才会用到hash索引
存储引擎会为hash索引中的每一列都计算hash码,Hash索引中存储的即hash码,所以每次读取都会进行两次查询
Hash索引无法用于排序
Hash不适用于区分度小的列上,如性别字段

二.MySQL主键与复合主键:
主键约束即在表中定义一个主键来唯一确定表中每一行数据的标识符。主键可以是表中的某一列或者多列的组合,其中由多列组合的主键称为复合主键。
主键应该遵守下面的规则:
每个表只能定义一个主键。
主键值必须唯一标识表中的每一行,且不能为 NULL,即表中不可能存在两行数据有相同的主键值。这是唯一性原则。
一个列名只能在复合主键列表中出现一次。
复合主键不能包含不必要的多余列。当把复合主键的某一列删除后,如果剩下的列构成的主键仍然满足唯一性原则,那么这个复合主键是不正确的。这是最小化原则。

三.MySQL存储引擎:(InnoDB,MyISAM )
InnoDB:
它提供了事务控制能力功能,它确保一组命令全部执行成功,或者当任何一个命令出现错误时所有命令的结果都被回退
区别:
MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。
MyISAM类型的表强调的是性能,其执行速度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持,外键等高级数据库功能。

3.a = ‘hello’ 和 b = ‘你好’ 编码成bytes类型

a = b'hello'
b = b'你好'

4.[1, 2, 3] + [4, 5, 6]的结果是多少

[1, 2, 3, 4, 5, 6]

5.解释一下python中有多少种运算符(is和==、join和+的区别)

-算术运算符(+,-,*,/,%,**,//)# /-结果为小数,//-结果取整数部分
-关系运算符(==,!=,>,<,>=,<=)# 返回bool值
-赋值运算符(=,+=,-=,*=,/=,%=,**=,//=)
-逻辑运算符(and,or,not)# 返回bool值
-位运算符(&,|,^,~,>>,<<)
-成员运算符(in,not in)# 返回bool值
-身份运算符(is, is not)# 返回bool值,判断变量是否引用自一个对象id()看地址否相同

==和is的区别:
==比较的是对象的值是否相等,内部调用__eq__(),可重载
is比较的是对象的身份,使用id()查看地址是否相同,不能重载

join 和 + 的区别(拼接字符串):
join先计算字符操作的空间大小在申请内存完成拼接,O(n)
+ 多个字符串每拼接一次会申请一个内存,时间复杂度O(n^2)

6.怎么移除一个字符串中的空格?

s = '    123'
s.lstrip()  # '123'
s = '123     '
s.rstrip()  # '123'
s = '   123    '
s,strip()  # '123'

strip()默认删除字符串前后的空格和换行符,也可以指定要删的字符

7.字符串大小写转换?

s = 'I love you'
s.lower()     # 全小写
s.upper()     # 全大写
s.title()       # 每个单词首字母大写
s.capitalize()  # 字符串第一个字母为大写

8.Python中的pass语句是什么?

是个空语句, 占位语句,为了保证程序结构的完整性

9.Python中的闭包是什么?

函数的嵌套,内层函数使用外层函数的局部变量,外层函数的返回结果是内层函数

# python中的闭包
def lazy_sum(*args):
	def sum():
		re = 0
		for i in args:
			re += i
		return re

	return sum

s = lazy_sum(1, 2, 3, 4, 5)
print(s, type(s), s(), sep='\n')

执行结果:
<function lazy_sum.<locals>.sum at 0x0000018A8D317840>
<class 'function'>
15

10.如何以就地操作的方式打乱一个列表的元素?

s = [1, 2, 3, 4, 5, 6]
random.shuffle(s)  # random模块的shuffle方法

11.解释python中的join()和split()函数

s1 = 'abcd'
s2 = [1, 2, 3, 4]
join()将容器对象拆分并以指定字符拼接起来,返回字符串str
''.join(s1)   # 'abcd'
'-'join(s2)   # '1-2-3-4'
split()以指定字符分割字符串,返回列表list
s3 = 'I love you'
s3.split()    # ['i', 'love', 'you'] 默认空格,可指定分隔符和分割次数

12.Python区分大小写吗?

区分,name和Name不一样, 会报NameError,没定义

13.Python中的标识符长度能有多长?

任意长度,开头 _ 或者字母,不能数字开头,其余部分都可以;
区分大小写,关键字不能作为标识符

14.列出python中的可变数据类型和不可变数据类型,并简述原理

可变:list,dict,set # 值变的时候对应的内存不变
不可变:int,str,tuple,float, bool # 改变值内存地址也改变

扫描二维码关注公众号,回复: 11882181 查看本文章

15.s = ‘ajldjlajfdljfddd’,去重并从小到大排列输出‘adfjl’

def str1(s):
	s1 = ''
	for i in s:
		if i not in s1:
			s1 += i

	return ''.join(sorted(s1))

print(str1('ajldjlajfdljfddd'))

执行结果:
adfjl

16.用lambda函数实现两个数相乘

lambda函数(匿名函数):即时使用简洁方便

# lambda函数实现两个数相乘
res = lambda x, y: x*y
print(res(5, 5))

执行结果:
25

17.用python删除文件和用linux命令删除文件方法

os.remove(path)  # path文件路径,可以提前判断文件和路径是否存在os.path.exists()
rm –rf path/filename

18.什么是猴子补丁?(monkey patch)

在运行时动态的替换方法、属性等
在不修改第三方代码的情况下增加原来不支持的功能
在运行时为内存中的对象增加patch而不是在磁盘的源代码中增加

# 猴子补丁 monkey patch
class Monkey:
	def monkey(self):
		return 'monkey'
	def main(self):
		return 'main'

m = Monkey()
print(m.main()) # main
m.main = m.monkey # 打补丁
print(m.main()) # monkey

19.写一个python逻辑,计算一个字符串中的大写字母数量

def upper_num(s):
	n = 0
	for i in s:
		if i == i.upper():
			n += 1

	return n
print(upper_num('adsfFAF'))  # 3

20.什么是负索引?

n = [1, 2, 3]
n[0] = n[-3] = 1
n[1] = n[-2] = 2
n[2] = n[-1] = 3

21.如何在一个函数内部修改局部变量?(nonlocal)

global 可以在函数内修改全局变量 3,2,3
nonlocal 可以在函数内修改函数外的局部变量 3,3,1
不使用声明,不能修改全局变量,输出为3,2,1

# global   可以在函数内修改全局变量
# nonlocal 可以在函数内修改函数外的局部变量
n = 1
def test():
	n = 2
	def test1():
		# global n      # 使用global   3,2,3
		# nonlocal n  # 使用nonlacal 3,3,1
		n = 3
		return n
	t = test1()
	print(t)  # global 3,nonlocal 3
	return n  # global 2,nonlocal 3

print(test())
print(n)      # global 3,nonlocal 1

22.简述面向对象中的__new__和__init__区别(new先init后)

继承自object的新式类才有__new__
1. __new__至少要有一个参数cls,代表要实例化的类,
此参数在实例化时由Python解释器自动提供
2. __new__必须要有返回值,返回实例化出来的实例,
这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,
或者直接是object的__new__出来的实例
3. __init__有一个参数self,就是这个__new__返回的实例,
__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
4. 若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行

23.Python中生成随机整数,随机小数,0-1之间的小数方法

import random
random.random()     # 返回0-1的随机小数,不包含0,1
random.randint(10, 20) # 返回10-20随机整数,包含10,20
random.uniform(10, 20)# 返回10-20随机小数,不包含10,20

24.避免转义给字符串加哪个字母表示原始字符串?(加r)

s = r'I \'love\' you\n'   # 加 r 忽视转义符号
s1 = 'I \'love\' you\n'
s2 = r'\[\d+\|[A-Z]+\]'   # 正则,腾讯第一题re.findall(s,str1)
s3 = '\[\d+\|[A-Z]+\]'
print(s, s1, s2, s3, sep='\n')

执行结果:
I \'love\' you\n
I 'love' you

\[\d+\|[A-Z]+\]
\[\d+\|[A-Z]+\]

例题:解压字符串。
输入一个字符串例如:‘A[2|B[3|C]]D’ 解压后为:‘ABCCCBCCCD’
匹配最小标准单位 ‘[数字|字母]’ 如:‘[2|A]’,表示2个A
对输入的字符串根据条件循环匹配:while ‘[’ in s: 一直匹配+替换
使用input输入:

def unzips(s):
    import re
    p = r'\[\d+\|[A-Z]+\]'
    while '[' in s:
        for b in re.findall(p, s):
            # re.findall 返回的是一个list包含所有匹配项
            n, s1 = re.findall(r'\d+', b)[0], re.findall(r'[A-Z]+', b)[0]
            s = s.replace(b, int(n)*s1)
    print(s)

if __name__ == '__main__':
# 输入s中只包含 '[', ']', '|', 'A-Z'
unzips('A[2|B[3|C]]D')  # ABCCCBCCCD
unzips('A[2|B[2|C]D]E') # ABCCDBCCDE

25.列举布尔值为False的常见值

None,False,值为零(0,0.0,0L,0.0+0.0j),
空字符串‘‘,空列表[],空字典{},空元组()

26.字符串,列表,元组,字典每个常用的5个方法?

字符串:islower,isdigit,format,decode,encode,find,count,index,endswith,ljust(左对齐)
列表:append,insert,pop,del,len,count,index,remove,reverse,sort
元组:len,min,max,cmp,del
字典:del,len,copy,clear,get,items,keys,values,has_key

27.*args和**kwargs作用

*args可传入多个位置参数
**kwargs可传入多个关键字参数
在类的继承和重写的时候用到*args和**kwargs接收父类的方法

函数传参‘*‘的使用:

# '*'的使用
def func(a, b, c):
	return a + b + c

print(func(1, 2, 3))

list1 = [1, 2, 3]  # list1的长度和形参个数保持一致
list2 = [2, 3]  # 小于lsit1,传参时多传一个参数,保证和形参个数一致

print(func(*list1))
print(func(1, *list2))

执行结果:
6
6
6

函数传参’*args’的使用(是一个元组):
也就是位置参数,可以有任意多个

# '*arg'的使用,是一个元组
def func(*args):
	print(args)

func(111)
func(222, 'aaa', [333])


def func(a, *args):
	print('a is : {}'.format(a))
	print('args is : {}'.format(args))

func(1)
func(1, 2, 3, 4)

执行结果:
(111,)
(222, 'aaa', [333])
a is : 1
args is : ()
a is : 1
args is : (2, 3, 4)

函数传参’**’的使用:

# '**'的使用
def func(a, b, c):
	return a + b + c

print(func(1, 1, 1))        # 位置传参
print(func(a=1, b=1, c=1))  # 关键字传参

d = {'a':1, 'b':1, 'c':1}   # 参数个数和形参个数保持一致
print(func(**d))            # 等同于func(a=1, b=1, c=1)

执行结果:
3
3
3

函数传参’**kwargs’的使用(是一个字典):
也就是关键字参数,可以有任意多个

# '**kwargs'的使用,是一个字典
def func(a, **kwargs):
	print('a is : {}'.format(a))
	print('kwargs is : {}'.format(kwargs))

func(1, b=2, c=3, d=4)

执行结果:
a is : 1
kwargs is : {'b': 2, 'c': 3, 'd': 4}

28.ascii,unicode,utf-8,gbk的区别

ASCII:
在计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit),有0和1两种状态,因此,8个二进制位可以组合出256种状态,这被称为字节(byte)。上个世纪60年代,美国制定了一套字符编码,对英文字符与二进制之间做了联系,这被称为ASCII码,一直沿用至今。
ASCII码一共规定了128个字符,比如SPACE是32,A是65,这128个符号只咱用了一个字节的后面七位,最前面的一位统一规定为0。

Unicode:
世界上有多种编码方法,同一个二进制数字可以被解释称不同的符号。因此,在打开一个文本文件时候,就必须知道它的编码方式,用错误的编码方式打开,就会出现乱码。
假如,有一种编码,将世界上所有的符号都纳入其中,每一种符号都给予独一无二的编码,那么乱码问题就不会存在了。因此,产生了Unicode编码,这是一种所有符号的编码。

GBK:
GBK编码是对GB2312的扩展,完全兼容GB2312。采用双字节编码方案,剔出xx7F码位,共23940个码位,共收录汉字和图形符号21886个,GBK编码方案于1995年12月15日发布。它几乎完美支持汉字,因此经常会遇见GBK与Unicode的转换。

UTF-8:
UTF8是Unicode的实现方式之一,也是最为常见的实现方式,它是一种变长编码,可以使用1-4个字节表示一个符号,根据不同的符号来变化字节长度。对于单字节的符号,字节的第一位设为0,后面的7位为这个符号的Unicode码。因此,对于英文字母,UTF8编码和ASCII编码是相同的。对于非单字节(假设字节长度为N)的符号,第一个字节的前N位都设为1,第N+1设为0,后面字节的前两位一律设为10,剩下的没有提及的二进制,全部为这个符号的Unicode码。

29.字节码和机器码的区别

机器码:
又叫原生码,是电脑CPU可直接解读的数据。就是计算机可以直接执行,并且执行速度最快的代码。

字节码:
二进制文件,是一种中间码。通常情况下它是已经经过编译,但与特定机器码无关。字节码通常不像源码一样可以让人阅读,而是编码后的数值常量、引用、指令等构成的序列

字节码是一种中间状态(中间码)的二进制代码(文件)。需要直译器转译后才能成为机器码。

30.三元运算写法和应用场景?

可以在赋值的时候,可以直接判断

# 三元运算符
def func(a, b):
	n = 1 if a > b else 0
	print(n)

func(2, 1)
func(1, 2)

执行结果:
1
0

31.Python3和Python2的区别

print,input,编码格式,py3取消long替换为int,
py3取消xrange替换为range,第三方包名字使用方法

32.一行代码实现数值交换

a = 1
b = 2
a, b = b, a

33.编写一个函数将IP地址转换成整数

ip = '127.168.1.1'
int(''.join([i for i in ip.split('.')]))

34.常用Linux命令

cd,rm,mv,cp,ls,ln,echo

35.Python中yield用法

生成器:使用yield语句的函数都称为生成器,也是一种迭代器(可迭代对象)
生成器函数只有在调用__next__()方法时才执行函数里面的语句,
__next__()的返回值就是生成值,每次调用__next__()方法时函数会运行到yield语句处停下来,
再次调用__next__()方法时才会从yield后的语句处开始继续执行。
一般不会手动调用__next__()方法,而是使用for循环:
for i in fab(5):
   print(i)
# yield生成器
def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        yield b      # 使用 yield
        # print(b)
        a, b = b, a + b 
        n = n + 1
# fab(5)返回一个可迭代对象,可以执行__next__()方法取到下一个值 
for n in fab(5): 
    print(n)  # 1 1 2 3 5
f = fab(5) # 调用函数不会执行fab函数,返回一个可迭代对象
print(f.__next__()) # 1
print(f.__next__()) # 1
print(f.__next__()) # 2
print(f.__next__()) # 3
print(f.__next__()) # 5

36.Python是如何内存管理的

(1)对象的引用机制
Python的内部使用引用计数来保持追踪内存中的对象,所有的对象都有引用计数。
引用计数增加:一个对象分配一个新名称;将一个对象放入容器中(list,tuple,dict)
引用计数减少:使用del语句对对象别名显式的销毁;引用超出作用域或被重新赋值sys.getrefcount()获取当前对象引用计数,函数也占一次计数,不可变数据(数字,字符串),解释器会在程序的不同部分共享内存,以节约内存。

(2)垃圾回收机制
当一个对象的引用计数归零后,它将被垃圾收集机制处理掉;
当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其它对象的引用,因此引用计数不会归零,对象也不会销毁(导致内存泄漏)。为了解决之一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们

(3)内存池机制
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到了内存池而不是直接返回给操作系统;
Pymalloc机制:为了加快python的执行效率,引入了一个内存池机制,用于管理对小块内存的申请和释放

python中所有小于256字节的对象都使用了pymalloc实现的分配器,而大的对象则使用系统的malloc

对于python对象,如整数,浮点数和list,都有其独享的私有内存池,对象间不共享它们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能在分配给浮点数

37.描述数组,链表,队列,堆栈的区别

1、数组与链表是数据存储方式的概念,数组在连续的空间中存储数据,而链表可以在非连续的空间中存储数据;python的list可以连续也可以不连续(存放多种数据类型)

2、队列和堆栈是描述数据存取方式的概念,队列是先进先出,而堆栈是后进先出;队列和堆栈可以用数组来实现,也可以用链表实现。

38.列表和元组有什么不同?

list可变,可以append,insert,pop
tuple不可变

39.解释python的help()和dir()函数

help():返回模块,类型,对象,方法,属性的详细消息
dir():返回一个类,对象的所有属性

40.当退出python时是否释放所有内存分配?

不是,循环引用其他对象或引用自全局命名空间的对象的模块,在python退出时并非完全释;另外,也不会释放c库保留的内存部分

41.迭代器和生成器的区别:

生成器是一种特殊的迭代器,使用yield语句的函数就是一个生成器,
yield保存当前运行状态,将生成器挂起,通过__next__()得到下一个值
# 生成器和迭代器
a = [i for i in range(3)]
b = (i for i in range(3))
print(a, b, sep='\n')

执行结果:
[0, 1, 2]
<generator object <genexpr> at 0x000001B2B5570ED0>

a,返回一个list [0, 1, 2] 可迭代对象
b,返回一个生成器,<generator object <genexpr> at 0x000001B2B5570ED0>
迭代器:一个对象包含__iter__()和__next__()方法,
可迭代对象通过__iter__()返回一个迭代器,然后不断地使用__next__()来获取对象里的值
区别:迭代器操作可迭代对象,返回数据;生成器操作生成器,返回生成器(携带数据
)

42.装饰器的作用和功能(语法糖)

装饰器是一种设计模式,用于动态的给对象添加行为,是一种语句的简便写法,
比如:a[idx] 就是 *[a+idx]
func1也是一个函数,特殊的是它的参数是一个函数,它的返回值是一个函数

# 装饰器,语法糖
def func1(f):
	def func2():
		print('111')
		f()
	return func2

@func1
def func():
	print('000')

func()

# 相当于:
def func1(f):
	def func2():
		print('111')
		f()
	return func2

def func():
	print('000')

func = func1(func)  # 等效于一个函数作为参数传入
func()  # 返回值是一个函数,再次调用函数

43.简单谈一下GIL(全局解释器锁)

由于GIL的存在python在同一时刻只能跑一个线程,这样在跑多线程的情况下,只有当线程获取到全局解释器锁后才能运行,而全局解释器锁只有一个,因此即使在多核的情况下也只能发挥出单核的功能。

44.如何提高python的运行效率

1、使用函数,局部变量比全局变量快很多
2、选择性的消除属性访问,使用:from math import sqrt 而不用import math然后math.sqrt()
3、避免不必要的抽象,如装饰器@property等
4、使用python内置数据结构容器
5、变量缓存,可重复利用
6、if语句优化

45.1行代码实现1-100之和

sum(range(101))
(1+100)*100//2

46.字典如何删除键和合并两个字典

删除键:

my_dict = {'a':1, 'b':2, 'c':3}
del my_dict['a']  # 删除键

合并字典:

# 合并字典
# 1
a = {'a':1, 'b':2, 'c':3}
b = {'d':4, 'e':5, 'f':6}
print(dict(a, **b))
# print(dict(a.items() + b.items()))  # py3不支持

# 2
c = {}
c.update(a)
c.update(b)

print(c)

执行结果:
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}

47.Python列表去重的方法

a = [1, 2, 3, 3, 2]
list(set(a))  # set()去重
b = {}     # dict()去重,字典键唯一
b = b.fromkeys(a)
c = list(b.keys())  # 字典的key转为list

48.Python中如何实现多线程

能独立运行的基本单位————线程
进程的创建,撤销,与切换存在较大的时空开销,因此需要引进轻型进程
进程是资源分配的最小单位,线程是cpu调度的最小单位,每一个进程至少有一个线程
进程是车间,线程是车间中的每一个工人

进程中可以开启多个线程
(1)开启一个线程所需的时间要远远小于开启一个进程
(2)多个线程内部有自己的数据栈,数据不共享
(3)全局变量在多个线程之间是共享的

python中GIL(全局解释器锁)确保一次执行单个线程。一个线程保存GIL并在将其传递给下个线程之前执行一些操作,这会让我们产生并行运行的错觉。实际上只是线程在CPU上轮流运行,当然,所有的传递会增加程序执行的内存压力。Python的多线程主要是由于IO阻塞的情况下不会等待,而是把cpu给到另一个线程继续执行。

实现python的多线程可以利用threading模块配合循环分配线程
开了守护线程,该线程会在所有子线程执行结束后才会结束

import time
from threading import Thread

def func1():
    while True:
        print('1'*10)
        time.sleep(1)

def func2():
    time.sleep(5)
    print('func2')
    
t = Thread(target=func1,)
t.daemon = True #守护线程
t.start()
t2 = Thread(target=func2,)
t2.start()
print('主线程')

执行结果:
1111111111
主线程
1111111111
1111111111
1111111111
1111111111
func2

49.解释python的继承

假设有三个类A,B,C
C继承B,B继承A,那么C就拥有A的所有属性和方法
在需要的位置使用super.父类方法的方式继承父类方法可以重写父类的方法,也可以添加新的方法

拓展部分:
1、常见设计模式:
https://www.cnblogs.com/tangkaishou/p/9246353.html

2、装饰器:
http://c.biancheng.net/view/1366.html

猜你喜欢

转载自blog.csdn.net/weixin_42563968/article/details/108549733
今日推荐