编程环境

  • Android Studio 3.1.2

问题

  • 升级win10 到了4月份更新1803,启动AS给我来了个 0xc0000005

过程

  • 一切正常升级,除了自己手贱把 Windows Defender 升级到1803 额外的安全全部打开..

解决

  • 万能的stackoverflow 给了答案.问题就在于 Windows Defender 下的 ALSR 好像是内存随机化..(具体意义不太明确)

    https://stackoverflow.com/questions/47500401/android-studio-cannot-be-initialized-0xc0000005

  • 翻译成中文:

    • Windows Defender -> 应用与程序控制 ->Exploit Protection ->程序设置 ->添加程序自定义
    • 找到android stuido安装目录下的 /bin/studio64.exe 一定要完整目录.编辑
    • 找到两个ASLR相关项.强制化ASLR 和 自下而上ASLR ,替换系统设置,关掉.重启AS.

备注

  • win10高级选项 别乱动…


背景

  • 编程环境
    • Android Studio 3.2

解除订阅

  • CompositeDisposable:
    • 得到一个Disposable实例时
    • 调用CompositeDisposable.add()添加到订阅
    • 生命周期结束 CompositeDisposable.clear() 可快速解除.


资料来源如下

常用的Android开发的一些技能点以及BAT公司面试题汇集

  • 感觉自己白学了////😂////

  • 一道一道的找答案..


Android面试题

Android面试题除了Android基础之外,更多的问的是一些源码级别的、原理这些等。所以想去大公司面试,一定要多看看源码和实现方式,常用框架可以试试自己能不能手写实现一下,锻炼一下自己。

一、Android基础知识点

  • 四大组件是什么
  • 四大组件的生命周期和简单用法
  • Activity之间的通信方式
  • Activity各种情况下的生命周期
  • 横竖屏切换的时候,Activity 各种情况下的生命周期
  • Activity与Fragment之间生命周期比较
  • Activity上有Dialog的时候按Home键时的生命周期
  • 两个Activity 之间跳转时必然会执行的是哪几个方法?
  • 前台切换到后台,然后再回到前台,Activity生命周期回调方法。弹出Dialog,生命值周期回调方法。
  • Activity的四种启动模式对比
  • Activity状态保存于恢复
  • fragment各种情况下的生命周期
  • Fragment状态保存startActivityForResult是哪个类的方法,在什么情况下使用?
  • 如何实现Fragment的滑动?
  • fragment之间传递数据的方式?
  • Activity 怎么和Service 绑定?
  • 怎么在Activity 中启动自己对应的Service?
  • service和activity怎么进行数据交互?
  • Service的开启方式
  • 请描述一下Service 的生命周期
  • 谈谈你对ContentProvider的理解
  • 说说ContentProvider、ContentResolver、ContentObserver 之间的关系
  • 请描述一下广播BroadcastReceiver的理解
  • 广播的分类
  • 广播使用的方式和场景
  • 在manifest 和代码中如何注册和使用BroadcastReceiver?
  • 本地广播和全局广播有什么差别?
  • BroadcastReceiver,LocalBroadcastReceiver 区别
  • AlertDialog,popupWindow,Activity区别
  • Application 和 Activity 的 Context 对象的区别
  • Android属性动画特性
  • 如何导入外部数据库?
  • LinearLayout、RelativeLayout、FrameLayout的特性及对比,并介绍使用场景。
  • 谈谈对接口与回调的理解
  • 回调的原理
  • 写一个回调demo
  • 介绍下SurfView
  • RecycleView的使用
  • 序列化的作用,以及Android两种序列化的区别
  • 差值器
  • 估值器
  • Android中数据存储方式

二、Android源码相关分析

  • Android动画框架实现原理
  • Android各个版本API的区别
  • Requestlayout,onlayout,onDraw,DrawChild区别与联系
  • invalidate和postInvalidate的区别及使用
  • Activity-Window-View三者的差别
  • 谈谈对Volley的理解
  • 如何优化自定义View
  • 低版本SDK如何实现高版本api?
  • 描述一次网络请求的流程
  • HttpUrlConnection 和 okhttp关系
  • Bitmap对象的理解
  • looper架构
  • ActivityThread,AMS,WMS的工作原理
  • 自定义View如何考虑机型适配
  • 自定义View的事件
  • AstncTask+HttpClient 与 AsyncHttpClient有什么区别?
  • LaunchMode应用场景
  • AsyncTask 如何使用?
  • SpareArray原理
  • 请介绍下ContentProvider 是如何实现数据共享的?
  • AndroidService与Activity之间通信的几种方式
  • IntentService原理及作用是什么?
  • 说说Activity、Intent、Service 是什么关系
  • ApplicationContext和ActivityContext的区别
  • SP是进程同步的吗?有什么方法做到同步?
  • 谈谈多线程在Android中的使用
  • 进程和 Application 的生命周期
  • 封装View的时候怎么知道view的大小
  • RecycleView原理
  • AndroidManifest的作用与理解

