Python 入门笔记

前言 :

Python 是一门相对比较好上手的程序语言,简洁的表述与直觉的语句使许多人易於上手;笔者作为一个初学者,想在学习 python 的过程中留一些笔记,也希望可以帮助到其他正在学习的人。

笔记目录:
-1. 基础概念与语法速览
-2. 未定

基础概念与语法速览

1. 基本资料型态与内建容器

python 作为动态型语言,其变数的资料型态(data type)是在运行时(Rum-time)动态决定的,因此变数的宣告方式也相当直观;而对於变数与变数之间的运算,运算结果的资料型态也是动态决定的,因此不用苦思储存时的型别为何。然而动态语言的特性相对上也增加了程序设计师的责任,需要去注意这些隐性型态转换的结果是否符合预期,虽然也有一些时候需要强制去转换计算的结果型态,不过动态的宣告与转换资料型态在大部分的情况还是相当友善的。

此外,变数的资料型态相当多样,除了基础的数字类型,例如:整数(interger)、浮点数(float)、复数(complex),布零值(bool)、字串(string)等也有提供;而构建於这些基本的型别上,你也可以自行定义类别(class)来取得对应的资料型别。定义完变数後,许多变数的内容可透过 print 函数来查看输出的值,其中与 format 函数搭配使用可以格式化输出的内容,并提升输出窗口(Console)的可读性。

eg.1-1

## I agree ';' is not a good idea in python..
int_var = 10 ; str_var = "Hello_var"   
complx_var = 4+3j ; bool_var = true ;  

# transfer into str type
str_result = int_var * str_var
print("int * str will get : {}".format(str_result)) 

## self-define -
## class cls_name(base_cls) :  for inherent.
class my_class: 
    def __init__(self, x):
        self.my_data = x
        ## \n for replace newline
        print("declare your class object \n")  
        
my_object = my_class(complx_var) 
print("my_object copied the complx var : {}\n".format(
        my_object))

容器(Container),以上述的内建型别为基础,用於储存、提取这些型别所创建的物件;而每种容器都提供了一种储存资料的特殊方式,例如:串列(list)塑造一维的向量结构,字典(dict)塑造了键值对(key-value pair)的结构,元组(tuple)则塑造了一个不可变动的有序组(ordered),而 Python 内建的容器也相当丰富,包含以上的各个容器类型。

Python 内建各种类型的容器使我们在开发和一些特定场景的应用上能较好的实现相关功能,例如两台电脑进行网路资料传输时,有时会运用 Dequeue 作为传输间的暂存区,以实现具优先权的资料传输作业;其中,传送端(Server)将优先权较高的资料插入前头(Front-end),而优先权较低的资料则插入尾端(Back-end),此时接收端(Client)持续从资料前头插入资料,以索取资料内容。

以上较为严谨、学术的相关概念,可能就要回到资料结构、演算法等相关学科了,不过作为一个使用者,我们仍可按着所见及所得(WYSIWYG)的观点去认识并使用这些基本的容器。

以笔者自身私心的角度来看,比较常用的容器有(内建):
1.串列(list) 2.字典(dict) 3.元组(tuple)
其余在 collection package 里比较好用的有 :
1.双头队列(deque) 2.命名元组(namedtuple)
@ 备注 : 上述的英文简写为显示的(explicitly)物件定义介面

关於上述容器的API坊间已有许多文章介绍,故不在此赘述;实际上运用的场景:

# Basic API --
# Explicitly define --
int_lst = list([1, 2, 3])
# Implicitly define --
chr_lst = ['a', 'b', 'c']

mix_lst = []
mix_lst.append([ int_lst[:2] ])  # [ [[1, 2]] ] -> mixed list
mix_lst.append(chr_lst)  # [ [[1, 2]], ['a', 'b', 'c']]

## Access the value in list with multi-dimension --
print(mix_lst[0][0][1])  # output : 2
print(mix_lst[1][1])     # output : 'b'
print(mix_lst[0][0])     # output : [1], not 1 !!

2. 浅谈函数

函数(function)的功能以实务的角度而言,像是将重复性高的程序(程序码)包装成 "一份" 程序码片段,并在需要时呼叫它;这样可以大幅减少重复的程序码,并降低程序整体的复杂性。这个概念对於接触过程序语言的人应该不陌生,而在 python 中定义函数也是一件简单的事情;通常对於时常呼叫的函数,我们可以使用关键字 def 来产生 "函数物件" (函数也是前述所提到的物件),而对於程序内容"简单"的函数,python 也提供了 lambda 关键字来产生匿名函数(anonymous function),使得函数可以像免洗碗筷--用完就丢的便利功能。

以下提供简短程序码范例,来计算并印出各个学生所有科目的平均分数:

