所以我说,刚开始要做什么呢?
RS 个人觉得,不管学习什么,不论是新技能、新知识,必须先在一开始就 迅速 建立 自信心,相信这一点大家都知道,但很多人会忽略一点是 迅速 两个字,人闲着就很容易想东想西,一旦你没有动手执行,随着时间的经过,你的自信心会呈现非线性的衰弱状态。
不知道你有没有这样子的经验,有些事情做着做着,就突然感觉很有自信,觉得你问什么问题我都可以回答你,没在怕的;还有一个经验是,以前明明很会做某件事,可是好一段时间没再接触了,突然有人问我以前很熟的事情,我却怀疑自己认为的是不是真正的事实。
而快速建立自信的方法,就是 先照着教学做 就对了,而且执行的中间尽量不要休息或隔太久,让自己保持在一个 启动 的状态,这就有点像是骑车的起步总是最难、静止到移动需要克服最大静摩擦力一样,当你呈现启动的状态后,摩擦力相对就没有像一开始那么大。
这也是为什么 30 天铁人赛这么迷人的地方,当你持续不间断的做同一件事情,你会 非常 有信心,不信吗? 你可以试试看。
摄影师:bruce mars,连结:Pexels
没有页码的目录
避免加上程式码会让文章冗长,所以先上目录,各位看官可以挑选自己有兴趣或不足的章节:
那我们就开始啰版本选择 & 安装第一支程式 (Hello World)基础语法们变数(Variables) & 资料型别 (Data Type)基本型别关于型别,你需要了解更多 (检查记忆体、型别转换、各种进位)区域变数 (Local variables) & 全域变数 (Global variables) & 作用範围(Scope)逻辑控制 (Control Statements)if else & for loop好用小技巧给多个变数单行指定同一个值给冗长或难读的 function name 指定成一个好读的别称吧 !那我们就开始啰
「工欲善其事,必先利其器」,而我们选定的框架是 Django,它是用 Python 写的,我们在这 30 天也必须跟 Python 搞好关係,Python 是着名的好写好上手,它不像 Java 一样有很严格的型态宣告,大大地加快编写程式码的速度,当然有好就有坏的一面,这就是程式语言之间的战争了 XD
我们这边将专注在熟悉 Python 的 语法,关于安装、版本选择、第一支程式可以参考以下文章:
版本选择 & 安装
Python有许多版本,除非你有特殊需求,不然一律选择 Python 3.x 的稳定版,有可以参考简体文章 是选择学习 Python2 还是 Python 3?,内有分析各版的差异性。Windows 用户可以参考 (2018 11 月的文章) 在Windows底下最适当安装Python环境的方法,这位邦友已经先帮大家踩过雷了,请服用。Mac 用户可以参考 (2015撰 2019更新) 在 Mac 上用 pyenv 轻鬆安装 Python3 (可直接支援安装多种版本),这位是用 terminal 中brew
套件来安装的,适合熟悉 terminal 的捧油们。如果以上两种都觉得太麻烦或看不懂,还可以参考 (2017 10月) 给自学者的Python教学(0) : 如何安装Python(Mac/Windows),其中包含了 Windows 与 Mac 的安装方法,而 Mac 是选用 pkg 安装档来安装 Python,适合喜欢无脑安装的捧油们。至于 Linux 用户,我相信你们都选择用 Linux 了,应该有能力自己解决 XD第一支程式 (Hello World)
Python 的开发方式有很多种,可以在 cmd 直接 > python
、也可以在文字编辑器写好再到 cmd 用 > python helloworld.py
、也可以用 Jupyter Notebook、也可以用 IDE,总之就看每个人喜好的方式,RS 建议可以从 IDE 切入,在我们对一个程式语言不熟悉的时候,有时候 IDE 可以给我们一些错误提醒或智慧补齐程式码等功能,可以参考 Python IDE and Python HelloWorld Program。
基础语法们
注意,虽然很基础,但却是写出高品质程式码,所不可忽略的部分,尤其是已经有点 coding 经验的人们,学习另一个程式语言需要 避免傲气,因为每个程式语言的特性都不一样,可能两种程式语言同样都有 int 整数,可是其代表的值域可能不同,举例来说,在极值的情况下,可能你的程式码就出错了,这时候可怪不了别人,总之,千万不可因为你好像懂了,就自动跳过这个阶段,怎么判断你懂了没,一个简单的判断方式就是:「你能够不看资料就回答出 python 有几种资料型别,并且讲出每个型别的值域範围。」
还有另一个重点,就是 你必须自己执行你自己写的程式码,参考我的程式码、修改参数、按下执行、检查输出值是不是和自己想像的相同,跟看 RS 写的输出结果,所带来的感受度是完全不一样的,透过修改参数,验证自己的观念是否正确,会带给你无限大的自信。以上讲的,都是 RS 本人痛过的经验谈。
变数 (Variables) & 资料型别 (Data Type)
基本型别: Python 是隐式宣告(宣告变数时,不需要表明它的型别),所以你更需要清楚了解 !
# ################################################################### # Boolean(布林/二元),值域範围是 0(False) 和 1(True),注意: 是大写 # ################################################################### this_is_boolean = True # ################################################################### # String(字串) # ################################################################### this_is_string = "字串可以用 双引号 所框起来" another_string = '也可以用 单引号 框起来,这两种都是字串' more_specific_about_string = '''如果你的字太多, 还可以用多行的方式呈现, 只要三个单引号或三个双引号就可以了。''' more_info = """ 用单、双引号交错的好处, 就是你不需要使用跳脱字元(escape char,反斜线(\)), 你可以在里面大胆的用'单引号' 有些情况还有跳脱你的跳脱,根本就像在玩风声,我识破你的识破XD (误 e.g. 1. print("我想t吃饭") # 输出为: 我想t吃饭 2. print("我想\t吃饭") # 输出为: 我想 吃饭 3. print("我想\\t吃饭") # 输出为: 我想\t吃饭 """ # ################################################################### # Integer(整数),值域範围在 Python 2 可以用 sys.maxint 来检查最大值, # 而最小值自然就是 -sys.maxint-1,但这件事情在 Python 3 就不一样了, # int 是没有值域限制的,说是这样说,但还是要看你的系统的位元数, # 可以用 sys.maxsize 来检查, # 所以值域是在 -sys.maxsize-1 ~ sys.maxsize。 # # 但 RS 必须老实说,我自己也没有搞得很懂 Python 3 的 int 範围, # 我的电脑是 64-bit,"理论上最大值"应该要是 9223372036854775807, # 我却可以将 int 设超过这个"最大值",如果大家有想法可以提出来救一下 RS。 # # 值得注意的是,在 Java 与 Kotlin 中,有区分出 Long(长整数), # Python 2 也还有 Long,而 Python 3 就只有 int。 # ################################################################### this_is_int = 9487 import sys # 必须先引入 sys 套件,才可以使用 max_int = sys.maxsize * 10 print(max_int) # 输出为 92233720368547758070 print(type(max_int)) # 输出为 <class 'int'> # ################################################################### # Float(浮点数),值域範围为 sys.float_info.min ~ sys.float_info.max # 值得注意的是,在 Java 与 Kotlin 中, # 有区分 float 与 double 这两种精度不同的浮点数, # 而 Python 只有 float 这一种浮点数。 # ################################################################### this_is_float = 3.14159 min_float = sys.float_info.min max_float = sys.float_info.max print("float max: ", sys.float_info.max, ", min: ", sys.float_info.min) # 输出为 float max: 1.7976931348623157e+308, # min: 2.2250738585072014e-308 # ################################################################### # Complex(複数),也就是实数和虚数的结合,在极座标等运算较常用到, # 这里先不讨论。值得注意的是,这边使用的是 j,而在数学上惯用的是 i。 # ################################################################### this_is_complex = 1 + 2j
基础型别小结
Boolean 要记得大写 (True, False)Integer 理论值无上下限Python 3 没有 Long, Double 型别关于型别,你需要了解更多
# ################################################################### # 怎么确认一个变数的型别? # 假设我们用一个 Float 乘上一个 Int,那么会变成什么型别呢? # ################################################################### this_is_float = 0.9527 this_is_int = 5278 secret_variable = this_is_float * this_is_int print(type(secret_variable)) # 输出为 <class 'float'> # ################################################################### # 各种进位该怎么表示? 假设以十进位的 10,转换成各种进位呢? # 十进位(Decimal)/ 二进位(Binary)/ 八进位(Octal)/ 十六进位(Hexadecimal) # ################################################################### decimal = 10 binary = bin(decimal) octal = oct(decimal) hexa = hex(decimal) print("num: ", decimal, ", bin: ", binary, ", octal: ", octal, ", hex: ", hexa) # 输出为 num: 10, bin: 0b1010 , octal: 0o12 , hex: 0xa # ################################################################### # 如何在各种基本型别中游走? 如何转换型别? # ################################################################### # 为了排版漂亮,各位就原谅 RS 不打 print 了齁 # int/float/boolean to string int_to_string = str(100) # 输出为 100 float_to_string = str(0.2266) # 输出为 0.2266 boolean_to_string = str(True) # 输出为 True complex_to_string = str(2+3j) # 输出为 (2+3j) # string to int/float/boolean string_to_int = int("100") # 输出为 100 string_to_int_base8 = int("14", 8) # 输出为 12 string_to_float = float("0.618") # 输出为 0.618 string_to_boolean = bool("True") # 输出为 True string_to_boolean = bool("False") # 输出为 True # 有没有觉得哪里奇怪? 为什么 bool("False") 会输出 True? # 事实上,bool() 内只要有值,就会输出 True # print(bool()) 或 print(bool("")) 就会输出 False # 如果你没有自己去替换这些参数 # 或许发现这件事的时候,就是你的程式码在系统出错的时候了 # 然后被老闆钉在墙上 string_to_complex = complex("2-3j") # 输出为 (2-3j) string_to_complex = complex(2, 3) # 输出为 (2+3j) # ################################################################### # 如何知道各个型别占多少记忆体? # 用 sys.getsizeof 来检查看看你的记忆体配置吧 # ################################################################### # 浮点数测试 print(sys.getsizeof(3.14159)) # 输出为 24 print(sys.getsizeof(3.14e+100)) # 输出为 24 print(sys.getsizeof(3.14e-100)) # 输出为 24 # 整数测试 print(sys.getsizeof(100)) # 输出为 28 print(sys.getsizeof(sys.maxsize)) # 输出为 36 print(sys.getsizeof(int(1e+308))) # 输出为 164 # 自创型别测试 class MyCustomObject: def __init__(self, var1, var2, var3): self.var1 = var1 self.arbitrary = var2 self.name = var3 print(sys.getsizeof(MyCustomObject(1, 2, 3))) # 输出为 48
区域变数 (Local variables) & 全域变数 (Global variables) & 作用範围(Scope)
Python 的 Scope 和 Java 有很大的不同,Java 除了 import 之外,所有变数、所有运算都要在 class 内宣告和执行,而 Python 虽然弹性,却可能让初学者替自己埋下许多坑。
# 我们的全域变数,藉由观察 global_var 在各阶段的值, # 可以看出 Variables 与 Scope 的互动关係 global_var = 10 # 注意: 在 local scope 宣告的变数名称,可以跟 global variable 同名, # 在逻辑上容易出错,应尽量避免同名的用法 def first_local_scope(): local_var = 20 # 此为 local variable, # 与 second_local_scope() 的 local_var, # 虽然同名,但两个是完全不相关的变数 global_var = 30 # 此为 local variable, # 与 global variable 的同名 print("global_var: ", global_var, ", local_var: ", local_var) def second_local_scope(): local_var = 40 # 此为 local variable, # 与 first_local_scope 无相关 # 在这个 local scope 中,虽然可以读取到 global_var, # 但无法修改 global_var 的值,如真的需要修改,需加入 global 关键字 print("global_var: ", global_var, ", local_var: ", local_var) def third_local_scope(): global global_var global_var = 50 # 因为有先加入 global 关键字, # 所以这次修改的是真正的全域变数 print("global_var: ", global_var) # 真正的执行顺序 print("global_var: ", global_var) # 输出为 10,全域变数的初始值 first_local_scope() # 输出为 30, 20, # 此处输出的是假的全域变数, # 事实上是区域变数 second_local_scope() # 输出为 10, 40, # 存取得到全域变数, # 可是无法修改 third_local_scope() # 输出为 50, # 此处修改的是真正的全域变数 print("global_var: ", global_var) # 输出为 50, # 被 third_local_scope() # 修改为 50
关于更详细的 Scope 测试,可以参考 (2017 5月) 有点複杂的 Python Scope,推荐从 Java 转 Python 的人们研究。
区域变数、全域变数、作用範围小结
local scope 和 global scope 的变数可以取一样的变数名称,但不要找自己麻烦,尽量用变数名称区分开来各个 local scopes 间的变数,不能互相修改local scope 可以取用 global scope 的变数,但需要加入global
的关键字尽量避免在 local scope 直接取用 global scope 变数,改用参数传入与 return
的方式处理逻辑控制 (Control Statements)
if else & for loop
让我们一起来用任性的鬼抓人小游戏感受一下迴圈以及逻辑判断:
print("鬼抓人开始!") # 值得注意的点是,counter 的值是从 0 到 11,不会到 12 for counter in range(0,12): if counter == 10: print("数到十啰,我要去抓人啰。") elif counter > 10: print("原来时间已经到了喔,我竟然还在发呆没去抓人。") else: # 除了等于、大于,剩下的自然就是小于的情况啰 print("现在数到 ", counter) print("游戏结束")
输出结果
鬼抓人开始! 现在数到 0 现在数到 1 现在数到 2 现在数到 3 现在数到 4 现在数到 5 现在数到 6 现在数到 7 现在数到 8 现在数到 9 数到十啰,我要去抓人啰。 原来时间已经到了喔,我竟然还在发呆没去抓人。 算了,我不玩了。
值得注意的地方是,没有 ++
、--
来做变数递增递减,到现在还是很不习惯QQ,至于 Python 为什么没有,可以参考 Python integer incrementing with ++。
好用小技巧
给多个变数单行指定同一个值
a = b = c = 10 print("a = ", a, ", b = ", b, ", c = ", c) # 输出为 10, 10, 10
给冗长或难读的 function name 指定成一个好读的别称吧 !
def just_print(var1): print(var1) custom_name = just_print # 将原本可能很长或可读性不好的 function, # 指定成一个自己好读的别称 custom_name(10) # 输出为 10
单日心得总结
先跟各位说抱歉,今天的量已经让文章长到不好阅读了,毕竟要在一篇的篇幅,把这么多东西塞进去真的很不容易,很想把基本但却占篇幅的讲完,但这是文章,不是出书QQ。
从各标题的篇幅就可以抓到 RS 觉得的重点在哪里,光是变数就占了一半,因为基础,才要更了解,希望大家可以耐住性子,真的花点时间,自己做过一次这些观念验证,找到自己的知识盲区那瞬间会很兴奋哈哈。
我是 RS,这是我的 不做怎么知道系列 文章,我们 明天见。
喜欢我的文章吗? 赶快来看看我都发了什么文章吧:我的文章目录
欢迎阅读我的上一篇: [不做怎么知道系列之Android开发者的30天后端养成故事 Day1] - 起源 #我是谁 #为什么 #目标
欢迎阅读我的下一篇: [不做怎么知道系列之Android开发者的30天后端养成故事 Day3] - 让热情烧一会儿 #别间断很重要 #Python资料结构