三、常见的一些原理性问题

  • Handler机制和底层实现
  • Handler、Thread和HandlerThread的差别
  • handler发消息给子线程,looper怎么启动?
  • 关于Handler,在任何地方new Handler 都是什么线程下?
  • ThreadLocal原理,实现及如何保证Local属性?
  • 请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系
  • 请描述一下View事件传递分发机制
  • Touch事件传递流程
  • 事件分发中的onTouch 和onTouchEvent 有什么区别,又该如何使用?
  • View和ViewGroup分别有哪些事件分发相关的回调方法
  • View刷新机制
  • View绘制流程
  • 自定义控件原理
  • 自定义View如何提供获取View属性的接口?
  • Android代码中实现WAP方式联网
  • AsyncTask机制
  • AsyncTask原理及不足
  • 如何取消AsyncTask?
  • 为什么不能在子线程更新UI?
  • ANR产生的原因是什么?
  • ANR定位和修正
  • oom是什么?
  • 什么情况导致oom?
  • 有什么解决方法可以避免OOM?
  • Oom 是否可以try catch?为什么?
  • 内存泄漏是什么?
  • 什么情况导致内存泄漏?
  • 如何防止线程的内存泄漏?
  • 内存泄露场的解决方法
  • 内存泄漏和内存溢出区别?
  • LruCache默认缓存大小
  • ContentProvider的权限管理(解答:读写分离,权限控制-精确到表级,URL控制)
  • 如何通过广播拦截和abort一条短信?
  • 广播是否可以请求网络?
  • 广播引起anr的时间限制是多少?
  • 计算一个view的嵌套层级
  • Activity栈
  • Android线程有没有上限?
  • 线程池有没有上限?
  • ListView重用的是什么?
  • Android为什么引入Parcelable?
  • 有没有尝试简化Parcelable的使用?

