python面试问题

python基础

meta编程(元编程)
元编程指编写代码的代码
python中,元编程是指一种构建函数和类的行为,这些函数和类可以通过修改、包装现有代码或生成代码来进行操纵。实现方法是装饰器或者元类(type)

  • 装饰器(不赘述)
def descr(func):
     @wraps(func)
     def inner(*args, **kwargs):
         print("descr after")
         req = func(*args, **kwargs)
         print("descr before")
         return req
     return inner
  • 元编程
    "python中,type生class,class生万物,type则自己生自己"
>>> class Foo:
...  pass
...
>>> type(Foo)
<class 'type'>
>>> f = Foo()
>>> type(f)
<class '__main__.Foo'>
>>> type(type)
<class 'type'>

上面代码显示了类实例,类和type的关系。也可以用.__class__来追溯这一过程。
下面用type来创造一个类

>>>class_example = type('class_example', (), {}) # 三个参数分别是类名字,继承的父类和类属性*(方法,属性等)
>>>print(class_example)
<class '__main__.class_example'>

同理python使用中经常用到的hasattr和setattr可查询和添加类属性(方法,属性)

>>> f.attr1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'attr1'
>>> setattr(Foo,"attr1","reslut attr1")
>>> f.attr1
'reslut attr1'
  • metaclass
    整个元编程上面都说完了,只是用起来没那么简洁或者没那么oop。metaclass就是生成类的方法(函数)
def my_meta(classname, father_class, attr):
    return type(classname, father_class, attr)


class Foo:
    __metaclass__ = my_meta

上面代码看得出,在创建class的时候python是去找的__metaclass__方法,要是没找到就直接用type,这里我们自定义了一个__metaclass_。(另外子类不继承父类的__metaclass__更深层次的看参考文章1)
应用实例:
django的model.Model。在orm(特指django的orm)中所有class都继承了model.Model在Ctrl点击进去看看就明白了

class Classes(models.Model):
    name = models.CharField(max_length=32)
    institude = models.CharField(max_length=32)
    headteacher = models.ForeignKey("Teacher")

Ctrl点进去models.Model

class Model(metaclass=ModelBase):  # == __meaclass__ 通过继承的方式显的更oop一些嘛
    ......

Ctrl点进去ModelBase

class ModelBase(type):  # 这里继承type也证明了一切都是type来的,包括你__metalclass__
    """Metaclass for all models."""
    def __new__(cls, name, bases, attrs, **kwargs):
        super_new = super().__new__
    ......

通过这种继承Model,Model再里面进行操作,最终导致我们在调用orm对象(一个实例)的属性(.age .name)的时候直接返回的是具体的数字或者字符串而不是IntegerField或者CharField的对象。
忽悠:元编程就是编写代码的代码,python中都知道万物皆对象,对象由类通过new生成,new调用init初始化内存生成实例。那类就是由metaclass调用type生成的。type就是元编程的方式之一。可以通过调用type和三个参数直接生成一个类;也可以在类中添加__metaclass__自定义方法最后return一个type,其实还是type。也可以通过setattr来修改类。广义上讲装饰器也是元编程,它也修改了函数这个对象的代码,所以叫编写代码的代码。比如django的model就是这么实现。装逼的说说......
参考链接:
https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python/6581949#6581949
https://blog.csdn.net/cdlwhm1217096231

  • python2和3的区别
    语法上:print input
    编码上:python3默认使用utf-8
    迭代器:生成列表range
    模块上:注意模块使用的不同
  • 生成器和迭代器
    迭代器是指实现iter和next方法的就是迭代器,生成器是延伸出来的通过yeild实现。
  • 深拷贝