# define function to show the result
def show_result(stud_dict):
    print("name : {} \n.format(stdu_dict['name']))
    print("avg score : {} \n".format(stdu_dict['score']))
    
if __name__ == "__main__":
    stud_lst = ["John", "Marie", "Harry", "Kali", "Joseph"]
    # score information
    math_score = [50, 75, 66, 86, 12]
    art_score = [40, 99, 78, 23, 63]
    lang_score = [90, 70, 56, 88, 42]
    scores_tup = [scores for scores in zip(math_score, art_score, lang_score)]
    
    # lambda function with simple procedure
    get_int_avg = lambda scores : int(sum(scores)/len(scores)) 
    
    for (name, scores) in zip(stud_lst, scores_tup):
        avg_score = get_int_avg(scores)
        show_result({'name':name, 'score':avg_score})

3. 浅谈类别

类别(class) 像是一个模板(template),用於创建对应的物件(object),这些物件使的我们能将其对应到设计的系统,并藉由物件间的交流达成我们所想像的业务逻辑;如前所述,在 Python 中我们能自己定义类别,并创建许多物件来达成以上的需求。

在此举一个具体的例子,若我们想要设计学生的成绩管理系统;或许可以从使用者的角度设想,这个系统可能需要一个使用者的登入介面(User Interface)、一个接收与传递操作命令的管理者(daemon, 在系统中比较常用这个名子),以及一个背後的资料储存库(Data Storage)来纪录分数。

从抽象的角度来看 Python 的类别,我们需要定义类别名(Class name)、类别属性(Attribute)、类别方法(Method);其中,类别属性就是位於该类别的变数,而类别方法则是位於该类别的函数,该函数可以操作与控制类别属性,已使物件藉由与外界的互动能改变自身的状态。为详述一些细节,我们分别说明类别属性和类别方法的定义:

  1. 定义类别属性
    一般而言,我们可以先实例化(instance)出物件,再定义类别属性:
class Person:  ## Person is class name.
    pass
person = Person()

## add the attribute via '.' dot operator
person.name = "Kali"  
person.age = 15
person.weight = 64.5
## Finally, it's ugly and hard to maintain the class..
  1. 定义类别方法
    正如一般定义函数的方式,我们使用 def 语句定义类别的方法;其中,一个关键的类别方法是 init,正如其名它帮助我们初始化该类别的内容,这些内容包括前述类别属性的定义,我们可以将类别属性存在一个 self 变数中,该变数就可以帮助我们良好的管理每个类别的属性与方法:
# person.py file

class Person:
    def __init__(self, my_name, my_age, my_weight):
        self.name = my_name
        self.age = my_age
        self.weight = my_weight
    def print_info():
        print("name : ", self.name)
        print("age : ", self.age)
        print("weight : ", self.weight)
        
Im_Kali = Person("Kali", 15, 64.5)

至此,相信读者已对类别实现的语法有了初步的认识,而在众多情况中物件间并非是完全独立的,有时多个物件间有许多关联(association);关於这种关联,我们在这里初浅列举一下(毕竟这是一个广大的议题)。物件间的关联以其耦合程度(相依程度),由小至大可分为两种:have-a 关系、is-a 关系;为便於举例,设有两个物件A, B,兹以下分述之。

  1. have-a 关系:B物件被包含并所有於A物件中,也就是若没有A物件被定义,B物件也不会单独存在。
  2.  is-a 关系:B物件是一种A物件,并且"A物件不是B物件",换言之,B物件理论上有A物件所有的属性与方法,而A物件则没有B物件在"继承"後所增添的属性与方法。
    直接下个具体的例子:
# hava-a association
class A:
    class B:
            def __init__(_b):
                self.attr_b = _b
    def __init__(self, _b):
        self.B_obj = B(_b)
    


有了上述的基础知识後,我们可以初步运用到之前成绩管理系统的例子中,而能写出简易的程序码来定义所运用到的物件:

from some_gui_lib import basic_UI
import person

class Student(person.Person):
    def __init__(self, my_name, my_age, my_weight, 
                        stud_id, score_sheet):
        self.name = name
        self.age = age
        self.weight = weight
        self.stud_id = stud_id
        self.score_sheet = score_sheet
        super(person.Person).__init__(self)
        
    def get_stud_id(self):
        return self.stud_id

    def get_stud_score(self):
        return self.score_sheet
    
class stud_score_UI(win):
    def __init__(self):
        ## initial inherited class via super keyword
        super(stud_score_UI).__init__(self)  
        self.set_UI_compnt()
        
    # you can omit this part 
    def set_UI_compnt(self):
        #param = {...} ; layout_param = {...}
        self.entry(**param).set_layout(**layout_param)
        self.btn(**param).set_layout(**layout_param)
        
if __name__ == "__main__":
    win = basic_UI.win()
    win.main_loop()

在上述的例子中,我们的程序无法良好的运作(先撇开一些未实作的GUI和参数设定),原因是类别 "stud_score_UI" 提供的功能暂且只是原封不动地回传初始化时的参数,也就是我们并未对资料作储存与处理,中间也没有守护程序(daemon)帮助我们做资料的交换与程序间的沟通;不过我们有机会在後面的例子中继续还善这个程序(空壳)。

即使如此,上述程序仍非常简要递给出一个系统中 GUI 的雏形,他并未完成任何後端(backend)的工作,他只接收并回应使用者对他的请求,与此同时,使用者在使用整个软件的过程中也只会跟这个GUI产生直接的互动,这样的概念也多少实现了封装(encapsulation)的思想,也就是说使用者依然 "可以看到" 一些类别中的重要属性,。

3.For loop 和 一些迭代物件

广义而言,虽然容器 "大多数" 都有提供储存、删除、更改物件的对应函数,但实现这些操作的方式却仍有所区别,因为容器储存资料的方式不尽相同;不过在遍历容器内的各个物件上,python 却提供了一种普遍的方式来让我们存取容器中的物件。

如同前述所言,容器本身也是一种物件,有对应的许多

int_lst = list([1, 2, 3])
chr_lst = ['a', 'b', 'c']
# Counter-based for loop -- not recommand..
for idx in range(0, len(int_lst)):  # len(.) -> length of obj 
    print(int_lst[idx])
    
# From Counter-based into range-based for loop
for item in chr_lst:
    print(item)

## How about iterative togather in the for loop ?!
# Zip the items into iterator..
mix_iter= zip(int_lst, chr_lst)  
# Added the index in the iteration..
for idx, (int_item, chr_item) in enumerate(mix_iterator):
    print("The {}-st element ; int : {} ; chr : {}".format(
            idx, int_item, chr_item))

3.Duck type与物件方法

Duck type 源起於一个语言哲学上的议题,如果一个未知的生物有翅膀、会游泳、会呱呱叫,在某种语言的脉络下,将这种未知的生物称为鸭子是否有其合理之处??

python 内的变数(variable)皆为物件(object),每个物件内都有相应的方法(method)可供使用,一般可以用函数 dir 查看物件内的方法,因此在进行运算时,许多运算子(operator)也会参照运算元的方法来决定计算的方式,例如:复写 eq, add, div 等方法将改变物件之间的比较、相加、除法等行为;许多 python 的概念与细节也往往取决於该物件所拥有的方法是如何实践的。

class my_cls:
    def __init__(self, val):
        self.val = val
        
    def call():
        print("my class is callable..")
        
    def __add__(self, y):
        print("we'll figure out x + y")
        return self.val + y
    
    def __eq__(self, y):
        return (str(self.x) == y)
        
    
my_obj = my_cls(val=10)

## Now, you know when should you use the "..'..'." for present the string..
# when '...' in the string of "...".
print("The following output the method of 'my_obj' \n")  

dir(my_obj)
var_y = 15 
print("addition : {}".format(my_obj + var_y))
str_var_1 = "15" ; str_var_2 = "10"
print("Show strictly equal : {0} for {1}".format( \
        (my_obj == str_var_1), str_var_1))

## format support {num} for format the order of output.
print("Show strictly equal : {1} for {0}".format( \
        str_var_2, (my_obj == str_var_2)))

不过从 Duck Type 的观念来看,运行 python 有时可能难以确定变数的 "型别",这容易造成一些程序架构设计上的难题;难以运用 "型别的概念来"

// 未完...2020/1/24


<<:  Gulp Babel ES6 编译(1) DAY83

>>:  请问如何用Jquery或javascript写出由卷轴控制太阳系的轨迹

Chapter4 附录 贝兹曲线

前言 什麽是贝兹曲线?它能创造一连串平滑的曲线,被应用在PS和AI中的钢笔、以及常见的CSS Ani...

那些被忽略但很好用的 Web API / Share

与你分享的快乐,胜过独自拥有 现代人看到有趣的网页、新闻、消息等等时,最常做的事情就是分享到社群帐...

什麽是统一建模语言 (UML)?

UML是统一建模语言的简称,是一种标准化建模语言,由一组集成的图表组成,旨在帮助系统和软件开发人员指...

基本面要看那些?

又到了每月公布营收的时间点了,随着营收的公布,可说是几家欢乐几家愁。 很多人认为,要在股市获利,就必...

[第二十七只羊] 迷雾森林舞会XVI 整理客厅,首页列表介面

天亮了 昨晚是平安夜 关於迷雾森林故事 悍跳 兔兔就这样使出吃奶的力气让大家停下舞步 兔兔暴怒地大喊...