四、开发中常见的一些问题

  • ListView 中图片错位的问题是如何产生的?
  • 混合开发有了解吗?
  • 知道哪些混合开发的方式?说出它们的优缺点和各自使用场景?(解答:比如:RN,weex,H5,小程序,WPA等。做Android的了解一些前端js等还是很有好处的);
  • 屏幕适配的处理技巧都有哪些?
  • 服务器只提供数据接收接口,在多线程或多进程条件下,如何保证数据的有序到达?
  • 动态布局的理解
  • 怎么去除重复代码?
  • 画出 Android 的大体架构图
  • Recycleview和ListView的区别
  • ListView图片加载错乱的原理和解决方案
  • 动态权限适配方案,权限组的概念
  • Android系统为什么会设计ContentProvider?
  • 下拉状态栏是不是影响activity的生命周期
  • 如果在onStop的时候做了网络请求,onResume的时候怎么恢复?
  • Bitmap 使用时候注意什么?
  • Bitmap的recycler()
  • Android中开启摄像头的主要步骤
  • ViewPager使用细节,如何设置成每次只初始化当前的Fragment,其他的不初始化?
  • 点击事件被拦截,但是想传到下面的View,如何操作?
  • 微信主页面的实现方式
  • 微信上消息小红点的原理
  • CAS介绍(这是阿里巴巴的面试题,我不是很了解,可以参考博客: CAS简介


资料来源如下

常用的Android开发的一些技能点以及BAT公司面试题汇集

  • 感觉自己白学了////😂////

  • 一道一道的找答案..


java面试题汇总

熟练掌握java是很关键的,大公司不仅仅要求你会使用几个api,更多的是要你熟悉源码实现原理,甚至要你知道有哪些不足,怎么改进,还有一些java有关的一些算法,设计模式等等。

一、java基础面试知识点

  • java中==和equals和hashCode的区别

    • 关系操作符 ==:
      • 基本数据类型,== 判断的是左右两边操作数的值是否相等
      • 引用数据类型,== 判断的是左右两边操作数的内存地址是否相同,是否是同一个对象。
    • equals方法 基类Object中的实例方法
      • 本质是期望比较 对象的内容
    • hashCode方法,基类Object中的实例方法,返回一个int类型 hash值.
      • 重写上述两个方法,必须保证hashCode与equals的结果一致性,内容相同的对象,hash值相同,比较返回 true
      • hash值为确定对象在哈希表中位置的标识.
  • int、char、long各占多少字节数

    • int 4字节
    • char 2个字节
    • long 8个字节
  • int与integer的区别

    • int为java的内置基本类型
    • integer 为int的包装类
  • 探探对java多态的理解

    • 类之间存在继承关系,子类可以重写父类相同的方法名.
    • 调用时 子类直接调用自己实现的同命方法.
  • String、StringBuffer、StringBuilder区别

    • String 是不可变对象,所有操作都会生成新的String对象
    • StringBuffer StringBuilder 为可变对象.
      • StringBufferd 线程安全
      • StringBuilder 线程不安全,但是单线程性能好
  • 什么是内部类?内部类的作用

    • 内部类主要定义在类的内部
      • 成员内部类
        • 作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private
        • 外部类要访问内部类的所有成员变量或方法,则需要通过内部类的对象来获取
        • 成员内部类不能含有 static 的变量和方法
      • 局部内部类
        • 指内部类定义在方法和作用域内,就是在外部类的方法中定义的内部类就是局部内部类
        • 局部内部类由于是在方法中定义的,其作用域也是在方法内部中,方法外执行到,则被JVM回收。局部内部类的实例化也只能在方法中进行
        • 局部内部类方法中想要使用局部变量,该变量必须声明为 final 类型
      • 静态内部类
        • 修饰为static的内部类
        • 直接引用 外部类.内部类
        • 实例化: 外部类.内部类 对象 = new 外部类.内部类()
      • 匿名内部类
        • 局部内部类一种
        • 没有名称,只能使用new声明new <类或接口> <类的主体>
        • 使用最多的实例(创建线程):
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          public class Demo {
          public static void main(String[] args) {
          Thread t = new Thread() {
          public void run() {
          for (int i = 1; i <= 5; i++) {
          System.out.print(i + " ");
          }
          }
          };
          t.start();
          }
          }
    • 内部类能独立地继承自一个类(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。
  • 抽象类和接口区别

    • 抽象类是对事物的抽象,接口是对行为的抽象
  • 抽象类的意义

    • 更利于代码的维护和重用
  • 抽象类与接口的应用场景

    • 接口是为了使用它规范的某一个行为
    • 抽象类是为了使用这个类属性和行为
  • 抽象类是否可以没有方法和属性?

    • 可以
  • 接口的意义

    • 补足多重继承关系.
    • 赋予多态更多的实现方式
  • 泛型中extends和super的区别

    • <? super T> 代表泛型T及其父类 ?的下界
    • <? extends T> 代表泛型T及其子类 ?的上界
    • 频繁往外读取内容的,适合用上界Extends。
    • 经常往里插入的,适合用下界Super。
  • 父类的静态方法能否被子类重写

    • 否 静态方法与对象无关
  • 进程和线程的区别

    • 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
    • 线程是进程的一个实体, 是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
    • 一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
    • 进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序 健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
  • final,finally,finalize的区别

    • final 修饰符 修饰类标识无法再被继承
    • finally 用于错误处理
    • finalize 析构函数,但调用后 资源回收时间由 jvm决定
  • 序列化的方式(待考)

    • 序列化,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地
    • Json,Serializable,Parcelable,ObjectOutputStream
  • Serializable 和Parcelable 的区别

    • Serializable是java api,Parcelable是Android api;
    • Serializable过程需要大量的I/O操作,开销大,效率低
    • Parcelable过程不需要大量的I/O操作,开销小,效率高
  • 静态属性和静态方法是否可以被继承?是否可以被重写?以及原因?

    • 可以被继承,但不能被重写,静态方法和静态属性是属于类.
  • 静态内部类的设计意图

    • 静态内部类可以独立存在,又希望只被外部类使用,private修饰的时候不被同一个包下的其他类使用。
    • 非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。
    • 静态内部类的作用:
    • 只是为了降低包的深度,方便类的使用,
    • 静态内部类适用于包含类当中,但又不依赖与外在的类,不能使用外在类的非静态属性和方法,只是为了方便管理类结构而定义。
    • 在创建静态内部类的时候,不需要外部类对象的引用。
    • 非静态内部类有一个很大的优点:可以自由使用外部类的所有变量和方法
  • 成员内部类、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用

    • 见上内部类
  • 谈谈对kotlin的理解

    • 代码量下降
    • 语法糖
    • 与java 100%兼容
    • 函数式编程
  • 闭包和局部内部类的区别

  • string 转换成 integer的方式及原理

二、java深入源码级的面试题(有难度)

  • 哪些情况下的对象会被垃圾回收机制处理掉?
  • 讲一下常见编码方式?
  • utf-8编码中的中文占几个字节;int型几个字节?
  • 静态代理和动态代理的区别,什么场景使用?
  • Java的异常体系
  • 谈谈你对解析与分派的认识。
  • 修改对象A的equals方法的签名,那么使用HashMap存放这个对象实例的时候,会调用哪个equals方法?
  • Java中实现多态的机制是什么?
  • 如何将一个Java对象序列化到文件里?
  • 说说你对Java反射的理解
  • 说说你对Java注解的理解
  • 说说你对依赖注入的理解
  • 说一下泛型原理,并举例说明
  • Java中String的了解
  • String为什么要设计成不可变的?
  • Object类的equal和hashCode方法重写,为什么?

三、数据结构

  • 常用数据结构简介

  • 并发集合了解哪些?

  • 列举java的集合以及集合之间的继承关系

  • 集合类以及集合框架

  • 容器类介绍以及之间的区别(容器类估计很多人没听这个词,Java容器主要可以划分为4个部分:List列表、Set集合、Map映射、工具类(Iterator迭代器、Enumeration枚举类、Arrays和Collections),具体的可以看看这篇博文 Java容器类

  • List,Set,Map的区别

  • List和Map的实现方式以及存储方式

  • HashMap的实现原理

  • HashMap数据结构?

  • HashMap源码理解

  • HashMap如何put数据(从HashMap源码角度讲解)?

  • HashMap怎么手写实现?

  • ConcurrentHashMap的实现原理

  • ArrayMap和HashMap的对比

  • HashTable实现原理

  • TreeMap具体实现

  • HashMap和HashTable的区别

  • HashMap与HashSet的区别

  • HashSet与HashMap怎么判断集合元素重复?

  • 集合Set实现Hash怎么防止碰撞

  • ArrayList和LinkedList的区别,以及应用场景

  • 数组和链表的区别

  • 二叉树的深度优先遍历和广度优先遍历的具体实现

  • 堆的结构

  • 堆和树的区别

  • 堆和栈在内存中的区别是什么(解答提示:可以从数据结构方面以及实际实现方面两个方面去回答)?

  • 什么是深拷贝和浅拷贝

  • 手写链表逆序代码

  • 讲一下对树,B+树的理解

  • 讲一下对图的理解

  • 判断单链表成环与否?

  • 链表翻转(即:翻转一个单项链表)

  • 合并多个单有序链表(假设都是递增的)

四、线程、多线程和线程池

  • 开启线程的三种方式?
  • 线程和进程的区别?
  • 为什么要有线程,而不是仅仅用进程?
  • run()和start()方法区别
  • 如何控制某个方法允许并发访问线程的个数?
  • 在Java中wait和seelp方法的不同;
  • 谈谈wait/notify关键字的理解
  • 什么导致线程阻塞?
  • 线程如何关闭?
  • 讲一下java中的同步的方法
  • 数据一致性如何保证?
  • 如何保证线程安全?
  • 如何实现线程同步?
  • 两个进程同时要求写或者读,能不能实现?如何防止进程的同步?
  • 线程间操作List
  • Java中对象的生命周期
  • Synchronized用法
  • synchronize的原理
  • 谈谈对Synchronized关键字,类锁,方法锁,重入锁的理解
  • static synchronized 方法的多线程访问和作用
  • 同一个类里面两个synchronized方法,两个线程同时访问的问题
  • volatile的原理
  • 谈谈volatile关键字的用法
  • 谈谈volatile关键字的作用
  • 谈谈NIO的理解
  • synchronized 和volatile 关键字的区别
  • synchronized与Lock的区别
  • ReentrantLock 、synchronized和volatile比较
  • ReentrantLock的内部实现
  • lock原理
  • 死锁的四个必要条件?
  • 怎么避免死锁?
  • 对象锁和类锁是否会互相影响?
  • 什么是线程池,如何使用?
  • Java的并发、多线程、线程模型
  • 谈谈对多线程的理解
  • 多线程有什么要注意的问题?
  • 谈谈你对并发编程的理解并举例说明
  • 谈谈你对多线程同步机制的理解?
  • 如何保证多线程读写文件的安全?
  • 多线程断点续传原理
  • 断点续传的实现

并发编程有关知识点(这个是一般Android开发用的少的,所以建议多去看看):

平时Android开发中对并发编程可以做得比较少,Thread这个类经常会用到,但是我们想提升自己的话,一定不能停留在表面,,我们也应该去了解一下java的关于线程相关的源码级别的东西。


学习的参考资料如下:

Java 内存模型

  • java线程安全总结
  • 深入理解java内存模型系列文章

线程状态:

  • 一张图让你看懂JAVA线程间的状态转换

锁:

  • 锁机制:synchronized、Lock、Condition
  • Java 中的锁

并发编程:

  • Java并发编程:Thread类的使用
  • Java多线程编程总结
  • Java并发编程的总结与思考
  • Java并发编程实战—–synchronized
  • 深入分析ConcurrentHashMap

面向对象

  • 类 方法 实例
  • 封装 继承 多态

类和实例

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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)
  • 定义类的关键词与java一样 class 括号内为继承的父类.没有父类时,选择 object 作为基类.(object是所有类的基类)

  • 变量比较特殊,不像java中有单独字段.python 类中变量定义是在__init__方法

  • 方法的声明和函数类似. def 方法名 (参数)

    • 类中 第一个参数必须是self,意为创建的实例自身.方法中调用类中其他变量都要通过 self.xxx 访问.
  • 一些必须实现的属性在__init__方法中定义.如示例.第一个参数是 self 之后是具体变量值,在方法内 使用self访问类中定义的变量.

  • Python允许对实例变量绑定任何数据,so just do it😈

访问限制

  • 类似java private 字段的python实现

  • 属性的名称前加上两个下划线 __ 该属性就成为了类的私有属性,只能在实例的内部访问.(self.xxx)

  • 获取/修改,使用 get/set 获取或修改对应属性.(一般在set中可以添加类型检查)

  • 类似__xxx__的变量,双下划线开头,并且以双下划线结尾的,是特殊变量.特殊变量是可以直接访问的,不是private变量.也最好不要定义__xxx__变量名

  • 以下划线开头的实例变量名,例如_name.可以在外部访问的,但是,约定俗成,请直接忽视.

  • 特例:

    • 双下划线开头的实例变量不能直接访问是因为Python解释器对外把__name变量改成了_Student__name.仍然可以通过_Student__name来访问__name变量.

    • 一个错误设置示例:

      1
      2
      3
      4
      5
      6
      7
      8
      >>> bart = Student('Bart Simpson', 59)
      >>> bart.get_name()
      'Bart Simpson'
      >>> bart.__name = 'New Name' # 设置__name变量!
      >>> bart.__name
      'New Name'
      >>> bart.get_name() # get_name()内部返回self.__name
      'Bart Simpson'
    • 如同示例,外部代码直接赋给 bart.__name 不会影响实例中原有属性,只会新增一个属性.究其原因,实例中的属性已经被解释器重命名为了bart._Student__name.

继承和多态

  • 继承和多态概念与java类似.不多语了.
  • 那么重点来了:
  • python本身是动态语言,体现在变量/类等各个方面,自由度极高.在继承上,亦是如此.
    • java中定义一个su方法,调用model类实例实现的run方法.su方法可传入的只有 model类或其子类的实例
    • 但python中 只要是定义了 run方法(别管内容/功能一样不一样)类的实例,都可以作为参数传入 su 方法.
  • java中对类的类型的处理,相当于照猫🐱画虎🐯,传入的起码要是个猫科动物. python 中对类的类型处理,额头写个字,哪怕传入具体对象是个猫头鹰🦉,也当作猫科处理了.

  • note:
    判断一个变量是否是某个类型可以用isinstance()

    1
    2
    >>> isinstance(a, list)
    True

获取对象信息


  • 让我想起了java反射..不过能获取的信息要全多了.

type()

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    >>> type(123)
    <class 'int'>

    >>> type(a)
    <class '__main__.Animal'>

    >>> type(123)==type(456)
    True
  • 判断对象类型

  • 由变量指向函数或者类,也可以用type()判断

  • type返回对应的Class类型,可直接 == 类型判断

  • 判断一个对象是否是函数:

    1
    2
    3
    4
    5
    6
    7
    8
    >>> import types
    >>> def fn():
    ... pass
    ...
    >>> type(fn)==types.FunctionType
    True
    >>> type(abs)==types.BuiltinFunctionType
    True

isinstance()

  • 示例:

    1
    2
    3
    4
    5
    >>> isinstance(h, Husky)
    True

    >>> isinstance([1, 2, 3], (list, tuple))
    True
  • 判断继承关系,一打一个准.

  • 能用type()判断的基本类型也可以用isinstance()判断

  • 总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。

dir()

  • 示例:

    1
    2
    >>> dir('ABC')
    ['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
  • 获得一个对象的所有属性和方法.直接返回一个字符串list.

  • 配合getattr()、setattr()以及hasattr(),可以直接操作一个对象的状态.

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    >>> hasattr(obj, 'x') # 有属性'x'吗?
    True
    >>> obj.x
    9
    >>> hasattr(obj, 'y') # 有属性'y'吗?
    False
    >>> setattr(obj, 'y', 19) # 设置一个属性'y'
    >>> hasattr(obj, 'y') # 有属性'y'吗?
    True
    >>> getattr(obj, 'y') # 获取属性'y'
    19
    >>> obj.y # 获取属性'y'
    19
  • 不存在的属性,会抛出AttributeError的错误,可以传入一个default参数,如果属性不存在,就返回默认值.

    1
    2
    >>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
    404
  • 也可以获得对象的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> hasattr(obj, 'power') # 有属性'power'吗?
    True
    >>> getattr(obj, 'power') # 获取属性'power'
    <bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
    >>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
    >>> fn # fn指向obj.power
    <bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
    >>> fn() # 调用fn()与调用obj.power()是一样的
    81
  • 只有在不知道对象信息的时候,才会去获取对象信息.谨记,谨记.

实例属性和类属性

  • 类似java类中静态变量 与 普通变量区别.

  • 类的属性,直接在类的cclass中声明.

    1
    2
    class Student(object):
    name = 'Student'
  • 访问时,类的属性会被实例的同名属性覆盖,但不会被修改,互相独立.

  • 删除实例属性后,再使用相同的名称,访问到的将是类属性

模块

  • 模块是一组Python代码的集合,可以使用其他模块,也可以被其他模块使用。

  • 涉及到概念 包(Package) 和 模块(Module)

  • 创建自己的模块时,要注意:

    • 模块名要遵循Python变量命名规范,不要使用中文、特殊字符;
    • 模块名不要和系统模块名冲突,最好先查看系统是否已存在该模块,检查方法是在Python交互环境执行import abc,若成功则说明系统存在此模块。

使用模块

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-

    ' a test module '

    __author__ = 'Michael Liao'

    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行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行
    • 第2行注释表示.py文件本身使用标准UTF-8编码;
    • 第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释
    • 第6行使用__author__变量把作者写进去
  • 重点if __name__=='__main__':

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

作用域

  • Python中,是通过_前缀 标记 private
  • note: python中语法没有限制 _开头的变量/函数!

安装第三方模块

  • pip命令

    1
    pip install xxx
  • 或者在文件中自定义路径.

函数式编程

  • 纯函数式编程没有变量,一个函数只要输出确定,输出就是确定的,称为没有副作用.使用变量的函数内部由于变量状态不确定性,有副作用.
  • 函数式编程另一个特点是允许函数本身作为参数传入,也可以直接返回另外一个函数.
  • python对函数式编程提供有限支持.(还使用变量 so不是纯函数式编程语言)

高阶函数

  • python中函数本身也可以赋值给变量,变量可以指向函数
  • 函数的参数可以传入另一个函数,这种函数称为高阶函数.

map/reduce

  • map()接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回

  • 示例

    1
    list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]) # list所有数字转为字符串
  • reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> from functools import reduce
    >>> def fn(x, y):
    ... return x * 10 + y
    ...
    >>> def char2num(s):
    ... digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
    ... return digits[s]
    ...
    >>> reduce(fn, map(char2num, '13579'))
    13579

filter

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

  • filter()函数返回的是一个 惰性序列 Iterator,也就是一个惰性序列,需要用list()函数获得所有结果并返回list

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def is_odd(n):
    return n % 2 == 1

    list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) # 只保留奇数

    def not_empty(s):
    return s and s.strip()

    list(filter(not_empty, ['A', '', 'B', None, 'C', ' '])) # 删除空字符