from copy import deepcopy
a = [1,2,3,[4,5]]
b=a
c = deepcopy(a)   // 深拷贝,copy.copy是浅拷贝。第一层相互不影响,内层影响
a.append(6)
b.append(7)
a[3].append(11)
print(a)
print(b)
print(c)
  • map,filter,reduce
    map:将一个列表(可迭代类型)每个元素带入到一个函数中 a = list(map(lambda x:x*x,[1,2,3])) 结果是 [1,4,9]
    filter:同理过滤一个列表 a = list(filter(lambda x:x%2==1, [1,2,3,4,5])) 结果是[1,3,5]
    reduce:将列表前后迭代入函数 a = reduce(lambda x, y: x + y, [1,2,3,4]) 结果是1+2+3+4=10
  • 多肽
    python面向对象的三个特征:封装,继承,多肽
    封装:使用构造方法将内容封装到对象中
    继承:继承父类,python3新式类的c3算法。
  • 字典的排序
    一种方法,多了不记,恶心蛋疼。
    sorted(dict.items(), lambda x:x[0]) # 0表示key排序 1表示值排序 reverse参数
  • 正则匹配中search和match
    match是开头匹配。search是在字符串中,并且match返回<re.Match object; span=(0, 5), match='https'> span表示从哪里匹配到的。search的方法是.group 返回匹配的数据。.groups返回一个列表里面是匹配在括号的内容。

