python指南(2):函數,對象和模塊

函數

函數的定義從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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章