sorted

  • sorted()函数接收一个key函数来实现自定义的排序.第三个参数reverse=True决定正序倒序.

  • 示例:

    1
    2
    3
    4
    5
    >>> sorted(['bob', 'about', 'Zoo', 'Credit'],key=str.lower)
    ['about', 'bob', 'Credit', 'Zoo']

    >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
    ['Zoo', 'Credit', 'bob', 'about']

返回函数

  • 将函数作为结果返回.(很随便😂)

  • 闭包(Closure):相关参数和变量都保存在返回函数.

  • **note:**返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用

  • 示例(坑):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def count():
    fs = []
    for i in range(1, 4):
    def f():
    return i*i
    fs.append(f)
    return fs

    f1, f2, f3 = count()

    >>> f1()
    9
    >>> f2()
    9
    >>> f3()
    9
  • 返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9

  • 一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def count():
    def f(j):
    def g():
    return j*j
    return g
    fs = []
    for i in range(1, 4):
    fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
    return fs

匿名函数

  • 不显式定义的函数. python中是 lambda 但与java不同.

  • python中lambda限制,只能有一个表达式,不用写return,返回值就是该表达式的结果

  • 匿名函数不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数

  • 示例

    1
    f = lambda x: x * x

装饰器

  • 代码运行期间,动态增加功能方式称为装饰器(Decorator)

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def log(func):
    def wrapper(*args, **kw):
    print('call %s():' % func.__name__)
    return func(*args, **kw)
    return wrapper

    @log
    def now():
    print('2015-3-25')

    >>> now()
    call now():
    2015-3-25
  • 如示例,装饰器 接受一个函数作为参数,并返回原函数.在原函数定义时,以 @ xxx作为标记.示例1 为2层,如果打印文本可以自定义.

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def log(text):
    def decorator(func):
    def wrapper(*args, **kw):
    print('%s %s():' % (text, func.__name__))
    return func(*args, **kw)
    return wrapper
    return decorator

    @log('execute')
    def now():
    print('2015-3-25')

    >>> now()
    execute now():
    2015-3-25

    打印可自定义 又加上了一层.

  • 如上两种定义后,函数对象的名称等发生了变化,so,终极版

  • Python内置的functools.wraps 会将原始函数的__name__等属性复制到wrapper()函数中.

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import functools
    # 不带参数
    def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
    print('call %s():' % func.__name__)
    return func(*args, **kw)
    return wrapper

    # 带参数

    def log(text):
    def decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
    print('%s %s():' % (text, func.__name__))
    return func(*args, **kw)
    return wrapper
    return decorator