框架(django主)相关

  • orm查询
    字段设置:
    V=models.CharField(max_length=None<, options>)    #varchar
    V=models.EmailField(<max_length=75, options="">)    #varchar
    V=models.URLField(<verify_exists=true, options="" max_length="200,">)    #varchar
    V=models.FileField(upload_to=None<, max_length=100, options>)    #varchar #upload_to指定保存目录可带格式,
    V=models.ImageField(upload_to=None<, height_field=None, width_field=None, max_length=100, options>)
    V=models.IPAddressField(<
    options>)    #varchar
    V=models.FilePathField(path=None<, match=None, recursive=False, max_length=100, options>) #varchar
    V=models.SlugField(<max_length=50, options="">)    #varchar,标签,内含索引
    V=models.CommaSeparatedIntegerField(max_length=None<, options>)    #varchar
    V=models.IntegerField(<
    options>)    #int
    V=models.PositiveIntegerField(<
    options>)    #int 正整数
    V=models.SmallIntegerField(<
    options>)    #smallint
    V=models.PositiveSmallIntegerField(<
    options>)    #smallint 正整数
    V=models.AutoField(
    options)    #int;在Django代码内是自增
    V=models.DecimalField(max_digits=None, decimal_places=None<, options>)    #decimal
    V=models.FloatField(<
    options>)    #real V=models.BooleanField(
    options)    #boolean或bit
    V=models.NullBooleanField(<
    options>)    #bit字段上可以设置上null值
    V=models.DateField(<auto_now=false, **options="" auto_now_add="False,">)  #date #auto_now最后修改记录的日期;auto_now_add添加记录的日期
    V=models.DateTimeField(<auto_now=false, **options="" auto_now_add="False,">)    #datetime
    V=models.TimeField(<auto_now=false, options="" auto_now_add="False,">)    #time
    V=models.TextField(<
    options>)    #text
    V=models.XMLField(schema_path=None<, **options>)    #text ——————————————————————————–
    V=models.ForeignKey(othermodel<, **options>)    #外键,关联其它模型,创建关联索引
    V=models.ManyToManyField(othermodel<, **options>)    #多对多,关联其它模型,创建关联表
    V=models.OneToOneField(othermodel<, parent_link=False, **options>)    #一对一,字段关联表属性
    字段参数设置:
    null 数据库中字段是否可以为空
    db_column 数据库中字段的列名
    default 数据库中字段的默认值
    primary_key 数据库中字段是否为主键
    db_index 数据库中字段是否可以建立索引
    unique 数据库中字段是否可以建立唯一索引
    unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
    unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
    unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
    verbose_name Admin中显示的字段名称
    blank Admin中是否允许用户输入为空
    editable Admin中是否可以编辑
    help_text Admin中该字段的提示信息
    choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
    如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
    error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
    字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
    如:{'null': "不能为空.", 'invalid': '格式错误'}
    validators 自定义错误验证(列表类型),从而定制想要的验证规则
    from django.core.validators import RegexValidator
    from django.core.validators import EmailValidator,URLValidator,DecimalValidator,
    MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
    如:
    test = models.CharField(
    max_length=32,
    error_messages={
    'c1': '优先错信息1',
    'c2': '优先错信息2',
    'c3': '优先错信息3',
    },
    validators=[
    RegexValidator(regex='root_d+', message='错误了', code='c1'),
    RegexValidator(regex='root_112233d+', message='又错误了', code='c2'),
    EmailValidator(message='又错误了', code='c3'), ]
    )
    元信息:
    class UserInfo(models.Model):
    nid = models.AutoField(primary_key=True)
    username = models.CharField(max_length=32)
    class Meta:
    # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
    db_table = "table_name"
    # 联合索引
    index_together = [
    ("pub_date", "deadline"),
    ]
    # 联合唯一索引
    unique_together = (("driver", "restaurant"),)
    # admin中显示的表名称
    verbose_name
    # verbose_name加s
    verbose_name_plural
    多对多参数:
    ForeignKey(ForeignObject) # ForeignObject(RelatedField)
    to, # 要进行关联的表名
    to_field=None, # 要关联的表中的字段名称
    on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
    - models.CASCADE,删除关联数据,与之关联也删除
    - models.DO_NOTHING,删除关联数据,引发错误IntegrityError
    - models.PROTECT,删除关联数据,引发错误ProtectedError
    - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
    - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
    - models.SET,删除关联数据,
    a. 与之关联的值设置为指定值,设置:models.SET(值)
    b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

                                                      def func():
                                                          return 10
    
                                                      class MyModel(models.Model):
                                                          user = models.ForeignKey(
                                                              to="User",
                                                              to_field="id"
                                                              on_delete=models.SET(func),)
      related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
      related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
      limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
                                  # 如:
                                          - limit_choices_to={'nid__gt': 5}
                                          - limit_choices_to=lambda : {'nid__gt': 5}
    
                                          from django.db.models import Q
                                          - limit_choices_to=Q(nid__gt=10)
                                          - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                          - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
      db_constraint=True          # 是否在数据库中创建外键约束
      parent_link=False           # 在Admin中是否显示关联数据
    

    OneToOneField(ForeignKey)
    to, # 要进行关联的表名
    to_field=None # 要关联的表中的字段名称
    on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为

                                  ###### 对于一对一 ######
                                  # 1. 一对一其实就是 一对多 + 唯一索引
                                  # 2.当两个类之间有继承关系时,默认会创建一个一对一字段
                                  # 如下会在A表中额外增加一个c_ptr_id列且唯一:
                                          class C(models.Model):
                                              nid = models.AutoField(primary_key=True)
                                              part = models.CharField(max_length=12)
    
                                          class A(C):
                                              id = models.AutoField(primary_key=True)
                                              code = models.CharField(max_length=1)
    

    ManyToManyField(RelatedField)
    to, # 要进行关联的表名
    related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
    related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
    limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
    # 如:
    - limit_choices_to={'nid__gt': 5}
    - limit_choices_to=lambda : {'nid__gt': 5}

                                          from django.db.models import Q
                                          - limit_choices_to=Q(nid__gt=10)
                                          - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                          - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
      symmetrical=None,           # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
                                  # 做如下操作时,不同的symmetrical会有不同的可选字段
                                      models.BB.objects.filter(...)
    
                                      # 可选字段有:code, id, m1
                                          class BB(models.Model):
    
                                          code = models.CharField(max_length=12)
                                          m1 = models.ManyToManyField('self',symmetrical=True)
    
                                      # 可选字段有: bb, code, id, m1
                                          class BB(models.Model):
    
                                          code = models.CharField(max_length=12)
                                          m1 = models.ManyToManyField('self',symmetrical=False)
    
      through=None,               # 自定义第三张表时,使用字段用于指定关系表
      through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
                                      from django.db import models
    
                                      class Person(models.Model):
                                          name = models.CharField(max_length=50)
    
                                      class Group(models.Model):
                                          name = models.CharField(max_length=128)
                                          members = models.ManyToManyField(
                                              Person,
                                              through='Membership',
                                              through_fields=('group', 'person'),
                                          )
    
                                      class Membership(models.Model):
                                          group = models.ForeignKey(Group, on_delete=models.CASCADE)
                                          person = models.ForeignKey(Person, on_delete=models.CASCADE)
                                          inviter = models.ForeignKey(
                                              Person,
                                              on_delete=models.CASCADE,
                                              related_name="membership_invites",
                                          )
                                          invite_reason = models.CharField(max_length=64)
      db_constraint=True,         # 是否在数据库中创建外键约束
      db_table=None,              # 默认创建第三张表时,数据库中表的名称
    

