Mga function sa Python: def, return, argumento, *args at **kwargs, lambda, at type annotation
Ang function sa Python ay pinangalanang bloke ng code na idinedeklara gamit ang def, tinatawag sa pamamagitan ng pangalan at mga panaklong, at nagbabalik ng resulta gamit ang return; kapag walang return, nagbabalik ito ng None. Ipinapasa ang mga argumento ayon sa pagkakasunod o ayon sa pangalan, kinokolekta ng *args ang mga dagdag na positional na halaga sa tuple, ng **kwargs ang mga dagdag na keyword sa dictionary, at ang lambda ay gumagawa ng maikling anonymous function mula sa iisang ekspresyon.
Ang function sa Python ay bahagi ng code na may pangalan, na maaaring tawagin nang maraming beses na may iba't ibang input. Idinedeklara ito gamit ang salitang def, tumatanggap ng mga halaga sa pamamagitan ng mga parameter, at nagbibigay ng resulta gamit ang return. Ang mga function ang pangunahing paraan para gawing malinaw at nasusubok na mga hakbang ang mahabang script.
Paano magdeklara ng function: def sa Python
Nagsisimula ang deklarasyon ng function sa def, sinusundan ng pangalan, mga parameter sa loob ng panaklong, at tutuldok. Ang katawan ay isinusulat na may indentation na apat na espasyo — hindi palamuti ang indentation sa Python, kundi bahagi ng sintaks.
def greet(name):
"""Nagbabalik ng pagbati para sa user."""
return f"Kumusta, {name}!"
print(greet("Anna")) # Kumusta, Anna!
Ang string na nasa triple quote kaagad pagkatapos ng header ay docstring, ang dokumentasyon ng function. Ito ang ipinapakita ng help(greet) at ng mga suhestiyon ng editor. Ayon sa PEP 8, isinusulat sa snake_case ang mga pangalan ng function: add_expense, get_rate.
Ang linyang def greet(name): ay tinatawag na signature ng function: pangalan kasama ang listahan ng mga parameter (at mga annotation, kung meron). Sa pamamagitan ng signature, nauunawaan ng nagbabasa kung paano ito tatawagin nang hindi tinitingnan ang katawan.
Ano ang ginagawa ng return sa Python
Tinatapos ng return ang function at ibinibigay ang halaga sa tumawag dito. Hindi na tatakbo ang code pagkatapos ng return na naisagawa na. Kapag walang return o walang halaga ang return, magbabalik ang function ng None.
def area(w, h):
w * h # kinalkula ang resulta at itinapon
print(area(3, 4)) # None
def area(w, h):
return w * h
print(area(3, 4)) # 12
Ang nakalimutang return ay isa sa pinakakaraniwang pagkakamali ng baguhan: "gumagana" ang function, pero None ang ibinabalik nito, at lumilitaw ang error sa susunod na linya. Puwede ring magbalik ng ilang halaga — sa totoo, iisang tuple ito na madaling i-unpack:
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([4, 1, 9])
print(low, high) # 1 9
Nakatutulong ang maagang return na maiwasan ang sobrang nesting: unang inaalis ang mga espesyal na kaso, saka isinusulat ang pangunahing lohika.
def discount(price, is_member):
if price <= 0:
return 0
if not is_member:
return price
return price * 0.9
Mga argumento ng function sa Python: positional at keyword
Ang mga parameter ay mga pangalan sa deklarasyon ng function, at ang mga argumento ay mga halagang ipinapasa sa pagtawag. Maaaring ipasa ang mga argumento ayon sa pagkakasunod (positional) o ayon sa pangalan (keyword). Ginagawang self-documenting ng keyword na argumento ang tawag, at hindi na mahalaga ang pagkakasunod.
def add_expense(title, amount, category="iba"):
return {"title": title, "amount": amount, "category": category}
add_expense("Kape", 250) # positional
add_expense(amount=250, title="Kape") # keyword
add_expense("Taksi", 600, category="transport") # halo
Opsyonal ang parameter na may default na halaga. Mga tuntunin: ang mga parameter na may default ay nasa likod ng mga kinakailangan, at sa pagtawag, nauuna ang positional na argumento bago ang keyword. Kung hindi, magbibigay ang Python ng SyntaxError.
Bitag: mutable na default na halaga
Kinakalkula nang isang beses ang default na halaga — sa oras na tumakbo ang linyang def, at hindi sa bawat tawag. Kapag listahan o dictionary ito, iisa lang ito para sa lahat ng tawag.
def add_item(item, acc=[]):
acc.append(item)
return acc
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] — "naaalala" ng listahan ang nakaraang tawag
Ang tamang gawin ay None bilang default, at paggawa ng bagong object sa loob:
def add_item(item, acc=None):
if acc is None:
acc = []
acc.append(item)
return acc
*args at **kwargs: anumang bilang ng argumento
Kinokolekta ng asterisk bago ang parameter ang lahat ng dagdag na positional na argumento sa tuple, at ng dalawang asterisk ang lahat ng dagdag na keyword na argumento sa dictionary. Ang mga pangalang args at kwargs ay kombensiyon lang; ang mahalaga ay ang mga asterisk mismo.
def total(*args):
return sum(args)
print(total(100, 250, 40)) # 390
def make_user(name, **kwargs):
user = {"name": name}
user.update(kwargs)
return user
print(make_user("Anna", city="Cebu", age=30))
# {'name': 'Anna', 'city': 'Cebu', 'age': 30}
Ginagamit din ang parehong asterisk sa kabaligtaran na direksiyon — sa pagtawag, inu-unpack nila ang sunod-sunod na datos o dictionary bilang mga argumento:
values = [3, 4]
print(pow(*values)) # 81
opts = {"sep": " | ", "end": "\n"}
print("a", "b", **opts) # a | b
Positional-only at keyword-only na mga parameter
Ang slash na / at ang asterisk na * sa listahan ng parameter ay gumagana na parang harang: lahat ng nasa unahan ng / ay ipinapasa lamang ayon sa pagkakasunod (lumitaw ang sintaks sa Python 3.8, PEP 570), at lahat ng nasa likod ng * ay ipinapasa lamang ayon sa pangalan.
def convert(amount, /, *, rate, currency="USD"):
return round(amount / rate, 2), currency
convert(100, rate=90.5) # (1.1, 'USD')
convert(amount=100, rate=90.5) # TypeError: amount ay ipinapasa lamang nang positional
convert(100, 90.5) # TypeError: rate — pangalan lamang
Pinipigilan ng keyword-only na mga parameter ang kalituhan sa mga tawag gaya ng convert(100, 90.5, "EUR"), kung saan hindi malinaw kung ano ang ano.
Saklaw ng variable: tuntunin ng LEGB
Hinahanap ng Python ang pangalan ng variable sa ganitong kadena: Local (sa loob ng function) → Enclosing (sa labas na function) → Global (sa antas ng module) → Built-in (mga built-in na pangalan gaya ng len). Puwedeng basahin ang global na variable sa loob ng function, pero para bigyan ito ng bagong halaga, kailangan ang deklarasyong global.
limit = 1000
def check(amount):
return amount > limit # pagbasa ng global — puwede
def raise_limit():
global limit
limit = 2000 # kung wala ang global, magkakaroon ng lokal na variable
Sa praktika, mas mabuting iwasan ang global: mahirap subukan ang function na nagbabago ng panlabas na estado. Mas mainam na tumanggap ng halaga bilang argumento at magbalik ng resulta.
Nested na function at closure
Maaaring ideklara ang function sa loob ng isa pang function. Nakikita ng nested na function ang mga variable ng panlabas kahit tapos na ang panlabas — ito ang tinatawag na closure. Para baguhin ang ganitong variable, ginagamit ang nonlocal.
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
c = make_counter()
print(c(), c(), c()) # 1 2 3
Nakabatay ang mga decorator at mga factory ng function sa mga closure.
Ang function ay isa ring object
Sa Python, ordinaryong object ang function: maaaring ilagay sa variable, ipasa sa ibang function, ibalik mula sa function, o itago sa dictionary. May mga attribute ito: __name__, __doc__, __defaults__, __annotations__.
def double(x):
return x * 2
f = double
print(f(5), f.__name__) # 10 double
print(list(map(double, [1, 2, 3]))) # [2, 4, 6]
Lambda sa Python: mga anonymous function
Ang lambda function ay maikling function na walang pangalan, at ang katawan nito ay iisang ekspresyon. Awtomatikong ibinabalik ang resulta ng ekspresyon, kaya hindi na isinusulat ang return.
square = lambda x: x ** 2
print(square(4)) # 16
expenses = [("Kape", 250), ("Taksi", 600), ("Tanghalian", 450)]
expenses.sort(key=lambda e: e[1], reverse=True)
print(expenses) # [('Taksi', 600), ('Tanghalian', 450), ('Kape', 250)]
print(list(filter(lambda n: n % 2 == 0, range(10)))) # [0, 2, 4, 6, 8]
Angkop ang lambda bilang maikling argumento ng sorted, max, map, at filter. Hindi inirerekomenda ng PEP 8 ang pag-assign ng lambda sa variable, gaya ng square sa itaas: kung kailangan ng function ng pangalan, isulat gamit ang def — magkakaroon ito ng tamang __name__ sa traceback at puwang para sa docstring.
| def | lambda | |
|---|---|---|
| Pangalan | mayroon | wala (<lambda>) |
| Katawan | anumang bilang ng pahayag | iisang ekspresyon |
| return | tahasan | hindi tahasan |
| Docstring, annotation | oo | hindi |
| Saan angkop | saanman | maikling key o callback |
Type annotation: mga pahiwatig, hindi pagsusuri
Inilalarawan ng annotation ang inaasahang uri ng mga parameter at ng resulta. Hindi sinusuri ng Python ang mga ito habang tumatakbo: tatanggapin ng function na may x: int ang string nang walang problema. Ang mga panlabas na kasangkapan — mypy, pyright, ty — at ang editor na nagpapakita ng error bago pa patakbuhin ang code ang nagsusuri nito.
def add_expense(title: str, amount: float, category: str = "iba") -> dict[str, object]:
return {"title": title, "amount": amount, "category": category}
def area(w: float, h: float) -> float:
w * h # mypy: Missing return statement
Maaaring patakbuhin ang pagsusuri nang walang pag-install gamit ang uvx mypy .. Ipinapakita ng halimbawa sa itaas ang kapakinabangan ng annotation: ang nakalimutang return sa -> float ay agad na nahuhuli ng analyzer.
Mula Python 3.12 (PEP 695), isinusulat ang generic na function nang walang TypeVar: inilalagay ang type parameter sa square bracket, at idinedeklara ang alias ng uri gamit ang salitang type.
def first[T](xs: list[T]) -> T:
return xs[0]
type Money = int | float
Sa Python 3.14 (PEP 649), naging lazy ang mga annotation: kinakalkula ang mga ito sa unang pagkakataong gamitin, kaya maaaring tukuyin ang klase na idineklara sa ibaba nang walang quote, at hindi na kailangan ang from __future__ import annotations.
"Hindi ipinasa" o "ipinasa ang None": sentinel sa 3.15
Hindi natutukoy ng None bilang default kung hindi ipinasa ang argumento o sinadyang ipinasa ang None. Sa loob ng maraming taon, sinosolusyunan ito gamit ang sariling placeholder:
_MISSING = object()
def get_rate(currency, default=_MISSING):
rates = {"USD": 90.5}
if currency in rates:
return rates[currency]
if default is _MISSING:
raise KeyError(currency)
return default
Sa Python 3.15, lumitaw ang built-in na function na sentinel (PEP 661): ang MISSING = sentinel("MISSING") ay gumagawa ng natatanging marker na may malinaw na repr, nananatili ang sarili nitong anyo kapag kinopya, nae-serialize gamit ang pickle, at magagamit sa annotation gaya ng float | MISSING. Sa mas lumang bersyon, gumagana pa rin ang paraan gamit ang object().
Karaniwang pagkakamali sa mga function
- Nakalimutan ang return —
Noneang ibinabalik ng function. - Nakalimutan ang panaklong — ang
print(greet)ay magpi-print ng object ng function, hindi ng resulta ng tawag. - Mutable na default na halaga — iisang listahan para sa lahat ng tawag.
- Maling bilang ng argumento —
TypeError: greet() missing 1 required positional argument: 'name'. - Pangalang kapareho ng built-in — ang function na
listosumay tatakpan ang built-in.
Buod
Idinedeklara ang mga function sa Python gamit ang def, nagbabalik ng resulta gamit ang return, at tumatanggap ng argumento ayon sa pagkakasunod o pangalan. Nagbibigay ng kakayahang umangkop ang *args at **kwargs, ng higpit sa tawag ang / at *, ng pagiging maikli ang lambda kapag kailangan ng isang beses na function, at ang type annotation kasama ng mypy ay humuhuli ng error bago patakbuhin. Tinatalakay ito nang praktikal sa kurso ng Python: hinahati ang tagasubaybay ng gastos sa mga function na may annotation at sinusuri gamit ang mypy.
Mga madalas itanong
Ano ang pagkakaiba ng parameter at argumento?
Ang parameter ay pangalan sa deklarasyon ng function, at ang argumento ay partikular na halagang ipinasa sa pagtawag. Sa def greet(name), ang name ay parameter; sa greet("Anna"), ang string na "Anna" ay argumento.
Maaari bang tawagin ang function bago ito ideklara?
Sa antas ng module, hindi — dapat naisagawa muna ang linyang def bago ang tawag, kung hindi ay NameError. Pero sa loob ng ibang function, puwedeng tawagin ang function na nasa ibaba, basta mangyari ang tawag pagkatapos ng deklarasyon nito.
Ilang halaga ang maibabalik ng function?
Pormal, isa lang, pero puwede itong tuple: ang return a, b ay nagbabalik ng tuple na may dalawang elemento, na maaaring i-unpack bilang x, y = f().
Kailangan ba talagang maglagay ng type annotation?
Hindi, gumagana ang Python nang wala ito. Pero sa code na binabasa ng ibang tao, malaki ang naitutulong ng annotation sa maintenance, at nahuhuli ng mypy o pyright ang mga error bago patakbuhin.
Maaari bang maglagay ng if sa lambda?
Maaari lang ang conditional expression: lambda x: "pares" if x % 2 == 0 else "di-pares". Hindi pinapayagan sa loob ng lambda ang mga pahayag, loop, at assignment.
Detalyadong tinatalakay ang paksang ito, may praktis, sa kursong “Python 3.15: от новичка до профи”.
Pumunta sa kurso