偏函数

  • functools.partial的作用是把一个函数的某些参数设置默认值,返回一个新的函数.

  • 示例:

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

    int2('1000000')
  • 注意: 仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值

  • 由于python 中函数也可以最为参数传入,so,参数固定成某一个函数也可.

  • 同理: *args**kw 也可以.

  • 简化函数调用.

高级特性

  • 代码精炼
  • python代码量越少,开发效率越高.

切片

  • 取list或tuple的部分元素

  • 示例

    1
    2
    L[0:3] #0到3,但结果不包括索引3
    L[:3] #0可省略
    1
    2
    L[-2:]  #-2到0 但不包括索引0
    L[-2:-1] #-2
    1
    2
    3
    L[:10:2] #前10 每隔2个取一个
    L[::5] #所有,每隔5个取一个
    L[:] #原样复制
  • 对tuple取切片,结果依然是tuple.

  • 字符串可以看作一个list,每个字符占一位.

迭代

  • 迭代很随便…太随便了…

  • list tuple不多说了

  • dict字典也可以迭代,因为无序,输出的顺序不一定相同.
    默认迭代的是key 但value 也可以迭代,key value也可以同时迭代

    1
    2
    for value in d.values()
    for k, v in d.items()
  • 上文书中说的,字符串可以当作list,所以也可以迭代.

  • 问题来了,如何判断可迭代对象?
    collections模块的Iterable类型判断

    1
    2
    3
    >>> from collections import Iterable
    >>> isinstance('abc', Iterable) # str是否可迭代
    True
  • 类似c/java的带下标循环实现?
    Python内置的enumerate函数,把一个list变成索引-元素对

    1
    2
    for i, value in enumerate(['A', 'B', 'C']):
    print(i, value)

