美文网首页
Python常见的基础面试题(day02)

Python常见的基础面试题(day02)

作者: 莫辜负自己的一世韶光 | 来源:发表于2019-03-11 20:59 被阅读0次

    1.Python的自省机制,以及比较常见的自省机制(函数用法)

    什么是自省
    自省就是程序在运行的时候可以明确的知道对象的类型.

    Python中常见的运用到自省机制的方法有哪些?

    • dir()函数
      dir()返回的是传递给它的任何对象的属性名称的列表.如果不指定对象,则dir()返回当前作用域中的名称.
      例如:
    >>> import keyword
    >>> dir(keyword)
    ['__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'iskeyword', 'kwlist', 'main']
    
    • type()
      type()用来确定我们的对象的类型.
    >>> type(42)
    <class 'int'>
    >>> type([])
    <class 'list'>
    
    • hasattr()和getattr()
      用来判断一个对象是否拥有某个属性
    >>> hasattr(id, '__doc__')
    True
    
    • isinstance()
      isinstance用来检测某个对象或者类是否属于某个类型.
    >>> isinstance("python", str)
    True
    

    2.类变量和实例变量

    类变量:
    1. 类变量是属于类的变量,不依赖于具体的实例对象,在内存中只有一份,所有的实例都共享这个类变量
    2. 实例对象和类都可以调用类变量,类变量一般定义在一个类的开头

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/6 14:07'
    
    # 类属性
    class Person(object):
        name = 'Tom' # 公有的类属性
        __age = 28   # 私有的类属性
    
    p = Person()
    print(p.name) # 实例对象调用类属性
    print(Person.name) # 类对象调用类属性
    # print(p.__age) # 错误 不能通过类实例直接访问私有的类属性
    # print(Person.__age) #错误 不能通过类对象直接访问私有的类属性
    

    实例变量:
    1.实例变量是属于具体的实例对象的变量,它依赖对象的存在而存在,每个对象的实例变量都是分开存储的
    2.实例变量只有实例对象才可以调用,实例变量一般在__init__()方法中进行定义初始化,或者使用实例加.的方式

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/6 14:12'
    class Person(object):
        name = 'Tom'  # 实例属性
    
    p = Person()
    p.age = 18
    
    print(p.name,p.age)
    # print(Person.age) # 错误,实例属性只能由实例调用,类对象不能调用
    
    print(p.name)
    print(Person.name)
    
    p.name = 'Jack'
    print(p.name,Person.name)  # 这里打印 Jack Tom 而不是 Jack Jack
    # 不能通过实例对象,修改类属性,它只会去创建一个实例属性,并不会改变类属性的值.
    

    3.类方法@classmethod,静态方法@staticmethod,实例方法objectmethod

    实例方法:
    定义:上面没有装饰器符号,第一个参数必须是实例对象,一般我们用self表示.通过它可以传递实例的属性和方法,也可以传递类的属性和方法.
    调用:只能通过实例来调用,类是没有办法调用实例方法的.

    类方法
    定义:上面有装饰器符号@classmethod,第一个参数必须是类对象,一般用cls来表示.通过它可以传递类的属性和方法,但是不能传递实例对象的属性和方法

    调用:实例对象和类对象都可以调用类方法.但是通过实例调用的时候,会被当成是类对象来处理.

    静态方法
    定义:和普通的函数没有什么区别?对参数没有要求.唯一的区别就是在方法上加一个@staticmethod.但是静态方法不能使用任何类的或者实例对象的属性,它就是一个普通的函数,放到了类中.
    调用:类对象和实例对象都可以调用

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/6 14:21'
    class Foo(object):
        # 实例方法
        def instance_method(self):
            print("这是类{}的实例方法,只能被实例对象调用".format(Foo))
    
        @classmethod
        def class_method(cls):
            print('这是类方法')
    
        @staticmethod
        def static_method():
            print('这是静态方法')
    
    foo = Foo()
    foo.instance_method()
    foo.class_method()
    foo.static_method()
    
    print('下面的方法只能通过实例来调用')
    foo.instance_method()
    # Foo.instance_method() 错误:类对象不能调用实例方法
    
    Foo.class_method()
    Foo.static_method()
    

    3.装饰器@property 和 @xxx.setter的用法

    @property
    1.这个方法的功能就是将一个属性,当成一个函数来调用.函数名必须和属性名一致.
    2.当给一个方法加上@property时,相当于是创建了一个getter方法,可以通过函数的方式获取这个属性的值
    3.@property装饰器你本身又创建了另外一个装饰器@xxx.setter

    @xxx.setter方法,相当于是给一个属性,加上了setter方法,可以再设置属性加一些判断,这样可以让一个属性的赋值安全和可控,不会再出现随便赋值的情况.

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/11 11:24'
    
    
    class Student(object):
        def __init__(self, name):
            self.name = name
    
        @property
        def score(self):
            return self.__score
    
        @score.setter
        def score(self, value):
            if not isinstance(value, int):
                raise ValueError('值必须是一个整数')
            if value < 0 or value > 100:
                raise ValueError('值必须在0到100之间')
    
            self.__score = value
    
    
    if __name__ == '__main__':
        s = Student('fioman')
        s.score = 100  # 直接赋值,相当于是调用了@score.setter装饰器装饰的方法
        print(s.score)  # 获取值,相当于是调用@property装饰器装饰的方法
        s.score = 1000  # 这里会报错
        print(s.score)
    

    通过只定义@property的方法,让一个属性只读,不可以设置更改
    如果一个类,它给一个函数只定义了@property装饰器,并没有定义@xxx.setter装饰器,则这个由函数改装之后的属性就是只读的属性,不能够设置更改

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/11 11:35'
    
    
    class Person(object):
        def __init__(self, name):
            self._birth = None
    
        @property
        def birth(self):
            return self._birth
    
        @birth.setter
        def birth(self, value):
            if 0 < value < 2020 and isinstance(value, int):
                self._birth = value
            else:
                raise ValueError('值错误')
    
        @property  # 年龄自动计算,不可以设置.是只读的属性
        def age(self):
            return 2019 - self.birth
    
    
    if __name__ == '__main__':
        p = Person('fioman')
        p.birth = 1987
        print(p.age)
    

    这里的birth就是只读的属性,因为它是可以通过生日计算出来的,所以没必要设置.

    4.Reverse number(将一个带负号的数反转)

    给定一个32位有符号整数,反转这个数显示.
    例子:
    Input:123
    Output:321
    Input:-123
    Output:-321
    Input:120
    Output:21

    思路,用切片.首先后去这个数的绝对值,然后操作绝对值.如果是负数,就在反转之后的数前面加个负号即可.字符串转换为int的时候,前面如果是0,会自动去除掉.

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/11 17:04'
    
    
    def reverse_number(num):
        ret = str(abs(num))[::-1] # 先将它的绝对值反转
        return int(ret) if num >=0 else -int(ret) # 根据它是否大于0来决定是否加负号
    
    
    if __name__ == '__main__':
        print("请输入一个数,可以带符号")
        num = int(input())
        num = reverse_number(num)
        print(num)
    

    5.简述下函数式编程,以及map和zip的使用.

    函数式编程是什么

    函数也是一个对象,可以看成是一个变量,可以作为参数传入另外一个函数,也可以作为另外一个函数的返回值.闭包和装饰器就是利用了函数式变成.

    好处:

    一个函数完成简单的功能,多个函数任意组合之后,可以完成更大的功能.

    高阶函数

    当满足如下条件之一的都是高阶函数.以函数作为参数,或者返回值也是一个函数.

    zip函数(打包成一个由元组组成的zip对象)
    原型:
    zip_object_iterable = zip(*iterable)
    将N个可迭代对象打包成一个包含元组的zip对象,并且这个对象也是可迭代的.通过list()可以将其转换为元组列表.元组的个数由可迭代对象中的最小元素个数决定.
    也就是说zip是一个打包函数,将后面的可迭代对象分别取出一个元素组成一个元组,然后由这些元组组成一个可迭代的zip对象.

    *zip(iterables)是zip的逆过程,将数据还原成打包之前的数据

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/11 19:52'
    
    a = [1,2,3]
    b = [4,5,6]
    c = [4,5,6,7,8]
    
    zipped = zip(a,b) #返回一个zip对象
    print(zipped) #<zip object at 0x0000025348B743C8>
    # 转化为列表
    list_zip = list(zipped)# 因为zip对象是可迭代的
    print(list_zip) # [(1, 4), (2, 5), (3, 6)]
    
    # 同时也可以直接遍历zip对象
    for i in list_zip:
        print(i) # (1, 4)(2, 5)(3, 6)
    
    # 当两个可迭代的对象长度不一致时,按最短的那个来生成结果
    zipped = zip(a,b,c)
    print(zipped)
    # 转换为元组
    tuple_zip = tuple(zipped)
    for i in tuple_zip:
        print(i)
    # 1, 4, 4) (2, 5, 5) (3, 6, 6)
    
    print(*zip(a,b,c))
    # (1, 4, 4) (2, 5, 5) (3, 6, 6)
    

    map函数(映射)
    原型:
    iterable = map(function,iterable1,iterable2,...)
    作用:

    将后面的可迭代对象,作为参数依次带入前面的function,用返回值生成一个新的可迭代对象.
    注意参数的个数必须和后面的可迭代的对象的个数一致.还有就是当有一个可迭代对象迭代完成,就结束求值.

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/11 20:20'
    
    
    # 使用map实现1到9的平方和
    def square_number(x):  # 求一个数的平方
        return x * x
    
    
    if __name__ == '__main__':
        # 使用遍历:
        ret = 0
        for i in range(1, 10):
            ret += square_number(i)
        print(ret)
        # 使用sum函数
        ret = sum(map(square_number, range(1, 10)))
        print(ret)
        # 使用lambda表达式一行实现
        print(sum(map(lambda x : x * x,range(1,10))))
    

    总结:map就是通过第一个参数传递函数,后面的可迭代对象分别作为参数.然后带入前面的函数映射成一个新的可迭代对象

    filter函数(过滤)
    原型
    iterable = filter(function,iterable)
    作用:

    将一个可迭代对象带入前面的function,如果function的返回值是真,就保留,如果是假,就丢弃过滤掉.
    然后将保留的放入到一个可迭代对象中返回.

    写一个过滤器,求100到200之间所有素数的和

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/11 20:32'
    
    
    def isPrimer(num):
        for i in range(2, num):
            if num % i == 0:
                return False
        return True
    
    
    # 通过filter过滤掉不是素数的数,只保留素数.
    ret = sum(filter(isPrimer, range(100, 201)))
    
    print(ret)
    

    写一个过滤器,过滤掉字符串中出现的数字

    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/11 20:39'
    
    
    def filter_number(c):
        if c >= '0' and c <= '9':
            return False
        return True
    
    
    s = "abcdefg12adf34hg012"
    
    ret = list(filter(filter_number, s))  # 过滤掉,直接转换为列表
    print(ret)
    
    # 使用lambda表达式搞定
    ret = list(filter(lambda c: False if '0' <= c <= '9' else True, s))
    print(ret)
    

    sorted函数(通过比较函数,进行排序的高阶函数)
    原型
    list = sorted(iterable,key=None,reverse=False)
    功能:

    传入一个可迭代对象,key是一个只传递一个参数的函数,用它的结果作为比较的键.reverse来决定是否反转.默认是升序.

    >>>sorted([5, 2, 3, 1, 4])
    [1, 2, 3, 4, 5]                      # 默认为升序
    
    # encoding:utf-8
    __author__ = 'Fioman'
    __time__ = '2019/3/11 20:50'
    # 将一个列表按照它的负数的大小从小到大进行排序
    L = [1, 4, 7, 6, 8, 10, 2, 3]
    L1 = sorted(L, key=lambda x: x * -1)
    print(L, L1)
    # 1, 4, 7, 6, 8, 10, 2, 3] [10, 8, 7, 6, 4, 3, 2, 1]
    L = [('a', 1), ('b', 2), ('c', 6), ('d', 4), ('e', 3)]
    # 按照字符串记性排序
    L2 = sorted(L,key=lambda x:x[0])
    print(L2)#[('a', 1), ('b', 2), ('c', 6), ('d', 4), ('e', 3)]
    # 按照数值降序排序
    L3 = sorted(L,key=lambda x:x[1],reverse=True)
    # key指定一个只包含一个参数的函数,来制定排序规则
    print(L3)
    

    sorted和sort的区别?
    sorted不改变原来的可迭代对象,排序之后,原对象位置不变.
    sort是在原对象上进行操作,如果位置变动,会改变原来的可迭代对象.

    sort是应用在list的方法,而sorted可以应用于所有的可迭代对象.
    内建函数sorted方法返回的是一个新的list,而不是在原来的可迭代对象上进行操作.

    reduce函数() 对参数序列中元素进行累积
    定义:

    reduce(function,sequence,[,intial]) -> value
    function参数是一个有两个参数的函数,reduce依次从squence中取一个元素和上一次调用function的结果做参数再次调用function.
    第一次调用function时,如果提供了initial参数,会以sequence中得一个元素和initial作为参数调用function,否则会以序列sequence中的前两个元素做参数调用function

    举例:比如有列表lst = [1,2,3,4,5],我们希望得到每个元素的和,可以这么做.

    from functools import reduce
    
    lst = [1, 2, 3, 4, 5, 6, 7]
    print(reduce(lambda x, y: x + y, lst))
    

    如果我们希望得到乘积呢

    print(reduce(lambda x,y:x*y,lst))
    

    如果有初始化的值,这个时候就不是取列表的前两项,而是取初始值为第一个参数,序列的第一个元素为第二个参数,开始进行lambda函数的应用计算.

    print(reduce(lambda x,y : x + y ,lst,100))
    

    相关文章

      网友评论

          本文标题:Python常见的基础面试题(day02)

          本文链接:https://www.haomeiwen.com/subject/hhfvpqtx.html