查询参数:
# 大于,小于
#
# models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值
# models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值
# models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值
# models.Tb1.objects.filter(id__lte=10) # 获取id小于10的值
# models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值

    # in
    #
    # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
    # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
    # order by
    #
    # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
    # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc
    # group by
    #
    # from django.db.models import Count, Min, Max, Sum
    # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
    # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE 
    "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
    # limit 、offset
    #
    # models.Tb1.objects.all()[10:20]

外键查询:
A表中ForeignKeyB(字段名b),A中有B
A.b 正常通过点来获取
A.objects.filter(b__id=0) 链式查询
B.A_set 反向查

  • 懒加载机制
    queryset默认施行懒加载,在.all()的queryset对象中,_result_cache用来缓存查询结果,只有在print或者list真正使用时候才在_result_cache中有数据。同理这种做法缺点也有容易多次重复查询。解决办法是:select_raleted和prefetch_raleted方法。前者是针对一对一和一对多,后者则是针对多对多或者方向一对多。两者都是一次讲关联数据查询到,防止重复查询。

  • asgi
    同 WSGI 一样,Django 也支持使用 ASGI 来部署,它是为了支持异步网络服务器和应用而新出现的 Python 标准。--来自django文档

  • 接口限流
    django throttle(基于登录未登录次数和频率)

  • 事务装饰器
    @transaction.atomic
    def view(req):
    try:
    ...
    save1 = transaction.savepoint()
    with tansaction.atomic():
    ...
    except:
    transaction.savepoint_rollback(save1) # 回滚到保存点
    transaction.savepoint_commit(save1) # 提交从保存点到当前状态的所有数据库事务操作

  • tornado异步调用同步
    文档推荐@run_on_exector(装饰器)调用同步函数。如若堵死,用concurrent开启多线程。
    数据库相关(mysql主)

  • 聚簇原则
    innodb的b+tree主键和数据行data都在一个子叶上,找到主键就找到了数据行。二级索引保存的是主键值,二级索引至少要两次查询才能找到数据行

  • cache机制(未命中走那两层)
    首先mysql的缓存机制是:
    当命中缓存是,会跳过sql解析,优化,生成计划阶段返回数据。而要命中缓存对sql要求很高,不能包含不确定sql语句(NOW(),CURRENT_DATE(),自定义函数,用户变量,有列权限的表等),且空格,注释的不同也不会命中。一旦涉及到的表或者数据库改变则缓存失效。
    缓存优点和缺点:查询很快,因为缓存存在内存中。缺点是每次的写操作会带来额外的失效缓存的时间;每次生成缓存排它锁一下;一旦某个大表缓存碎片很多,经历过一次修改后,造成雪崩。所以根据优缺点去设置表的缓存。
    mysql就连接层,sql服务层,引擎层和存储层,还搁那里两层。面试的人一般都要显示自己的牛逼。

  • b+tree能存多少数据,计算方式
    假设一个页数据默认16KB,主键一般占用4B,外加其他数据假如是12B。那一个页就有1k(1024)个主键,三阶就能存10**3乘三次就是10亿数据。

  • redis哪些数据结构和语法
    字符串类型:get,set,mset,mget,setbite
    hash类型:hget,hset,hmset,hgetall
    list:lpop,lpush,lindex

  • 关系型和非关系型数据库的区别
    结构上:关系型数据结构固定;非关系型离散,k-v对,文档类型。MongoDB字段和表都是随意添加。
    扩展性:关系型横向拓展不容易
    数据一致性:关系型对ACID要求严格

  • 为什么使用monggodb,为什么使用mysql
    MongoDB新增数据或者增加字段非常容易,mysql则是我们结构性字段,一般不修改。修改就是大修改。