列表生成式

  • 用来生成list

  • 示例: [1x1, 2x2, 3x3, …, 10x10]

    1
    2
    [x * x for x in range(1, 11)]
    [m + n for m in 'ABC' for n in 'XYZ'] #两层
  • for可以同时循环两个甚至多个变量,dict的items()可以同时迭代key和value

    1
    2
    3
    d = {'x': 'A', 'y': 'B', 'z': 'C' } # 多个变量
    [k + '=' + v for k, v in d.items()] # 生成list
    [s.lower() for s in L] # 全部小写

生成器

  • generator 依照某种算法不断循环生成数据,而不是一次性生成完.节省大量空间.

  • 创建generator

    • 把列表生成式的[]改成()

      1
      g = (x * x for x in range(10))

      调用next(g)可获取下一个值.
      最常用for n in g:代入for循环.也没有抛出错误.

    • 定义一个包含yield关键字的函数.

      1
      2
      3
      4
      5
      6
      7
      def fib(max):
      n, a, b = 0, 0, 1
      while n < max:
      yield b
      a, b = b, a + b
      n = n + 1
      return 'done'
      • 变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
      • 用for循环调用generator时,拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中.

迭代器

  • 可以被for循环的对象统称为可迭代对象:Iterable
    使用isinstance()判断一个对象是否是Iterable对象

    1
    isinstance({}, Iterable)
  • 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator 表示一个惰性计算的序列 Iterator甚至可以表示一个无限大的数据流
    isinstance()判断一个对象是否是Iterator对象

    1
    isinstance((x for x in range(10)), Iterator)
  • 集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

  • Python的for循环本质上就是通过不断调用next()

