函數
函數的定義從def
開始,下面定義了一個入參爲x,y的函數,
>>> def a(x,y='誰???'): # 如果y沒有被輸入,我就默認你是'誰???'
... print('我是', x, '你是', y)
...
>>> a(1, int)
我是 1 你是 <class 'int'>
>>> a(1)
我是 1 你是 誰???
可見,python對參數的類型是不做限制的。
函數還可以擁有返回值
>>> def fib(x, u = 0, v = 1):
... if x == 0:
... return 0, u + v
... else:
... 次數, 答案 = fib(x - 1, v, u + v)
... return 次數 + 1, 答案
...
>>> fib(1)
(1, 2)
>>> fib(2)
(2, 3)
>>> fib(3)
(3, 5)
>>> fib(4)
(4, 8)
>>> fib(5)
(5, 13)
可見,返回值如果是r1,r2,…,那麼會被構造爲(r1,r2,…)的元組。
當我們再構造fib函數的語句時,可用的變量爲向前探的所有變量,這裏面自然包括fib。這種函數編寫方式又稱爲遞歸。
在python中,遞歸會消耗大量資源,請謹慎使用。
對象
在python中,一切事物都是對象。下面我們定義一個函數
,但是不同的是使用class關鍵字。
>>> class ReturnAnObject:
... pass
...
>>> ReturnAnObject()
<__main__.ReturnAnObject object at 0x000001EC7520D6D8>
>>> type(ReturnAnObject())
<class '__main__.ReturnAnObject'>
見到type的返回值,你是不是心有了然。原來int, float, str ...
都是這麼來的。
一個class的屬性可以被放置入域中,如下:
class ReturnAnObject:
property1
property2
property3
...
>>> class ReturnAnObject:
... a = 1
... b = 2
...
... def mymethod(self):
... print('my method')
...
>>> a = ReturnAnObject()
>>> a.a
1
>>> a.b
2
>>> a.mymethod()
my method
所有包含在裏面的property都是ReturnAnObject
這個對象的成員(member)
你這一看,class不就是function麼?修改一下class的魔法成分,ReturnAnObject
不過如此。
def ReturnAnObject():
obj = object()
obj.a = 1
obj.b = 2
def mymethod(self):
print('my method')
obj.mymethod = mymethod
return obj
那麼mymethod的self參數是什麼?先繼續往下看。
如果需要爲ReturnAnObject
添加參數,我們需要一些魔法成分。
對象的魔法
所謂魔法,就是在對象中被聲明爲__XXX__
的函數
先列舉一些比較常用或具有代表性的方法
__init__ # a = Class(...) 等價於 a = Class.__init__(a = object(), ...) (一般來說)
__lt__ # Class() < other 等價於 Class.__lt__(a, other)
__call__ # Class()(...) 等價於 a(...) 等價於 Class.__call__(a, ...)
__getattr__ # Class().Property 等價於 Class.__getattr__(a, 'Property')
__len__ # len(Class())
__str__ # str(Class())
__init__
來看這句話a = Class(...) 等價於 a = Class.__init__(a = object(), ...) (一般來說)
撇去(一般來說)
這4個字,你看了這句描述大概就明白如何爲ReturnAnObject
“函數”添加參數了。
>>> class Class:
... a = 1
... def __init__(self, a):
... print(self.a)
... self.a = a
...
>>> a = Class(2)
1
>>> a.a
2
這裏的self是從何而來的?self來源於魔法方法__new__
,但在入門時我們一般不會動這個函數,如果有興趣可以自己去了解。
python以Class的屬性爲模板,構造出了self,傳遞到__init__
時,構造行爲由我們來操控。這時候self.a
還等於1,但我們再在__init__
中將其改爲2以後,返回的對象的屬性a就變成2了。
__lt__
來看看這句話Class() < other 等價於 Class.__lt__(a, other)
好的,自行編寫__lt__
,看看下面的MyInt
對象的行爲是否符合你的猜想。
>>> a = MyInt(2)
>>> a < 2
False
>>> a < 3
True
__call__
來看看這句話Class()(...) 等價於 a(...) 等價於 Class.__call__(a, ...)
這樣看來,似乎函數這個對象只不過是<class Function>
的一個實例而已。所謂類即函數,函數也即對象。
__getattr__
Class().Property 等價於 Class.__getattr__(a, 'Property')
__len__
猜猜它的函數簽名是什麼?
__str__
猜猜它的函數簽名是什麼?
其他常用魔法方法
只要記得有這樣的方法即可,需要的時候可以自行查閱…
與__lt__
行爲類似的方法
__lt__ # a < other 等價於 Class().__lt__(a, other)
__le__ # a <= other 等價於 Class().__le__(a, other)
__eq__ # a == other 等價於 Class().__eq__(a, other)
__ne__ # a != other 等價於 Class().__ne__(a, other)
__gt__ # a > other 等價於 Class().__gt__(a, other)
__ge__ # a >= other 等價於 Class().__ge__(a, other)
__add__ # a + other 等價於 Class().__add__(a, other)
__sub__ # a - other 等價於 Class().__sub__(a, other)
__mul__ # a * other 等價於 Class().__mul__(a, other)
__truediv__ # a / other 等價於 Class().__truediv__(a, other)
__floordiv__ # a // other 等價於 Class().__floordiv__(a, other)
__mod__ # a % other 等價於 Class().__mod__(a, other)
__divmod__ # divmod(a) 等價於 Class().__divmod__(a, other)
__pow__ # a ** other 等價於 Class().__pow__(a, other)
__lshift__ # a << other 等價於 Class().__lshift__(a, other)
__rshift__ # a >> other 等價於 Class().__rshift__(a, other)
__and__ # a & other 等價於 Class().__and__(a, other)
__xor__ # a ^ other 等價於 Class().__xor__(a, other)
__or__ # a | other 等價於 Class().__or__(a, other)
__radd__ # other + a, 當 a + other 不支持時才調用這個
__rsub__ ...__ror__ # 與上類似
__iadd__ # a += other
__isub__ ... __ior__ # 與上類似
__neg__ # -a
__pos__ # +a
__invert__ # ~a
關鍵字行爲
__enter__
__exit__
# with a(...) as b:
# ...
# 相當於
# b = a.__enter__(...)
# ...
# a.__exit__()
__getitem__ # a[key] 相當於 Class.__getitem__(a, key)
__setitem__ # a[key] = value 相當於 Class.__setitem__(a, key, value)
__delitem__ # del a[key] 相當於 Class.__delitem__(a, key)
# __contains__ # x in a 相當於 Class.__contains__(a, x)
與__str__
行爲類似的方法
__bytes__
__bool__
__complex__
__int__
__float__
與__len__
行爲類似的方法
__hash__
__format__
__dir__
__reversed__
__round__
__abs__
TODO: staticmethod, classmethod, abstractmethod
TODO: property
TODO: metaclass
TODO: inheritance
模塊
每一個文件都是一個模塊
假設有下列文件
a.py
b.py
c
c/__init__.py # 空的
c/d.py
# a.py
# 使用模塊只需要 import 路徑1.路徑2.文件名即可
import b, c.d
print(b.fn(), c.d.fn())
# b.py
def fn():
return 'orz'
# c/d.py
def fn():
return 'orzz'
使用python運行程序
>> python a.py
orz orzz
最簡單的方法就這樣了,模塊的高級應用可以在有一定編程經驗以後再深入學習。
其他模塊
下面列舉了一些我覺得比較好的內建模塊
# 類型
>>> import time
>>> import datetime
>>> import collections
>>> import enum
# 方法庫
>>> import re
>>> import copy
>>> import math
>>> import itertools
>>> import functools
# 系統/IO
>>> import argparse
>>> import shutil
>>> import os.path
>>> import os
>>> import io
>>> import sys
# 並行,併發,異步編程
>>> import threading
>>> import queue
>>> import subprocess
>>> import asyncio
# 文件
>>> import json
>>> import csv
>>> import zlib
>>> import zipfile
>>> import tarfile
# 序列化
>>> import pickle
>>> import struct
# 網絡
>>> import urllib
>>> import http
# 幫助庫
>>> import logging
>>> import venv
>>> import typing
>>> import pydoc
>>> import unittest
>>> import abc