算法
匹配一个IP地址

import re
#简单的匹配给定的字符串是否是ip地址,下面的例子它不是IPv4的地址,但是它满足正则表达式
if re.match(r"^(?:[0-9]{1,3}.){3}[0-9]{1,3}$", "272.168,1,1"):
    print "IP vaild"
else:
    print "IP invaild"
#精确的匹配给定的字符串是否是IP地址
if re.match(r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$", "223.168.1.1"):
    print "IP vaild"
else:
    print "IP invaild"
#简单的从长文本中提取中提取ip地址
string_ip = "is this 289.22.22.22 ip ?
result = re.findall(r"(?:[0-9]{1,3}.){3}[0-9]{1,3}", string_ip)
if result:
    print result
else:
    print "re cannot find ip"
#精确提取IP
result = re.findall(r"(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)", string_ip):
if result:
    print result
else:
    print "re cannot find ip
  • 冒泡,归并和快速
# 冒泡 先排最大的 所以第二循环去除最后len(arr) - 1
# def bubbleSort(arr):
#     g = 0
#     for i in range(1, len(arr)):
#         for j in range(0, len(arr)-i):
#             g += 1
#             if arr[j] > arr[j+1]:
#                 arr[j], arr[j + 1] = arr[j + 1], arr[j]
#             print(arr)
#     print(g)
#     return arr
# bubbleSort(a)

# 归并 无限分成两段 默认每段都是有序的 俩俩比对
# def merge(l, r):
#     req = []
#
#     while l and r:
#         if l[0] < r[0]:
#             req.append(l.pop(0))
#         else:
#             req.append(r.pop(0))
#
#     if l:
#         for i in l:
#             req.append(i)
#     if r:
#         for i in r:
#             req.append(i)
#     return req
#
# def merge_s(a):
#     if len(a) < 2:
#         return a
#     mid = round(len(a)/2)
#     l = a[0:mid]
#     r = a[mid:]
#     return merge(merge_s(l), merge_s(r))
#
# print(merge_s(a))
# 
# 快速排序
# def quicksort(arr):
#     if len(arr) <= 1:
#         return arr
#     pivot = arr[round(len(arr) / 2)]
#     left = [x for x in arr if x < pivot]
#     middle = [x for x in arr if x == pivot]
#     right = [x for x in arr if x > pivot]
#     return quicksort(left) + middle + quicksort(right)

网络和web

  • tcp/ip五层结构
    应用层:应用程序和他们的协议存放的地方。HTTP,SMTP,FTP
    运输层:运送应用程序端点之间传送应用层报文。TCP,UDP
    网络层:负责主机间的数据交互 IP
    链路层:负责路由数据报文
    物理层:负责更进一步
  • 上下文管理器如何切换
    1挂起被中断的进程或者线程(系统中断,用户yeild)2 讲挂起的进程信息(堆栈,指令行)保存到cpu的一个内存中(PCB) 3cpu寄存器加载下个进程在PCB的信息 4在被中断的位置找到指令行执行
  • 内核态和用户态
    系统执行进程的两种状态。区别在于权力的大小:内核态是cpu ring0级用户态是ring4级别,内核态可以调配系统资源(cpu,内存,文件和网络等)而限制用户态的权力。用户态用过系统调用转为内核态
原文地址:https://www.cnblogs.com/khal-Cgg/p/14533636.html