函数

常用

  • 参数数量不对 TypeError错误

  • 参数类型错误,TypeError的错误,并且给出错误信息

  • int()转换为int类型

  • float()

  • bool()

  • str()

  • 函数名为一指向函数对象的引用,可以将变量指向函数,再调用

    1
    2
    3
    >>> a = abs # 变量a指向abs函数
    >>> a(-1) # 所以也可以通过a调用abs函数
    1

定义函数

  • 示例

    1
    2
    3
    4
    5
    def my_abs(x):
    if x >= 0:
    return x
    else:
    return -x

    def 函数名(参数) :
    函数体
    return

  • 没有return 则返回 None

  • import 包含模块,java一样

  • 空函数 pass 语句.

    1
    2
    def nop():
    pass
  • 示例 返回多个参数

    1
    2
    3
    4
    5
    6
    import math

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

    返回的是一个tuple .. 按位置赋值给变量

函数参数

  • 参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数

默认参数

  • 示例:

    1
    2
    3
    4
    def power(x, n=2):
    ...

    power(5) power(5, 2) power(n=3,5)
  • 默认参数必须指向不变对象

  • 多个参数时,变化大的参数在前,变化小的参数在后。变化小的参数就可以作为默认参数。

  • 多个默认参数,可以按顺序提供默认参数

  • 也可以不按顺序提供。当不按顺序提供部分默认参数时,需要把参数名写上 enroll('Adam', 'M', city='Tianjin')

    • 默认参数 不可变性 每次调用均会改变其值.

可变参数

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def calc(*numbers):
    sum = 0
    for n in numbers:
    sum = sum + n * n
    return sum

    nums = [1, 2, 3]
    calc(*nums) #相同
    calc(1, 2, 3)
  • 传入的参数个数可变,传入组装成了tuple

  • 当作c语言指针吧😂 传入数组的地址

命名关键字参数

  • 示例:

    1
    2
    3
    4
    def person(name, age, *, city, job):
    print(name, age, city, job)

    person('Jack', 24, city='Beijing', job='Engineer')
  • 命名关键字参数需要一个特殊分隔符后面的参数被视为命名关键字参数

  • 函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*

    1
    2
    def person(name, age, *args, city, job):
    print(name, age, args, city, job)
  • 如果没有可变参数,就必须加一个作为特殊分隔符。如果缺少,Python解释器将无法识别位置参数和命名关键字参数

关键字参数

  • 示例

    1
    2
    3
    4
    5
    6
    7
    8
    def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

    extra = {'city': 'Beijing', 'job': 'Engineer'}
    person('Jack', 24, city=extra['city'], job=extra['job'])
    #相同
    extra = {'city': 'Beijing', 'job': 'Engineer'}
    person('Jack', 24, **extra)
  • 关键字参数在函数内部组装为一个dict

  • 函数内部获得是 dict的拷贝,修改对原值无影响.

  • 可以传入任意不受限制的关键字参数

递归函数

  • python 不含尾递归优化,注意层级,否则非常容易堆栈溢出.

数据类型

  • 整数 浮点数

字符串

  • 字符串以单引号 ‘ 或 “ 包括.
  • 转义字符 \ 依然有效. r’’表示此字符串默认不转移.
  • /n有效, 可用 开头 … 替换

布尔

  • 只有True 和 Flase
  • and or not 3种常用操作

常量

  • 通常都为大写表示.
  • 除法有两种 / 或 //
    / 结果可能为浮点, // 结果为整数(地板除)

其他

  • None 空值,不为0.谨记
  • 动态语言,so,变量的类型无所谓.
  • 浮点数精度无限,但超过限制直接表示为 inf

字符编码

  • 简而言之 文件使用utf-8就对了.
  • utf-8 属于万国码的简化,低位与 ASCII 兼容.

python字符串编码

  • py3中默认是 Unicode 万国码.

  • ord()获取字符的整数表示,chr()把编码转换为字符.

  • Python对bytes类型的数据用带b前缀的单引号或双引号表示 x = b'ABC'

  • 以Unicode表示的str通过encode()方法可以编码为指定的bytes

    1
    2
    3
    4
    'ABC'.encode('ascii')
    b'ABC'
    '中文'.encode('utf-8')
    b'\xe4\xb8\xad\xe6\x96\x87'
  • 对应的decode()方法

    1
    2
    3
    4
    >>> b'ABC'.decode('ascii')
    'ABC'
    >>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
    '中文'

    可以传入errors=’ignore’忽略错误的字节

    1
    b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
  • len(),str计算字符.bytes计算字节

  • 开头,第一行,可执行文件(windows会忽视注释)
    第二行,以utf-8处理文件.

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

字符串格式化

  • 占位符与c基本相同 %d %s %x %f

    1
    2
    print('%2d-%02d' % (3, 1))
    print('%.2f' % 3.1415926)

    需要 % 时, %%

  • format()

    1
    2
    >>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
    'Hello, 小明, 成绩提升了 17.1%'

list tuple

list 列表

  • 示例, = [ , , ] 可变 有序

    1
    classmates = ['Michael', 'Bob', 'Tracy']
  • 索引以 0 开始,可以倒序 -n 当然越界都是 IndexError 错误

  • .len(),list元素个数.

  • .append(x) 末尾添加

  • .insert(i,x) 对应索引处插入

  • .pop(i) 删除i对应元素,为空则删除末尾元素.

  • 替换i位置,直接赋值.

  • list的元素可以为一个list.多重数组.

tuple 元组

  • 示例= ( , , ) 不可变 有序 更安全,其他与list相同

    1
    t = (1, 2)
  • t = (1,)声明一个元素元组,比较特殊.

条件判断

  • 示例

    1
    2
    3
    4
    5
    6
    if true :
    print("1")
    elif true :
    print("2")
    else :
    print("3")
  • if 条件可简写,if x x非零数值、非空字符串、非空list 则为true

  • 提及用户输入 input()

  • input默认返回字符串,如需要其他类型 int()转换.

循环

  • 示例 与c相同

    1
    2
    for x in names:
    print(x)
  • 示例 与c相同

    1
    2
    while n > 0:
    print(n)
  • break 跳出此层循环

  • continue 跳出本轮循环

dict 和 set

dict

  • 字典,使用键值对储存数据,索引极快,空间换时间.

  • 对应其他语言的 map

  • 示例: {‘’: ,’’: ,…}

    1
    2
    3
    d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
    d['Michael']
    95
  • key

    • 必须为不可变对象,整数、字符串等

    • 一个key对应一个value

    • key不存在

      • in判断

        1
        2
        >>> 'Thomas' in d
        False
      • get()获取

        1
        2
        d.get('Thomas') # 返回空
        d.get('Thomas', -1) # 不存在? 返回-1: ;
    • pop()删除

      1
      d.pop('Bob')

set

  • key的集合,但不存在value

  • 无序、不重复、元素为不可变对象.

  • set可以看作是一个无序和无重复元素的集合.

  • 创建set需要一个list

  • 示例 set([ , , …])

    1
    2
    3
    >>> s = set([1, 2, 3])
    >>> s
    {1, 2, 3}
  • .add(key)/.remove(key)

  • 不同的set之间可以交集(&)取并集(|).